1 /* 2 * PROJECT: ReactOS Universal Serial Bus Driver/Helper Library 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: drivers/usb/usbd/usbd.c 5 * PURPOSE: Helper Library for USB 6 * PROGRAMMERS: 7 * Filip Navara <xnavara@volny.cz> 8 * Michael Martin <michael.martin@reactos.org> 9 * 10 */ 11 12 /* 13 * Universal Serial Bus Driver/Helper Library 14 * 15 * Written by Filip Navara <xnavara@volny.cz> 16 * 17 * Notes: 18 * This driver was obsoleted in Windows XP and most functions 19 * became pure stubs. But some of them were retained for backward 20 * compatibility with existing drivers. 21 * 22 * Preserved functions: 23 * 24 * USBD_Debug_GetHeap (implemented) 25 * USBD_Debug_RetHeap (implemented) 26 * USBD_CalculateUsbBandwidth (implemented, tested) 27 * USBD_CreateConfigurationRequestEx (implemented) 28 * USBD_CreateConfigurationRequest 29 * USBD_GetInterfaceLength (implemented) 30 * USBD_ParseConfigurationDescriptorEx (implemented) 31 * USBD_ParseDescriptors (implemented) 32 * USBD_GetPdoRegistryParameters (implemented) 33 */ 34 35 #define _USBD_ 36 #define NDEBUG 37 #include <ntddk.h> 38 #include <usbdi.h> 39 #include <usbdlib.h> 40 #include <debug.h> 41 #ifndef PLUGPLAY_REGKEY_DRIVER 42 #define PLUGPLAY_REGKEY_DRIVER 2 43 #endif 44 45 NTSTATUS NTAPI 46 DriverEntry(PDRIVER_OBJECT DriverObject, 47 PUNICODE_STRING RegistryPath) 48 { 49 return STATUS_SUCCESS; 50 } 51 52 /* 53 * @implemented 54 */ 55 ULONG NTAPI 56 DllInitialize(ULONG Unknown) 57 { 58 return 0; 59 } 60 61 /* 62 * @implemented 63 */ 64 ULONG NTAPI 65 DllUnload(VOID) 66 { 67 return 0; 68 } 69 70 /* 71 * @implemented 72 */ 73 PVOID NTAPI 74 USBD_Debug_GetHeap(ULONG Unknown1, POOL_TYPE PoolType, ULONG NumberOfBytes, 75 ULONG Tag) 76 { 77 return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag); 78 } 79 80 /* 81 * @implemented 82 */ 83 VOID NTAPI 84 USBD_Debug_RetHeap(PVOID Heap, ULONG Unknown2, ULONG Unknown3) 85 { 86 ExFreePool(Heap); 87 } 88 89 /* 90 * @implemented 91 */ 92 VOID NTAPI 93 USBD_Debug_LogEntry(PCHAR Name, ULONG_PTR Info1, ULONG_PTR Info2, 94 ULONG_PTR Info3) 95 { 96 } 97 98 /* 99 * @implemented 100 */ 101 PVOID NTAPI 102 USBD_AllocateDeviceName(ULONG Unknown) 103 { 104 UNIMPLEMENTED; 105 return NULL; 106 } 107 108 /* 109 * @implemented 110 */ 111 ULONG NTAPI 112 USBD_CalculateUsbBandwidth( 113 ULONG MaxPacketSize, 114 UCHAR EndpointType, 115 BOOLEAN LowSpeed 116 ) 117 { 118 ULONG OverheadTable[] = { 119 0x00, /* UsbdPipeTypeControl */ 120 0x09, /* UsbdPipeTypeIsochronous */ 121 0x00, /* UsbdPipeTypeBulk */ 122 0x0d /* UsbdPipeTypeInterrupt */ 123 }; 124 ULONG Result; 125 126 if (OverheadTable[EndpointType] != 0) 127 { 128 Result = ((MaxPacketSize + OverheadTable[EndpointType]) * 8 * 7) / 6; 129 if (LowSpeed) 130 return Result << 3; 131 return Result; 132 } 133 return 0; 134 } 135 136 /* 137 * @implemented 138 */ 139 ULONG NTAPI 140 USBD_Dispatch(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4) 141 { 142 UNIMPLEMENTED; 143 return 1; 144 } 145 146 /* 147 * @implemented 148 */ 149 VOID NTAPI 150 USBD_FreeDeviceMutex(PVOID Unknown) 151 { 152 UNIMPLEMENTED; 153 } 154 155 /* 156 * @implemented 157 */ 158 VOID NTAPI 159 USBD_FreeDeviceName(PVOID Unknown) 160 { 161 UNIMPLEMENTED; 162 } 163 164 /* 165 * @implemented 166 */ 167 VOID NTAPI 168 USBD_WaitDeviceMutex(PVOID Unknown) 169 { 170 UNIMPLEMENTED; 171 } 172 173 /* 174 * @implemented 175 */ 176 ULONG NTAPI 177 USBD_GetSuspendPowerState(ULONG Unknown1) 178 { 179 UNIMPLEMENTED; 180 return 0; 181 } 182 183 /* 184 * @implemented 185 */ 186 NTSTATUS NTAPI 187 USBD_InitializeDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, 188 ULONG Unknown4, ULONG Unknown5, ULONG Unknown6) 189 { 190 UNIMPLEMENTED; 191 return STATUS_NOT_SUPPORTED; 192 } 193 194 /* 195 * @implemented 196 */ 197 NTSTATUS NTAPI 198 USBD_RegisterHostController(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, 199 ULONG Unknown4, ULONG Unknown5, ULONG Unknown6, ULONG Unknown7, 200 ULONG Unknown8, ULONG Unknown9, ULONG Unknown10) 201 { 202 UNIMPLEMENTED; 203 return STATUS_NOT_SUPPORTED; 204 } 205 206 /* 207 * @implemented 208 */ 209 NTSTATUS NTAPI 210 USBD_GetDeviceInformation(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3) 211 { 212 UNIMPLEMENTED; 213 return STATUS_NOT_SUPPORTED; 214 } 215 216 /* 217 * @implemented 218 */ 219 NTSTATUS NTAPI 220 USBD_CreateDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, 221 ULONG Unknown4, ULONG Unknown5) 222 { 223 UNIMPLEMENTED; 224 return STATUS_NOT_SUPPORTED; 225 } 226 227 /* 228 * @implemented 229 */ 230 NTSTATUS NTAPI 231 USBD_RemoveDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3) 232 { 233 UNIMPLEMENTED; 234 return STATUS_NOT_SUPPORTED; 235 } 236 237 /* 238 * @implemented 239 */ 240 VOID NTAPI 241 USBD_CompleteRequest(ULONG Unknown1, ULONG Unknown2) 242 { 243 UNIMPLEMENTED; 244 } 245 246 /* 247 * @implemented 248 */ 249 VOID NTAPI 250 USBD_RegisterHcFilter( 251 PDEVICE_OBJECT DeviceObject, 252 PDEVICE_OBJECT FilterDeviceObject 253 ) 254 { 255 UNIMPLEMENTED; 256 } 257 258 /* 259 * @implemented 260 */ 261 VOID NTAPI 262 USBD_SetSuspendPowerState(ULONG Unknown1, ULONG Unknown2) 263 { 264 UNIMPLEMENTED; 265 } 266 267 /* 268 * @implemented 269 */ 270 NTSTATUS NTAPI 271 USBD_MakePdoName(ULONG Unknown1, ULONG Unknown2) 272 { 273 UNIMPLEMENTED; 274 return STATUS_NOT_SUPPORTED; 275 } 276 277 /* 278 * @implemented 279 */ 280 NTSTATUS NTAPI 281 USBD_QueryBusTime( 282 PDEVICE_OBJECT RootHubPdo, 283 PULONG CurrentFrame 284 ) 285 { 286 UNIMPLEMENTED; 287 return STATUS_NOT_SUPPORTED; 288 } 289 290 /* 291 * @implemented 292 */ 293 VOID NTAPI 294 USBD_GetUSBDIVersion( 295 PUSBD_VERSION_INFORMATION Version 296 ) 297 { 298 if (Version != NULL) 299 { 300 Version->USBDI_Version = USBDI_VERSION; 301 Version->Supported_USB_Version = 0x200; 302 } 303 } 304 305 /* 306 * @implemented 307 */ 308 NTSTATUS NTAPI 309 USBD_RestoreDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3) 310 { 311 UNIMPLEMENTED; 312 return STATUS_NOT_SUPPORTED; 313 } 314 315 /* 316 * @implemented 317 */ 318 VOID NTAPI 319 USBD_RegisterHcDeviceCapabilities(ULONG Unknown1, ULONG Unknown2, 320 ULONG Unknown3) 321 { 322 UNIMPLEMENTED; 323 } 324 325 /* 326 * @implemented 327 */ 328 PURB NTAPI 329 USBD_CreateConfigurationRequestEx( 330 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, 331 PUSBD_INTERFACE_LIST_ENTRY InterfaceList 332 ) 333 { 334 PURB Urb; 335 ULONG UrbSize = 0; 336 ULONG InterfaceCount = 0, PipeCount = 0; 337 ULONG InterfaceNumber, EndPointNumber; 338 PUSBD_INTERFACE_INFORMATION InterfaceInfo; 339 340 while(InterfaceList[InterfaceCount].InterfaceDescriptor) 341 { 342 // pipe count 343 PipeCount += InterfaceList[InterfaceCount].InterfaceDescriptor->bNumEndpoints; 344 345 // interface count 346 InterfaceCount++; 347 } 348 349 // size of urb 350 UrbSize = GET_SELECT_CONFIGURATION_REQUEST_SIZE(InterfaceCount, PipeCount); 351 352 // allocate urb 353 Urb = ExAllocatePool(NonPagedPool, UrbSize); 354 if (!Urb) 355 { 356 // no memory 357 return NULL; 358 } 359 360 // zero urb 361 RtlZeroMemory(Urb, UrbSize); 362 363 // init urb header 364 Urb->UrbSelectConfiguration.Hdr.Function = URB_FUNCTION_SELECT_CONFIGURATION; 365 Urb->UrbSelectConfiguration.Hdr.Length = UrbSize; 366 Urb->UrbSelectConfiguration.ConfigurationDescriptor = ConfigurationDescriptor; 367 368 // init interface information 369 InterfaceInfo = &Urb->UrbSelectConfiguration.Interface; 370 for (InterfaceNumber = 0; InterfaceNumber < InterfaceCount; InterfaceNumber++) 371 { 372 // init interface info 373 InterfaceList[InterfaceNumber].Interface = InterfaceInfo; 374 InterfaceInfo->InterfaceNumber = InterfaceList[InterfaceNumber].InterfaceDescriptor->bInterfaceNumber; 375 InterfaceInfo->AlternateSetting = InterfaceList[InterfaceNumber].InterfaceDescriptor->bAlternateSetting; 376 InterfaceInfo->NumberOfPipes = InterfaceList[InterfaceNumber].InterfaceDescriptor->bNumEndpoints; 377 378 // store length 379 InterfaceInfo->Length = GET_USBD_INTERFACE_SIZE(InterfaceList[InterfaceNumber].InterfaceDescriptor->bNumEndpoints); 380 381 // sanity check 382 //C_ASSERT(FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes) == 16); 383 384 for (EndPointNumber = 0; EndPointNumber < InterfaceInfo->NumberOfPipes; EndPointNumber++) 385 { 386 // init max transfer size 387 InterfaceInfo->Pipes[EndPointNumber].MaximumTransferSize = PAGE_SIZE; 388 } 389 390 // next interface info 391 InterfaceInfo = (PUSBD_INTERFACE_INFORMATION) ((ULONG_PTR)InterfaceInfo + InterfaceInfo->Length); 392 } 393 394 return Urb; 395 } 396 397 /* 398 * @implemented 399 */ 400 PURB NTAPI 401 USBD_CreateConfigurationRequest( 402 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, 403 PUSHORT Size 404 ) 405 { 406 /* WindowsXP returns NULL */ 407 return NULL; 408 } 409 410 /* 411 * @implemented 412 */ 413 ULONG NTAPI 414 USBD_GetInterfaceLength( 415 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor, 416 PUCHAR BufferEnd 417 ) 418 { 419 ULONG_PTR Current; 420 PUSB_INTERFACE_DESCRIPTOR CurrentDescriptor = InterfaceDescriptor; 421 ULONG Length = 0; 422 BOOLEAN InterfaceFound = FALSE; 423 424 for (Current = (ULONG_PTR)CurrentDescriptor; 425 Current < (ULONG_PTR)BufferEnd; 426 Current += CurrentDescriptor->bLength) 427 { 428 CurrentDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Current; 429 430 if ((CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) && (InterfaceFound)) 431 break; 432 else if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) 433 InterfaceFound = TRUE; 434 435 Length += CurrentDescriptor->bLength; 436 } 437 438 return Length; 439 } 440 441 /* 442 * @implemented 443 */ 444 PUSB_COMMON_DESCRIPTOR NTAPI 445 USBD_ParseDescriptors( 446 PVOID DescriptorBuffer, 447 ULONG TotalLength, 448 PVOID StartPosition, 449 LONG DescriptorType 450 ) 451 { 452 PUSB_COMMON_DESCRIPTOR CommonDescriptor; 453 454 /* use start position */ 455 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)StartPosition; 456 457 458 /* find next available descriptor */ 459 while(CommonDescriptor) 460 { 461 if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)DescriptorBuffer + TotalLength)) 462 { 463 /* end reached */ 464 DPRINT("End reached %p\n", CommonDescriptor); 465 return NULL; 466 } 467 468 DPRINT("CommonDescriptor Type %x Length %x\n", CommonDescriptor->bDescriptorType, CommonDescriptor->bLength); 469 470 /* is the requested one */ 471 if (CommonDescriptor->bDescriptorType == DescriptorType) 472 { 473 /* it is */ 474 return CommonDescriptor; 475 } 476 477 if (CommonDescriptor->bLength == 0) 478 { 479 /* invalid usb descriptor */ 480 return NULL; 481 } 482 483 /* move to next descriptor */ 484 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength); 485 } 486 487 /* no descriptor found */ 488 return NULL; 489 } 490 491 492 /* 493 * @implemented 494 */ 495 PUSB_INTERFACE_DESCRIPTOR NTAPI 496 USBD_ParseConfigurationDescriptorEx( 497 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, 498 PVOID StartPosition, 499 LONG InterfaceNumber, 500 LONG AlternateSetting, 501 LONG InterfaceClass, 502 LONG InterfaceSubClass, 503 LONG InterfaceProtocol 504 ) 505 { 506 BOOLEAN Found; 507 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; 508 509 /* set to start position */ 510 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)StartPosition; 511 512 DPRINT("USBD_ParseConfigurationDescriptorEx\n"); 513 DPRINT("ConfigurationDescriptor %p Length %lu\n", ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength); 514 DPRINT("CurrentOffset %p Offset %lu\n", StartPosition, ((ULONG_PTR)StartPosition - (ULONG_PTR)ConfigurationDescriptor)); 515 516 while(InterfaceDescriptor) 517 { 518 /* get interface descriptor */ 519 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, InterfaceDescriptor, USB_INTERFACE_DESCRIPTOR_TYPE); 520 if (!InterfaceDescriptor) 521 { 522 /* no more descriptors available */ 523 break; 524 } 525 526 DPRINT("InterfaceDescriptor %p InterfaceNumber %x AlternateSetting %x Length %lu\n", InterfaceDescriptor, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting, InterfaceDescriptor->bLength); 527 528 /* set found */ 529 Found = TRUE; 530 531 /* is there an interface number provided */ 532 if(InterfaceNumber != -1) 533 { 534 if(InterfaceNumber != InterfaceDescriptor->bInterfaceNumber) 535 { 536 /* interface number does not match */ 537 Found = FALSE; 538 } 539 } 540 541 /* is there an alternate setting provided */ 542 if(AlternateSetting != -1) 543 { 544 if(AlternateSetting != InterfaceDescriptor->bAlternateSetting) 545 { 546 /* alternate setting does not match */ 547 Found = FALSE; 548 } 549 } 550 551 /* match on interface class */ 552 if(InterfaceClass != -1) 553 { 554 if(InterfaceClass != InterfaceDescriptor->bInterfaceClass) 555 { 556 /* no match with interface class criteria */ 557 Found = FALSE; 558 } 559 } 560 561 /* match on interface sub class */ 562 if(InterfaceSubClass != -1) 563 { 564 if(InterfaceSubClass != InterfaceDescriptor->bInterfaceSubClass) 565 { 566 /* no interface sub class match */ 567 Found = FALSE; 568 } 569 } 570 571 /* interface protocol criteria */ 572 if(InterfaceProtocol != -1) 573 { 574 if(InterfaceProtocol != InterfaceDescriptor->bInterfaceProtocol) 575 { 576 /* no interface protocol match */ 577 Found = FALSE; 578 } 579 } 580 581 if (Found) 582 { 583 /* the chosen one */ 584 return InterfaceDescriptor; 585 } 586 587 /* sanity check */ 588 ASSERT(InterfaceDescriptor->bLength); 589 590 /* move to next descriptor */ 591 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength); 592 } 593 594 DPRINT("No Descriptor With InterfaceNumber %ld AlternateSetting %ld InterfaceClass %ld InterfaceSubClass %ld InterfaceProtocol %ld found\n", InterfaceNumber, 595 AlternateSetting, InterfaceClass, InterfaceSubClass, InterfaceProtocol); 596 597 return NULL; 598 } 599 600 /* 601 * @implemented 602 */ 603 PUSB_INTERFACE_DESCRIPTOR NTAPI 604 USBD_ParseConfigurationDescriptor( 605 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, 606 UCHAR InterfaceNumber, 607 UCHAR AlternateSetting 608 ) 609 { 610 return USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, 611 (PVOID)ConfigurationDescriptor, InterfaceNumber, AlternateSetting, 612 -1, -1, -1); 613 } 614 615 616 /* 617 * @implemented 618 */ 619 ULONG NTAPI 620 USBD_GetPdoRegistryParameter( 621 PDEVICE_OBJECT PhysicalDeviceObject, 622 PVOID Parameter, 623 ULONG ParameterLength, 624 PWCHAR KeyName, 625 ULONG KeyNameLength 626 ) 627 { 628 NTSTATUS Status; 629 HANDLE DevInstRegKey; 630 631 /* Open the device key */ 632 Status = IoOpenDeviceRegistryKey(PhysicalDeviceObject, 633 PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, &DevInstRegKey); 634 if (NT_SUCCESS(Status)) 635 { 636 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo; 637 UNICODE_STRING ValueName; 638 ULONG Length; 639 640 /* Initialize the unicode string based on caller data */ 641 ValueName.Buffer = KeyName; 642 ValueName.Length = ValueName.MaximumLength = KeyNameLength; 643 644 Length = ParameterLength + sizeof(KEY_VALUE_PARTIAL_INFORMATION); 645 PartialInfo = ExAllocatePool(PagedPool, Length); 646 if (PartialInfo) 647 { 648 Status = ZwQueryValueKey(DevInstRegKey, &ValueName, 649 KeyValuePartialInformation, PartialInfo, Length, &Length); 650 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 651 { 652 /* The caller doesn't want all the data */ 653 ExFreePool(PartialInfo); 654 PartialInfo = ExAllocatePool(PagedPool, Length); 655 if (PartialInfo) 656 { 657 Status = ZwQueryValueKey(DevInstRegKey, &ValueName, 658 KeyValuePartialInformation, PartialInfo, Length, &Length); 659 } 660 else 661 { 662 Status = STATUS_NO_MEMORY; 663 } 664 } 665 666 if (NT_SUCCESS(Status)) 667 { 668 /* Compute the length to copy back */ 669 if (ParameterLength < PartialInfo->DataLength) 670 Length = ParameterLength; 671 else 672 Length = PartialInfo->DataLength; 673 674 RtlCopyMemory(Parameter, 675 PartialInfo->Data, 676 Length); 677 } 678 679 if (PartialInfo) 680 { 681 ExFreePool(PartialInfo); 682 } 683 } else 684 Status = STATUS_NO_MEMORY; 685 ZwClose(DevInstRegKey); 686 } 687 return Status; 688 } 689