xref: /reactos/drivers/usb/usbaudio/usbaudio.c (revision 34593d93)
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
SubmitUrbSync(IN PDEVICE_OBJECT DeviceObject,IN PURB Urb)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
USBAudioSelectConfiguration(IN PKSDEVICE Device,IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)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
USBAudioStartDevice(IN PKSDEVICE Device)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
USBAudioAddDevice(_In_ PKSDEVICE Device)287 USBAudioAddDevice(
288   _In_ PKSDEVICE Device)
289 {
290     /* no op */
291     DPRINT1("USBAudioAddDevice\n");
292     return STATUS_SUCCESS;
293 }
294 
295 NTSTATUS
296 NTAPI
USBAudioPnPStart(_In_ PKSDEVICE Device,_In_ PIRP Irp,_In_opt_ PCM_RESOURCE_LIST TranslatedResourceList,_In_opt_ PCM_RESOURCE_LIST UntranslatedResourceList)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 retrieve interface */
328             Status = USBAudioCreateFilterContext(Device);
329         }
330     }
331 
332     return Status;
333 }
334 
335 NTSTATUS
336 NTAPI
USBAudioPnPQueryStop(_In_ PKSDEVICE Device,_In_ PIRP Irp)337 USBAudioPnPQueryStop(
338   _In_ PKSDEVICE Device,
339   _In_ PIRP      Irp)
340 {
341     /* no op */
342     return STATUS_SUCCESS;
343 }
344 
345 VOID
346 NTAPI
USBAudioPnPCancelStop(_In_ PKSDEVICE Device,_In_ PIRP Irp)347 USBAudioPnPCancelStop(
348   _In_ PKSDEVICE Device,
349   _In_ PIRP      Irp)
350 {
351     /* no op */
352 }
353 
354 VOID
355 NTAPI
USBAudioPnPStop(_In_ PKSDEVICE Device,_In_ PIRP Irp)356 USBAudioPnPStop(
357   _In_ PKSDEVICE Device,
358   _In_ PIRP      Irp)
359 {
360     /* TODO: stop device */
361 	UNIMPLEMENTED;
362 }
363 
364 NTSTATUS
365 NTAPI
USBAudioPnPQueryRemove(_In_ PKSDEVICE Device,_In_ PIRP Irp)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
USBAudioPnPCancelRemove(_In_ PKSDEVICE Device,_In_ PIRP Irp)377 USBAudioPnPCancelRemove(
378   _In_ PKSDEVICE Device,
379   _In_ PIRP      Irp)
380 {
381     /* no op */
382 }
383 
384 VOID
385 NTAPI
USBAudioPnPRemove(_In_ PKSDEVICE Device,_In_ PIRP Irp)386 USBAudioPnPRemove(
387   _In_ PKSDEVICE Device,
388   _In_ PIRP      Irp)
389 {
390     /* TODO: stop device */
391 	UNIMPLEMENTED;
392 }
393 
394 NTSTATUS
395 NTAPI
USBAudioPnPQueryCapabilities(_In_ PKSDEVICE Device,_In_ PIRP Irp,_Inout_ PDEVICE_CAPABILITIES Capabilities)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
USBAudioPnPSurpriseRemoval(_In_ PKSDEVICE Device,_In_ PIRP Irp)408 USBAudioPnPSurpriseRemoval(
409   _In_ PKSDEVICE Device,
410   _In_ PIRP      Irp)
411 {
412     /* TODO: stop streams */
413 	UNIMPLEMENTED;
414 }
415 
416 NTSTATUS
417 NTAPI
USBAudioPnPQueryPower(_In_ PKSDEVICE Device,_In_ PIRP Irp,_In_ DEVICE_POWER_STATE DeviceTo,_In_ DEVICE_POWER_STATE DeviceFrom,_In_ SYSTEM_POWER_STATE SystemTo,_In_ SYSTEM_POWER_STATE SystemFrom,_In_ POWER_ACTION Action)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
USBAudioPnPSetPower(_In_ PKSDEVICE Device,_In_ PIRP Irp,_In_ DEVICE_POWER_STATE To,_In_ DEVICE_POWER_STATE From)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
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)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 }
461