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)
13 GetMaxPacketSizeForInterface(
14 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
,
15 IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
,
16 KSPIN_DATAFLOW DataFlow
)
18 PUSB_COMMON_DESCRIPTOR CommonDescriptor
;
19 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
;
21 /* loop descriptors */
22 CommonDescriptor
= (PUSB_COMMON_DESCRIPTOR
)((ULONG_PTR
)InterfaceDescriptor
+ InterfaceDescriptor
->bLength
);
23 ASSERT(InterfaceDescriptor
->bNumEndpoints
> 0);
24 while (CommonDescriptor
)
26 if (CommonDescriptor
->bDescriptorType
== USB_ENDPOINT_DESCRIPTOR_TYPE
)
28 EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)CommonDescriptor
;
29 return EndpointDescriptor
->wMaxPacketSize
;
32 if (CommonDescriptor
->bDescriptorType
== USB_INTERFACE_DESCRIPTOR_TYPE
)
34 /* reached next interface descriptor */
38 if ((ULONG_PTR
)CommonDescriptor
+ CommonDescriptor
->bLength
>= ((ULONG_PTR
)ConfigurationDescriptor
+ ConfigurationDescriptor
->wTotalLength
))
41 CommonDescriptor
= (PUSB_COMMON_DESCRIPTOR
)((ULONG_PTR
)CommonDescriptor
+ CommonDescriptor
->bLength
);
49 UsbAudioAllocCaptureUrbIso(
50 IN USBD_PIPE_HANDLE PipeHandle
,
51 IN ULONG MaxPacketSize
,
53 IN ULONG BufferLength
,
61 /* calculate packet count */
62 PacketCount
= BufferLength
/ MaxPacketSize
;
64 /* calculate urb size*/
65 UrbSize
= GET_ISO_URB_SIZE(PacketCount
);
68 Urb
= AllocFunction(UrbSize
);
72 return STATUS_INSUFFICIENT_RESOURCES
;
76 Urb
->UrbIsochronousTransfer
.Hdr
.Function
= URB_FUNCTION_ISOCH_TRANSFER
;
77 Urb
->UrbIsochronousTransfer
.Hdr
.Length
= UrbSize
;
78 Urb
->UrbIsochronousTransfer
.PipeHandle
= PipeHandle
;
79 Urb
->UrbIsochronousTransfer
.TransferFlags
= USBD_TRANSFER_DIRECTION_IN
| USBD_START_ISO_TRANSFER_ASAP
;
80 Urb
->UrbIsochronousTransfer
.TransferBufferLength
= BufferLength
;
81 Urb
->UrbIsochronousTransfer
.TransferBuffer
= Buffer
;
82 Urb
->UrbIsochronousTransfer
.NumberOfPackets
= PacketCount
;
84 for (Index
= 0; Index
< PacketCount
; Index
++)
86 Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Offset
= Index
* MaxPacketSize
;
90 return STATUS_SUCCESS
;
101 PUCHAR SampleRateBuffer
;
102 PPIN_CONTEXT PinContext
;
104 PKSDATAFORMAT_WAVEFORMATEX WaveFormatEx
;
106 /* allocate sample rate buffer */
107 SampleRateBuffer
= AllocFunction(sizeof(ULONG
));
108 if (!SampleRateBuffer
)
111 return STATUS_INSUFFICIENT_RESOURCES
;
114 if (IsEqualGUIDAligned(&Pin
->ConnectionFormat
->MajorFormat
, &KSDATAFORMAT_TYPE_AUDIO
) &&
115 IsEqualGUIDAligned(&Pin
->ConnectionFormat
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) &&
116 IsEqualGUIDAligned(&Pin
->ConnectionFormat
->Specifier
, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
))
118 WaveFormatEx
= (PKSDATAFORMAT_WAVEFORMATEX
)Pin
->ConnectionFormat
;
119 SampleRateBuffer
[2] = (WaveFormatEx
->WaveFormatEx
.nSamplesPerSec
>> 16) & 0xFF;
120 SampleRateBuffer
[1] = (WaveFormatEx
->WaveFormatEx
.nSamplesPerSec
>> 8) & 0xFF;
121 SampleRateBuffer
[0] = (WaveFormatEx
->WaveFormatEx
.nSamplesPerSec
>> 0) & 0xFF;
123 /* TODO: verify connection format */
127 /* not supported yet*/
129 FreeFunction(SampleRateBuffer
);
130 return STATUS_INVALID_PARAMETER
;
134 Urb
= AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
));
138 FreeFunction(SampleRateBuffer
);
139 return STATUS_INSUFFICIENT_RESOURCES
;
143 UsbBuildVendorRequest(Urb
,
144 URB_FUNCTION_CLASS_ENDPOINT
,
145 sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
),
146 USBD_TRANSFER_DIRECTION_OUT
,
150 0x81, //FIXME bEndpointAddress
156 /* get pin context */
157 PinContext
= Pin
->Context
;
160 Status
= SubmitUrbSync(PinContext
->LowerDevice
, Urb
);
162 DPRINT1("USBAudioPinSetDataFormat Pin %p Status %x\n", Pin
, Status
);
164 FreeFunction(SampleRateBuffer
);
169 USBAudioSelectAudioStreamingInterface(
170 IN PPIN_CONTEXT PinContext
,
171 IN PDEVICE_EXTENSION DeviceExtension
,
172 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
175 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
;
178 /* grab interface descriptor */
179 InterfaceDescriptor
= USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor
, ConfigurationDescriptor
, -1, -1, USB_DEVICE_CLASS_AUDIO
, -1, -1);
180 if (!InterfaceDescriptor
)
182 /* no such interface */
183 return STATUS_INVALID_PARAMETER
;
186 /* FIXME selects the first interface with audio streaming and non zero num of endpoints */
187 while (InterfaceDescriptor
!= NULL
)
189 if (InterfaceDescriptor
->bInterfaceSubClass
== 0x02 /* AUDIO_STREAMING */ && InterfaceDescriptor
->bNumEndpoints
> 0)
193 InterfaceDescriptor
= USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor
, (PVOID
)((ULONG_PTR
)InterfaceDescriptor
+ InterfaceDescriptor
->bLength
), -1, -1, USB_DEVICE_CLASS_AUDIO
, -1, -1);
196 if (!InterfaceDescriptor
)
198 /* no such interface */
199 return STATUS_INVALID_PARAMETER
;
202 Urb
= AllocFunction(GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor
->bNumEndpoints
));
206 return USBD_STATUS_INSUFFICIENT_RESOURCES
;
209 /* now prepare interface urb */
210 UsbBuildSelectInterfaceRequest(Urb
, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor
->bNumEndpoints
), DeviceExtension
->ConfigurationHandle
, InterfaceDescriptor
->bInterfaceNumber
, InterfaceDescriptor
->bAlternateSetting
);
212 /* now select the interface */
213 Status
= SubmitUrbSync(DeviceExtension
->LowerDevice
, Urb
);
215 DPRINT1("USBAudioSelectAudioStreamingInterface Status %x UrbStatus %x\n", Status
, Urb
->UrbSelectInterface
.Hdr
.Status
);
217 /* did it succeeed */
218 if (NT_SUCCESS(Status
))
220 /* free old interface info */
221 if (DeviceExtension
->InterfaceInfo
)
224 FreeFunction(DeviceExtension
->InterfaceInfo
);
227 /* alloc interface info */
228 DeviceExtension
->InterfaceInfo
= AllocFunction(Urb
->UrbSelectInterface
.Interface
.Length
);
229 if (DeviceExtension
->InterfaceInfo
== NULL
)
233 return STATUS_INSUFFICIENT_RESOURCES
;
236 /* copy interface info */
237 RtlCopyMemory(DeviceExtension
->InterfaceInfo
, &Urb
->UrbSelectInterface
.Interface
, Urb
->UrbSelectInterface
.Interface
.Length
);
238 PinContext
->InterfaceDescriptor
= InterfaceDescriptor
;
253 ULONG MaximumPacketSize
;
256 PPIN_CONTEXT PinContext
;
257 PIO_STACK_LOCATION IoStack
;
258 PKSALLOCATOR_FRAMING_EX Framing
;
260 /* set sample rate */
261 Status
= UsbAudioSetFormat(Pin
);
262 if (!NT_SUCCESS(Status
))
268 /* get pin context */
269 PinContext
= Pin
->Context
;
271 /* lets get maximum packet size */
272 MaximumPacketSize
= GetMaxPacketSizeForInterface(PinContext
->DeviceExtension
->ConfigurationDescriptor
, PinContext
->InterfaceDescriptor
, Pin
->DataFlow
);
274 /* lets edit framing struct */
275 Framing
= (PKSALLOCATOR_FRAMING_EX
)Pin
->Descriptor
->AllocatorFraming
;
276 Framing
->FramingItem
[0].PhysicalRange
.MinFrameSize
=
277 Framing
->FramingItem
[0].PhysicalRange
.MaxFrameSize
=
278 Framing
->FramingItem
[0].FramingRange
.Range
.MinFrameSize
=
279 Framing
->FramingItem
[0].FramingRange
.Range
.MaxFrameSize
=
282 /* calculate buffer size 8 irps * 10 iso packets * max packet size */
283 BufferSize
= 8 * 10 * MaximumPacketSize
;
285 /* allocate pin capture buffer */
286 PinContext
->Buffer
= AllocFunction(BufferSize
);
287 if (!PinContext
->Buffer
)
290 return STATUS_INSUFFICIENT_RESOURCES
;
292 KsAddItemToObjectBag(Pin
->Bag
, PinContext
->Buffer
, ExFreePool
);
295 for (Index
= 0; Index
< 8; Index
++)
298 Irp
= IoAllocateIrp(PinContext
->DeviceExtension
->LowerDevice
->StackSize
, FALSE
);
302 return STATUS_INSUFFICIENT_RESOURCES
;
305 DPRINT1("InitCapturePin Irp %p\n", Irp
);
306 /* insert into irp list */
307 InsertTailList(&PinContext
->IrpListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
309 /* add to object bag*/
310 KsAddItemToObjectBag(Pin
->Bag
, Irp
, IoFreeIrp
);
312 /* FIXME select correct pipe handle */
313 Status
= UsbAudioAllocCaptureUrbIso(PinContext
->DeviceExtension
->InterfaceInfo
->Pipes
[0].PipeHandle
,
315 &PinContext
->Buffer
[MaximumPacketSize
* 10 * Index
],
316 MaximumPacketSize
* 10,
319 if (NT_SUCCESS(Status
))
321 /* get next stack location */
322 IoStack
= IoGetNextIrpStackLocation(Irp
);
325 IoStack
->Parameters
.Others
.Argument1
= Urb
;
326 Irp
->Tail
.Overlay
.DriverContext
[0] = Urb
;
342 return STATUS_NOT_IMPLEMENTED
;
353 PFILTER_CONTEXT FilterContext
;
354 PPIN_CONTEXT PinContext
;
357 Filter
= KsPinGetParentFilter(Pin
);
360 /* invalid parameter */
361 return STATUS_INVALID_PARAMETER
;
364 /* get filter context */
365 FilterContext
= Filter
->Context
;
367 /* allocate pin context */
368 PinContext
= AllocFunction(sizeof(PIN_CONTEXT
));
372 return STATUS_INSUFFICIENT_RESOURCES
;
375 /* init pin context */
376 PinContext
->DeviceExtension
= FilterContext
->DeviceExtension
;
377 PinContext
->LowerDevice
= FilterContext
->LowerDevice
;
378 InitializeListHead(&PinContext
->IrpListHead
);
379 InitializeListHead(&PinContext
->DoneIrpListHead
);
380 KeInitializeSpinLock(&PinContext
->IrpListLock
);
382 /* store pin context*/
383 Pin
->Context
= PinContext
;
385 /* lets edit allocator framing struct */
386 Status
= _KsEdit(Pin
->Bag
, &Pin
->Descriptor
, sizeof(KSPIN_DESCRIPTOR_EX
), sizeof(KSPIN_DESCRIPTOR_EX
), USBAUDIO_TAG
);
387 if (NT_SUCCESS(Status
))
389 Status
= _KsEdit(Pin
->Bag
, &Pin
->Descriptor
->AllocatorFraming
, sizeof(KSALLOCATOR_FRAMING_EX
), sizeof(KSALLOCATOR_FRAMING_EX
), USBAUDIO_TAG
);
390 ASSERT(Status
== STATUS_SUCCESS
);
394 /* select streaming interface */
395 Status
= USBAudioSelectAudioStreamingInterface(PinContext
, PinContext
->DeviceExtension
, PinContext
->DeviceExtension
->ConfigurationDescriptor
);
396 if (!NT_SUCCESS(Status
))
402 if (Pin
->DataFlow
== KSPIN_DATAFLOW_OUT
)
404 /* init capture pin */
405 Status
= InitCapturePin(Pin
);
409 /* audio streaming pin*/
410 Status
= InitStreamPin(Pin
);
413 return STATUS_SUCCESS
;
423 return STATUS_NOT_IMPLEMENTED
;
428 UsbAudioCaptureComplete(
429 IN PDEVICE_OBJECT DeviceObject
,
434 PPIN_CONTEXT PinContext
;
437 /* get pin context */
439 PinContext
= Pin
->Context
;
442 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
444 /* insert entry into done list */
445 InsertTailList(&PinContext
->DoneIrpListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
448 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
450 DPRINT1("UsbAudioCaptureComplete Irp %p\n", Irp
);
453 return STATUS_MORE_PROCESSING_REQUIRED
;
460 PKSSTREAM_POINTER LeadingStreamPointer
;
462 PPIN_CONTEXT PinContext
;
463 PLIST_ENTRY CurEntry
;
465 PIO_STACK_LOCATION IoStack
;
467 PUCHAR TransferBuffer
;
470 LeadingStreamPointer
= KsPinGetLeadingEdgeStreamPointer(Pin
, KSSTREAM_POINTER_STATE_LOCKED
);
471 if (LeadingStreamPointer
== NULL
)
472 return STATUS_SUCCESS
;
474 /* get pin context */
475 PinContext
= Pin
->Context
;
477 /* acquire spin lock */
478 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
480 while (!IsListEmpty(&PinContext
->DoneIrpListHead
))
482 /* remove entry from list */
483 CurEntry
= RemoveHeadList(&PinContext
->DoneIrpListHead
);
486 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
489 Irp
= (PIRP
)CONTAINING_RECORD(CurEntry
, IRP
, Tail
.Overlay
.ListEntry
);
491 /* get urb from irp */
492 IoStack
= IoGetNextIrpStackLocation(Irp
);
493 Urb
= (PURB
)Irp
->Tail
.Overlay
.DriverContext
[0];
497 for (Index
= 0; Index
< Urb
->UrbIsochronousTransfer
.NumberOfPackets
; Index
++)
500 Offset
+= Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Offset
;
502 /* get transfer buffer */
503 TransferBuffer
= Urb
->UrbIsochronousTransfer
.TransferBuffer
;
506 if (LeadingStreamPointer
->OffsetOut
.Remaining
>= Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Length
)
509 RtlCopyMemory((PUCHAR
)LeadingStreamPointer
->OffsetOut
.Data
, &TransferBuffer
[Offset
], Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Length
);
513 /* advance to next frame */
514 KsStreamPointerAdvanceOffsetsAndUnlock(LeadingStreamPointer
, 0, 0, TRUE
);
515 LeadingStreamPointer
= KsPinGetLeadingEdgeStreamPointer(Pin
, KSSTREAM_POINTER_STATE_LOCKED
);
516 if (LeadingStreamPointer
== NULL
)
518 /* FIXME handle half processed packets */
523 ASSERT(LeadingStreamPointer
->OffsetOut
.Remaining
>= Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Length
);
526 RtlCopyMemory((PUCHAR
)LeadingStreamPointer
->OffsetOut
.Data
, &TransferBuffer
[Offset
], Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Length
);
529 if (LeadingStreamPointer
->OffsetOut
.Remaining
== Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Length
)
531 KsStreamPointerAdvanceOffsetsAndUnlock(LeadingStreamPointer
, 0, Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Length
, TRUE
);
532 LeadingStreamPointer
= KsPinGetLeadingEdgeStreamPointer(Pin
, KSSTREAM_POINTER_STATE_LOCKED
);
533 if (LeadingStreamPointer
== NULL
)
538 KsStreamPointerAdvanceOffsets(LeadingStreamPointer
, 0, Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Length
, FALSE
);
542 /* acquire spin lock */
543 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
545 /* get next stack location */
546 IoStack
= IoGetNextIrpStackLocation(Irp
);
548 /* init stack location */
549 IoStack
->Parameters
.Others
.Argument1
= Urb
;
550 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
551 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
553 IoSetCompletionRoutine(Irp
, UsbAudioCaptureComplete
, Pin
, TRUE
, TRUE
, TRUE
);
555 InsertTailList(&PinContext
->IrpListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
557 if (LeadingStreamPointer
== NULL
)
561 while (!IsListEmpty(&PinContext
->IrpListHead
))
563 /* remove entry from list */
564 CurEntry
= RemoveHeadList(&PinContext
->IrpListHead
);
567 Irp
= (PIRP
)CONTAINING_RECORD(CurEntry
, IRP
, Tail
.Overlay
.ListEntry
);
569 /* get next stack location */
570 IoStack
= IoGetNextIrpStackLocation(Irp
);
572 /* init stack location */
573 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
574 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
576 IoSetCompletionRoutine(Irp
, UsbAudioCaptureComplete
, Pin
, TRUE
, TRUE
, TRUE
);
579 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
581 DPRINT1("PinCaptureProcess Irp %p\n", Irp
);
582 IoCallDriver(PinContext
->DeviceExtension
->LowerDevice
, Irp
);
584 /* acquire spin lock */
585 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
590 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
592 if (LeadingStreamPointer
!= NULL
)
593 KsStreamPointerUnlock(LeadingStreamPointer
, FALSE
);
595 return STATUS_SUCCESS
;
606 if (Pin
->DataFlow
== KSPIN_DATAFLOW_OUT
)
608 Status
= PinCaptureProcess(Pin
);
613 Status
= STATUS_NOT_IMPLEMENTED
;
630 USBAudioPinSetDataFormat(
632 _In_opt_ PKSDATAFORMAT OldFormat
,
633 _In_opt_ PKSMULTIPLE_ITEM OldAttributeList
,
634 _In_
const KSDATARANGE
* DataRange
,
635 _In_opt_
const KSATTRIBUTE_LIST
* AttributeRange
)
637 if (OldFormat
== NULL
)
639 /* TODO: verify connection format */
641 return STATUS_SUCCESS
;
644 return UsbAudioSetFormat(Pin
);
648 StartCaptureIsocTransfer(
651 PPIN_CONTEXT PinContext
;
652 PLIST_ENTRY CurEntry
;
654 PIO_STACK_LOCATION IoStack
;
658 /* get pin context */
659 PinContext
= Pin
->Context
;
661 /* acquire spin lock */
662 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
664 while(!IsListEmpty(&PinContext
->IrpListHead
))
666 /* remove entry from list */
667 CurEntry
= RemoveHeadList(&PinContext
->IrpListHead
);
670 Irp
= (PIRP
)CONTAINING_RECORD(CurEntry
, IRP
, Tail
.Overlay
.ListEntry
);
673 /* get next stack location */
674 IoStack
= IoGetNextIrpStackLocation(Irp
);
676 /* init stack location */
677 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
678 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
680 IoSetCompletionRoutine(Irp
, UsbAudioCaptureComplete
, Pin
, TRUE
, TRUE
, TRUE
);
683 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
685 DPRINT1("StartCaptureIsocTransfer Irp %p\n", Irp
);
686 Status
= IoCallDriver(PinContext
->DeviceExtension
->LowerDevice
, Irp
);
688 /* acquire spin lock */
689 KeAcquireSpinLock(&PinContext
->IrpListLock
, &OldLevel
);
694 KeReleaseSpinLock(&PinContext
->IrpListLock
, OldLevel
);
696 return STATUS_SUCCESS
;
700 CapturePinStateChange(
702 _In_ KSSTATE ToState
,
703 _In_ KSSTATE FromState
)
707 if (FromState
!= ToState
)
711 if (ToState
== KSSTATE_PAUSE
)
713 if (FromState
== KSSTATE_RUN
)
715 /* wait until pin processing is finished*/
720 if (ToState
== KSSTATE_RUN
)
722 Status
= StartCaptureIsocTransfer(Pin
);
733 USBAudioPinSetDeviceState(
735 _In_ KSSTATE ToState
,
736 _In_ KSSTATE FromState
)
740 if (Pin
->DataFlow
== KSPIN_DATAFLOW_OUT
)
742 /* handle capture state changes */
743 Status
= CapturePinStateChange(Pin
, ToState
, FromState
);
748 Status
= STATUS_NOT_IMPLEMENTED
;