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