[USBAUDIO]
[reactos.git] / reactos / drivers / usb / usbaudio / usbaudio.c
1 /*
2 * PROJECT: ReactOS Universal Audio Class Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbaudio/usbaudio.c
5 * PURPOSE: USB Audio device driver.
6 * PROGRAMMERS:
7 * Johannes Anderwald (johannes.anderwald@reactos.org)
8 */
9
10 #include "usbaudio.h"
11
12 static KSDEVICE_DISPATCH KsDeviceDispatch = {
13 USBAudioAddDevice,
14 USBAudioPnPStart,
15 NULL,
16 USBAudioPnPQueryStop,
17 USBAudioPnPCancelStop,
18 USBAudioPnPStop,
19 USBAudioPnPQueryRemove,
20 USBAudioPnPCancelRemove,
21 USBAudioPnPRemove,
22 USBAudioPnPQueryCapabilities,
23 USBAudioPnPSurpriseRemoval,
24 USBAudioPnPQueryPower,
25 USBAudioPnPSetPower
26 };
27
28 static KSDEVICE_DESCRIPTOR KsDeviceDescriptor = {
29 &KsDeviceDispatch,
30 0,
31 NULL,
32 0x100, //KSDEVICE_DESCRIPTOR_VERSION,
33 0
34 };
35
36 NTSTATUS
37 NTAPI
38 USBAudioCancelCompleteSynch(
39 IN PDEVICE_OBJECT DeviceObject,
40 IN PIRP Irp,
41 IN PVOID Context)
42 {
43 /* signal event */
44 KeSetEvent(Context, 0, FALSE);
45
46 /* done */
47 return STATUS_MORE_PROCESSING_REQUIRED;
48 }
49
50 NTSTATUS
51 SubmitUrbSync(
52 IN PKSDEVICE Device,
53 IN PURB Urb)
54 {
55 PIRP Irp;
56 KEVENT Event;
57 PDEVICE_EXTENSION DeviceExtension;
58 IO_STATUS_BLOCK IoStatus;
59 PIO_STACK_LOCATION IoStack;
60 NTSTATUS Status;
61
62 // init event
63 KeInitializeEvent(&Event, NotificationEvent, FALSE);
64
65 // get device extension
66 DeviceExtension = (PDEVICE_EXTENSION)Device->Context;
67
68 // build irp
69 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
70 DeviceExtension->LowerDevice,
71 NULL,
72 0,
73 NULL,
74 0,
75 TRUE,
76 &Event,
77 &IoStatus);
78
79 if (!Irp)
80 {
81 //
82 // no memory
83 //
84 return STATUS_INSUFFICIENT_RESOURCES;
85 }
86
87 // get next stack location
88 IoStack = IoGetNextIrpStackLocation(Irp);
89
90 // store urb
91 IoStack->Parameters.Others.Argument1 = Urb;
92
93 // set completion routine
94 IoSetCompletionRoutine(Irp, USBAudioCancelCompleteSynch, &Event, TRUE, TRUE, TRUE);
95
96 // call driver
97 Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
98
99 // wait for the request to finish
100 if (Status == STATUS_PENDING)
101 {
102 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
103 }
104
105 // complete request
106 IoCompleteRequest(Irp, IO_NO_INCREMENT);
107
108 if (Status == STATUS_PENDING)
109 {
110 // get final status
111 Status = IoStatus.Status;
112 }
113
114 // done
115 return Status;
116 }
117
118 NTSTATUS
119 NTAPI
120 USBAudioSelectConfiguration(
121 IN PKSDEVICE Device,
122 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
123 {
124 PDEVICE_EXTENSION DeviceExtension;
125 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
126 PUSBD_INTERFACE_LIST_ENTRY InterfaceList;
127 PURB Urb;
128 NTSTATUS Status;
129 ULONG InterfaceDescriptorCount;
130
131 /* alloc item for configuration request */
132 InterfaceList = AllocFunction(sizeof(USBD_INTERFACE_LIST_ENTRY) * (ConfigurationDescriptor->bNumInterfaces + 1));
133 if (!InterfaceList)
134 {
135 /* insufficient resources*/
136 return USBD_STATUS_INSUFFICIENT_RESOURCES;
137 }
138
139 /* grab interface descriptor */
140 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
141 if (!InterfaceDescriptor)
142 {
143 /* no such interface */
144 return STATUS_INVALID_PARAMETER;
145 }
146
147 /* lets enumerate the interfaces */
148 InterfaceDescriptorCount = 0;
149 while (InterfaceDescriptor != NULL)
150 {
151 if (InterfaceDescriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL*/
152 {
153 InterfaceList[InterfaceDescriptorCount++].InterfaceDescriptor = InterfaceDescriptor;
154 }
155 else if (InterfaceDescriptor->bInterfaceSubClass == 0x03) /* MIDI_STREAMING*/
156 {
157 InterfaceList[InterfaceDescriptorCount++].InterfaceDescriptor = InterfaceDescriptor;
158 }
159
160 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
161 }
162
163 /* build urb */
164 Urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor, InterfaceList);
165 if (!Urb)
166 {
167 /* no memory */
168 FreeFunction(InterfaceList);
169 return STATUS_INSUFFICIENT_RESOURCES;
170 }
171
172 /* submit configuration urb */
173 Status = SubmitUrbSync(Device, Urb);
174 if (!NT_SUCCESS(Status))
175 {
176 /* free resources */
177 ExFreePool(Urb);
178 FreeFunction(InterfaceList);
179 return Status;
180 }
181
182 /* store configuration handle */
183 DeviceExtension = Device->Context;
184 DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
185
186 /* alloc interface info */
187 DeviceExtension->InterfaceInfo = AllocFunction(Urb->UrbSelectConfiguration.Interface.Length);
188 if (DeviceExtension->InterfaceInfo)
189 {
190 /* copy interface info */
191 RtlCopyMemory(DeviceExtension->InterfaceInfo, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length);
192 }
193 return STATUS_SUCCESS;
194 }
195
196 NTSTATUS
197 NTAPI
198 USBAudioStartDevice(
199 IN PKSDEVICE Device)
200 {
201 PURB Urb;
202 PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
203 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
204 PDEVICE_EXTENSION DeviceExtension;
205 NTSTATUS Status;
206 ULONG Length;
207
208 /* allocate urb */
209 Urb = AllocFunction(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
210 if (!Urb)
211 {
212 /* no memory */
213 return STATUS_INSUFFICIENT_RESOURCES;
214 }
215
216 /* alloc buffer for device descriptor */
217 DeviceDescriptor = AllocFunction(sizeof(USB_DEVICE_DESCRIPTOR));
218 if (!DeviceDescriptor)
219 {
220 /* insufficient resources */
221 FreeFunction(Urb);
222 return STATUS_INSUFFICIENT_RESOURCES;
223 }
224
225 /* build descriptor request */
226 UsbBuildGetDescriptorRequest(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, DeviceDescriptor, NULL, sizeof(USB_DEVICE_DESCRIPTOR), NULL);
227
228 /* submit urb */
229 Status = SubmitUrbSync(Device, Urb);
230 if (!NT_SUCCESS(Status))
231 {
232 /* free resources */
233 FreeFunction(Urb);
234 FreeFunction(DeviceDescriptor);
235 return Status;
236 }
237
238 /* now allocate some space for partial configuration descriptor */
239 ConfigurationDescriptor = AllocFunction(sizeof(USB_CONFIGURATION_DESCRIPTOR));
240 if (!ConfigurationDescriptor)
241 {
242 /* free resources */
243 FreeFunction(Urb);
244 FreeFunction(DeviceDescriptor);
245 return Status;
246 }
247
248 /* build descriptor request */
249 UsbBuildGetDescriptorRequest(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, ConfigurationDescriptor, NULL, sizeof(USB_CONFIGURATION_DESCRIPTOR), NULL);
250
251 /* submit urb */
252 Status = SubmitUrbSync(Device, Urb);
253 if (!NT_SUCCESS(Status))
254 {
255 /* free resources */
256 FreeFunction(Urb);
257 FreeFunction(DeviceDescriptor);
258 FreeFunction(ConfigurationDescriptor);
259 return Status;
260 }
261
262 /* backup length */
263 Length = ConfigurationDescriptor->wTotalLength;
264
265 /* free old descriptor */
266 FreeFunction(ConfigurationDescriptor);
267
268 /* now allocate some space for full configuration descriptor */
269 ConfigurationDescriptor = AllocFunction(Length);
270 if (!ConfigurationDescriptor)
271 {
272 /* free resources */
273 FreeFunction(Urb);
274 FreeFunction(DeviceDescriptor);
275 return Status;
276 }
277
278 /* build descriptor request */
279 UsbBuildGetDescriptorRequest(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, ConfigurationDescriptor, NULL, Length, NULL);
280
281 /* submit urb */
282 Status = SubmitUrbSync(Device, Urb);
283
284 /* free urb */
285 FreeFunction(Urb);
286 if (!NT_SUCCESS(Status))
287 {
288 /* free resources */
289 FreeFunction(DeviceDescriptor);
290 FreeFunction(ConfigurationDescriptor);
291 return Status;
292 }
293
294 /* lets add to object bag */
295 KsAddItemToObjectBag(Device->Bag, DeviceDescriptor, ExFreePool);
296 KsAddItemToObjectBag(Device->Bag, ConfigurationDescriptor, ExFreePool);
297
298 Status = USBAudioSelectConfiguration(Device, ConfigurationDescriptor);
299 if (NT_SUCCESS(Status))
300 {
301 DeviceExtension = Device->Context;
302 DeviceExtension->ConfigurationDescriptor = ConfigurationDescriptor;
303 DeviceExtension->DeviceDescriptor = DeviceDescriptor;
304 }
305 return Status;
306 }
307
308
309 NTSTATUS
310 NTAPI
311 USBAudioAddDevice(
312 _In_ PKSDEVICE Device)
313 {
314 /* no op */
315 DPRINT1("USBAudioAddDevice\n");
316 return STATUS_SUCCESS;
317 }
318
319 NTSTATUS
320 NTAPI
321 USBAudioPnPStart(
322 _In_ PKSDEVICE Device,
323 _In_ PIRP Irp,
324 _In_opt_ PCM_RESOURCE_LIST TranslatedResourceList,
325 _In_opt_ PCM_RESOURCE_LIST UntranslatedResourceList)
326 {
327 NTSTATUS Status = STATUS_SUCCESS;
328 PDEVICE_EXTENSION DeviceExtension;
329
330 if (!Device->Started)
331 {
332 /* alloc context */
333 DeviceExtension = AllocFunction(sizeof(DEVICE_EXTENSION));
334 if (DeviceExtension == NULL)
335 {
336 /* insufficient resources */
337 return STATUS_INSUFFICIENT_RESOURCES;
338 }
339
340 /* init context */
341 Device->Context = DeviceExtension;
342 DeviceExtension->LowerDevice = Device->NextDeviceObject;
343
344 /* add to object bag*/
345 KsAddItemToObjectBag(Device->Bag, Device->Context, ExFreePool);
346
347 /* init device*/
348 Status = USBAudioStartDevice(Device);
349 if (NT_SUCCESS(Status))
350 {
351 /* TODO build filter topology and pin descriptors and retrieve interface */
352 Status = USBAudioCreateFilterContext(Device);
353 }
354 }
355
356 return Status;
357 }
358
359 NTSTATUS
360 NTAPI
361 USBAudioPnPQueryStop(
362 _In_ PKSDEVICE Device,
363 _In_ PIRP Irp)
364 {
365 /* no op */
366 return STATUS_SUCCESS;
367 }
368
369 VOID
370 NTAPI
371 USBAudioPnPCancelStop(
372 _In_ PKSDEVICE Device,
373 _In_ PIRP Irp)
374 {
375 /* no op */
376 }
377
378 VOID
379 NTAPI
380 USBAudioPnPStop(
381 _In_ PKSDEVICE Device,
382 _In_ PIRP Irp)
383 {
384 /* TODO: stop device */
385 UNIMPLEMENTED
386 }
387
388 NTSTATUS
389 NTAPI
390 USBAudioPnPQueryRemove(
391 _In_ PKSDEVICE Device,
392 _In_ PIRP Irp)
393 {
394 /* no op */
395 return STATUS_SUCCESS;
396 }
397
398
399 VOID
400 NTAPI
401 USBAudioPnPCancelRemove(
402 _In_ PKSDEVICE Device,
403 _In_ PIRP Irp)
404 {
405 /* no op */
406 }
407
408 VOID
409 NTAPI
410 USBAudioPnPRemove(
411 _In_ PKSDEVICE Device,
412 _In_ PIRP Irp)
413 {
414 /* TODO: stop device */
415 UNIMPLEMENTED
416 }
417
418 NTSTATUS
419 NTAPI
420 USBAudioPnPQueryCapabilities(
421 _In_ PKSDEVICE Device,
422 _In_ PIRP Irp,
423 _Inout_ PDEVICE_CAPABILITIES Capabilities)
424 {
425 /* TODO: set caps */
426 UNIMPLEMENTED
427 return STATUS_SUCCESS;
428 }
429
430 VOID
431 NTAPI
432 USBAudioPnPSurpriseRemoval(
433 _In_ PKSDEVICE Device,
434 _In_ PIRP Irp)
435 {
436 /* TODO: stop streams */
437 UNIMPLEMENTED
438 }
439
440 NTSTATUS
441 NTAPI
442 USBAudioPnPQueryPower(
443 _In_ PKSDEVICE Device,
444 _In_ PIRP Irp,
445 _In_ DEVICE_POWER_STATE DeviceTo,
446 _In_ DEVICE_POWER_STATE DeviceFrom,
447 _In_ SYSTEM_POWER_STATE SystemTo,
448 _In_ SYSTEM_POWER_STATE SystemFrom,
449 _In_ POWER_ACTION Action)
450 {
451 /* no op */
452 return STATUS_SUCCESS;
453 }
454
455 VOID
456 NTAPI
457 USBAudioPnPSetPower(
458 _In_ PKSDEVICE Device,
459 _In_ PIRP Irp,
460 _In_ DEVICE_POWER_STATE To,
461 _In_ DEVICE_POWER_STATE From)
462 {
463 /* TODO: stop streams */
464 UNIMPLEMENTED
465 }
466
467 NTSTATUS
468 NTAPI
469 DriverEntry(
470 IN PDRIVER_OBJECT DriverObject,
471 IN PUNICODE_STRING RegistryPath)
472 {
473 NTSTATUS Status;
474
475 // initialize driver
476 Status = KsInitializeDriver(DriverObject, RegistryPath, &KsDeviceDescriptor);
477 if (!NT_SUCCESS(Status))
478 {
479 // failed to initialize driver
480 DPRINT1("Failed to initialize driver with %x\n", Status);
481 return Status;
482 }
483 return Status;
484 }