c0a05d4ef64835c2670061b611a79176f2bfe6db
[reactos.git] / reactos / drivers / usb / usbaudio / pin.c
1 /*
2 * PROJECT: ReactOS Universal Audio Class Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbaudio/pin.c
5 * PURPOSE: USB Audio device driver.
6 * PROGRAMMERS:
7 * Johannes Anderwald (johannes.anderwald@reactos.org)
8 */
9
10 #include "usbaudio.h"
11
12 NTSTATUS
13 GetMaxPacketSizeForInterface(
14 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
15 IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
16 KSPIN_DATAFLOW DataFlow)
17 {
18 PUSB_COMMON_DESCRIPTOR CommonDescriptor;
19 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
20
21 /* loop descriptors */
22 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
23 ASSERT(InterfaceDescriptor->bNumEndpoints > 0);
24 while (CommonDescriptor)
25 {
26 if (CommonDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
27 {
28 EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CommonDescriptor;
29 return EndpointDescriptor->wMaxPacketSize;
30 }
31
32 if (CommonDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
33 {
34 /* reached next interface descriptor */
35 break;
36 }
37
38 if ((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
39 break;
40
41 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
42 }
43
44 /* default to 100 */
45 return 100;
46 }
47
48 NTSTATUS
49 UsbAudioAllocCaptureUrbIso(
50 IN USBD_PIPE_HANDLE PipeHandle,
51 IN ULONG MaxPacketSize,
52 IN PVOID Buffer,
53 IN ULONG BufferLength,
54 OUT PURB * OutUrb)
55 {
56 PURB Urb;
57 ULONG PacketCount;
58 ULONG UrbSize;
59 ULONG Index;
60
61 /* calculate packet count */
62 PacketCount = BufferLength / MaxPacketSize;
63
64 /* calculate urb size*/
65 UrbSize = GET_ISO_URB_SIZE(PacketCount);
66
67 /* allocate urb */
68 Urb = AllocFunction(UrbSize);
69 if (!Urb)
70 {
71 /* no memory */
72 return STATUS_INSUFFICIENT_RESOURCES;
73 }
74
75 /* init urb */
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;
83
84 for (Index = 0; Index < PacketCount; Index++)
85 {
86 Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset = Index * MaxPacketSize;
87 }
88
89 *OutUrb = Urb;
90 return STATUS_SUCCESS;
91
92 }
93
94
95
96 NTSTATUS
97 UsbAudioSetFormat(
98 IN PKSPIN Pin)
99 {
100 PURB Urb;
101 PUCHAR SampleRateBuffer;
102 PPIN_CONTEXT PinContext;
103 NTSTATUS Status;
104 PKSDATAFORMAT_WAVEFORMATEX WaveFormatEx;
105
106 /* allocate sample rate buffer */
107 SampleRateBuffer = AllocFunction(sizeof(ULONG));
108 if (!SampleRateBuffer)
109 {
110 /* no memory */
111 return STATUS_INSUFFICIENT_RESOURCES;
112 }
113
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))
117 {
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;
122
123 /* TODO: verify connection format */
124 }
125 else
126 {
127 /* not supported yet*/
128 UNIMPLEMENTED;
129 FreeFunction(SampleRateBuffer);
130 return STATUS_INVALID_PARAMETER;
131 }
132
133 /* allocate urb */
134 Urb = AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
135 if (!Urb)
136 {
137 /* no memory */
138 FreeFunction(SampleRateBuffer);
139 return STATUS_INSUFFICIENT_RESOURCES;
140 }
141
142 /* 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,
149 0x100,
150 0x81, //FIXME bEndpointAddress
151 SampleRateBuffer,
152 NULL,
153 3,
154 NULL);
155
156 /* get pin context */
157 PinContext = Pin->Context;
158
159 /* submit urb */
160 Status = SubmitUrbSync(PinContext->LowerDevice, Urb);
161
162 DPRINT1("USBAudioPinSetDataFormat Pin %p Status %x\n", Pin, Status);
163 FreeFunction(Urb);
164 FreeFunction(SampleRateBuffer);
165 return Status;
166 }
167
168 NTSTATUS
169 USBAudioSelectAudioStreamingInterface(
170 IN PPIN_CONTEXT PinContext,
171 IN PDEVICE_EXTENSION DeviceExtension,
172 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
173 {
174 PURB Urb;
175 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
176 NTSTATUS Status;
177
178 /* grab interface descriptor */
179 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
180 if (!InterfaceDescriptor)
181 {
182 /* no such interface */
183 return STATUS_INVALID_PARAMETER;
184 }
185
186 /* FIXME selects the first interface with audio streaming and non zero num of endpoints */
187 while (InterfaceDescriptor != NULL)
188 {
189 if (InterfaceDescriptor->bInterfaceSubClass == 0x02 /* AUDIO_STREAMING */ && InterfaceDescriptor->bNumEndpoints > 0)
190 {
191 break;
192 }
193 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
194 }
195
196 if (!InterfaceDescriptor)
197 {
198 /* no such interface */
199 return STATUS_INVALID_PARAMETER;
200 }
201
202 Urb = AllocFunction(GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints));
203 if (!Urb)
204 {
205 /* no memory */
206 return USBD_STATUS_INSUFFICIENT_RESOURCES;
207 }
208
209 /* now prepare interface urb */
210 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
211
212 /* now select the interface */
213 Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
214
215 DPRINT1("USBAudioSelectAudioStreamingInterface Status %x UrbStatus %x\n", Status, Urb->UrbSelectInterface.Hdr.Status);
216
217 /* did it succeeed */
218 if (NT_SUCCESS(Status))
219 {
220 /* free old interface info */
221 if (DeviceExtension->InterfaceInfo)
222 {
223 /* free old info */
224 FreeFunction(DeviceExtension->InterfaceInfo);
225 }
226
227 /* alloc interface info */
228 DeviceExtension->InterfaceInfo = AllocFunction(Urb->UrbSelectInterface.Interface.Length);
229 if (DeviceExtension->InterfaceInfo == NULL)
230 {
231 /* no memory */
232 FreeFunction(Urb);
233 return STATUS_INSUFFICIENT_RESOURCES;
234 }
235
236 /* copy interface info */
237 RtlCopyMemory(DeviceExtension->InterfaceInfo, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
238 PinContext->InterfaceDescriptor = InterfaceDescriptor;
239 }
240
241 /* free urb */
242 FreeFunction(Urb);
243 return Status;
244 }
245
246 NTSTATUS
247 InitCapturePin(
248 IN PKSPIN Pin)
249 {
250 NTSTATUS Status;
251 ULONG Index;
252 ULONG BufferSize;
253 ULONG MaximumPacketSize;
254 PIRP Irp;
255 PURB Urb;
256 PPIN_CONTEXT PinContext;
257 PIO_STACK_LOCATION IoStack;
258
259 /* set sample rate */
260 Status = UsbAudioSetFormat(Pin);
261 if (!NT_SUCCESS(Status))
262 {
263 /* failed */
264 return Status;
265 }
266
267 /* get pin context */
268 PinContext = Pin->Context;
269
270 MaximumPacketSize = GetMaxPacketSizeForInterface(PinContext->DeviceExtension->ConfigurationDescriptor, PinContext->InterfaceDescriptor, Pin->DataFlow);
271
272 /* calculate buffer size 8 irps * 10 iso packets * max packet size */
273 BufferSize = 8 * 10 * MaximumPacketSize;
274
275 /* allocate pin capture buffer */
276 PinContext->Buffer = AllocFunction(BufferSize);
277 if (!PinContext->Buffer)
278 {
279 /* no memory */
280 return STATUS_INSUFFICIENT_RESOURCES;
281 }
282 KsAddItemToObjectBag(Pin->Bag, PinContext->Buffer, ExFreePool);
283
284 /* init irps */
285 for (Index = 0; Index < 8; Index++)
286 {
287 /* allocate irp */
288 Irp = IoAllocateIrp(PinContext->DeviceExtension->LowerDevice->StackSize, FALSE);
289 if (!Irp)
290 {
291 /* no memory */
292 return STATUS_INSUFFICIENT_RESOURCES;
293 }
294
295 /* insert into irp list */
296 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
297
298 /* add to object bag*/
299 KsAddItemToObjectBag(Pin->Bag, Irp, IoFreeIrp);
300
301 /* FIXME select correct pipe handle */
302 Status = UsbAudioAllocCaptureUrbIso(PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle,
303 MaximumPacketSize,
304 &PinContext->Buffer[MaximumPacketSize * 10 * Index],
305 MaximumPacketSize * 10,
306 &Urb);
307
308 if (NT_SUCCESS(Status))
309 {
310 /* get next stack location */
311 IoStack = IoGetNextIrpStackLocation(Irp);
312
313 /* store urb */
314 IoStack->Parameters.Others.Argument1 = Urb;
315 }
316 else
317 {
318 /* failed */
319 return Status;
320 }
321 }
322 return Status;
323 }
324
325 NTSTATUS
326 InitStreamPin(
327 IN PKSPIN Pin)
328 {
329 UNIMPLEMENTED
330 return STATUS_NOT_IMPLEMENTED;
331 }
332
333
334 NTSTATUS
335 NTAPI
336 USBAudioPinCreate(
337 _In_ PKSPIN Pin,
338 _In_ PIRP Irp)
339 {
340 PKSFILTER Filter;
341 PFILTER_CONTEXT FilterContext;
342 PPIN_CONTEXT PinContext;
343 NTSTATUS Status;
344
345 Filter = KsPinGetParentFilter(Pin);
346 if (Filter == NULL)
347 {
348 /* invalid parameter */
349 return STATUS_INVALID_PARAMETER;
350 }
351
352 /* get filter context */
353 FilterContext = Filter->Context;
354
355 /* allocate pin context */
356 PinContext = AllocFunction(sizeof(PIN_CONTEXT));
357 if (!PinContext)
358 {
359 /* no memory*/
360 return STATUS_INSUFFICIENT_RESOURCES;
361 }
362
363 /* init pin context */
364 PinContext->DeviceExtension = FilterContext->DeviceExtension;
365 PinContext->LowerDevice = FilterContext->LowerDevice;
366 InitializeListHead(&PinContext->IrpListHead);
367
368 /* store pin context*/
369 Pin->Context = PinContext;
370
371 /* select streaming interface */
372 Status = USBAudioSelectAudioStreamingInterface(PinContext, PinContext->DeviceExtension, PinContext->DeviceExtension->ConfigurationDescriptor);
373 if (!NT_SUCCESS(Status))
374 {
375 /* failed */
376 return Status;
377 }
378
379 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
380 {
381 /* init capture pin */
382 Status = InitCapturePin(Pin);
383 }
384 else
385 {
386 /* audio streaming pin*/
387 Status = InitStreamPin(Pin);
388 }
389
390 return STATUS_SUCCESS;
391 }
392
393 NTSTATUS
394 NTAPI
395 USBAudioPinClose(
396 _In_ PKSPIN Pin,
397 _In_ PIRP Irp)
398 {
399 UNIMPLEMENTED
400 return STATUS_NOT_IMPLEMENTED;
401 }
402
403
404 NTSTATUS
405 NTAPI
406 USBAudioPinProcess(
407 _In_ PKSPIN Pin)
408 {
409 return STATUS_SUCCESS;
410 }
411
412
413 VOID
414 NTAPI
415 USBAudioPinReset(
416 _In_ PKSPIN Pin)
417 {
418 UNIMPLEMENTED
419 }
420
421 NTSTATUS
422 NTAPI
423 USBAudioPinSetDataFormat(
424 _In_ PKSPIN Pin,
425 _In_opt_ PKSDATAFORMAT OldFormat,
426 _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
427 _In_ const KSDATARANGE* DataRange,
428 _In_opt_ const KSATTRIBUTE_LIST* AttributeRange)
429 {
430 if (OldFormat == NULL)
431 {
432 /* TODO: verify connection format */
433 UNIMPLEMENTED
434 return STATUS_SUCCESS;
435 }
436
437 return UsbAudioSetFormat(Pin);
438 }
439
440 NTSTATUS
441 NTAPI
442 USBAudioPinSetDeviceState(
443 _In_ PKSPIN Pin,
444 _In_ KSSTATE ToState,
445 _In_ KSSTATE FromState)
446 {
447 UNIMPLEMENTED
448 return STATUS_SUCCESS;
449 }