[USBAUDIO]
[reactos.git] / reactos / drivers / usb / usbaudio / pin.c
1 /*
2 * PROJECT: ReactOS Universal Audio Class Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbaudio/pin.c
5 * PURPOSE: USB Audio device driver.
6 * PROGRAMMERS:
7 * Johannes Anderwald (johannes.anderwald@reactos.org)
8 */
9
10 #include "usbaudio.h"
11
12 #define PACKET_COUNT 10
13
14
15 NTSTATUS
16 GetMaxPacketSizeForInterface(
17 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
18 IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
19 KSPIN_DATAFLOW DataFlow)
20 {
21 PUSB_COMMON_DESCRIPTOR CommonDescriptor;
22 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
23
24 /* loop descriptors */
25 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
26 ASSERT(InterfaceDescriptor->bNumEndpoints > 0);
27 while (CommonDescriptor)
28 {
29 if (CommonDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
30 {
31 EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CommonDescriptor;
32 return EndpointDescriptor->wMaxPacketSize;
33 }
34
35 if (CommonDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
36 {
37 /* reached next interface descriptor */
38 break;
39 }
40
41 if ((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
42 break;
43
44 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
45 }
46
47 /* default to 100 */
48 return 100;
49 }
50
51 NTSTATUS
52 UsbAudioAllocCaptureUrbIso(
53 IN USBD_PIPE_HANDLE PipeHandle,
54 IN ULONG MaxPacketSize,
55 IN PVOID Buffer,
56 IN ULONG BufferLength,
57 OUT PURB * OutUrb)
58 {
59 PURB Urb;
60 ULONG UrbSize;
61 ULONG Index;
62
63 /* calculate urb size*/
64 UrbSize = GET_ISO_URB_SIZE(PACKET_COUNT);
65
66 /* allocate urb */
67 Urb = AllocFunction(UrbSize);
68 if (!Urb)
69 {
70 /* no memory */
71 return STATUS_INSUFFICIENT_RESOURCES;
72 }
73
74 /* init urb */
75 Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
76 Urb->UrbIsochronousTransfer.Hdr.Length = UrbSize;
77 Urb->UrbIsochronousTransfer.PipeHandle = PipeHandle;
78 Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_START_ISO_TRANSFER_ASAP;
79 Urb->UrbIsochronousTransfer.TransferBufferLength = BufferLength;
80 Urb->UrbIsochronousTransfer.TransferBuffer = Buffer;
81 Urb->UrbIsochronousTransfer.NumberOfPackets = PACKET_COUNT;
82
83 for (Index = 0; Index < PACKET_COUNT; Index++)
84 {
85 Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset = Index * MaxPacketSize;
86 }
87
88 *OutUrb = Urb;
89 return STATUS_SUCCESS;
90
91 }
92
93 NTSTATUS
94 UsbAudioSetFormat(
95 IN PKSPIN Pin)
96 {
97 PURB Urb;
98 PUCHAR SampleRateBuffer;
99 PPIN_CONTEXT PinContext;
100 NTSTATUS Status;
101 PKSDATAFORMAT_WAVEFORMATEX WaveFormatEx;
102
103 /* allocate sample rate buffer */
104 SampleRateBuffer = AllocFunction(sizeof(ULONG));
105 if (!SampleRateBuffer)
106 {
107 /* no memory */
108 return STATUS_INSUFFICIENT_RESOURCES;
109 }
110
111 if (IsEqualGUIDAligned(&Pin->ConnectionFormat->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
112 IsEqualGUIDAligned(&Pin->ConnectionFormat->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
113 IsEqualGUIDAligned(&Pin->ConnectionFormat->Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
114 {
115 WaveFormatEx = (PKSDATAFORMAT_WAVEFORMATEX)Pin->ConnectionFormat;
116 SampleRateBuffer[2] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 16) & 0xFF;
117 SampleRateBuffer[1] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 8) & 0xFF;
118 SampleRateBuffer[0] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 0) & 0xFF;
119
120 /* TODO: verify connection format */
121 }
122 else
123 {
124 /* not supported yet*/
125 UNIMPLEMENTED;
126 FreeFunction(SampleRateBuffer);
127 return STATUS_INVALID_PARAMETER;
128 }
129
130 /* allocate urb */
131 Urb = AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
132 if (!Urb)
133 {
134 /* no memory */
135 FreeFunction(SampleRateBuffer);
136 return STATUS_INSUFFICIENT_RESOURCES;
137 }
138
139 /* FIXME: determine controls and format urb */
140 UsbBuildVendorRequest(Urb,
141 URB_FUNCTION_CLASS_ENDPOINT,
142 sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
143 USBD_TRANSFER_DIRECTION_OUT,
144 0,
145 0x01, // SET_CUR
146 0x100,
147 0x81, //FIXME bEndpointAddress
148 SampleRateBuffer,
149 NULL,
150 3,
151 NULL);
152
153 /* get pin context */
154 PinContext = Pin->Context;
155
156 /* submit urb */
157 Status = SubmitUrbSync(PinContext->LowerDevice, Urb);
158
159 DPRINT1("USBAudioPinSetDataFormat Pin %p Status %x\n", Pin, Status);
160 FreeFunction(Urb);
161 FreeFunction(SampleRateBuffer);
162 return Status;
163 }
164
165 NTSTATUS
166 USBAudioSelectAudioStreamingInterface(
167 IN PPIN_CONTEXT PinContext,
168 IN PDEVICE_EXTENSION DeviceExtension,
169 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
170 {
171 PURB Urb;
172 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
173 NTSTATUS Status;
174
175 /* grab interface descriptor */
176 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
177 if (!InterfaceDescriptor)
178 {
179 /* no such interface */
180 return STATUS_INVALID_PARAMETER;
181 }
182
183 /* FIXME selects the first interface with audio streaming and non zero num of endpoints */
184 while (InterfaceDescriptor != NULL)
185 {
186 if (InterfaceDescriptor->bInterfaceSubClass == 0x02 /* AUDIO_STREAMING */ && InterfaceDescriptor->bNumEndpoints > 0)
187 {
188 break;
189 }
190 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
191 }
192
193 if (!InterfaceDescriptor)
194 {
195 /* no such interface */
196 return STATUS_INVALID_PARAMETER;
197 }
198
199 Urb = AllocFunction(GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints));
200 if (!Urb)
201 {
202 /* no memory */
203 return USBD_STATUS_INSUFFICIENT_RESOURCES;
204 }
205
206 /* now prepare interface urb */
207 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
208
209 /* now select the interface */
210 Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
211
212 DPRINT1("USBAudioSelectAudioStreamingInterface Status %x UrbStatus %x\n", Status, Urb->UrbSelectInterface.Hdr.Status);
213
214 /* did it succeeed */
215 if (NT_SUCCESS(Status))
216 {
217 /* free old interface info */
218 if (DeviceExtension->InterfaceInfo)
219 {
220 /* free old info */
221 FreeFunction(DeviceExtension->InterfaceInfo);
222 }
223
224 /* alloc interface info */
225 DeviceExtension->InterfaceInfo = AllocFunction(Urb->UrbSelectInterface.Interface.Length);
226 if (DeviceExtension->InterfaceInfo == NULL)
227 {
228 /* no memory */
229 FreeFunction(Urb);
230 return STATUS_INSUFFICIENT_RESOURCES;
231 }
232
233 /* copy interface info */
234 RtlCopyMemory(DeviceExtension->InterfaceInfo, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
235 PinContext->InterfaceDescriptor = InterfaceDescriptor;
236 }
237
238 /* free urb */
239 FreeFunction(Urb);
240 return Status;
241 }
242
243 VOID
244 NTAPI
245 CaptureGateOnWorkItem(
246 _In_ PVOID Context)
247 {
248 PKSPIN Pin;
249 PPIN_CONTEXT PinContext;
250 PKSGATE Gate;
251 ULONG Count;
252
253 /* get pin */
254 Pin = Context;
255
256 /* get pin context */
257 PinContext = Pin->Context;
258
259 do
260 {
261 /* acquire processing mutex */
262 KsPinAcquireProcessingMutex(Pin);
263
264 /* get pin control gate */
265 Gate = KsPinGetAndGate(Pin);
266
267 /* turn input on */
268 KsGateTurnInputOn(Gate);
269
270 /* schedule processing */
271 KsPinAttemptProcessing(Pin, TRUE);
272
273 /* release processing mutex */
274 KsPinReleaseProcessingMutex(Pin);
275
276 /* decrement worker count */
277 Count = KsDecrementCountedWorker(PinContext->CaptureWorker);
278 } while (Count);
279 }
280
281
282
283 VOID
284 CaptureInitializeUrbAndIrp(
285 IN PKSPIN Pin,
286 IN PIRP Irp)
287 {
288 PIO_STACK_LOCATION IoStack;
289 PURB Urb;
290 PUCHAR TransferBuffer;
291 ULONG Index;
292 PPIN_CONTEXT PinContext;
293
294 /* get pin context */
295 PinContext = Pin->Context;
296
297 /* backup urb and transferbuffer */
298 Urb = Irp->Tail.Overlay.DriverContext[0];
299 TransferBuffer = Urb->UrbIsochronousTransfer.TransferBuffer;
300
301 /* initialize irp */
302 IoInitializeIrp(Irp, IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize), PinContext->DeviceExtension->LowerDevice->StackSize);
303
304 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
305 Irp->IoStatus.Information = 0;
306 Irp->Flags = 0;
307 Irp->UserBuffer = NULL;
308 Irp->Tail.Overlay.DriverContext[0] = Urb;
309 Irp->Tail.Overlay.DriverContext[1] = NULL;
310
311 /* init stack location */
312 IoStack = IoGetNextIrpStackLocation(Irp);
313 IoStack->DeviceObject = PinContext->DeviceExtension->LowerDevice;
314 IoStack->Parameters.Others.Argument1 = Urb;
315 IoStack->Parameters.Others.Argument2 = NULL;
316 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
317 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
318
319 IoSetCompletionRoutine(Irp, UsbAudioCaptureComplete, Pin, TRUE, TRUE, TRUE);
320
321 RtlZeroMemory(Urb, GET_ISO_URB_SIZE(PACKET_COUNT));
322
323 /* init urb */
324 Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
325 Urb->UrbIsochronousTransfer.Hdr.Length = GET_ISO_URB_SIZE(10);
326 Urb->UrbIsochronousTransfer.PipeHandle = PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle;
327 Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_START_ISO_TRANSFER_ASAP;
328 Urb->UrbIsochronousTransfer.TransferBufferLength = PinContext->DeviceExtension->InterfaceInfo->Pipes[0].MaximumPacketSize * 10;
329 Urb->UrbIsochronousTransfer.TransferBuffer = TransferBuffer;
330 Urb->UrbIsochronousTransfer.NumberOfPackets = PACKET_COUNT;
331 Urb->UrbIsochronousTransfer.StartFrame = 0;
332
333 for (Index = 0; Index < PACKET_COUNT; Index++)
334 {
335 Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset = Index * PinContext->DeviceExtension->InterfaceInfo->Pipes[0].MaximumPacketSize;
336 }
337 }
338
339
340 VOID
341 NTAPI
342 CaptureAvoidPipeStarvationWorker(
343 _In_ PVOID Context)
344 {
345 PKSPIN Pin;
346 PPIN_CONTEXT PinContext;
347 KIRQL OldLevel;
348 PLIST_ENTRY CurEntry;
349 PIRP Irp;
350
351 /* get pin */
352 Pin = Context;
353
354 /* get pin context */
355 PinContext = Pin->Context;
356
357 /* acquire spin lock */
358 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
359
360 if (!IsListEmpty(&PinContext->IrpListHead))
361 {
362 /* sanity check */
363 ASSERT(!IsListEmpty(&PinContext->IrpListHead));
364
365 /* remove entry from list */
366 CurEntry = RemoveHeadList(&PinContext->IrpListHead);
367
368 /* release lock */
369 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
370
371 /* get irp offset */
372 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
373
374 /* reinitialize irp and urb */
375 CaptureInitializeUrbAndIrp(Pin, Irp);
376
377 KsDecrementCountedWorker(PinContext->StarvationWorker);
378
379 /* call driver */
380 IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
381 }
382 else
383 {
384 /* release lock */
385 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
386
387 KsDecrementCountedWorker(PinContext->StarvationWorker);
388 }
389 }
390
391
392
393 NTSTATUS
394 InitCapturePin(
395 IN PKSPIN Pin)
396 {
397 NTSTATUS Status;
398 ULONG Index;
399 ULONG BufferSize;
400 ULONG MaximumPacketSize;
401 PIRP Irp;
402 PURB Urb;
403 PPIN_CONTEXT PinContext;
404 PIO_STACK_LOCATION IoStack;
405 PKSALLOCATOR_FRAMING_EX Framing;
406 PKSGATE Gate;
407
408
409 /* set sample rate */
410 Status = UsbAudioSetFormat(Pin);
411 if (!NT_SUCCESS(Status))
412 {
413 /* failed */
414 return Status;
415 }
416
417 /* get pin context */
418 PinContext = Pin->Context;
419
420 /* lets get maximum packet size */
421 MaximumPacketSize = GetMaxPacketSizeForInterface(PinContext->DeviceExtension->ConfigurationDescriptor, PinContext->InterfaceDescriptor, Pin->DataFlow);
422
423 /* initialize work item for capture worker */
424 ExInitializeWorkItem(&PinContext->CaptureWorkItem, CaptureGateOnWorkItem, (PVOID)Pin);
425
426 /* register worker */
427 Status = KsRegisterCountedWorker(CriticalWorkQueue, &PinContext->CaptureWorkItem, &PinContext->CaptureWorker);
428 if (!NT_SUCCESS(Status))
429 {
430 /* failed */
431 return Status;
432 }
433
434 /* initialize work item */
435 ExInitializeWorkItem(&PinContext->StarvationWorkItem, CaptureAvoidPipeStarvationWorker, (PVOID)Pin);
436
437 /* register worker */
438 Status = KsRegisterCountedWorker(CriticalWorkQueue, &PinContext->StarvationWorkItem, &PinContext->StarvationWorker);
439 if (!NT_SUCCESS(Status))
440 {
441 /* failed */
442 KsUnregisterWorker(PinContext->CaptureWorker);
443 }
444
445 /* lets edit framing struct */
446 Framing = (PKSALLOCATOR_FRAMING_EX)Pin->Descriptor->AllocatorFraming;
447 Framing->FramingItem[0].PhysicalRange.MinFrameSize =
448 Framing->FramingItem[0].PhysicalRange.MaxFrameSize =
449 Framing->FramingItem[0].FramingRange.Range.MinFrameSize =
450 Framing->FramingItem[0].FramingRange.Range.MaxFrameSize =
451 MaximumPacketSize;
452
453 /* calculate buffer size 8 irps * 10 iso packets * max packet size */
454 BufferSize = 8 * PACKET_COUNT * MaximumPacketSize;
455
456 /* allocate pin capture buffer */
457 PinContext->BufferSize = BufferSize;
458 PinContext->Buffer = AllocFunction(BufferSize);
459 if (!PinContext->Buffer)
460 {
461 /* no memory */
462 return STATUS_INSUFFICIENT_RESOURCES;
463 }
464 KsAddItemToObjectBag(Pin->Bag, PinContext->Buffer, ExFreePool);
465
466 /* init irps */
467 for (Index = 0; Index < 8; Index++)
468 {
469 /* allocate irp */
470 Irp = AllocFunction(IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize));
471 if (!Irp)
472 {
473 /* no memory */
474 return STATUS_INSUFFICIENT_RESOURCES;
475 }
476
477 /* initialize irp */
478 IoInitializeIrp(Irp, IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize), PinContext->DeviceExtension->LowerDevice->StackSize);
479
480 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
481 Irp->IoStatus.Information = 0;
482 Irp->Flags = 0;
483 Irp->UserBuffer = NULL;
484
485 IoStack = IoGetNextIrpStackLocation(Irp);
486 IoStack->DeviceObject = PinContext->DeviceExtension->LowerDevice;
487 IoStack->Parameters.Others.Argument2 = NULL;
488 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
489 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
490
491 IoSetCompletionRoutine(Irp, UsbAudioCaptureComplete, Pin, TRUE, TRUE, TRUE);
492
493 /* insert into irp list */
494 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
495
496 /* add to object bag*/
497 KsAddItemToObjectBag(Pin->Bag, Irp, ExFreePool);
498
499 /* FIXME select correct pipe handle */
500 Status = UsbAudioAllocCaptureUrbIso(PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle,
501 MaximumPacketSize,
502 &PinContext->Buffer[MaximumPacketSize * PACKET_COUNT * Index],
503 MaximumPacketSize * PACKET_COUNT,
504 &Urb);
505
506 DPRINT1("InitCapturePin Irp %p Urb %p\n", Irp, Urb);
507
508 if (NT_SUCCESS(Status))
509 {
510 /* get next stack location */
511 IoStack = IoGetNextIrpStackLocation(Irp);
512
513 /* store urb */
514 IoStack->Parameters.Others.Argument1 = Urb;
515 Irp->Tail.Overlay.DriverContext[0] = Urb;
516 }
517 else
518 {
519 /* failed */
520 return Status;
521 }
522 }
523
524 /* get process control gate */
525 Gate = KsPinGetAndGate(Pin);
526
527 /* turn input off */
528 KsGateTurnInputOff(Gate);
529
530 return Status;
531 }
532
533 NTSTATUS
534 InitStreamPin(
535 IN PKSPIN Pin)
536 {
537 UNIMPLEMENTED
538 return STATUS_NOT_IMPLEMENTED;
539 }
540
541
542
543
544 NTSTATUS
545 NTAPI
546 USBAudioPinCreate(
547 _In_ PKSPIN Pin,
548 _In_ PIRP Irp)
549 {
550 PKSFILTER Filter;
551 PFILTER_CONTEXT FilterContext;
552 PPIN_CONTEXT PinContext;
553 NTSTATUS Status;
554
555 Filter = KsPinGetParentFilter(Pin);
556 if (Filter == NULL)
557 {
558 /* invalid parameter */
559 return STATUS_INVALID_PARAMETER;
560 }
561
562 /* get filter context */
563 FilterContext = Filter->Context;
564
565 /* allocate pin context */
566 PinContext = AllocFunction(sizeof(PIN_CONTEXT));
567 if (!PinContext)
568 {
569 /* no memory*/
570 return STATUS_INSUFFICIENT_RESOURCES;
571 }
572
573 /* init pin context */
574 PinContext->DeviceExtension = FilterContext->DeviceExtension;
575 PinContext->LowerDevice = FilterContext->LowerDevice;
576 InitializeListHead(&PinContext->IrpListHead);
577 InitializeListHead(&PinContext->DoneIrpListHead);
578 KeInitializeSpinLock(&PinContext->IrpListLock);
579
580 /* store pin context*/
581 Pin->Context = PinContext;
582
583 /* lets edit allocator framing struct */
584 Status = _KsEdit(Pin->Bag, (PVOID*)&Pin->Descriptor, sizeof(KSPIN_DESCRIPTOR_EX), sizeof(KSPIN_DESCRIPTOR_EX), USBAUDIO_TAG);
585 if (NT_SUCCESS(Status))
586 {
587 Status = _KsEdit(Pin->Bag, (PVOID*)&Pin->Descriptor->AllocatorFraming, sizeof(KSALLOCATOR_FRAMING_EX), sizeof(KSALLOCATOR_FRAMING_EX), USBAUDIO_TAG);
588 ASSERT(Status == STATUS_SUCCESS);
589 }
590
591 /* select streaming interface */
592 Status = USBAudioSelectAudioStreamingInterface(PinContext, PinContext->DeviceExtension, PinContext->DeviceExtension->ConfigurationDescriptor);
593 if (!NT_SUCCESS(Status))
594 {
595 /* failed */
596 return Status;
597 }
598
599 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
600 {
601 /* init capture pin */
602 Status = InitCapturePin(Pin);
603 }
604 else
605 {
606 /* audio streaming pin*/
607 Status = InitStreamPin(Pin);
608 }
609
610 return STATUS_SUCCESS;
611 }
612
613 NTSTATUS
614 NTAPI
615 USBAudioPinClose(
616 _In_ PKSPIN Pin,
617 _In_ PIRP Irp)
618 {
619 UNIMPLEMENTED
620 return STATUS_NOT_IMPLEMENTED;
621 }
622
623 NTSTATUS
624 NTAPI
625 UsbAudioCaptureComplete(
626 IN PDEVICE_OBJECT DeviceObject,
627 IN PIRP Irp,
628 IN PVOID Context)
629 {
630 PKSPIN Pin;
631 PPIN_CONTEXT PinContext;
632 KIRQL OldLevel;
633 PURB Urb;
634
635 /* get pin context */
636 Pin = Context;
637 PinContext = Pin->Context;
638
639 /* get urb */
640 Urb = Irp->Tail.Overlay.DriverContext[0];
641
642 /* acquire lock */
643 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
644
645 if (!NT_SUCCESS(Urb->UrbIsochronousTransfer.Hdr.Status))
646 {
647 //DPRINT("UsbAudioCaptureComplete Irp %p Urb %p Status %x Packet Status %x\n", Irp, Urb, Urb->UrbIsochronousTransfer.Hdr.Status, Urb->UrbIsochronousTransfer.IsoPacket[0].Status);
648
649 /* insert entry into ready list */
650 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
651
652 /* release lock */
653 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
654
655 KsIncrementCountedWorker(PinContext->StarvationWorker);
656 }
657 else
658 {
659 /* insert entry into done list */
660 InsertTailList(&PinContext->DoneIrpListHead, &Irp->Tail.Overlay.ListEntry);
661
662 /* release lock */
663 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
664
665 KsIncrementCountedWorker(PinContext->CaptureWorker);
666 }
667
668 /* done */
669 return STATUS_MORE_PROCESSING_REQUIRED;
670 }
671
672 NTSTATUS
673 PinCaptureProcess(
674 IN PKSPIN Pin)
675 {
676 PKSSTREAM_POINTER LeadingStreamPointer;
677 KIRQL OldLevel;
678 PPIN_CONTEXT PinContext;
679 PLIST_ENTRY CurEntry;
680 PIRP Irp;
681 PURB Urb;
682 PUCHAR TransferBuffer, OutBuffer;
683 ULONG Offset, Length;
684 NTSTATUS Status;
685 PKSGATE Gate;
686
687 //DPRINT1("PinCaptureProcess\n");
688 LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
689 if (LeadingStreamPointer == NULL)
690 {
691 /* get process control gate */
692 Gate = KsPinGetAndGate(Pin);
693
694 /* shutdown processing */
695 KsGateTurnInputOff(Gate);
696
697 return STATUS_SUCCESS;
698 }
699
700 /* get pin context */
701 PinContext = Pin->Context;
702
703 /* acquire spin lock */
704 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
705
706 while (!IsListEmpty(&PinContext->DoneIrpListHead))
707 {
708 /* remove entry from list */
709 CurEntry = RemoveHeadList(&PinContext->DoneIrpListHead);
710
711 /* release lock */
712 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
713
714 /* get irp offset */
715 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
716
717 /* get urb from irp */
718 Urb = (PURB)Irp->Tail.Overlay.DriverContext[0];
719 ASSERT(Urb);
720
721 Offset = PtrToUlong(Irp->Tail.Overlay.DriverContext[1]);
722
723 /* get transfer buffer */
724 TransferBuffer = Urb->UrbIsochronousTransfer.TransferBuffer;
725
726 /* get target buffer */
727 OutBuffer = (PUCHAR)LeadingStreamPointer->StreamHeader->Data;
728
729 /* calculate length */
730 Length = min(LeadingStreamPointer->OffsetOut.Count - LeadingStreamPointer->StreamHeader->DataUsed, Urb->UrbIsochronousTransfer.TransferBufferLength - Offset);
731
732 /* FIXME copy each packet extra */
733 /* copy audio bytes */
734 RtlCopyMemory((PUCHAR)&OutBuffer[LeadingStreamPointer->StreamHeader->DataUsed], &TransferBuffer[Offset], Length);
735
736 //DPRINT1("Irp %p Urb %p OutBuffer %p TransferBuffer %p Offset %lu Remaining %lu TransferBufferLength %lu Length %lu\n", Irp, Urb, OutBuffer, TransferBuffer, Offset, LeadingStreamPointer->OffsetOut.Remaining, Urb->UrbIsochronousTransfer.TransferBufferLength, Length);
737
738 /* adjust streampointer */
739 LeadingStreamPointer->StreamHeader->DataUsed += Length;
740
741 if (Length == LeadingStreamPointer->OffsetOut.Remaining)
742 {
743 KsStreamPointerAdvanceOffsetsAndUnlock(LeadingStreamPointer, 0, Length, TRUE);
744
745 /* acquire spin lock */
746 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
747
748 /* adjust offset */
749 Irp->Tail.Overlay.DriverContext[1] = UlongToPtr(Length);
750
751 /* reinsert into processed list */
752 InsertHeadList(&PinContext->DoneIrpListHead, &Irp->Tail.Overlay.ListEntry);
753
754 /* release lock */
755 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
756
757 LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
758 if (LeadingStreamPointer == NULL)
759 {
760 /* no more work to be done*/
761 return STATUS_PENDING;
762 }
763 else
764 {
765 /* resume work on this irp */
766 continue;
767 }
768 }
769 else
770 {
771 Status = KsStreamPointerAdvanceOffsets(LeadingStreamPointer, 0, Length, FALSE);
772 NT_ASSERT(NT_SUCCESS(Status));
773 ASSERT(Length == Urb->UrbIsochronousTransfer.TransferBufferLength - Offset);
774 }
775
776
777 /* acquire spin lock */
778 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
779
780 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
781 }
782
783 while (!IsListEmpty(&PinContext->IrpListHead))
784 {
785 /* remove entry from list */
786 CurEntry = RemoveHeadList(&PinContext->IrpListHead);
787
788 /* release lock */
789 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
790
791 /* get irp offset */
792 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
793
794 /* reinitialize irp and urb */
795 CaptureInitializeUrbAndIrp(Pin, Irp);
796
797 IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
798
799 /* acquire spin lock */
800 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
801
802 }
803
804 /* release lock */
805 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
806
807 if (LeadingStreamPointer != NULL)
808 KsStreamPointerUnlock(LeadingStreamPointer, FALSE);
809
810 /* get process control gate */
811 Gate = KsPinGetAndGate(Pin);
812
813 /* shutdown processing */
814 KsGateTurnInputOff(Gate);
815
816 return STATUS_PENDING;
817 }
818
819
820 NTSTATUS
821 NTAPI
822 USBAudioPinProcess(
823 _In_ PKSPIN Pin)
824 {
825 NTSTATUS Status;
826
827 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
828 {
829 Status = PinCaptureProcess(Pin);
830 }
831 else
832 {
833 UNIMPLEMENTED;
834 Status = STATUS_NOT_IMPLEMENTED;
835 }
836
837 return Status;
838 }
839
840
841 VOID
842 NTAPI
843 USBAudioPinReset(
844 _In_ PKSPIN Pin)
845 {
846 UNIMPLEMENTED
847 }
848
849 NTSTATUS
850 NTAPI
851 USBAudioPinSetDataFormat(
852 _In_ PKSPIN Pin,
853 _In_opt_ PKSDATAFORMAT OldFormat,
854 _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
855 _In_ const KSDATARANGE* DataRange,
856 _In_opt_ const KSATTRIBUTE_LIST* AttributeRange)
857 {
858 if (OldFormat == NULL)
859 {
860 /* TODO: verify connection format */
861 UNIMPLEMENTED
862 return STATUS_SUCCESS;
863 }
864
865 return UsbAudioSetFormat(Pin);
866 }
867
868 NTSTATUS
869 StartCaptureIsocTransfer(
870 IN PKSPIN Pin)
871 {
872 PPIN_CONTEXT PinContext;
873 PLIST_ENTRY CurEntry;
874 PIRP Irp;
875 KIRQL OldLevel;
876
877 /* get pin context */
878 PinContext = Pin->Context;
879
880 /* acquire spin lock */
881 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
882
883 while(!IsListEmpty(&PinContext->IrpListHead))
884 {
885 /* remove entry from list */
886 CurEntry = RemoveHeadList(&PinContext->IrpListHead);
887
888 /* get irp offset */
889 Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
890
891 /* release lock */
892 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
893
894 /* reinitialize irp and urb */
895 CaptureInitializeUrbAndIrp(Pin, Irp);
896
897 DPRINT("StartCaptureIsocTransfer Irp %p\n", Irp);
898 IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
899
900 /* acquire spin lock */
901 KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
902
903 }
904
905 /* release lock */
906 KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
907
908 return STATUS_SUCCESS;
909 }
910
911 NTSTATUS
912 CapturePinStateChange(
913 _In_ PKSPIN Pin,
914 _In_ KSSTATE ToState,
915 _In_ KSSTATE FromState)
916 {
917 NTSTATUS Status;
918
919 if (FromState != ToState)
920 {
921 if (ToState)
922 {
923 if (ToState == KSSTATE_PAUSE)
924 {
925 if (FromState == KSSTATE_RUN)
926 {
927 /* wait until pin processing is finished*/
928 }
929 }
930 else
931 {
932 if (ToState == KSSTATE_RUN)
933 {
934 Status = StartCaptureIsocTransfer(Pin);
935 }
936 }
937 }
938 }
939 return Status;
940 }
941
942
943 NTSTATUS
944 NTAPI
945 USBAudioPinSetDeviceState(
946 _In_ PKSPIN Pin,
947 _In_ KSSTATE ToState,
948 _In_ KSSTATE FromState)
949 {
950 NTSTATUS Status;
951
952 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
953 {
954 /* handle capture state changes */
955 Status = CapturePinStateChange(Pin, ToState, FromState);
956 }
957 else
958 {
959 UNIMPLEMENTED
960 Status = STATUS_NOT_IMPLEMENTED;
961 }
962
963 return Status;
964 }
965
966
967 NTSTATUS
968 NTAPI
969 UsbAudioPinDataIntersect(
970 _In_ PVOID Context,
971 _In_ PIRP Irp,
972 _In_ PKSP_PIN Pin,
973 _In_ PKSDATARANGE DataRange,
974 _In_ PKSDATARANGE MatchingDataRange,
975 _In_ ULONG DataBufferSize,
976 _Out_ PVOID Data,
977 _Out_ PULONG DataSize)
978 {
979 PKSFILTER Filter;
980 PKSPIN_DESCRIPTOR_EX PinDescriptor;
981 PKSDATAFORMAT_WAVEFORMATEX DataFormat;
982 PKSDATARANGE_AUDIO DataRangeAudio;
983
984 /* get filter from irp*/
985 Filter = KsGetFilterFromIrp(Irp);
986 if (!Filter)
987 {
988 /* no match*/
989 return STATUS_NO_MATCH;
990 }
991
992 /* get pin descriptor */
993 PinDescriptor = (PKSPIN_DESCRIPTOR_EX)&Filter->Descriptor->PinDescriptors[Pin->PinId];
994
995 *DataSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
996 if (DataBufferSize == 0)
997 {
998 /* buffer too small */
999 return STATUS_BUFFER_OVERFLOW;
1000 }
1001
1002 /* sanity checks*/
1003 ASSERT(PinDescriptor->PinDescriptor.DataRangesCount >= 0);
1004 ASSERT(PinDescriptor->PinDescriptor.DataRanges[0]->FormatSize == sizeof(KSDATARANGE_AUDIO));
1005
1006 DataRangeAudio = (PKSDATARANGE_AUDIO)PinDescriptor->PinDescriptor.DataRanges[0];
1007
1008 DataFormat = Data;
1009 DataFormat->WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
1010 DataFormat->WaveFormatEx.nChannels = DataRangeAudio->MaximumChannels;
1011 DataFormat->WaveFormatEx.nSamplesPerSec = DataRangeAudio->MaximumSampleFrequency;
1012 DataFormat->WaveFormatEx.nAvgBytesPerSec = DataRangeAudio->MaximumSampleFrequency * (DataRangeAudio->MaximumBitsPerSample / 8) * DataRangeAudio->MaximumChannels;
1013 DataFormat->WaveFormatEx.nBlockAlign = (DataRangeAudio->MaximumBitsPerSample / 8) * DataRangeAudio->MaximumChannels;
1014 DataFormat->WaveFormatEx.wBitsPerSample = DataRangeAudio->MaximumBitsPerSample;
1015 DataFormat->WaveFormatEx.cbSize = 0;
1016
1017 DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
1018 DataFormat->DataFormat.Flags = 0;
1019 DataFormat->DataFormat.Reserved = 0;
1020 DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
1021 DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1022 DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
1023 DataFormat->DataFormat.SampleSize = (DataRangeAudio->MaximumBitsPerSample / 8) * DataRangeAudio->MaximumChannels;
1024
1025 return STATUS_SUCCESS;
1026 }