xref: /reactos/drivers/usb/usbaudio/pin.c (revision 34593d93)
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
GetMaxPacketSizeForInterface(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,KSPIN_DATAFLOW DataFlow)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
UsbAudioAllocCaptureUrbIso(IN USBD_PIPE_HANDLE PipeHandle,IN ULONG MaxPacketSize,IN PVOID Buffer,IN ULONG BufferLength,OUT PURB * OutUrb)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
UsbAudioSetFormat(IN PKSPIN Pin)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     /* get pin context */
140     PinContext = Pin->Context;
141 
142     /* FIXME: determine controls and format urb */
143     UsbBuildVendorRequest(Urb,
144         URB_FUNCTION_CLASS_ENDPOINT,
145         sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
146         USBD_TRANSFER_DIRECTION_OUT,
147         0,
148         0x01, // SET_CUR
149         0x100,
150         PinContext->DeviceExtension->InterfaceInfo->Pipes[0].EndpointAddress,
151         SampleRateBuffer,
152         NULL,
153         3,
154         NULL);
155 
156 
157 
158     /* submit urb */
159     Status = SubmitUrbSync(PinContext->LowerDevice, Urb);
160 
161     DPRINT1("USBAudioPinSetDataFormat Pin %p Status %x\n", Pin, Status);
162     FreeFunction(Urb);
163     FreeFunction(SampleRateBuffer);
164     return Status;
165 }
166 
167 NTSTATUS
USBAudioSelectAudioStreamingInterface(IN PKSPIN Pin,IN PPIN_CONTEXT PinContext,IN PDEVICE_EXTENSION DeviceExtension,IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,IN ULONG FormatDescriptorIndex)168 USBAudioSelectAudioStreamingInterface(
169     IN PKSPIN Pin,
170     IN PPIN_CONTEXT PinContext,
171     IN PDEVICE_EXTENSION DeviceExtension,
172     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
173     IN ULONG FormatDescriptorIndex)
174 {
175     PURB Urb;
176     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
177     NTSTATUS Status;
178     ULONG Found, Index;
179 
180     PUSB_AUDIO_STREAMING_INTERFACE_DESCRIPTOR StreamingInterfaceDescriptor;
181     PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor = NULL;
182 
183     /* search for terminal descriptor of that irp sink / irp source */
184     TerminalDescriptor = UsbAudioGetStreamingTerminalDescriptorByIndex(DeviceExtension->ConfigurationDescriptor, Pin->Id);
185     ASSERT(TerminalDescriptor != NULL);
186 
187     /* grab interface descriptor */
188     InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
189     if (!InterfaceDescriptor)
190     {
191         /* no such interface */
192         return STATUS_INVALID_PARAMETER;
193     }
194 
195     Found = FALSE;
196     Index = 0;
197 
198     /* selects the interface which has an audio streaming interface descriptor associated to the input / output terminal at the given format index */
199     while (InterfaceDescriptor != NULL)
200     {
201         if (InterfaceDescriptor->bInterfaceSubClass == 0x02 /* AUDIO_STREAMING */ && InterfaceDescriptor->bNumEndpoints > 0)
202         {
203             StreamingInterfaceDescriptor = (PUSB_AUDIO_STREAMING_INTERFACE_DESCRIPTOR)USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, InterfaceDescriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
204             if (StreamingInterfaceDescriptor != NULL)
205             {
206                 ASSERT(StreamingInterfaceDescriptor->bDescriptorSubtype == 0x01);
207                 ASSERT(StreamingInterfaceDescriptor->wFormatTag == WAVE_FORMAT_PCM);
208                 if (StreamingInterfaceDescriptor->bTerminalLink == TerminalDescriptor->bTerminalID)
209                 {
210                     if (FormatDescriptorIndex == Index)
211                     {
212                         Found = TRUE;
213                         break;
214                     }
215                     Index++;
216                 }
217             }
218         }
219         InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
220     }
221 
222     if (!Found)
223     {
224         /* no such interface */
225         DPRINT1("No Interface found\n");
226         return STATUS_INVALID_PARAMETER;
227     }
228 
229     Urb = AllocFunction(GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints));
230     if (!Urb)
231     {
232         /* no memory */
233         return STATUS_INSUFFICIENT_RESOURCES;
234     }
235 
236      /* now prepare interface urb */
237      UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
238 
239      /* now select the interface */
240      Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
241 
242      DPRINT1("USBAudioSelectAudioStreamingInterface Status %x UrbStatus %x InterfaceNumber %x AlternateSetting %x\n", Status, Urb->UrbSelectInterface.Hdr.Status, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
243 
244      /* did it succeeed */
245      if (NT_SUCCESS(Status))
246      {
247          /* free old interface info */
248          if (DeviceExtension->InterfaceInfo)
249          {
250              /* free old info */
251              FreeFunction(DeviceExtension->InterfaceInfo);
252          }
253 
254          /* alloc interface info */
255          DeviceExtension->InterfaceInfo = AllocFunction(Urb->UrbSelectInterface.Interface.Length);
256          if (DeviceExtension->InterfaceInfo == NULL)
257          {
258              /* no memory */
259              FreeFunction(Urb);
260              return STATUS_INSUFFICIENT_RESOURCES;
261          }
262 
263          /* copy interface info */
264          RtlCopyMemory(DeviceExtension->InterfaceInfo, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
265          PinContext->InterfaceDescriptor = InterfaceDescriptor;
266      }
267 
268      /* free urb */
269      FreeFunction(Urb);
270      return Status;
271 }
272 
273 VOID
274 NTAPI
CaptureGateOnWorkItem(_In_ PVOID Context)275 CaptureGateOnWorkItem(
276     _In_ PVOID Context)
277 {
278     PKSPIN Pin;
279     PPIN_CONTEXT PinContext;
280     PKSGATE Gate;
281     ULONG Count;
282 
283     /* get pin */
284     Pin = Context;
285 
286     /* get pin context */
287     PinContext = Pin->Context;
288 
289     do
290     {
291         /* acquire processing mutex */
292         KsPinAcquireProcessingMutex(Pin);
293 
294         /* get pin control gate */
295         Gate = KsPinGetAndGate(Pin);
296 
297         /* turn input on */
298         KsGateTurnInputOn(Gate);
299 
300         /* schedule processing */
301         KsPinAttemptProcessing(Pin, TRUE);
302 
303         /* release processing mutex */
304         KsPinReleaseProcessingMutex(Pin);
305 
306         /* decrement worker count */
307         Count = KsDecrementCountedWorker(PinContext->CaptureWorker);
308     } while (Count);
309 }
310 
311 NTSTATUS
RenderInitializeUrbAndIrp(IN PKSPIN Pin,IN PPIN_CONTEXT PinContext,IN OUT PIRP Irp,IN PVOID TransferBuffer,IN ULONG TransferBufferSize,IN ULONG PacketSize)312 RenderInitializeUrbAndIrp(
313     IN PKSPIN Pin,
314     IN PPIN_CONTEXT PinContext,
315     IN OUT PIRP Irp,
316     IN PVOID TransferBuffer,
317     IN ULONG TransferBufferSize,
318     IN ULONG PacketSize)
319 {
320     ULONG Index, PacketCount;
321     PURB Urb;
322     PIO_STACK_LOCATION IoStack;
323 
324     /* initialize irp */
325     IoInitializeIrp(Irp, IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize), PinContext->DeviceExtension->LowerDevice->StackSize);
326 
327     /* set irp members */
328     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
329     Irp->IoStatus.Information = 0;
330     Irp->Flags = 0;
331     Irp->UserBuffer = NULL;
332 
333     /* init stack location */
334     IoStack = IoGetNextIrpStackLocation(Irp);
335     IoStack->DeviceObject = PinContext->DeviceExtension->LowerDevice;
336     IoStack->Parameters.Others.Argument2 = NULL;
337     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
338     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
339 
340     /* set completion routine */
341     IoSetCompletionRoutine(Irp, UsbAudioRenderComplete, Pin, TRUE, TRUE, TRUE);
342 
343     /* calculate packet count */
344     PacketCount = TransferBufferSize / PacketSize;
345     ASSERT(TransferBufferSize % PacketSize == 0);
346 
347     /* lets allocate urb */
348     Urb = (PURB)AllocFunction(GET_ISO_URB_SIZE(PacketCount));
349     if (!Urb)
350     {
351         /* no memory */
352         return STATUS_INSUFFICIENT_RESOURCES;
353     }
354 
355     /* init urb */
356     Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
357     Urb->UrbIsochronousTransfer.Hdr.Length = GET_ISO_URB_SIZE(PacketCount);
358     Urb->UrbIsochronousTransfer.PipeHandle = PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle;
359     Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT | USBD_START_ISO_TRANSFER_ASAP;
360     Urb->UrbIsochronousTransfer.TransferBufferLength = TransferBufferSize;
361     Urb->UrbIsochronousTransfer.TransferBuffer = TransferBuffer;
362     Urb->UrbIsochronousTransfer.NumberOfPackets = PacketCount;
363     Urb->UrbIsochronousTransfer.StartFrame = 0;
364 
365     for (Index = 0; Index < PacketCount; Index++)
366     {
367         Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset = Index * PacketSize;
368     }
369 
370     /* store urb */
371     IoStack->Parameters.Others.Argument1 = Urb;
372     Irp->Tail.Overlay.DriverContext[0] = Urb;
373 
374 
375     /* done */
376     return STATUS_SUCCESS;
377 }
378 
379 VOID
CaptureInitializeUrbAndIrp(IN PKSPIN Pin,IN PIRP Irp)380 CaptureInitializeUrbAndIrp(
381     IN PKSPIN Pin,
382     IN PIRP Irp)
383 {
384     PIO_STACK_LOCATION IoStack;
385     PURB Urb;
386     PUCHAR TransferBuffer;
387     ULONG Index;
388     PPIN_CONTEXT PinContext;
389 
390     /* get pin context */
391     PinContext = Pin->Context;
392 
393     /* backup urb and transferbuffer */
394     Urb = Irp->Tail.Overlay.DriverContext[0];
395     TransferBuffer = Urb->UrbIsochronousTransfer.TransferBuffer;
396 
397     /* initialize irp */
398     IoInitializeIrp(Irp, IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize), PinContext->DeviceExtension->LowerDevice->StackSize);
399 
400     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
401     Irp->IoStatus.Information = 0;
402     Irp->Flags = 0;
403     Irp->UserBuffer = NULL;
404     Irp->Tail.Overlay.DriverContext[0] = Urb;
405     Irp->Tail.Overlay.DriverContext[1] = NULL;
406 
407     /* init stack location */
408     IoStack = IoGetNextIrpStackLocation(Irp);
409     IoStack->DeviceObject = PinContext->DeviceExtension->LowerDevice;
410     IoStack->Parameters.Others.Argument1 = Urb;
411     IoStack->Parameters.Others.Argument2 = NULL;
412     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
413     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
414 
415     IoSetCompletionRoutine(Irp, UsbAudioCaptureComplete, Pin, TRUE, TRUE, TRUE);
416 
417     RtlZeroMemory(Urb, GET_ISO_URB_SIZE(PACKET_COUNT));
418 
419     /* init urb */
420     Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
421     Urb->UrbIsochronousTransfer.Hdr.Length = GET_ISO_URB_SIZE(10);
422     Urb->UrbIsochronousTransfer.PipeHandle = PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle;
423     Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_START_ISO_TRANSFER_ASAP;
424     Urb->UrbIsochronousTransfer.TransferBufferLength = PinContext->DeviceExtension->InterfaceInfo->Pipes[0].MaximumPacketSize * 10;
425     Urb->UrbIsochronousTransfer.TransferBuffer = TransferBuffer;
426     Urb->UrbIsochronousTransfer.NumberOfPackets = PACKET_COUNT;
427     Urb->UrbIsochronousTransfer.StartFrame = 0;
428 
429     for (Index = 0; Index < PACKET_COUNT; Index++)
430     {
431         Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset = Index * PinContext->DeviceExtension->InterfaceInfo->Pipes[0].MaximumPacketSize;
432     }
433 }
434 
435 
436 VOID
437 NTAPI
CaptureAvoidPipeStarvationWorker(_In_ PVOID Context)438 CaptureAvoidPipeStarvationWorker(
439     _In_ PVOID Context)
440 {
441     PKSPIN Pin;
442     PPIN_CONTEXT PinContext;
443     KIRQL OldLevel;
444     PLIST_ENTRY CurEntry;
445     PIRP Irp;
446 
447     /* get pin */
448     Pin = Context;
449 
450     /* get pin context */
451     PinContext = Pin->Context;
452 
453     /* acquire spin lock */
454     KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
455 
456     if (!IsListEmpty(&PinContext->IrpListHead))
457     {
458         /* sanity check */
459         ASSERT(!IsListEmpty(&PinContext->IrpListHead));
460 
461         /* remove entry from list */
462         CurEntry = RemoveHeadList(&PinContext->IrpListHead);
463 
464         /* release lock */
465         KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
466 
467         /* get irp offset */
468         Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
469 
470         /* reinitialize irp and urb */
471         CaptureInitializeUrbAndIrp(Pin, Irp);
472 
473         KsDecrementCountedWorker(PinContext->StarvationWorker);
474 
475         /* call driver */
476         IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
477     }
478     else
479     {
480         /* release lock */
481         KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
482 
483         KsDecrementCountedWorker(PinContext->StarvationWorker);
484     }
485 }
486 
487 
488 
489 NTSTATUS
InitCapturePin(IN PKSPIN Pin)490 InitCapturePin(
491     IN PKSPIN Pin)
492 {
493     NTSTATUS Status;
494     ULONG Index;
495     ULONG BufferSize;
496     ULONG MaximumPacketSize;
497     PIRP Irp;
498     PURB Urb;
499     PPIN_CONTEXT PinContext;
500     PIO_STACK_LOCATION IoStack;
501     PKSALLOCATOR_FRAMING_EX Framing;
502     PKSGATE Gate;
503 
504 
505     /* set sample rate */
506     Status = UsbAudioSetFormat(Pin);
507     if (!NT_SUCCESS(Status))
508     {
509         /* failed */
510         return Status;
511     }
512 
513     /* get pin context */
514     PinContext = Pin->Context;
515 
516     /* lets get maximum packet size */
517     MaximumPacketSize = GetMaxPacketSizeForInterface(PinContext->DeviceExtension->ConfigurationDescriptor, PinContext->InterfaceDescriptor, Pin->DataFlow);
518 
519     /* initialize work item for capture worker */
520     ExInitializeWorkItem(&PinContext->CaptureWorkItem, CaptureGateOnWorkItem, (PVOID)Pin);
521 
522     /* register worker */
523     Status = KsRegisterCountedWorker(CriticalWorkQueue, &PinContext->CaptureWorkItem, &PinContext->CaptureWorker);
524     if (!NT_SUCCESS(Status))
525     {
526         /* failed */
527         return Status;
528     }
529 
530     /* initialize work item */
531     ExInitializeWorkItem(&PinContext->StarvationWorkItem, CaptureAvoidPipeStarvationWorker, (PVOID)Pin);
532 
533     /* register worker */
534     Status = KsRegisterCountedWorker(CriticalWorkQueue, &PinContext->StarvationWorkItem, &PinContext->StarvationWorker);
535     if (!NT_SUCCESS(Status))
536     {
537         /* failed */
538         KsUnregisterWorker(PinContext->CaptureWorker);
539     }
540 
541     /* lets edit framing struct */
542     Framing = (PKSALLOCATOR_FRAMING_EX)Pin->Descriptor->AllocatorFraming;
543     Framing->FramingItem[0].PhysicalRange.MinFrameSize =
544         Framing->FramingItem[0].PhysicalRange.MaxFrameSize =
545         Framing->FramingItem[0].FramingRange.Range.MinFrameSize =
546         Framing->FramingItem[0].FramingRange.Range.MaxFrameSize =
547     MaximumPacketSize;
548 
549     /* calculate buffer size 8 irps * 10 iso packets * max packet size */
550     BufferSize = 8 * PACKET_COUNT * MaximumPacketSize;
551 
552     /* allocate pin capture buffer */
553     PinContext->BufferSize = BufferSize;
554     PinContext->Buffer = AllocFunction(BufferSize);
555     if (!PinContext->Buffer)
556     {
557         /* no memory */
558         return STATUS_INSUFFICIENT_RESOURCES;
559     }
560     KsAddItemToObjectBag(Pin->Bag, PinContext->Buffer, ExFreePool);
561 
562     /* init irps */
563     for (Index = 0; Index < 8; Index++)
564     {
565         /* allocate irp */
566         Irp = AllocFunction(IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize));
567         if (!Irp)
568         {
569             /* no memory */
570             return STATUS_INSUFFICIENT_RESOURCES;
571         }
572 
573         /* initialize irp */
574         IoInitializeIrp(Irp, IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize), PinContext->DeviceExtension->LowerDevice->StackSize);
575 
576         Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
577         Irp->IoStatus.Information = 0;
578         Irp->Flags = 0;
579         Irp->UserBuffer = NULL;
580 
581         IoStack = IoGetNextIrpStackLocation(Irp);
582         IoStack->DeviceObject = PinContext->DeviceExtension->LowerDevice;
583         IoStack->Parameters.Others.Argument2 = NULL;
584         IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
585         IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
586 
587         IoSetCompletionRoutine(Irp, UsbAudioCaptureComplete, Pin, TRUE, TRUE, TRUE);
588 
589         /* insert into irp list */
590         InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
591 
592         /* add to object bag*/
593         KsAddItemToObjectBag(Pin->Bag, Irp, ExFreePool);
594 
595         /* FIXME select correct pipe handle */
596         Status = UsbAudioAllocCaptureUrbIso(PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle,
597                                             MaximumPacketSize,
598                                             &PinContext->Buffer[MaximumPacketSize * PACKET_COUNT * Index],
599                                             MaximumPacketSize * PACKET_COUNT,
600                                             &Urb);
601 
602         DPRINT1("InitCapturePin Irp %p Urb %p\n", Irp, Urb);
603 
604         if (NT_SUCCESS(Status))
605         {
606             /* get next stack location */
607             IoStack = IoGetNextIrpStackLocation(Irp);
608 
609             /* store urb */
610             IoStack->Parameters.Others.Argument1 = Urb;
611             Irp->Tail.Overlay.DriverContext[0] = Urb;
612         }
613         else
614         {
615             /* failed */
616             return Status;
617         }
618     }
619 
620     /* get process control gate */
621     Gate = KsPinGetAndGate(Pin);
622 
623     /* turn input off */
624     KsGateTurnInputOff(Gate);
625 
626     return Status;
627 }
628 
629 NTSTATUS
InitStreamPin(IN PKSPIN Pin)630 InitStreamPin(
631     IN PKSPIN Pin)
632 {
633     ULONG Index;
634     PIRP Irp;
635     PPIN_CONTEXT PinContext;
636     PKSDATAFORMAT_WAVEFORMATEX WaveFormatEx;
637     PIO_STACK_LOCATION IoStack;
638 
639     DPRINT1("InitStreamPin\n");
640 
641     /* get pin context */
642     PinContext = Pin->Context;
643 
644     /* allocate 1 sec buffer */
645     WaveFormatEx = (PKSDATAFORMAT_WAVEFORMATEX)Pin->ConnectionFormat;
646     PinContext->Buffer = AllocFunction(WaveFormatEx->WaveFormatEx.nAvgBytesPerSec);
647     if (!PinContext->Buffer)
648     {
649         /* no memory */
650         return STATUS_INSUFFICIENT_RESOURCES;
651     }
652 
653     /* init buffer size*/
654     PinContext->BufferSize = WaveFormatEx->WaveFormatEx.nAvgBytesPerSec;
655     PinContext->BufferOffset = 0;
656     PinContext->BufferLength = 0;
657 
658     /* init irps */
659     for (Index = 0; Index < 12; Index++)
660     {
661         /* allocate irp */
662         Irp = AllocFunction(IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize));
663         if (!Irp)
664         {
665             /* no memory */
666             return STATUS_INSUFFICIENT_RESOURCES;
667         }
668 
669         DPRINT1("InitStreamPin Irp %p\n", Irp);
670 
671         /* initialize irp */
672         IoInitializeIrp(Irp, IoSizeOfIrp(PinContext->DeviceExtension->LowerDevice->StackSize), PinContext->DeviceExtension->LowerDevice->StackSize);
673 
674         Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
675         Irp->IoStatus.Information = 0;
676         Irp->Flags = 0;
677         Irp->UserBuffer = NULL;
678 
679         IoStack = IoGetNextIrpStackLocation(Irp);
680         IoStack->DeviceObject = PinContext->DeviceExtension->LowerDevice;
681         IoStack->Parameters.Others.Argument2 = NULL;
682         IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
683         IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
684 
685         IoSetCompletionRoutine(Irp, UsbAudioRenderComplete, Pin, TRUE, TRUE, TRUE);
686 
687         /* insert into irp list */
688         InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
689 
690         /* add to object bag*/
691         KsAddItemToObjectBag(Pin->Bag, Irp, ExFreePool);
692     }
693 
694     return STATUS_SUCCESS;
695 }
696 
697 ULONG
GetDataRangeIndexForFormat(IN PKSDATARANGE ConnectionFormat,IN const PKSDATARANGE * DataRanges,IN ULONG DataRangesCount)698 GetDataRangeIndexForFormat(
699     IN PKSDATARANGE ConnectionFormat,
700     IN const PKSDATARANGE * DataRanges,
701     IN ULONG DataRangesCount)
702 {
703     ULONG Index;
704     PKSDATARANGE CurrentDataRange;
705     PKSDATARANGE_AUDIO CurrentAudioDataRange;
706     PKSDATAFORMAT_WAVEFORMATEX ConnectionDataFormat;
707 
708     if (ConnectionFormat->FormatSize != sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX))
709     {
710         /* unsupported connection format */
711         DPRINT1("GetDataRangeIndexForFormat expected KSDATARANGE_AUDIO\n");
712         return MAXULONG;
713     }
714 
715     /* cast to right type */
716     ConnectionDataFormat = (PKSDATAFORMAT_WAVEFORMATEX)ConnectionFormat;
717 
718     for (Index = 0; Index < DataRangesCount; Index++)
719     {
720          /* get current data range */
721          CurrentDataRange = DataRanges[Index];
722 
723          /* compare guids */
724          if (!IsEqualGUIDAligned(&CurrentDataRange->MajorFormat, &ConnectionFormat->MajorFormat) ||
725              !IsEqualGUIDAligned(&CurrentDataRange->SubFormat, &ConnectionFormat->SubFormat) ||
726              !IsEqualGUIDAligned(&CurrentDataRange->Specifier, &ConnectionFormat->Specifier))
727          {
728              /* no match */
729              continue;
730          }
731 
732          /* all pin data ranges are KSDATARANGE_AUDIO */
733          CurrentAudioDataRange = (PKSDATARANGE_AUDIO)CurrentDataRange;
734 
735          /* check if number of channel match */
736          if (CurrentAudioDataRange->MaximumChannels != ConnectionDataFormat->WaveFormatEx.nChannels)
737          {
738              /* number of channels mismatch */
739              continue;
740          }
741 
742          if (CurrentAudioDataRange->MinimumSampleFrequency > ConnectionDataFormat->WaveFormatEx.nSamplesPerSec)
743          {
744              /* channel frequency too low */
745              continue;
746          }
747 
748          if (CurrentAudioDataRange->MaximumSampleFrequency < ConnectionDataFormat->WaveFormatEx.nSamplesPerSec)
749          {
750              /* channel frequency too high */
751              continue;
752          }
753 
754          /* FIXME add checks for bitrate / sample size etc */
755          return Index;
756     }
757 
758     /* no datarange found */
759     return MAXULONG;
760 }
761 
762 NTSTATUS
763 NTAPI
USBAudioPinCreate(_In_ PKSPIN Pin,_In_ PIRP Irp)764 USBAudioPinCreate(
765     _In_ PKSPIN Pin,
766     _In_ PIRP Irp)
767 {
768     PKSFILTER Filter;
769     PFILTER_CONTEXT FilterContext;
770     PPIN_CONTEXT PinContext;
771     NTSTATUS Status;
772     ULONG FormatIndex;
773 
774     Filter = KsPinGetParentFilter(Pin);
775     if (Filter == NULL)
776     {
777         /* invalid parameter */
778         return STATUS_INVALID_PARAMETER;
779     }
780 
781     /* get filter context */
782     FilterContext = Filter->Context;
783 
784     /* allocate pin context */
785     PinContext = AllocFunction(sizeof(PIN_CONTEXT));
786     if (!PinContext)
787     {
788         /* no memory*/
789         return STATUS_INSUFFICIENT_RESOURCES;
790     }
791 
792     /* init pin context */
793     PinContext->DeviceExtension = FilterContext->DeviceExtension;
794     PinContext->LowerDevice = FilterContext->LowerDevice;
795     InitializeListHead(&PinContext->IrpListHead);
796     InitializeListHead(&PinContext->DoneIrpListHead);
797     KeInitializeSpinLock(&PinContext->IrpListLock);
798 
799     /* store pin context*/
800     Pin->Context = PinContext;
801 
802     /* lets edit allocator framing struct */
803     Status = _KsEdit(Pin->Bag, (PVOID*)&Pin->Descriptor, sizeof(KSPIN_DESCRIPTOR_EX), sizeof(KSPIN_DESCRIPTOR_EX), USBAUDIO_TAG);
804     if (NT_SUCCESS(Status))
805     {
806         Status = _KsEdit(Pin->Bag, (PVOID*)&Pin->Descriptor->AllocatorFraming, sizeof(KSALLOCATOR_FRAMING_EX), sizeof(KSALLOCATOR_FRAMING_EX), USBAUDIO_TAG);
807         ASSERT(Status == STATUS_SUCCESS);
808     }
809 
810     /* choose correct dataformat */
811     FormatIndex = GetDataRangeIndexForFormat(Pin->ConnectionFormat, Pin->Descriptor->PinDescriptor.DataRanges, Pin->Descriptor->PinDescriptor.DataRangesCount);
812     if (FormatIndex == MAXULONG)
813     {
814         /* no format match */
815         return STATUS_NO_MATCH;
816     }
817 
818     /* select streaming interface */
819     Status = USBAudioSelectAudioStreamingInterface(Pin, PinContext, PinContext->DeviceExtension, PinContext->DeviceExtension->ConfigurationDescriptor, FormatIndex);
820     if (!NT_SUCCESS(Status))
821     {
822         /* failed */
823         DPRINT1("USBAudioSelectAudioStreamingInterface failed with %x\n", Status);
824         return Status;
825     }
826 
827     if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
828     {
829         /* init capture pin */
830         Status = InitCapturePin(Pin);
831     }
832     else
833     {
834         /* audio streaming pin*/
835         Status = InitStreamPin(Pin);
836     }
837 
838     return Status;
839 }
840 
841 NTSTATUS
842 NTAPI
USBAudioPinClose(_In_ PKSPIN Pin,_In_ PIRP Irp)843 USBAudioPinClose(
844     _In_ PKSPIN Pin,
845     _In_ PIRP Irp)
846 {
847     UNIMPLEMENTED;
848     return STATUS_NOT_IMPLEMENTED;
849 }
850 
851 NTSTATUS
852 NTAPI
UsbAudioRenderComplete(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)853 UsbAudioRenderComplete(
854     IN PDEVICE_OBJECT DeviceObject,
855     IN PIRP Irp,
856     IN PVOID Context)
857 {
858     PKSPIN Pin;
859     PPIN_CONTEXT PinContext;
860     KIRQL OldLevel;
861     PKSSTREAM_POINTER StreamPointerClone;
862     NTSTATUS Status;
863     PURB Urb;
864 
865     /* get pin context */
866     Pin = Context;
867     PinContext = Pin->Context;
868 
869     /* get status */
870     Status = Irp->IoStatus.Status;
871 
872     /* get streampointer */
873     StreamPointerClone = Irp->Tail.Overlay.DriverContext[1];
874 
875     /* get urb */
876     Urb = Irp->Tail.Overlay.DriverContext[0];
877 
878     /* and free it */
879     FreeFunction(Urb);
880 
881     /* acquire lock */
882     KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
883 
884     /* insert entry into ready list */
885     InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
886 
887     /* release lock */
888     KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
889 
890     if (!NT_SUCCESS(Status) && StreamPointerClone)
891     {
892         /* set status code because it failed */
893         KsStreamPointerSetStatusCode(StreamPointerClone, STATUS_DEVICE_DATA_ERROR);
894         DPRINT1("UsbAudioRenderComplete failed with %x\n", Status);
895     }
896 
897     if (StreamPointerClone)
898     {
899         /* lets delete the stream pointer clone */
900         KsStreamPointerDelete(StreamPointerClone);
901     }
902 
903     /* done */
904     return STATUS_MORE_PROCESSING_REQUIRED;
905 }
906 
907 NTSTATUS
908 NTAPI
UsbAudioCaptureComplete(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)909 UsbAudioCaptureComplete(
910     IN PDEVICE_OBJECT DeviceObject,
911     IN PIRP Irp,
912     IN PVOID Context)
913 {
914     PKSPIN Pin;
915     PPIN_CONTEXT PinContext;
916     KIRQL OldLevel;
917     PURB Urb;
918 
919     /* get pin context */
920     Pin = Context;
921     PinContext = Pin->Context;
922 
923     /* get urb */
924     Urb = Irp->Tail.Overlay.DriverContext[0];
925 
926     /* acquire lock */
927     KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
928 
929     if (!NT_SUCCESS(Urb->UrbIsochronousTransfer.Hdr.Status))
930     {
931         //DPRINT("UsbAudioCaptureComplete Irp %p Urb %p Status %x Packet Status %x\n", Irp, Urb, Urb->UrbIsochronousTransfer.Hdr.Status, Urb->UrbIsochronousTransfer.IsoPacket[0].Status);
932 
933         /* insert entry into ready list */
934         InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
935 
936         /* release lock */
937         KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
938 
939         KsIncrementCountedWorker(PinContext->StarvationWorker);
940     }
941     else
942     {
943         /* insert entry into done list */
944         InsertTailList(&PinContext->DoneIrpListHead, &Irp->Tail.Overlay.ListEntry);
945 
946         /* release lock */
947         KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
948 
949         KsIncrementCountedWorker(PinContext->CaptureWorker);
950     }
951 
952     /* done */
953     return STATUS_MORE_PROCESSING_REQUIRED;
954 }
955 
956 PIRP
PinGetIrpFromReadyList(IN PKSPIN Pin)957 PinGetIrpFromReadyList(
958     IN PKSPIN Pin)
959 {
960     PPIN_CONTEXT PinContext;
961     PLIST_ENTRY CurEntry;
962     KIRQL OldLevel;
963     PIRP Irp = NULL;
964 
965     /* get pin context */
966     PinContext = Pin->Context;
967 
968     /* acquire spin lock */
969     KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
970 
971     if (!IsListEmpty(&PinContext->IrpListHead))
972     {
973         /* remove entry from list */
974         CurEntry = RemoveHeadList(&PinContext->IrpListHead);
975 
976         /* get irp offset */
977         Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
978     }
979 
980     /* release lock */
981     KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
982 
983     return Irp;
984 }
985 
986 NTSTATUS
PinRenderProcess(IN PKSPIN Pin)987 PinRenderProcess(
988     IN PKSPIN Pin)
989 {
990     PKSSTREAM_POINTER LeadingStreamPointer;
991     PKSSTREAM_POINTER CloneStreamPointer;
992     NTSTATUS Status;
993     PPIN_CONTEXT PinContext;
994     ULONG PacketCount, TotalPacketSize, Offset;
995     PKSDATAFORMAT_WAVEFORMATEX WaveFormatEx;
996     PUCHAR TransferBuffer;
997     PIRP Irp = NULL;
998 
999     //DPRINT1("PinRenderProcess\n");
1000 
1001     LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
1002     if (LeadingStreamPointer == NULL)
1003     {
1004         return STATUS_SUCCESS;
1005     }
1006 
1007     if (NULL == LeadingStreamPointer->StreamHeader->Data)
1008     {
1009         Status = KsStreamPointerAdvance(LeadingStreamPointer);
1010         DPRINT1("Advancing Streampointer\n");
1011     }
1012 
1013 
1014     /* get pin context */
1015     PinContext = Pin->Context;
1016 
1017     /* get irp from ready list */
1018     Irp = PinGetIrpFromReadyList(Pin);
1019 
1020     if (!Irp)
1021     {
1022         /* no irps available */
1023         DPRINT1("No irps available");
1024         KsStreamPointerUnlock(LeadingStreamPointer, TRUE);
1025         return STATUS_SUCCESS;
1026     }
1027 
1028     /* clone stream pointer */
1029     Status = KsStreamPointerClone(LeadingStreamPointer, NULL, 0, &CloneStreamPointer);
1030     if (!NT_SUCCESS(Status))
1031     {
1032         /* failed */
1033         KsStreamPointerUnlock(LeadingStreamPointer, TRUE);
1034         DPRINT1("Leaking Irp %p\n", Irp);
1035         return STATUS_SUCCESS;
1036     }
1037 
1038     /* calculate packet count */
1039     /* FIXME support various sample rates */
1040     WaveFormatEx = (PKSDATAFORMAT_WAVEFORMATEX)Pin->ConnectionFormat;
1041     TotalPacketSize = WaveFormatEx->WaveFormatEx.nAvgBytesPerSec / 1000;
1042 
1043     /* init transfer buffer*/
1044     TransferBuffer = CloneStreamPointer->StreamHeader->Data;
1045 
1046     Offset = 0;
1047 
1048     /* are there bytes from previous request*/
1049     if (PinContext->BufferLength)
1050     {
1051         ASSERT(PinContext->BufferLength < TotalPacketSize);
1052 
1053         /* calculate offset*/
1054         Offset = TotalPacketSize - PinContext->BufferLength;
1055 
1056         if (PinContext->BufferOffset + TotalPacketSize >= PinContext->BufferSize)
1057         {
1058             RtlMoveMemory(PinContext->Buffer, &PinContext->Buffer[PinContext->BufferOffset - PinContext->BufferLength], PinContext->BufferLength);
1059             PinContext->BufferOffset = PinContext->BufferLength;
1060         }
1061 
1062         /* copy audio bytes */
1063         RtlCopyMemory(&PinContext->Buffer[PinContext->BufferOffset], TransferBuffer, Offset);
1064 
1065         /* init irp*/
1066         Status = RenderInitializeUrbAndIrp(Pin, PinContext, Irp, &PinContext->Buffer[PinContext->BufferOffset-PinContext->BufferLength], TotalPacketSize, TotalPacketSize);
1067         if (NT_SUCCESS(Status))
1068         {
1069             /* render audio bytes */
1070             Status = IoCallDriver(PinContext->LowerDevice, Irp);
1071         }
1072         else
1073         {
1074             ASSERT(FALSE);
1075         }
1076 
1077         PinContext->BufferLength = 0;
1078         PinContext->BufferOffset += Offset;
1079 
1080         /* get new irp from ready list */
1081         Irp = PinGetIrpFromReadyList(Pin);
1082         ASSERT(Irp);
1083 
1084     }
1085 
1086     /* FIXME correct MaximumPacketSize ? */
1087     PacketCount = (CloneStreamPointer->OffsetIn.Remaining - Offset) / TotalPacketSize;
1088 
1089     Status = RenderInitializeUrbAndIrp(Pin, PinContext, Irp, &TransferBuffer[Offset], PacketCount * TotalPacketSize, TotalPacketSize);
1090     if (NT_SUCCESS(Status))
1091     {
1092         /* store in irp context */
1093         Irp->Tail.Overlay.DriverContext[1] = CloneStreamPointer;
1094 
1095         if ((PacketCount * TotalPacketSize) + Offset < CloneStreamPointer->OffsetIn.Remaining)
1096         {
1097             /* calculate remaining buffer bytes */
1098             PinContext->BufferLength = CloneStreamPointer->OffsetIn.Remaining - ((PacketCount * TotalPacketSize) + Offset);
1099 
1100             /* check for overflow */
1101             if (PinContext->BufferOffset + TotalPacketSize >= PinContext->BufferSize)
1102             {
1103                 /* reset buffer offset*/
1104                 PinContext->BufferOffset = 0;
1105             }
1106             RtlCopyMemory(&PinContext->Buffer[PinContext->BufferOffset], &TransferBuffer[(PacketCount * TotalPacketSize) + Offset], PinContext->BufferLength);
1107             PinContext->BufferOffset += PinContext->BufferLength;
1108         }
1109 
1110         /* render audio bytes */
1111         Status = IoCallDriver(PinContext->LowerDevice, Irp);
1112     }
1113 
1114 
1115     /* unlock stream pointer and finish*/
1116     KsStreamPointerUnlock(LeadingStreamPointer, TRUE);
1117     return STATUS_PENDING;
1118 }
1119 
1120 NTSTATUS
PinCaptureProcess(IN PKSPIN Pin)1121 PinCaptureProcess(
1122     IN PKSPIN Pin)
1123 {
1124     PKSSTREAM_POINTER LeadingStreamPointer;
1125     KIRQL OldLevel;
1126     PPIN_CONTEXT PinContext;
1127     PLIST_ENTRY CurEntry;
1128     PIRP Irp;
1129     PURB Urb;
1130     PUCHAR TransferBuffer, OutBuffer;
1131     ULONG Offset, Length;
1132     NTSTATUS Status;
1133     PKSGATE Gate;
1134 
1135     //DPRINT1("PinCaptureProcess\n");
1136     LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
1137     if (LeadingStreamPointer == NULL)
1138     {
1139         /* get process control gate */
1140         Gate = KsPinGetAndGate(Pin);
1141 
1142         /* shutdown processing */
1143         KsGateTurnInputOff(Gate);
1144 
1145         return STATUS_SUCCESS;
1146     }
1147 
1148     /* get pin context */
1149     PinContext = Pin->Context;
1150 
1151     /* acquire spin lock */
1152     KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
1153 
1154     while (!IsListEmpty(&PinContext->DoneIrpListHead))
1155     {
1156         /* remove entry from list */
1157         CurEntry = RemoveHeadList(&PinContext->DoneIrpListHead);
1158 
1159         /* release lock */
1160         KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
1161 
1162         /* get irp offset */
1163         Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
1164 
1165         /* get urb from irp */
1166         Urb = (PURB)Irp->Tail.Overlay.DriverContext[0];
1167         ASSERT(Urb);
1168 
1169         Offset = PtrToUlong(Irp->Tail.Overlay.DriverContext[1]);
1170 
1171         /* get transfer buffer */
1172         TransferBuffer = Urb->UrbIsochronousTransfer.TransferBuffer;
1173 
1174         /* get target buffer */
1175         OutBuffer = (PUCHAR)LeadingStreamPointer->StreamHeader->Data;
1176 
1177         /* calculate length */
1178         Length = min(LeadingStreamPointer->OffsetOut.Count - LeadingStreamPointer->StreamHeader->DataUsed, Urb->UrbIsochronousTransfer.TransferBufferLength - Offset);
1179 
1180         /* FIXME copy each packet extra */
1181         /* copy audio bytes */
1182         RtlCopyMemory((PUCHAR)&OutBuffer[LeadingStreamPointer->StreamHeader->DataUsed], &TransferBuffer[Offset], Length);
1183 
1184         //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);
1185 
1186         /* adjust streampointer */
1187         LeadingStreamPointer->StreamHeader->DataUsed += Length;
1188 
1189         if (Length == LeadingStreamPointer->OffsetOut.Remaining)
1190         {
1191             KsStreamPointerAdvanceOffsetsAndUnlock(LeadingStreamPointer, 0, Length, TRUE);
1192 
1193             /* acquire spin lock */
1194             KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
1195 
1196             /* adjust offset */
1197             Irp->Tail.Overlay.DriverContext[1] = UlongToPtr(Length);
1198 
1199             /* reinsert into processed list */
1200             InsertHeadList(&PinContext->DoneIrpListHead, &Irp->Tail.Overlay.ListEntry);
1201 
1202             /* release lock */
1203             KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
1204 
1205             LeadingStreamPointer = KsPinGetLeadingEdgeStreamPointer(Pin, KSSTREAM_POINTER_STATE_LOCKED);
1206             if (LeadingStreamPointer == NULL)
1207             {
1208                 /* no more work to be done*/
1209                 return STATUS_PENDING;
1210             }
1211             else
1212             {
1213                 /* resume work on this irp */
1214                 continue;
1215             }
1216         }
1217         else
1218         {
1219             Status = KsStreamPointerAdvanceOffsets(LeadingStreamPointer, 0, Length, FALSE);
1220             NT_ASSERT(NT_SUCCESS(Status));
1221             ASSERT(Length == Urb->UrbIsochronousTransfer.TransferBufferLength - Offset);
1222         }
1223 
1224 
1225         /* acquire spin lock */
1226         KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
1227 
1228         InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
1229     }
1230 
1231     while (!IsListEmpty(&PinContext->IrpListHead))
1232     {
1233         /* remove entry from list */
1234         CurEntry = RemoveHeadList(&PinContext->IrpListHead);
1235 
1236         /* release lock */
1237         KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
1238 
1239         /* get irp offset */
1240         Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
1241 
1242         /* reinitialize irp and urb */
1243         CaptureInitializeUrbAndIrp(Pin, Irp);
1244 
1245         IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
1246 
1247         /* acquire spin lock */
1248         KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
1249 
1250     }
1251 
1252     /* release lock */
1253     KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
1254 
1255     if (LeadingStreamPointer != NULL)
1256         KsStreamPointerUnlock(LeadingStreamPointer, FALSE);
1257 
1258     /* get process control gate */
1259     Gate = KsPinGetAndGate(Pin);
1260 
1261     /* shutdown processing */
1262     KsGateTurnInputOff(Gate);
1263 
1264     return STATUS_PENDING;
1265 }
1266 
1267 
1268 NTSTATUS
1269 NTAPI
USBAudioPinProcess(_In_ PKSPIN Pin)1270 USBAudioPinProcess(
1271     _In_ PKSPIN Pin)
1272 {
1273     NTSTATUS Status;
1274 
1275     if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
1276     {
1277         Status = PinCaptureProcess(Pin);
1278     }
1279     else
1280     {
1281         Status = PinRenderProcess(Pin);
1282     }
1283 
1284     return Status;
1285 }
1286 
1287 
1288 VOID
1289 NTAPI
USBAudioPinReset(_In_ PKSPIN Pin)1290 USBAudioPinReset(
1291     _In_ PKSPIN Pin)
1292 {
1293     UNIMPLEMENTED;
1294 }
1295 
1296 NTSTATUS
1297 NTAPI
USBAudioPinSetDataFormat(_In_ PKSPIN Pin,_In_opt_ PKSDATAFORMAT OldFormat,_In_opt_ PKSMULTIPLE_ITEM OldAttributeList,_In_ const KSDATARANGE * DataRange,_In_opt_ const KSATTRIBUTE_LIST * AttributeRange)1298 USBAudioPinSetDataFormat(
1299     _In_ PKSPIN Pin,
1300     _In_opt_ PKSDATAFORMAT OldFormat,
1301     _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
1302     _In_ const KSDATARANGE* DataRange,
1303     _In_opt_ const KSATTRIBUTE_LIST* AttributeRange)
1304 {
1305     if (OldFormat == NULL)
1306     {
1307         /* TODO: verify connection format */
1308         UNIMPLEMENTED;
1309         return STATUS_SUCCESS;
1310     }
1311 
1312     return UsbAudioSetFormat(Pin);
1313 }
1314 
1315 NTSTATUS
StartCaptureIsocTransfer(IN PKSPIN Pin)1316 StartCaptureIsocTransfer(
1317     IN PKSPIN Pin)
1318 {
1319     PPIN_CONTEXT PinContext;
1320     PLIST_ENTRY CurEntry;
1321     PIRP Irp;
1322     KIRQL OldLevel;
1323 
1324     /* get pin context */
1325     PinContext = Pin->Context;
1326 
1327     /* acquire spin lock */
1328     KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
1329 
1330     while(!IsListEmpty(&PinContext->IrpListHead))
1331     {
1332         /* remove entry from list */
1333         CurEntry = RemoveHeadList(&PinContext->IrpListHead);
1334 
1335         /* get irp offset */
1336         Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
1337 
1338         /* release lock */
1339         KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
1340 
1341         /* reinitialize irp and urb */
1342         CaptureInitializeUrbAndIrp(Pin, Irp);
1343 
1344         DPRINT("StartCaptureIsocTransfer Irp %p\n", Irp);
1345         IoCallDriver(PinContext->DeviceExtension->LowerDevice, Irp);
1346 
1347         /* acquire spin lock */
1348         KeAcquireSpinLock(&PinContext->IrpListLock, &OldLevel);
1349 
1350     }
1351 
1352     /* release lock */
1353     KeReleaseSpinLock(&PinContext->IrpListLock, OldLevel);
1354 
1355     return STATUS_SUCCESS;
1356 }
1357 
1358 NTSTATUS
CapturePinStateChange(_In_ PKSPIN Pin,_In_ KSSTATE ToState,_In_ KSSTATE FromState)1359 CapturePinStateChange(
1360     _In_ PKSPIN Pin,
1361     _In_ KSSTATE ToState,
1362     _In_ KSSTATE FromState)
1363 {
1364     NTSTATUS Status = STATUS_SUCCESS;
1365 
1366     if (FromState != ToState)
1367     {
1368         if (ToState)
1369         {
1370             if (ToState == KSSTATE_PAUSE)
1371             {
1372                 if (FromState == KSSTATE_RUN)
1373                 {
1374                     /* wait until pin processing is finished*/
1375                 }
1376             }
1377             else
1378             {
1379                 if (ToState == KSSTATE_RUN)
1380                 {
1381                     Status = StartCaptureIsocTransfer(Pin);
1382                 }
1383             }
1384         }
1385     }
1386     return Status;
1387 }
1388 
1389 
1390 NTSTATUS
1391 NTAPI
USBAudioPinSetDeviceState(_In_ PKSPIN Pin,_In_ KSSTATE ToState,_In_ KSSTATE FromState)1392 USBAudioPinSetDeviceState(
1393     _In_ PKSPIN Pin,
1394     _In_ KSSTATE ToState,
1395     _In_ KSSTATE FromState)
1396 {
1397     NTSTATUS Status;
1398 
1399     if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
1400     {
1401         /* handle capture state changes */
1402         Status = CapturePinStateChange(Pin, ToState, FromState);
1403     }
1404     else
1405     {
1406         UNIMPLEMENTED;
1407         Status = STATUS_SUCCESS;
1408     }
1409 
1410     return Status;
1411 }
1412 
1413 
1414 NTSTATUS
1415 NTAPI
UsbAudioPinDataIntersect(_In_ PVOID Context,_In_ PIRP Irp,_In_ PKSP_PIN Pin,_In_ PKSDATARANGE DataRange,_In_ PKSDATARANGE MatchingDataRange,_In_ ULONG DataBufferSize,_Out_ PVOID Data,_Out_ PULONG DataSize)1416 UsbAudioPinDataIntersect(
1417     _In_  PVOID        Context,
1418     _In_  PIRP         Irp,
1419     _In_  PKSP_PIN     Pin,
1420     _In_  PKSDATARANGE DataRange,
1421     _In_  PKSDATARANGE MatchingDataRange,
1422     _In_  ULONG        DataBufferSize,
1423     _Out_ PVOID        Data,
1424     _Out_ PULONG       DataSize)
1425 {
1426     PKSFILTER Filter;
1427     PKSPIN_DESCRIPTOR_EX PinDescriptor;
1428     PKSDATAFORMAT_WAVEFORMATEX DataFormat;
1429     PKSDATARANGE_AUDIO DataRangeAudio;
1430 
1431     /* get filter from irp*/
1432     Filter = KsGetFilterFromIrp(Irp);
1433     if (!Filter)
1434     {
1435         /* no match*/
1436         return STATUS_NO_MATCH;
1437     }
1438 
1439     /* get pin descriptor */
1440     PinDescriptor = (PKSPIN_DESCRIPTOR_EX)&Filter->Descriptor->PinDescriptors[Pin->PinId];
1441 
1442     *DataSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
1443     if (DataBufferSize == 0)
1444     {
1445         /* buffer too small */
1446         return STATUS_BUFFER_OVERFLOW;
1447     }
1448 
1449     /* sanity checks*/
1450     ASSERT(PinDescriptor->PinDescriptor.DataRangesCount >= 0);
1451     ASSERT(PinDescriptor->PinDescriptor.DataRanges[0]->FormatSize == sizeof(KSDATARANGE_AUDIO));
1452 
1453     DataRangeAudio = (PKSDATARANGE_AUDIO)PinDescriptor->PinDescriptor.DataRanges[0];
1454 
1455     DataFormat = Data;
1456     DataFormat->WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
1457     DataFormat->WaveFormatEx.nChannels = DataRangeAudio->MaximumChannels;
1458     DataFormat->WaveFormatEx.nSamplesPerSec = DataRangeAudio->MaximumSampleFrequency;
1459     DataFormat->WaveFormatEx.nAvgBytesPerSec = DataRangeAudio->MaximumSampleFrequency * (DataRangeAudio->MaximumBitsPerSample / 8) * DataRangeAudio->MaximumChannels;
1460     DataFormat->WaveFormatEx.nBlockAlign = (DataRangeAudio->MaximumBitsPerSample / 8) * DataRangeAudio->MaximumChannels;
1461     DataFormat->WaveFormatEx.wBitsPerSample = DataRangeAudio->MaximumBitsPerSample;
1462     DataFormat->WaveFormatEx.cbSize = 0;
1463 
1464     DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
1465     DataFormat->DataFormat.Flags = 0;
1466     DataFormat->DataFormat.Reserved = 0;
1467     DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
1468     DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1469     DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
1470     DataFormat->DataFormat.SampleSize = (DataRangeAudio->MaximumBitsPerSample / 8) * DataRangeAudio->MaximumChannels;
1471 
1472     return STATUS_SUCCESS;
1473 }
1474