1 /* 2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: drivers/usb/usbccgp/descriptor.c 5 * PURPOSE: USB device driver. 6 * PROGRAMMERS: 7 * Michael Martin (michael.martin@reactos.org) 8 * Johannes Anderwald (johannes.anderwald@reactos.org) 9 * Cameron Gutman 10 */ 11 12 #include "usbccgp.h" 13 14 #define NDEBUG 15 #include <debug.h> 16 17 NTSTATUS 18 NTAPI 19 USBCCGP_GetDescriptor( 20 IN PDEVICE_OBJECT DeviceObject, 21 IN UCHAR DescriptorType, 22 IN ULONG DescriptorLength, 23 IN UCHAR DescriptorIndex, 24 IN LANGID LanguageId, 25 OUT PVOID *OutDescriptor) 26 { 27 PURB Urb; 28 NTSTATUS Status; 29 PVOID Descriptor; 30 31 // 32 // sanity checks 33 // 34 ASSERT(DeviceObject); 35 ASSERT(OutDescriptor); 36 ASSERT(DescriptorLength); 37 38 // 39 // first allocate descriptor buffer 40 // 41 Descriptor = AllocateItem(NonPagedPool, DescriptorLength); 42 if (!Descriptor) 43 { 44 // 45 // no memory 46 // 47 return STATUS_INSUFFICIENT_RESOURCES; 48 } 49 50 // 51 // allocate urb 52 // 53 Urb = (PURB) AllocateItem(NonPagedPool, sizeof(URB)); 54 if (!Urb) 55 { 56 // 57 // no memory 58 // 59 FreeItem(Descriptor); 60 return STATUS_INSUFFICIENT_RESOURCES; 61 } 62 63 // 64 // initialize urb 65 // 66 UsbBuildGetDescriptorRequest(Urb, 67 sizeof(Urb->UrbControlDescriptorRequest), 68 DescriptorType, 69 DescriptorIndex, 70 LanguageId, 71 Descriptor, 72 NULL, 73 DescriptorLength, 74 NULL); 75 76 // 77 // submit urb 78 // 79 Status = USBCCGP_SyncUrbRequest(DeviceObject, Urb); 80 81 // 82 // free urb 83 // 84 FreeItem(Urb); 85 86 if (NT_SUCCESS(Status)) 87 { 88 // 89 // store result 90 // 91 *OutDescriptor = Descriptor; 92 } 93 94 // 95 // done 96 // 97 return Status; 98 } 99 100 NTSTATUS 101 NTAPI 102 USBCCGP_GetStringDescriptor( 103 IN PDEVICE_OBJECT DeviceObject, 104 IN ULONG DescriptorLength, 105 IN UCHAR DescriptorIndex, 106 IN LANGID LanguageId, 107 OUT PVOID *OutDescriptor) 108 { 109 NTSTATUS Status; 110 PUSB_STRING_DESCRIPTOR StringDescriptor; 111 ULONG Size; 112 PVOID Buffer; 113 114 // retrieve descriptor 115 Status = USBCCGP_GetDescriptor(DeviceObject, USB_STRING_DESCRIPTOR_TYPE, DescriptorLength, DescriptorIndex, LanguageId, OutDescriptor); 116 if (!NT_SUCCESS(Status)) 117 { 118 // failed 119 return Status; 120 } 121 122 // get descriptor structure 123 StringDescriptor = (PUSB_STRING_DESCRIPTOR)*OutDescriptor; 124 125 // sanity check 126 ASSERT(StringDescriptor->bLength < DescriptorLength - 2); 127 128 if (StringDescriptor->bLength == 2) 129 { 130 // invalid descriptor 131 FreeItem(StringDescriptor); 132 return STATUS_DEVICE_DATA_ERROR; 133 } 134 135 // calculate size 136 Size = StringDescriptor->bLength + sizeof(WCHAR); 137 138 // allocate buffer 139 Buffer = AllocateItem(NonPagedPool, Size); 140 if (!Buffer) 141 { 142 // no memory 143 FreeItem(StringDescriptor); 144 return STATUS_INSUFFICIENT_RESOURCES; 145 } 146 147 // copy result 148 RtlCopyMemory(Buffer, StringDescriptor->bString, Size - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString)); 149 150 // free buffer 151 FreeItem(StringDescriptor); 152 153 // store result 154 *OutDescriptor = (PVOID)Buffer; 155 return STATUS_SUCCESS; 156 } 157 158 159 NTSTATUS 160 USBCCGP_GetDescriptors( 161 IN PDEVICE_OBJECT DeviceObject) 162 { 163 NTSTATUS Status; 164 PFDO_DEVICE_EXTENSION DeviceExtension; 165 USHORT DescriptorLength; 166 167 // 168 // get device extension 169 // 170 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 171 172 // 173 // first get device descriptor 174 // 175 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_DEVICE_DESCRIPTOR_TYPE, sizeof(USB_DEVICE_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->DeviceDescriptor); 176 if (!NT_SUCCESS(Status)) 177 { 178 // 179 // failed to get device descriptor 180 // 181 DeviceExtension->DeviceDescriptor = NULL; 182 return Status; 183 } 184 185 // 186 // now get basic configuration descriptor 187 // 188 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, sizeof(USB_CONFIGURATION_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor); 189 if (!NT_SUCCESS(Status)) 190 { 191 // 192 // failed to get configuration descriptor 193 // 194 FreeItem(DeviceExtension->DeviceDescriptor); 195 DeviceExtension->DeviceDescriptor = NULL; 196 return Status; 197 } 198 199 // 200 // backup length 201 // 202 DescriptorLength = DeviceExtension->ConfigurationDescriptor->wTotalLength; 203 204 // 205 // release basic descriptor 206 // 207 FreeItem(DeviceExtension->ConfigurationDescriptor); 208 DeviceExtension->ConfigurationDescriptor = NULL; 209 210 // 211 // allocate full descriptor 212 // 213 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, DescriptorLength, 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor); 214 if (!NT_SUCCESS(Status)) 215 { 216 // 217 // failed to get configuration descriptor 218 // 219 FreeItem(DeviceExtension->DeviceDescriptor); 220 DeviceExtension->DeviceDescriptor = NULL; 221 return Status; 222 } 223 return Status; 224 } 225 226 NTSTATUS 227 AllocateInterfaceDescriptorsArray( 228 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, 229 OUT PUSB_INTERFACE_DESCRIPTOR **OutArray) 230 { 231 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; 232 ULONG Count = 0; 233 PUSB_INTERFACE_DESCRIPTOR *Array; 234 235 // 236 // allocate array 237 // 238 Array = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * ConfigurationDescriptor->bNumInterfaces); 239 if (!Array) 240 return STATUS_INSUFFICIENT_RESOURCES; 241 242 // 243 // enumerate all interfaces 244 // 245 Count = 0; 246 do 247 { 248 // 249 // find next descriptor 250 // 251 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, Count, 0, -1, -1, -1); 252 if (!InterfaceDescriptor) 253 break; 254 255 // 256 // store descriptor 257 // 258 Array[Count] = InterfaceDescriptor; 259 Count++; 260 261 }while(TRUE); 262 263 // 264 // store result 265 // 266 *OutArray = Array; 267 268 // 269 // done 270 // 271 return STATUS_SUCCESS; 272 } 273 274 VOID 275 DumpFullConfigurationDescriptor( 276 IN PFDO_DEVICE_EXTENSION FDODeviceExtension, 277 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor) 278 { 279 PUSB_COMMON_DESCRIPTOR Descriptor; 280 281 Descriptor = (PUSB_COMMON_DESCRIPTOR)ConfigurationDescriptor; 282 283 DbgPrint("Bogus ConfigurationDescriptor Found\n"); 284 DbgPrint("InterfaceCount %x\n", ConfigurationDescriptor->bNumInterfaces); 285 286 do 287 { 288 if (((ULONG_PTR)Descriptor) >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength)) 289 break; 290 291 DbgPrint("Descriptor Type %x Length %lu Offset %lu\n", Descriptor->bDescriptorType, Descriptor->bLength, ((ULONG_PTR)Descriptor - (ULONG_PTR)ConfigurationDescriptor)); 292 293 // check for invalid descriptors 294 if (!Descriptor->bLength) 295 { 296 DbgPrint("Bogus Descriptor!!!\n"); 297 break; 298 } 299 300 // advance to next descriptor 301 Descriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength); 302 303 }while(TRUE); 304 305 306 } 307 308 309 NTSTATUS 310 NTAPI 311 USBCCGP_ScanConfigurationDescriptor( 312 IN OUT PFDO_DEVICE_EXTENSION FDODeviceExtension, 313 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor) 314 { 315 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; 316 ULONG InterfaceIndex = 0; 317 ULONG DescriptorCount; 318 319 // 320 // sanity checks 321 // 322 ASSERT(ConfigurationDescriptor); 323 ASSERT(ConfigurationDescriptor->bNumInterfaces); 324 325 // 326 // count all interface descriptors 327 // 328 DescriptorCount = ConfigurationDescriptor->bNumInterfaces; 329 if (DescriptorCount == 0) 330 { 331 DPRINT1("[USBCCGP] DescriptorCount is zero\n"); 332 return STATUS_INVALID_PARAMETER; 333 } 334 335 // 336 // allocate array holding the interface descriptors 337 // 338 FDODeviceExtension->InterfaceList = AllocateItem(NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (DescriptorCount + 1)); 339 if (!FDODeviceExtension->InterfaceList) 340 { 341 // 342 // no memory 343 // 344 return STATUS_INSUFFICIENT_RESOURCES; 345 } 346 347 // 348 // reset interface list count 349 // 350 FDODeviceExtension->InterfaceListCount = 0; 351 352 do 353 { 354 // 355 // parse configuration descriptor 356 // 357 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, InterfaceIndex, -1, -1, -1, -1); 358 if (InterfaceDescriptor) 359 { 360 // 361 // store in interface list 362 // 363 ASSERT(FDODeviceExtension->InterfaceListCount < DescriptorCount); 364 FDODeviceExtension->InterfaceList[FDODeviceExtension->InterfaceListCount].InterfaceDescriptor = InterfaceDescriptor; 365 FDODeviceExtension->InterfaceListCount++; 366 } 367 else 368 { 369 DumpConfigurationDescriptor(ConfigurationDescriptor); 370 DumpFullConfigurationDescriptor(FDODeviceExtension, ConfigurationDescriptor); 371 372 // 373 // see issue 374 // CORE-6574 Test 3 (USB Web Cam) 375 // 376 if (FDODeviceExtension->DeviceDescriptor && FDODeviceExtension->DeviceDescriptor->idVendor == 0x0458 && FDODeviceExtension->DeviceDescriptor->idProduct == 0x705f) 377 ASSERT(FALSE); 378 } 379 380 // 381 // move to next interface 382 // 383 InterfaceIndex++; 384 385 }while(InterfaceIndex < DescriptorCount); 386 387 // 388 // sanity check 389 // 390 ASSERT(FDODeviceExtension->InterfaceListCount); 391 392 // 393 // done 394 // 395 return STATUS_SUCCESS; 396 } 397 398 VOID 399 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor) 400 { 401 DbgPrint("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor); 402 DbgPrint("bLength %x\n", ConfigurationDescriptor->bLength); 403 DbgPrint("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType); 404 DbgPrint("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength); 405 DbgPrint("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces); 406 DbgPrint("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue); 407 DbgPrint("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration); 408 DbgPrint("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes); 409 DbgPrint("MaxPower %x\n", ConfigurationDescriptor->MaxPower); 410 } 411 412 NTSTATUS 413 USBCCGP_SelectInterface( 414 IN PDEVICE_OBJECT DeviceObject, 415 IN PFDO_DEVICE_EXTENSION DeviceExtension, 416 IN ULONG InterfaceIndex) 417 { 418 NTSTATUS Status; 419 PURB Urb; 420 421 // 422 // allocate urb 423 // 424 Urb = AllocateItem(NonPagedPool, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints)); 425 if (!Urb) 426 { 427 // 428 // no memory 429 // 430 return STATUS_INSUFFICIENT_RESOURCES; 431 } 432 433 // 434 // now prepare interface urb 435 // 436 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bInterfaceNumber, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bAlternateSetting); 437 438 // 439 // now select the interface 440 // 441 Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb); 442 443 // 444 // did it succeed 445 // 446 if (NT_SUCCESS(Status)) 447 { 448 // 449 // update configuration info 450 // 451 ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceList[InterfaceIndex].Interface->Length); 452 RtlCopyMemory(DeviceExtension->InterfaceList[InterfaceIndex].Interface, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length); 453 } 454 455 // 456 // free urb 457 // 458 FreeItem(Urb); 459 460 // 461 // done 462 // 463 return Status; 464 } 465 466 NTSTATUS 467 USBCCGP_SelectConfiguration( 468 IN PDEVICE_OBJECT DeviceObject, 469 IN PFDO_DEVICE_EXTENSION DeviceExtension) 470 { 471 PUSBD_INTERFACE_INFORMATION InterfaceInformation; 472 NTSTATUS Status; 473 PURB Urb; 474 ULONG Index; 475 476 // 477 // now scan configuration descriptors 478 // 479 Status = USBCCGP_ScanConfigurationDescriptor(DeviceExtension, DeviceExtension->ConfigurationDescriptor); 480 if (!NT_SUCCESS(Status)) 481 { 482 // 483 // failed to scan 484 // 485 return Status; 486 } 487 488 // 489 // now allocate the urb 490 // 491 Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->InterfaceList); 492 if (!Urb) 493 { 494 // 495 // no memory 496 // 497 return STATUS_INSUFFICIENT_RESOURCES; 498 } 499 500 // 501 // submit urb 502 // 503 Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb); 504 if (!NT_SUCCESS(Status)) 505 { 506 // 507 // failed to set configuration 508 // 509 DPRINT1("USBCCGP_SyncUrbRequest failed to set interface %x\n", Status); 510 ExFreePool(Urb); 511 return Status; 512 } 513 514 // 515 // get interface information 516 // 517 InterfaceInformation = &Urb->UrbSelectConfiguration.Interface; 518 for(Index = 0; Index < DeviceExtension->InterfaceListCount; Index++) 519 { 520 // 521 // allocate buffer to store interface information 522 // 523 DeviceExtension->InterfaceList[Index].Interface = AllocateItem(NonPagedPool, InterfaceInformation->Length); 524 if (!DeviceExtension->InterfaceList[Index].Interface) 525 { 526 // 527 // no memory 528 // 529 return STATUS_INSUFFICIENT_RESOURCES; 530 } 531 532 // 533 // copy interface information 534 // 535 RtlCopyMemory(DeviceExtension->InterfaceList[Index].Interface, InterfaceInformation, InterfaceInformation->Length); 536 537 // 538 // move to next interface 539 // 540 InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length); 541 } 542 543 544 // 545 // store pipe handle 546 // 547 DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle; 548 549 // 550 // free interface list & urb 551 // 552 ExFreePool(Urb); 553 554 // 555 // done 556 // 557 return Status; 558 } 559