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 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 } 461