9daecd47040bbf20f8f8c2e9a06c148007eafaa2
[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 /* copy interface information */
213 RtlCopyMemory(&Urb->UrbSelectInterface.Interface, DeviceExtension->InterfaceInfo, DeviceExtension->InterfaceInfo->Length);
214
215 /* now select the interface */
216 Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
217
218 DPRINT1("USBAudioSelectAudioStreamingInterface Status %x UrbStatus %x\n", Status, Urb->UrbSelectInterface.Hdr.Status);
219
220 /* did it succeeed */
221 if (NT_SUCCESS(Status))
222 {
223 /* update configuration info */
224 ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceInfo->Length);
225 RtlCopyMemory(DeviceExtension->InterfaceInfo, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
226 PinContext->InterfaceDescriptor = InterfaceDescriptor;
227 }
228
229 /* free urb */
230 FreeFunction(Urb);
231 return Status;
232 }
233
234 NTSTATUS
235 InitCapturePin(
236 IN PKSPIN Pin)
237 {
238 NTSTATUS Status;
239 ULONG Index;
240 ULONG BufferSize;
241 ULONG MaximumPacketSize;
242 PIRP Irp;
243 PURB Urb;
244 PPIN_CONTEXT PinContext;
245 PIO_STACK_LOCATION IoStack;
246
247 /* set sample rate */
248 Status = UsbAudioSetFormat(Pin);
249 if (!NT_SUCCESS(Status))
250 {
251 /* failed */
252 return Status;
253 }
254
255 /* get pin context */
256 PinContext = Pin->Context;
257 DbgBreakPoint();
258 MaximumPacketSize = GetMaxPacketSizeForInterface(PinContext->DeviceExtension->ConfigurationDescriptor, PinContext->InterfaceDescriptor, Pin->DataFlow);
259
260 /* calculate buffer size 8 irps * 10 iso packets * max packet size */
261 BufferSize = 8 * 10 * MaximumPacketSize;
262
263 /* allocate pin capture buffer */
264 PinContext->Buffer = AllocFunction(BufferSize);
265 if (!PinContext->Buffer)
266 {
267 /* no memory */
268 return STATUS_INSUFFICIENT_RESOURCES;
269 }
270 KsAddItemToObjectBag(Pin->Bag, PinContext->Buffer, ExFreePool);
271
272 /* init irps */
273 for (Index = 0; Index < 8; Index++)
274 {
275 /* allocate irp */
276 Irp = IoAllocateIrp(PinContext->DeviceExtension->LowerDevice->StackSize, FALSE);
277 if (!Irp)
278 {
279 /* no memory */
280 return STATUS_INSUFFICIENT_RESOURCES;
281 }
282
283 /* insert into irp list */
284 InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
285
286 /* add to object bag*/
287 KsAddItemToObjectBag(Pin->Bag, Irp, IoFreeIrp);
288
289 Status = UsbAudioAllocCaptureUrbIso(PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle,
290 MaximumPacketSize,
291 &PinContext->Buffer[MaximumPacketSize * 10 * Index],
292 MaximumPacketSize * 10,
293 &Urb);
294
295 if (NT_SUCCESS(Status))
296 {
297 /* get next stack location */
298 IoStack = IoGetNextIrpStackLocation(Irp);
299
300 /* store urb */
301 IoStack->Parameters.Others.Argument1 = Urb;
302 }
303 else
304 {
305 /* failed */
306 return Status;
307 }
308 }
309 return Status;
310 }
311
312 NTSTATUS
313 InitStreamPin(
314 IN PKSPIN Pin)
315 {
316 UNIMPLEMENTED
317 return STATUS_NOT_IMPLEMENTED;
318 }
319
320
321 NTSTATUS
322 NTAPI
323 USBAudioPinCreate(
324 _In_ PKSPIN Pin,
325 _In_ PIRP Irp)
326 {
327 PKSFILTER Filter;
328 PFILTER_CONTEXT FilterContext;
329 PPIN_CONTEXT PinContext;
330 NTSTATUS Status;
331
332 Filter = KsPinGetParentFilter(Pin);
333 if (Filter == NULL)
334 {
335 /* invalid parameter */
336 return STATUS_INVALID_PARAMETER;
337 }
338
339 /* get filter context */
340 FilterContext = Filter->Context;
341
342 /* allocate pin context */
343 PinContext = AllocFunction(sizeof(PIN_CONTEXT));
344 if (!PinContext)
345 {
346 /* no memory*/
347 return STATUS_INSUFFICIENT_RESOURCES;
348 }
349
350 /* init pin context */
351 PinContext->DeviceExtension = FilterContext->DeviceExtension;
352 PinContext->LowerDevice = FilterContext->LowerDevice;
353 InitializeListHead(&PinContext->IrpListHead);
354
355 /* store pin context*/
356 Pin->Context = PinContext;
357
358 /* select streaming interface */
359 Status = USBAudioSelectAudioStreamingInterface(PinContext, PinContext->DeviceExtension, PinContext->DeviceExtension->ConfigurationDescriptor);
360 if (!NT_SUCCESS(Status))
361 {
362 /* failed */
363 return Status;
364 }
365
366 if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
367 {
368 /* init capture pin */
369 Status = InitCapturePin(Pin);
370 }
371 else
372 {
373 /* audio streaming pin*/
374 Status = InitStreamPin(Pin);
375 }
376
377 return STATUS_SUCCESS;
378 }
379
380 NTSTATUS
381 NTAPI
382 USBAudioPinClose(
383 _In_ PKSPIN Pin,
384 _In_ PIRP Irp)
385 {
386 UNIMPLEMENTED
387 return STATUS_NOT_IMPLEMENTED;
388 }
389
390
391 NTSTATUS
392 NTAPI
393 USBAudioPinProcess(
394 _In_ PKSPIN Pin)
395 {
396 return STATUS_SUCCESS;
397 }
398
399
400 VOID
401 NTAPI
402 USBAudioPinReset(
403 _In_ PKSPIN Pin)
404 {
405 UNIMPLEMENTED
406 }
407
408 NTSTATUS
409 NTAPI
410 USBAudioPinSetDataFormat(
411 _In_ PKSPIN Pin,
412 _In_opt_ PKSDATAFORMAT OldFormat,
413 _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
414 _In_ const KSDATARANGE* DataRange,
415 _In_opt_ const KSATTRIBUTE_LIST* AttributeRange)
416 {
417 if (OldFormat == NULL)
418 {
419 /* TODO: verify connection format */
420 UNIMPLEMENTED
421 return STATUS_SUCCESS;
422 }
423
424 return UsbAudioSetFormat(Pin);
425 }
426
427 NTSTATUS
428 NTAPI
429 USBAudioPinSetDeviceState(
430 _In_ PKSPIN Pin,
431 _In_ KSSTATE ToState,
432 _In_ KSSTATE FromState)
433 {
434 UNIMPLEMENTED
435 return STATUS_SUCCESS;
436 }