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