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
;
259 /* set sample rate */
260 Status
= UsbAudioSetFormat(Pin
);
261 if (!NT_SUCCESS(Status
))
267 /* get pin context */
268 PinContext
= Pin
->Context
;
270 MaximumPacketSize
= GetMaxPacketSizeForInterface(PinContext
->DeviceExtension
->ConfigurationDescriptor
, PinContext
->InterfaceDescriptor
, Pin
->DataFlow
);
272 /* calculate buffer size 8 irps * 10 iso packets * max packet size */
273 BufferSize
= 8 * 10 * MaximumPacketSize
;
275 /* allocate pin capture buffer */
276 PinContext
->Buffer
= AllocFunction(BufferSize
);
277 if (!PinContext
->Buffer
)
280 return STATUS_INSUFFICIENT_RESOURCES
;
282 KsAddItemToObjectBag(Pin
->Bag
, PinContext
->Buffer
, ExFreePool
);
285 for (Index
= 0; Index
< 8; Index
++)
288 Irp
= IoAllocateIrp(PinContext
->DeviceExtension
->LowerDevice
->StackSize
, FALSE
);
292 return STATUS_INSUFFICIENT_RESOURCES
;
295 /* insert into irp list */
296 InsertTailList(&PinContext
->IrpListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
298 /* add to object bag*/
299 KsAddItemToObjectBag(Pin
->Bag
, Irp
, IoFreeIrp
);
301 /* FIXME select correct pipe handle */
302 Status
= UsbAudioAllocCaptureUrbIso(PinContext
->DeviceExtension
->InterfaceInfo
->Pipes
[0].PipeHandle
,
304 &PinContext
->Buffer
[MaximumPacketSize
* 10 * Index
],
305 MaximumPacketSize
* 10,
308 if (NT_SUCCESS(Status
))
310 /* get next stack location */
311 IoStack
= IoGetNextIrpStackLocation(Irp
);
314 IoStack
->Parameters
.Others
.Argument1
= Urb
;
330 return STATUS_NOT_IMPLEMENTED
;
341 PFILTER_CONTEXT FilterContext
;
342 PPIN_CONTEXT PinContext
;
345 Filter
= KsPinGetParentFilter(Pin
);
348 /* invalid parameter */
349 return STATUS_INVALID_PARAMETER
;
352 /* get filter context */
353 FilterContext
= Filter
->Context
;
355 /* allocate pin context */
356 PinContext
= AllocFunction(sizeof(PIN_CONTEXT
));
360 return STATUS_INSUFFICIENT_RESOURCES
;
363 /* init pin context */
364 PinContext
->DeviceExtension
= FilterContext
->DeviceExtension
;
365 PinContext
->LowerDevice
= FilterContext
->LowerDevice
;
366 InitializeListHead(&PinContext
->IrpListHead
);
368 /* store pin context*/
369 Pin
->Context
= PinContext
;
371 /* select streaming interface */
372 Status
= USBAudioSelectAudioStreamingInterface(PinContext
, PinContext
->DeviceExtension
, PinContext
->DeviceExtension
->ConfigurationDescriptor
);
373 if (!NT_SUCCESS(Status
))
379 if (Pin
->DataFlow
== KSPIN_DATAFLOW_OUT
)
381 /* init capture pin */
382 Status
= InitCapturePin(Pin
);
386 /* audio streaming pin*/
387 Status
= InitStreamPin(Pin
);
390 return STATUS_SUCCESS
;
400 return STATUS_NOT_IMPLEMENTED
;
409 return STATUS_SUCCESS
;
423 USBAudioPinSetDataFormat(
425 _In_opt_ PKSDATAFORMAT OldFormat
,
426 _In_opt_ PKSMULTIPLE_ITEM OldAttributeList
,
427 _In_
const KSDATARANGE
* DataRange
,
428 _In_opt_
const KSATTRIBUTE_LIST
* AttributeRange
)
430 if (OldFormat
== NULL
)
432 /* TODO: verify connection format */
434 return STATUS_SUCCESS
;
437 return UsbAudioSetFormat(Pin
);
442 USBAudioPinSetDeviceState(
444 _In_ KSSTATE ToState
,
445 _In_ KSSTATE FromState
)
448 return STATUS_SUCCESS
;