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.
7 * Johannes Anderwald (johannes.anderwald@reactos.org)
12 #define PACKET_COUNT 10
16 GetMaxPacketSizeForInterface(
17 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
,
18 IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
,
19 KSPIN_DATAFLOW DataFlow
)
21 PUSB_COMMON_DESCRIPTOR CommonDescriptor
;
22 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
;
24 /* loop descriptors */
25 CommonDescriptor
= (PUSB_COMMON_DESCRIPTOR
)((ULONG_PTR
)InterfaceDescriptor
+ InterfaceDescriptor
->bLength
);
26 ASSERT(InterfaceDescriptor
->bNumEndpoints
> 0);
27 while (CommonDescriptor
)
29 if (CommonDescriptor
->bDescriptorType
== USB_ENDPOINT_DESCRIPTOR_TYPE
)
31 EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)CommonDescriptor
;
32 return EndpointDescriptor
->wMaxPacketSize
;
35 if (CommonDescriptor
->bDescriptorType
== USB_INTERFACE_DESCRIPTOR_TYPE
)
37 /* reached next interface descriptor */
41 if ((ULONG_PTR
)CommonDescriptor
+ CommonDescriptor
->bLength
>= ((ULONG_PTR
)ConfigurationDescriptor
+ ConfigurationDescriptor
->wTotalLength
))
44 CommonDescriptor
= (PUSB_COMMON_DESCRIPTOR
)((ULONG_PTR
)CommonDescriptor
+ CommonDescriptor
->bLength
);
52 UsbAudioAllocCaptureUrbIso(
53 IN USBD_PIPE_HANDLE PipeHandle
,
54 IN ULONG MaxPacketSize
,
56 IN ULONG BufferLength
,
63 /* calculate urb size*/
64 UrbSize
= GET_ISO_URB_SIZE(PACKET_COUNT
);
67 Urb
= AllocFunction(UrbSize
);
71 return STATUS_INSUFFICIENT_RESOURCES
;
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
;
83 for (Index
= 0; Index
< PACKET_COUNT
; Index
++)
85 Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Offset
= Index
* MaxPacketSize
;
89 return STATUS_SUCCESS
;
98 PUCHAR SampleRateBuffer
;
99 PPIN_CONTEXT PinContext
;
102 /* allocate sample rate buffer */
103 SampleRateBuffer
= AllocFunction(sizeof(ULONG
));
104 if (!SampleRateBuffer
)
107 return STATUS_INSUFFICIENT_RESOURCES
;
111 Urb
= AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
));
115 FreeFunction(SampleRateBuffer
);
116 return STATUS_INSUFFICIENT_RESOURCES
;
119 /* FIXME: determine controls and format urb */
120 UsbBuildVendorRequest(Urb
,
121 URB_FUNCTION_CLASS_INTERFACE
,
122 sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
),
123 USBD_TRANSFER_DIRECTION_OUT
,
133 /* get pin context */
134 PinContext
= Pin
->Context
;
136 SampleRateBuffer
[0] = 0xC2;
137 SampleRateBuffer
[1] = 0xFE;
140 Status
= SubmitUrbSync(PinContext
->LowerDevice
, Urb
);
142 DPRINT1("UsbAudioSetVolume Pin %p Status %x\n", Pin
, Status
);
144 FreeFunction(SampleRateBuffer
);
153 PUCHAR SampleRateBuffer
;
154 PPIN_CONTEXT PinContext
;
156 PKSDATAFORMAT_WAVEFORMATEX WaveFormatEx
;
158 /* allocate sample rate buffer */
159 SampleRateBuffer
= AllocFunction(sizeof(ULONG
));
160 if (!SampleRateBuffer
)
163 return STATUS_INSUFFICIENT_RESOURCES
;
166 if (IsEqualGUIDAligned(&Pin
->ConnectionFormat
->MajorFormat
, &KSDATAFORMAT_TYPE_AUDIO
) &&
167 IsEqualGUIDAligned(&Pin
->ConnectionFormat
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) &&
168 IsEqualGUIDAligned(&Pin
->ConnectionFormat
->Specifier
, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
))
170 WaveFormatEx
= (PKSDATAFORMAT_WAVEFORMATEX
)Pin
->ConnectionFormat
;
171 SampleRateBuffer
[2] = (WaveFormatEx
->WaveFormatEx
.nSamplesPerSec
>> 16) & 0xFF;
172 SampleRateBuffer
[1] = (WaveFormatEx
->WaveFormatEx
.nSamplesPerSec
>> 8) & 0xFF;
173 SampleRateBuffer
[0] = (WaveFormatEx
->WaveFormatEx
.nSamplesPerSec
>> 0) & 0xFF;
175 /* TODO: verify connection format */
179 /* not supported yet*/
181 FreeFunction(SampleRateBuffer
);
182 return STATUS_INVALID_PARAMETER
;
186 Urb
= AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
));
190 FreeFunction(SampleRateBuffer
);
191 return STATUS_INSUFFICIENT_RESOURCES
;
194 /* FIXME: determine controls and format urb */
195 UsbBuildVendorRequest(Urb
,
196 URB_FUNCTION_CLASS_ENDPOINT
,
197 sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
),
198 USBD_TRANSFER_DIRECTION_OUT
,
202 0x81, //FIXME bEndpointAddress
208 /* get pin context */
209 PinContext
= Pin
->Context
;
212 Status
= SubmitUrbSync(PinContext
->LowerDevice
, Urb
);
214 DPRINT1("USBAudioPinSetDataFormat Pin %p Status %x\n", Pin
, Status
);
216 FreeFunction(SampleRateBuffer
);
221 USBAudioSelectAudioStreamingInterface(
222 IN PPIN_CONTEXT PinContext
,
223 IN PDEVICE_EXTENSION DeviceExtension
,
224 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
227 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
;
230 /* grab interface descriptor */
231 InterfaceDescriptor
= USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor
, ConfigurationDescriptor
, -1, -1, USB_DEVICE_CLASS_AUDIO
, -1, -1);
232 if (!InterfaceDescriptor
)
234 /* no such interface */
235 return STATUS_INVALID_PARAMETER
;
238 /* FIXME selects the first interface with audio streaming and non zero num of endpoints */
239 while (InterfaceDescriptor
!= NULL
)
241 if (InterfaceDescriptor
->bInterfaceSubClass
== 0x02 /* AUDIO_STREAMING */ && InterfaceDescriptor
->bNumEndpoints
> 0)
245 InterfaceDescriptor
= USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor
, (PVOID
)((ULONG_PTR
)InterfaceDescriptor
+ InterfaceDescriptor
->bLength
), -1, -1, USB_DEVICE_CLASS_AUDIO
, -1, -1);
248 if (!InterfaceDescriptor
)
250 /* no such interface */
251 return STATUS_INVALID_PARAMETER
;
254 Urb
= AllocFunction(GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor
->bNumEndpoints
));
258 return USBD_STATUS_INSUFFICIENT_RESOURCES
;
261 /* now prepare interface urb */
262 UsbBuildSelectInterfaceRequest(Urb
, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor
->bNumEndpoints
), DeviceExtension
->ConfigurationHandle
, InterfaceDescriptor
->bInterfaceNumber
, InterfaceDescriptor
->bAlternateSetting
);
264 /* now select the interface */
265 Status
= SubmitUrbSync(DeviceExtension
->LowerDevice
, Urb
);
267 DPRINT1("USBAudioSelectAudioStreamingInterface Status %x UrbStatus %x\n", Status
, Urb
->UrbSelectInterface
.Hdr
.Status
);
269 /* did it succeeed */
270 if (NT_SUCCESS(Status
))
272 /* free old interface info */
273 if (DeviceExtension
->InterfaceInfo
)
276 FreeFunction(DeviceExtension
->InterfaceInfo
);
279 /* alloc interface info */
280 DeviceExtension
->InterfaceInfo
= AllocFunction(Urb
->UrbSelectInterface
.Interface
.Length
);
281 if (DeviceExtension
->InterfaceInfo
== NULL
)
285 return STATUS_INSUFFICIENT_RESOURCES
;
288 /* copy interface info */
289 RtlCopyMemory(DeviceExtension
->InterfaceInfo
, &Urb
->UrbSelectInterface
.Interface
, Urb
->UrbSelectInterface
.Interface
.Length
);
290 PinContext
->InterfaceDescriptor
= InterfaceDescriptor
;
300 CaptureGateOnWorkItem(
304 PPIN_CONTEXT PinContext
;
311 /* get pin context */
312 PinContext
= Pin
->Context
;
316 /* acquire processing mutex */
317 KsPinAcquireProcessingMutex(Pin
);
319 /* get pin control gate */
320 Gate
= KsPinGetAndGate(Pin
);
323 KsGateTurnInputOn(Gate
);
325 /* schedule processing */
326 KsPinAttemptProcessing(Pin
, TRUE
);
328 /* release processing mutex */
329 KsPinReleaseProcessingMutex(Pin
);
331 /* decrement worker count */
332 Count
= KsDecrementCountedWorker(PinContext
->CaptureWorker
);
339 CaptureInitializeUrbAndIrp(
343 PIO_STACK_LOCATION IoStack
;
345 PUCHAR TransferBuffer
;
347 PPIN_CONTEXT PinContext
;
349 /* get pin context */
350 PinContext
= Pin
->Context
;
352 /* backup urb and transferbuffer */
353 Urb
= Irp
->Tail
.Overlay
.DriverContext
[0];
354 TransferBuffer
= Urb
->UrbIsochronousTransfer
.TransferBuffer
;
357 IoInitializeIrp(Irp
, IoSizeOfIrp(PinContext
->DeviceExtension
->LowerDevice
->StackSize
), PinContext
->DeviceExtension
->LowerDevice
->StackSize
);
359 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
360 Irp
->IoStatus
.Information
= 0;
362 Irp
->UserBuffer
= NULL
;
363 Irp
->Tail
.Overlay
.DriverContext
[0] = Urb
;
364 Irp
->Tail
.Overlay
.DriverContext
[1] = NULL
;
366 /* init stack location */
367 IoStack
= IoGetNextIrpStackLocation(Irp
);
368 IoStack
->DeviceObject
= PinContext
->DeviceExtension
->LowerDevice
;
369 IoStack
->Parameters
.Others
.Argument1
= Urb
;
370 IoStack
->Parameters
.Others
.Argument2
= NULL
;
371 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
372 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
374 IoSetCompletionRoutine(Irp
, UsbAudioCaptureComplete
, Pin
, TRUE
, TRUE
, TRUE
);
376 RtlZeroMemory(Urb
, GET_ISO_URB_SIZE(PACKET_COUNT
));
379 Urb
->UrbIsochronousTransfer
.Hdr
.Function
= URB_FUNCTION_ISOCH_TRANSFER
;
380 Urb
->UrbIsochronousTransfer
.Hdr
.Length
= GET_ISO_URB_SIZE(10);
381 Urb
->UrbIsochronousTransfer
.PipeHandle
= PinContext
->DeviceExtension
->InterfaceInfo
->Pipes
[0].PipeHandle
;
382 Urb
->UrbIsochronousTransfer
.TransferFlags
= USBD_TRANSFER_DIRECTION_IN
| USBD_START_ISO_TRANSFER_ASAP
;
383 Urb
->UrbIsochronousTransfer
.TransferBufferLength
= PinContext
->DeviceExtension
->InterfaceInfo
->Pipes
[0].MaximumPacketSize
* 10;
384 Urb
->UrbIsochronousTransfer
.TransferBuffer
= TransferBuffer
;
385 Urb
->UrbIsochronousTransfer
.NumberOfPackets
= PACKET_COUNT
;
386 Urb
->UrbIsochronousTransfer
.StartFrame
= 0;
388 for (Index
= 0; Index
< PACKET_COUNT
; Index
++)
390 Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Offset
= Index
* PinContext
->DeviceExtension
->InterfaceInfo
->Pipes
[0].MaximumPacketSize
;
397 CaptureAvoidPipeStarvationWorker(
401 PPIN_CONTEXT PinContext
;
403 PLIST_ENTRY CurEntry
;
409 /* get pin context */
410 PinContext
= Pin
->Context
;
412 /* acquire spin lock */
413 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
415 if (!IsListEmpty(&PinContext
->IrpListHead
))
418 ASSERT(!IsListEmpty(&PinContext
->IrpListHead
));
420 /* remove entry from list */
421 CurEntry
= RemoveHeadList(&PinContext
->IrpListHead
);
424 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
427 Irp
= (PIRP
)CONTAINING_RECORD(CurEntry
, IRP
, Tail
.Overlay
.ListEntry
);
429 /* reinitialize irp and urb */
430 CaptureInitializeUrbAndIrp(Pin
, Irp
);
432 KsDecrementCountedWorker(PinContext
->StarvationWorker
);
435 IoCallDriver(PinContext
->DeviceExtension
->LowerDevice
, Irp
);
440 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
442 KsDecrementCountedWorker(PinContext
->StarvationWorker
);
455 ULONG MaximumPacketSize
;
458 PPIN_CONTEXT PinContext
;
459 PIO_STACK_LOCATION IoStack
;
460 PKSALLOCATOR_FRAMING_EX Framing
;
464 /* set sample rate */
465 Status
= UsbAudioSetFormat(Pin
);
466 if (!NT_SUCCESS(Status
))
472 /* get pin context */
473 PinContext
= Pin
->Context
;
475 /* lets get maximum packet size */
476 MaximumPacketSize
= GetMaxPacketSizeForInterface(PinContext
->DeviceExtension
->ConfigurationDescriptor
, PinContext
->InterfaceDescriptor
, Pin
->DataFlow
);
478 /* initialize work item for capture worker */
479 ExInitializeWorkItem(&PinContext
->CaptureWorkItem
, CaptureGateOnWorkItem
, (PVOID
)Pin
);
481 /* register worker */
482 Status
= KsRegisterCountedWorker(CriticalWorkQueue
, &PinContext
->CaptureWorkItem
, &PinContext
->CaptureWorker
);
483 if (!NT_SUCCESS(Status
))
489 /* initialize work item */
490 ExInitializeWorkItem(&PinContext
->StarvationWorkItem
, CaptureAvoidPipeStarvationWorker
, (PVOID
)Pin
);
492 /* register worker */
493 Status
= KsRegisterCountedWorker(CriticalWorkQueue
, &PinContext
->StarvationWorkItem
, &PinContext
->StarvationWorker
);
494 if (!NT_SUCCESS(Status
))
497 KsUnregisterWorker(PinContext
->CaptureWorker
);
500 /* lets edit framing struct */
501 Framing
= (PKSALLOCATOR_FRAMING_EX
)Pin
->Descriptor
->AllocatorFraming
;
502 Framing
->FramingItem
[0].PhysicalRange
.MinFrameSize
=
503 Framing
->FramingItem
[0].PhysicalRange
.MaxFrameSize
=
504 Framing
->FramingItem
[0].FramingRange
.Range
.MinFrameSize
=
505 Framing
->FramingItem
[0].FramingRange
.Range
.MaxFrameSize
=
508 /* calculate buffer size 8 irps * 10 iso packets * max packet size */
509 BufferSize
= 8 * PACKET_COUNT
* MaximumPacketSize
;
511 /* allocate pin capture buffer */
512 PinContext
->BufferSize
= BufferSize
;
513 PinContext
->Buffer
= AllocFunction(BufferSize
);
514 if (!PinContext
->Buffer
)
517 return STATUS_INSUFFICIENT_RESOURCES
;
519 KsAddItemToObjectBag(Pin
->Bag
, PinContext
->Buffer
, ExFreePool
);
522 for (Index
= 0; Index
< 8; Index
++)
525 Irp
= AllocFunction(IoSizeOfIrp(PinContext
->DeviceExtension
->LowerDevice
->StackSize
));
529 return STATUS_INSUFFICIENT_RESOURCES
;
533 IoInitializeIrp(Irp
, IoSizeOfIrp(PinContext
->DeviceExtension
->LowerDevice
->StackSize
), PinContext
->DeviceExtension
->LowerDevice
->StackSize
);
535 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
536 Irp
->IoStatus
.Information
= 0;
538 Irp
->UserBuffer
= NULL
;
540 IoStack
= IoGetNextIrpStackLocation(Irp
);
541 IoStack
->DeviceObject
= PinContext
->DeviceExtension
->LowerDevice
;
542 IoStack
->Parameters
.Others
.Argument2
= NULL
;
543 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
544 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
546 IoSetCompletionRoutine(Irp
, UsbAudioCaptureComplete
, Pin
, TRUE
, TRUE
, TRUE
);
548 /* insert into irp list */
549 InsertTailList(&PinContext
->IrpListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
551 /* add to object bag*/
552 KsAddItemToObjectBag(Pin
->Bag
, Irp
, ExFreePool
);
554 /* FIXME select correct pipe handle */
555 Status
= UsbAudioAllocCaptureUrbIso(PinContext
->DeviceExtension
->InterfaceInfo
->Pipes
[0].PipeHandle
,
557 &PinContext
->Buffer
[MaximumPacketSize
* PACKET_COUNT
* Index
],
558 MaximumPacketSize
* PACKET_COUNT
,
561 DPRINT1("InitCapturePin Irp %p Urb %p\n", Irp
, Urb
);
563 if (NT_SUCCESS(Status
))
565 /* get next stack location */
566 IoStack
= IoGetNextIrpStackLocation(Irp
);
569 IoStack
->Parameters
.Others
.Argument1
= Urb
;
570 Irp
->Tail
.Overlay
.DriverContext
[0] = Urb
;
579 /* get process control gate */
580 Gate
= KsPinGetAndGate(Pin
);
583 KsGateTurnInputOff(Gate
);
593 return STATUS_NOT_IMPLEMENTED
;
606 PFILTER_CONTEXT FilterContext
;
607 PPIN_CONTEXT PinContext
;
610 Filter
= KsPinGetParentFilter(Pin
);
613 /* invalid parameter */
614 return STATUS_INVALID_PARAMETER
;
617 /* get filter context */
618 FilterContext
= Filter
->Context
;
620 /* allocate pin context */
621 PinContext
= AllocFunction(sizeof(PIN_CONTEXT
));
625 return STATUS_INSUFFICIENT_RESOURCES
;
628 /* init pin context */
629 PinContext
->DeviceExtension
= FilterContext
->DeviceExtension
;
630 PinContext
->LowerDevice
= FilterContext
->LowerDevice
;
631 InitializeListHead(&PinContext
->IrpListHead
);
632 InitializeListHead(&PinContext
->DoneIrpListHead
);
633 KeInitializeSpinLock(&PinContext
->IrpListLock
);
635 /* store pin context*/
636 Pin
->Context
= PinContext
;
638 /* lets edit allocator framing struct */
639 Status
= _KsEdit(Pin
->Bag
, (PVOID
*)&Pin
->Descriptor
, sizeof(KSPIN_DESCRIPTOR_EX
), sizeof(KSPIN_DESCRIPTOR_EX
), USBAUDIO_TAG
);
640 if (NT_SUCCESS(Status
))
642 Status
= _KsEdit(Pin
->Bag
, (PVOID
*)&Pin
->Descriptor
->AllocatorFraming
, sizeof(KSALLOCATOR_FRAMING_EX
), sizeof(KSALLOCATOR_FRAMING_EX
), USBAUDIO_TAG
);
643 ASSERT(Status
== STATUS_SUCCESS
);
646 /* FIXME move to build filter topology*/
647 UsbAudioSetVolume(Pin
);
649 /* select streaming interface */
650 Status
= USBAudioSelectAudioStreamingInterface(PinContext
, PinContext
->DeviceExtension
, PinContext
->DeviceExtension
->ConfigurationDescriptor
);
651 if (!NT_SUCCESS(Status
))
657 if (Pin
->DataFlow
== KSPIN_DATAFLOW_OUT
)
659 /* init capture pin */
660 Status
= InitCapturePin(Pin
);
664 /* audio streaming pin*/
665 Status
= InitStreamPin(Pin
);
668 return STATUS_SUCCESS
;
678 return STATUS_NOT_IMPLEMENTED
;
683 UsbAudioCaptureComplete(
684 IN PDEVICE_OBJECT DeviceObject
,
689 PPIN_CONTEXT PinContext
;
693 /* get pin context */
695 PinContext
= Pin
->Context
;
698 Urb
= Irp
->Tail
.Overlay
.DriverContext
[0];
701 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
703 if (!NT_SUCCESS(Urb
->UrbIsochronousTransfer
.Hdr
.Status
))
705 //DPRINT("UsbAudioCaptureComplete Irp %p Urb %p Status %x Packet Status %x\n", Irp, Urb, Urb->UrbIsochronousTransfer.Hdr.Status, Urb->UrbIsochronousTransfer.IsoPacket[0].Status);
707 /* insert entry into ready list */
708 InsertTailList(&PinContext
->IrpListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
711 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
713 KsIncrementCountedWorker(PinContext
->StarvationWorker
);
717 /* insert entry into done list */
718 InsertTailList(&PinContext
->DoneIrpListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
721 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
723 KsIncrementCountedWorker(PinContext
->CaptureWorker
);
727 return STATUS_MORE_PROCESSING_REQUIRED
;
734 PKSSTREAM_POINTER LeadingStreamPointer
;
736 PPIN_CONTEXT PinContext
;
737 PLIST_ENTRY CurEntry
;
740 PUCHAR TransferBuffer
, OutBuffer
;
741 ULONG Offset
, Length
;
745 //DPRINT1("PinCaptureProcess\n");
746 LeadingStreamPointer
= KsPinGetLeadingEdgeStreamPointer(Pin
, KSSTREAM_POINTER_STATE_LOCKED
);
747 if (LeadingStreamPointer
== NULL
)
749 /* get process control gate */
750 Gate
= KsPinGetAndGate(Pin
);
752 /* shutdown processing */
753 KsGateTurnInputOff(Gate
);
755 return STATUS_SUCCESS
;
758 /* get pin context */
759 PinContext
= Pin
->Context
;
761 /* acquire spin lock */
762 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
764 while (!IsListEmpty(&PinContext
->DoneIrpListHead
))
766 /* remove entry from list */
767 CurEntry
= RemoveHeadList(&PinContext
->DoneIrpListHead
);
770 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
773 Irp
= (PIRP
)CONTAINING_RECORD(CurEntry
, IRP
, Tail
.Overlay
.ListEntry
);
775 /* get urb from irp */
776 Urb
= (PURB
)Irp
->Tail
.Overlay
.DriverContext
[0];
779 Offset
= PtrToUlong(Irp
->Tail
.Overlay
.DriverContext
[1]);
781 /* get transfer buffer */
782 TransferBuffer
= Urb
->UrbIsochronousTransfer
.TransferBuffer
;
784 /* get target buffer */
785 OutBuffer
= (PUCHAR
)LeadingStreamPointer
->StreamHeader
->Data
;
787 /* calculate length */
788 Length
= min(LeadingStreamPointer
->OffsetOut
.Count
- LeadingStreamPointer
->StreamHeader
->DataUsed
, Urb
->UrbIsochronousTransfer
.TransferBufferLength
- Offset
);
790 /* FIXME copy each packet extra */
791 /* copy audio bytes */
792 RtlCopyMemory((PUCHAR
)&OutBuffer
[LeadingStreamPointer
->StreamHeader
->DataUsed
], &TransferBuffer
[Offset
], Length
);
794 //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);
796 /* adjust streampointer */
797 LeadingStreamPointer
->StreamHeader
->DataUsed
+= Length
;
799 if (Length
== LeadingStreamPointer
->OffsetOut
.Remaining
)
801 KsStreamPointerAdvanceOffsetsAndUnlock(LeadingStreamPointer
, 0, Length
, TRUE
);
803 /* acquire spin lock */
804 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
807 Irp
->Tail
.Overlay
.DriverContext
[1] = UlongToPtr(Length
);
809 /* reinsert into processed list */
810 InsertHeadList(&PinContext
->DoneIrpListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
813 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
815 LeadingStreamPointer
= KsPinGetLeadingEdgeStreamPointer(Pin
, KSSTREAM_POINTER_STATE_LOCKED
);
816 if (LeadingStreamPointer
== NULL
)
818 /* no more work to be done*/
819 return STATUS_PENDING
;
823 /* resume work on this irp */
829 Status
= KsStreamPointerAdvanceOffsets(LeadingStreamPointer
, 0, Length
, FALSE
);
830 NT_ASSERT(NT_SUCCESS(Status
));
831 ASSERT(Length
== Urb
->UrbIsochronousTransfer
.TransferBufferLength
- Offset
);
835 /* acquire spin lock */
836 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
838 InsertTailList(&PinContext
->IrpListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
841 while (!IsListEmpty(&PinContext
->IrpListHead
))
843 /* remove entry from list */
844 CurEntry
= RemoveHeadList(&PinContext
->IrpListHead
);
847 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
850 Irp
= (PIRP
)CONTAINING_RECORD(CurEntry
, IRP
, Tail
.Overlay
.ListEntry
);
852 /* reinitialize irp and urb */
853 CaptureInitializeUrbAndIrp(Pin
, Irp
);
855 IoCallDriver(PinContext
->DeviceExtension
->LowerDevice
, Irp
);
857 /* acquire spin lock */
858 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
863 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
865 if (LeadingStreamPointer
!= NULL
)
866 KsStreamPointerUnlock(LeadingStreamPointer
, FALSE
);
868 /* get process control gate */
869 Gate
= KsPinGetAndGate(Pin
);
871 /* shutdown processing */
872 KsGateTurnInputOff(Gate
);
874 return STATUS_PENDING
;
885 if (Pin
->DataFlow
== KSPIN_DATAFLOW_OUT
)
887 Status
= PinCaptureProcess(Pin
);
892 Status
= STATUS_NOT_IMPLEMENTED
;
909 USBAudioPinSetDataFormat(
911 _In_opt_ PKSDATAFORMAT OldFormat
,
912 _In_opt_ PKSMULTIPLE_ITEM OldAttributeList
,
913 _In_
const KSDATARANGE
* DataRange
,
914 _In_opt_
const KSATTRIBUTE_LIST
* AttributeRange
)
916 if (OldFormat
== NULL
)
918 /* TODO: verify connection format */
920 return STATUS_SUCCESS
;
923 return UsbAudioSetFormat(Pin
);
927 StartCaptureIsocTransfer(
930 PPIN_CONTEXT PinContext
;
931 PLIST_ENTRY CurEntry
;
935 /* get pin context */
936 PinContext
= Pin
->Context
;
938 /* acquire spin lock */
939 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
941 while(!IsListEmpty(&PinContext
->IrpListHead
))
943 /* remove entry from list */
944 CurEntry
= RemoveHeadList(&PinContext
->IrpListHead
);
947 Irp
= (PIRP
)CONTAINING_RECORD(CurEntry
, IRP
, Tail
.Overlay
.ListEntry
);
950 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
952 /* reinitialize irp and urb */
953 CaptureInitializeUrbAndIrp(Pin
, Irp
);
955 DPRINT("StartCaptureIsocTransfer Irp %p\n", Irp
);
956 IoCallDriver(PinContext
->DeviceExtension
->LowerDevice
, Irp
);
958 /* acquire spin lock */
959 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
964 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
966 return STATUS_SUCCESS
;
970 CapturePinStateChange(
972 _In_ KSSTATE ToState
,
973 _In_ KSSTATE FromState
)
977 if (FromState
!= ToState
)
981 if (ToState
== KSSTATE_PAUSE
)
983 if (FromState
== KSSTATE_RUN
)
985 /* wait until pin processing is finished*/
990 if (ToState
== KSSTATE_RUN
)
992 Status
= StartCaptureIsocTransfer(Pin
);
1003 USBAudioPinSetDeviceState(
1005 _In_ KSSTATE ToState
,
1006 _In_ KSSTATE FromState
)
1010 if (Pin
->DataFlow
== KSPIN_DATAFLOW_OUT
)
1012 /* handle capture state changes */
1013 Status
= CapturePinStateChange(Pin
, ToState
, FromState
);
1018 Status
= STATUS_NOT_IMPLEMENTED
;
1027 UsbAudioPinDataIntersect(
1031 _In_ PKSDATARANGE DataRange
,
1032 _In_ PKSDATARANGE MatchingDataRange
,
1033 _In_ ULONG DataBufferSize
,
1035 _Out_ PULONG DataSize
)
1038 PKSPIN_DESCRIPTOR_EX PinDescriptor
;
1039 PKSDATAFORMAT_WAVEFORMATEX DataFormat
;
1040 PKSDATARANGE_AUDIO DataRangeAudio
;
1042 /* get filter from irp*/
1043 Filter
= KsGetFilterFromIrp(Irp
);
1047 return STATUS_NO_MATCH
;
1050 /* get pin descriptor */
1051 PinDescriptor
= (PKSPIN_DESCRIPTOR_EX
)&Filter
->Descriptor
->PinDescriptors
[Pin
->PinId
];
1053 *DataSize
= sizeof(KSDATAFORMAT_WAVEFORMATEX
);
1054 if (DataBufferSize
== 0)
1056 /* buffer too small */
1057 return STATUS_BUFFER_OVERFLOW
;
1061 ASSERT(PinDescriptor
->PinDescriptor
.DataRangesCount
>= 0);
1062 ASSERT(PinDescriptor
->PinDescriptor
.DataRanges
[0]->FormatSize
== sizeof(KSDATARANGE_AUDIO
));
1064 DataRangeAudio
= (PKSDATARANGE_AUDIO
)PinDescriptor
->PinDescriptor
.DataRanges
[0];
1067 DataFormat
->WaveFormatEx
.wFormatTag
= WAVE_FORMAT_PCM
;
1068 DataFormat
->WaveFormatEx
.nChannels
= DataRangeAudio
->MaximumChannels
;
1069 DataFormat
->WaveFormatEx
.nSamplesPerSec
= DataRangeAudio
->MaximumSampleFrequency
;
1070 DataFormat
->WaveFormatEx
.nAvgBytesPerSec
= DataRangeAudio
->MaximumSampleFrequency
* (DataRangeAudio
->MaximumBitsPerSample
/ 8) * DataRangeAudio
->MaximumChannels
;
1071 DataFormat
->WaveFormatEx
.nBlockAlign
= (DataRangeAudio
->MaximumBitsPerSample
/ 8) * DataRangeAudio
->MaximumChannels
;
1072 DataFormat
->WaveFormatEx
.wBitsPerSample
= DataRangeAudio
->MaximumBitsPerSample
;
1073 DataFormat
->WaveFormatEx
.cbSize
= 0;
1075 DataFormat
->DataFormat
.FormatSize
= sizeof(KSDATAFORMAT
) + sizeof(WAVEFORMATEX
);
1076 DataFormat
->DataFormat
.Flags
= 0;
1077 DataFormat
->DataFormat
.Reserved
= 0;
1078 DataFormat
->DataFormat
.MajorFormat
= KSDATAFORMAT_TYPE_AUDIO
;
1079 DataFormat
->DataFormat
.SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1080 DataFormat
->DataFormat
.Specifier
= KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
;
1081 DataFormat
->DataFormat
.SampleSize
= (DataRangeAudio
->MaximumBitsPerSample
/ 8) * DataRangeAudio
->MaximumChannels
;
1083 return STATUS_SUCCESS
;