1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxUsbInterface.cpp 8 9 Abstract: 10 11 Author: 12 13 Environment: 14 15 Both kernel and user mode 16 17 Revision History: 18 19 --*/ 20 21 #include "fxusbpch.hpp" 22 23 extern "C" { 24 #include "FxUsbInterface.tmh" 25 } 26 27 FxUsbInterface::FxUsbInterface( 28 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 29 __in FxUsbDevice* UsbDevice, 30 __in PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor 31 ) : 32 FxNonPagedObject(FX_TYPE_USB_INTERFACE ,sizeof(FxUsbInterface), FxDriverGlobals), 33 m_UsbDevice(UsbDevice) 34 { 35 m_UsbDevice->ADDREF(this); 36 37 m_InterfaceNumber = InterfaceDescriptor->bInterfaceNumber; 38 m_Protocol = InterfaceDescriptor->bInterfaceProtocol; 39 m_Class = InterfaceDescriptor->bInterfaceClass; 40 m_SubClass = InterfaceDescriptor->bInterfaceSubClass; 41 42 m_CurAlternateSetting = 0; 43 m_NumSettings = 0; 44 m_NumberOfConfiguredPipes = 0; 45 m_ConfiguredPipes = NULL; 46 m_Settings = NULL; 47 48 MarkNoDeleteDDI(ObjectDoNotLock); 49 } 50 51 FxUsbInterface::~FxUsbInterface() 52 { 53 ULONG i; 54 55 m_UsbDevice->RemoveDeletedInterface(this); 56 57 for (i = 0; i < m_NumberOfConfiguredPipes; i++) { 58 ASSERT(m_ConfiguredPipes[i] == NULL); 59 } 60 61 if (m_ConfiguredPipes != NULL) { 62 FxPoolFree(m_ConfiguredPipes); 63 m_ConfiguredPipes = NULL; 64 } 65 66 m_NumberOfConfiguredPipes = 0; 67 68 if (m_Settings != NULL) { 69 FxPoolFree(m_Settings); 70 m_Settings = NULL; 71 } 72 73 // 74 // Release the reference taken in the constructor 75 // 76 m_UsbDevice->RELEASE(this); 77 } 78 79 VOID 80 FxUsbInterface::CleanUpAndDelete( 81 __in BOOLEAN Failure 82 ) 83 /*++ 84 85 Routine Description: 86 Deletes the pipes contained on the interface. 87 88 Arguments: 89 Failure - if TRUE, the pipes were never exposed to the client, so any attributes 90 are cleared before deletion (via DeleteFromFailedCreate) 91 92 Assumes: 93 FxUsbDevice::InterfaceIterationLock is held by the caller 94 95 Return Value: 96 None 97 98 --*/ 99 { 100 FxUsbPipe** pPipes; 101 ULONG numPipes; 102 KIRQL irql; 103 ULONG i; 104 105 // 106 // Capture the values, clear them out of the object and then clean them up 107 // outside of the lock. 108 // 109 m_UsbDevice->Lock(&irql); 110 111 pPipes = m_ConfiguredPipes; 112 numPipes = m_NumberOfConfiguredPipes; 113 114 m_ConfiguredPipes = NULL; 115 m_NumberOfConfiguredPipes = 0; 116 117 m_UsbDevice->Unlock(irql); 118 119 if (pPipes != NULL) { 120 for (i = 0; i < numPipes; i++) { 121 if (pPipes[i] != NULL) { 122 if (Failure) { 123 // 124 // FxIoTarget::Remove will be called in FxIoTarget::Dispose() 125 // 126 pPipes[i]->DeleteFromFailedCreate(); 127 } 128 else { 129 pPipes[i]->DeleteObject(); 130 } 131 } 132 else { 133 // 134 // No more pointers to delete, break out of the loop 135 // 136 break; 137 } 138 } 139 140 FxPoolFree(pPipes); 141 pPipes = NULL; 142 } 143 } 144 145 VOID 146 FxUsbInterface::RemoveDeletedPipe( 147 __in FxUsbPipe* Pipe 148 ) 149 { 150 ULONG i; 151 152 if (m_ConfiguredPipes == NULL) { 153 return; 154 } 155 156 for (i = 0; i < m_NumberOfConfiguredPipes; i++) { 157 if (m_ConfiguredPipes[i] == Pipe) { 158 m_ConfiguredPipes[i] = NULL; 159 return; 160 } 161 } 162 } 163 164 VOID 165 FxUsbInterface::SetInfo( 166 __in PUSBD_INTERFACE_INFORMATION InterfaceInfo 167 ) 168 /*++ 169 170 Routine Description: 171 Captures the alternate from the interface information into this structure 172 and then assigns info to all the created pipes. 173 174 Arguments: 175 InterfaceInfo - info to capture 176 177 Return Value: 178 None 179 180 --*/ 181 { 182 UCHAR i; 183 184 ASSERT(m_InterfaceNumber == InterfaceInfo->InterfaceNumber); 185 186 m_CurAlternateSetting = InterfaceInfo->AlternateSetting; 187 188 for (i = 0; i < m_NumberOfConfiguredPipes ; i++) { 189 m_ConfiguredPipes[i]->InitPipe(&InterfaceInfo->Pipes[i], 190 InterfaceInfo->InterfaceNumber, 191 this); 192 } 193 } 194 195 _Must_inspect_result_ 196 NTSTATUS 197 FxUsbInterface::CreateSettings( 198 VOID 199 ) 200 /*++ 201 202 Routine Description: 203 1) Find the max number of settings for the interface 204 2) Allocate an array for the settings 205 3) Create a setting object for each setting and initialize 206 207 Arguments: 208 None 209 210 Return Value: 211 NTSTATUS 212 213 --*/ 214 { 215 PUSB_INTERFACE_DESCRIPTOR pDescriptor; 216 ULONG size; 217 UCHAR i; 218 219 // 220 // No need to validate the size of the interface descriptor since FxUsbDevice::CreateInterfaces 221 // has already done so 222 // 223 pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( 224 m_UsbDevice->m_ConfigDescriptor, 225 m_UsbDevice->m_ConfigDescriptor->wTotalLength, 226 m_UsbDevice->m_ConfigDescriptor, 227 USB_INTERFACE_DESCRIPTOR_TYPE 228 ); 229 230 // 231 // Calculate the number of settings for this interface 232 // 233 while (pDescriptor != NULL) { 234 if (m_InterfaceNumber == pDescriptor->bInterfaceNumber) { 235 m_NumSettings++; 236 } 237 pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( 238 m_UsbDevice->m_ConfigDescriptor, 239 m_UsbDevice->m_ConfigDescriptor->wTotalLength, 240 WDF_PTR_ADD_OFFSET(pDescriptor, pDescriptor->bLength), 241 USB_INTERFACE_DESCRIPTOR_TYPE 242 ); 243 } 244 size = sizeof(FxUsbInterfaceSetting) * m_NumSettings; 245 m_Settings = (FxUsbInterfaceSetting *) FxPoolAllocate( 246 GetDriverGlobals(), NonPagedPool, size); 247 248 if (m_Settings == NULL) { 249 DoTraceLevelMessage( 250 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 251 "Could not allocate memory for %d settings for bInterfaceNumber %d " 252 "(Protocol %d, Class %d, SubClass %d), %!STATUS!", 253 m_NumSettings, m_InterfaceNumber, m_Protocol, m_Class, m_SubClass, 254 STATUS_INSUFFICIENT_RESOURCES); 255 256 return STATUS_INSUFFICIENT_RESOURCES; 257 } 258 259 RtlZeroMemory(m_Settings, size); 260 261 // 262 // Add all the settings for this interface 263 // 264 pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( 265 m_UsbDevice->m_ConfigDescriptor, 266 m_UsbDevice->m_ConfigDescriptor->wTotalLength, 267 m_UsbDevice->m_ConfigDescriptor, 268 USB_INTERFACE_DESCRIPTOR_TYPE 269 ); 270 271 while (pDescriptor != NULL) { 272 if (m_InterfaceNumber == pDescriptor->bInterfaceNumber) { 273 if (pDescriptor->bAlternateSetting < m_NumSettings) { 274 m_Settings[pDescriptor->bAlternateSetting].InterfaceDescriptor = pDescriptor; 275 } 276 else { 277 DoTraceLevelMessage( 278 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 279 "Interface Number %d does not have contiguous alternate settings," 280 "expected %d settings, found alt setting %d, %!STATUS!", 281 pDescriptor->bInterfaceNumber, m_NumSettings, 282 pDescriptor->bAlternateSetting, STATUS_INVALID_DEVICE_REQUEST); 283 284 return STATUS_INVALID_DEVICE_REQUEST; 285 } 286 } 287 288 pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( 289 m_UsbDevice->m_ConfigDescriptor, 290 m_UsbDevice->m_ConfigDescriptor->wTotalLength, 291 WDF_PTR_ADD_OFFSET(pDescriptor, pDescriptor->bLength), 292 USB_INTERFACE_DESCRIPTOR_TYPE 293 ); 294 } 295 296 for (i = 0; i < m_NumSettings; i++) { 297 298 if (m_Settings[i].InterfaceDescriptor == NULL) { 299 DoTraceLevelMessage( 300 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 301 "Interface Number %d does not have contiguous alternate settings," 302 "expected consecutive %d settings, but alt setting %d missing " 303 "%!STATUS!", m_InterfaceNumber, m_NumSettings, i, 304 STATUS_INVALID_DEVICE_REQUEST); 305 306 return STATUS_INVALID_DEVICE_REQUEST; 307 } 308 309 // 310 // Only validate the endpoints if the interface reports it has some. We don't 311 // want to validate EP descriptors that may be after the interface descriptor 312 // that are never used because bNumEndpoints doesn't indicate they are present. 313 // 314 if (m_Settings[i].InterfaceDescriptor->bNumEndpoints > 0) { 315 PVOID pRelativeEnd; 316 NTSTATUS status; 317 318 // 319 // Validate that each endpoint descriptor is the correct size for this alt setting. 320 // We will use the next inteface descriptor as the end, and if this is the last 321 // interface descriptor, use the end of the config descriptor as our end. 322 // 323 pRelativeEnd = FxUsbFindDescriptorType( 324 m_UsbDevice->m_ConfigDescriptor, 325 m_UsbDevice->m_ConfigDescriptor->wTotalLength, 326 m_Settings[i].InterfaceDescriptor, 327 USB_INTERFACE_DESCRIPTOR_TYPE 328 ); 329 330 if (pRelativeEnd == NULL) { 331 // 332 // This is the last alt setting in the config descriptor, use the end of the 333 // config descriptor as our end 334 // 335 pRelativeEnd = WDF_PTR_ADD_OFFSET(m_UsbDevice->m_ConfigDescriptor, 336 m_UsbDevice->m_ConfigDescriptor->wTotalLength); 337 } 338 339 // 340 // Limit the number of endpoints validated to bNumEndpoints. In theory 341 // there could be EP descriptors after N EP descriptors that are never 342 // used, thus we don't want to risk valdiating them and failing them 343 // (ie an app compat concern, in a perfect world we would validate them) 344 // 345 status = FxUsbValidateDescriptorType( 346 GetDriverGlobals(), 347 m_UsbDevice->m_ConfigDescriptor, 348 m_Settings[i].InterfaceDescriptor, 349 pRelativeEnd, 350 USB_ENDPOINT_DESCRIPTOR_TYPE, 351 sizeof(USB_ENDPOINT_DESCRIPTOR), 352 FxUsbValidateDescriptorOpAtLeast, 353 m_Settings[i].InterfaceDescriptor->bNumEndpoints 354 ); 355 356 if (!NT_SUCCESS(status)) { 357 DoTraceLevelMessage( 358 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 359 "Interface Number %d does not have a valid endpoint descriptor," 360 "%!STATUS!", m_InterfaceNumber, status); 361 362 return status; 363 } 364 } 365 } 366 367 return STATUS_SUCCESS; 368 } 369 370 _Must_inspect_result_ 371 NTSTATUS 372 FxUsbInterface::SelectSettingByIndex( 373 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, 374 __in UCHAR SettingIndex 375 ) 376 /*++ 377 378 Routine Description: 379 Setlects a setting by alternate setting index. 380 381 Arguments: 382 PipesAttributes - optional attributes to apply to each of the created pipes 383 384 SettingIndex - alternate setting index to use 385 386 Return Value: 387 NTSTATUS 388 389 --*/ 390 { 391 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 392 PURB urb; 393 #elif (FX_CORE_MODE == FX_CORE_USER_MODE) 394 UMURB urb; 395 PUSB_INTERFACE_DESCRIPTOR interfaceDesc; 396 #endif 397 FxUsbInterfaceSetting entry; 398 UCHAR numEP; 399 NTSTATUS status; 400 USHORT size; 401 402 status = STATUS_SUCCESS; 403 404 // 405 // We should have at least 1 setting on the interface 406 // 407 ASSERT(m_NumSettings != 0); 408 409 // 410 // If m_NumberOfConfiguredPipes == 0 then it also tells us that 411 // the interface wasn't configured. So it can keep track of configuredness 412 // of the interface. Could there be a case when the selected setting has 0 413 // EP's. Due to the above case we use m_InterfaceConfigured. 414 // 415 if (IsInterfaceConfigured() && m_CurAlternateSetting == SettingIndex) { 416 return STATUS_SUCCESS; 417 } 418 419 // 420 // Check for an invalid alternate setting 421 // 422 if (SettingIndex >= m_NumSettings){ 423 return STATUS_INVALID_PARAMETER; 424 } 425 426 RtlCopyMemory(&entry, &m_Settings[SettingIndex], sizeof(entry)); 427 428 // 429 // Create the configured pipes 430 // 431 numEP = entry.InterfaceDescriptor->bNumEndpoints; 432 433 size = GET_SELECT_INTERFACE_REQUEST_SIZE(numEP); 434 435 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 436 urb = (PURB) FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size); 437 438 if (urb == NULL) { 439 status = STATUS_INSUFFICIENT_RESOURCES; 440 } 441 else { 442 FormatSelectSettingUrb(urb, numEP, SettingIndex); 443 444 status = SelectSetting(PipesAttributes, urb); 445 446 FxPoolFree(urb); 447 urb = NULL; 448 } 449 #elif (FX_CORE_MODE == FX_CORE_USER_MODE) 450 RtlZeroMemory(&urb, sizeof(UMURB)); 451 452 urb.UmUrbSelectInterface.Hdr.InterfaceHandle = m_WinUsbHandle; 453 urb.UmUrbSelectInterface.Hdr.Function = UMURB_FUNCTION_SELECT_INTERFACE; 454 urb.UmUrbSelectInterface.Hdr.Length = sizeof(_UMURB_SELECT_INTERFACE); 455 456 urb.UmUrbSelectInterface.AlternateSetting = SettingIndex; 457 458 status = m_UsbDevice->SendSyncUmUrb(&urb, 2); 459 460 if (NT_SUCCESS(status)) { 461 RtlZeroMemory(&urb, sizeof(UMURB)); 462 463 urb.UmUrbInterfaceInformation.Hdr.InterfaceHandle = m_WinUsbHandle; 464 urb.UmUrbInterfaceInformation.Hdr.Function = UMURB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE; 465 urb.UmUrbInterfaceInformation.Hdr.Length = sizeof(_UMURB_INTERFACE_INFORMATION); 466 467 urb.UmUrbInterfaceInformation.AlternateSetting = SettingIndex; 468 469 status = m_UsbDevice->SendSyncUmUrb(&urb, 2); 470 471 if (NT_SUCCESS(status)) { 472 interfaceDesc = &urb.UmUrbInterfaceInformation.UsbInterfaceDescriptor; 473 474 m_Settings[SettingIndex].InterfaceDescriptorAlloc = *interfaceDesc; 475 476 m_CurAlternateSetting = SettingIndex; 477 478 MakeAndConfigurePipes(PipesAttributes, interfaceDesc->bNumEndpoints); 479 } 480 } 481 #endif 482 483 return status; 484 } 485 486 _Must_inspect_result_ 487 NTSTATUS 488 FxUsbInterface::SelectSettingByDescriptor( 489 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, 490 __in PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor 491 ) 492 /*++ 493 494 Routine Description: 495 Selects an alternate setting by using a USB interface descriptor 496 497 Arguments: 498 PipesAttributes - optional attributes to apply to each of the created pipes 499 500 Return Value: 501 NTSTATUS 502 503 --*/ 504 { 505 PURB urb; 506 NTSTATUS status; 507 USHORT size; 508 509 if (IsInterfaceConfigured() && 510 (m_CurAlternateSetting == InterfaceDescriptor->bAlternateSetting)) { 511 // 512 // Don't do anything 513 // 514 return STATUS_SUCCESS; 515 } 516 517 if (InterfaceDescriptor->bInterfaceNumber != m_InterfaceNumber) { 518 status = STATUS_INVALID_PARAMETER; 519 520 DoTraceLevelMessage( 521 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 522 "WDFUSBINTERFACE %p has interface num %d, select setting by " 523 "descriptor specified interface num %d, %!STATUS!", 524 GetHandle(), m_InterfaceNumber, 525 InterfaceDescriptor->bInterfaceNumber, status 526 ); 527 528 return status; 529 } 530 531 size = GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints); 532 533 urb = (PURB) FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size); 534 535 if (urb == NULL) { 536 status = STATUS_INSUFFICIENT_RESOURCES; 537 } 538 else { 539 FormatSelectSettingUrb( 540 urb, 541 InterfaceDescriptor->bNumEndpoints, 542 InterfaceDescriptor->bAlternateSetting 543 ); 544 545 status = SelectSetting(PipesAttributes, urb); 546 547 FxPoolFree(urb); 548 } 549 550 return status; 551 } 552 553 _Must_inspect_result_ 554 NTSTATUS 555 FxUsbInterface::CheckAndSelectSettingByIndex( 556 __in UCHAR SettingIndex 557 ) 558 /*++ 559 560 Routine Description: 561 Checks if the give SettingIndex is the current alternate setting 562 and if not, selects that setting 563 564 Arguments: 565 SettingIndex - Alternate setting 566 567 Return Value: 568 NTSTATUS 569 570 --*/ 571 { 572 if (GetConfiguredSettingIndex() != SettingIndex) { 573 return SelectSettingByIndex(NULL, 574 SettingIndex); 575 } 576 else { 577 return STATUS_SUCCESS; 578 } 579 } 580 581 _Must_inspect_result_ 582 NTSTATUS 583 FxUsbInterface::SelectSetting( 584 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, 585 __in PURB Urb 586 ) 587 /*++ 588 589 Routine Description: 590 Worker function which all top level SelectSetting DDIs call into. This will 591 1) preallocate all required objects so that we can return failure before 592 we make any undoable changes to the device's state 593 2) send the select interface URB to the device 594 3) initialize all created objects 595 596 Arguments: 597 PipesAttributes - optional attributes to apply to all created pipes 598 599 Urb - Urb to send to the device 600 601 Return Value: 602 NTSTATUS 603 604 --*/ 605 { 606 FxSyncRequest request(GetDriverGlobals(), NULL); 607 LIST_ENTRY pendHead; 608 FxUsbPipe* pPipe; 609 NTSTATUS status; 610 UCHAR iPipe, numPipes; 611 WDF_REQUEST_SEND_OPTIONS options; 612 FxUsbPipe ** ppPipes; 613 ULONG size; 614 615 // 616 // FxSyncRequest always succeesds for KM but can fail for UM. 617 // 618 status = request.Initialize(); 619 if (!NT_SUCCESS(status)) { 620 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 621 "Failed to initialize FxSyncRequest"); 622 return status; 623 } 624 625 // 626 // Subtract the size of the embedded pipe. 627 // 628 const ULONG interfaceStructSize = sizeof(Urb->UrbSelectInterface.Interface) - 629 sizeof(USBD_PIPE_INFORMATION); 630 631 // 632 // This check will happen twice for SelectSettingByInterface/Descriptor. 633 // 634 // We could just do it here, but the above two functions will unnecessarily 635 // have to build an URB. 636 // 637 if (IsInterfaceConfigured() && 638 m_CurAlternateSetting == 639 Urb->UrbSelectInterface.Interface.AlternateSetting) { 640 // 641 // don't do anything 642 // 643 return STATUS_SUCCESS; 644 } 645 646 InitializeListHead(&pendHead); 647 numPipes = 0; 648 ppPipes = NULL; 649 650 if (Urb->UrbSelectInterface.Hdr.Length < interfaceStructSize) { 651 status = STATUS_INVALID_PARAMETER; 652 DoTraceLevelMessage( 653 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 654 "Urb header length 0x%x is less than expected 0x%x" 655 "%!STATUS!", Urb->UrbSelectInterface.Hdr.Length, interfaceStructSize,status 656 ); 657 return status; 658 } 659 660 status = request.m_TrueRequest->ValidateTarget(m_UsbDevice); 661 if (!NT_SUCCESS(status)) { 662 goto Done; 663 } 664 665 // 666 // Urb->UrbSelectInterface.Interface.NumberOfPipes is set when the URB 667 // completes. So, we must compute the number of pipes being requested based 668 // on the size of the structure and its Length (as set by the caller). 669 // To calculate the number of pipes we need to account for the 670 // embedded pipe in the structure. 671 // 672 numPipes = (UCHAR) ((Urb->UrbSelectInterface.Interface.Length - 673 interfaceStructSize) / 674 sizeof(USBD_PIPE_INFORMATION) 675 ); 676 677 if (numPipes > 0) { 678 size = numPipes * sizeof(FxUsbPipe *); 679 } 680 else { 681 // 682 // It is valid to have an interface with zero pipes in it. In that 683 // case, we just allocate one entry so that we have a valid array 684 // and keep the remaining code simple. 685 // 686 size = sizeof(FxUsbPipe*); 687 } 688 689 // 690 // If the interface is already configured don't do anything with the old 691 // settings till we allocate new. 692 // 693 ppPipes = (FxUsbPipe **) FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size); 694 695 if (ppPipes == NULL) { 696 status = STATUS_INSUFFICIENT_RESOURCES; 697 DoTraceLevelMessage( 698 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 699 "Unable to allocate memory %!STATUS!" 700 , status); 701 goto Done; 702 } 703 704 RtlZeroMemory(ppPipes, size); 705 706 for (iPipe = 0; iPipe < numPipes; iPipe++) { 707 ppPipes[iPipe] = new (GetDriverGlobals(), PipesAttributes) 708 FxUsbPipe(GetDriverGlobals(),m_UsbDevice); 709 710 if (ppPipes[iPipe] == NULL) { 711 status = STATUS_INSUFFICIENT_RESOURCES; 712 DoTraceLevelMessage( 713 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 714 "Unable to allocate memory for the pipes %!STATUS!", status); 715 goto Done; 716 } 717 718 pPipe = ppPipes[iPipe]; 719 720 status = pPipe->Init(m_UsbDevice->m_Device); 721 if (!NT_SUCCESS(status)) { 722 DoTraceLevelMessage( 723 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 724 "Init pipe failed %!STATUS!", status); 725 goto Done; 726 } 727 728 status = pPipe->Commit(PipesAttributes, NULL, this); 729 730 if (!NT_SUCCESS(status)) { 731 DoTraceLevelMessage( 732 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 733 "Commit pipe failed %!STATUS!", status); 734 goto Done; 735 } 736 } 737 738 if (IsInterfaceConfigured()) { 739 // 740 // Delete the old pipes 741 // 742 m_UsbDevice->CleanupInterfacePipesAndDelete(this); 743 } 744 745 746 WDF_REQUEST_SEND_OPTIONS_INIT(&options, 747 WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); 748 749 WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(2)); 750 751 FxFormatUsbRequest(request.m_TrueRequest, Urb, FxUrbTypeLegacy, NULL); 752 status = m_UsbDevice->SubmitSync(request.m_TrueRequest, &options, NULL); 753 754 // 755 // If select interface URB fails we are at the point of no return and we 756 // will end up with no configured pipes. 757 // 758 if (NT_SUCCESS(status)) { 759 SetNumConfiguredPipes(numPipes); 760 SetConfiguredPipes(ppPipes); 761 SetInfo(&Urb->UrbSelectInterface.Interface); 762 } 763 764 Done: 765 if (!NT_SUCCESS(status)) { 766 if (ppPipes != NULL) { 767 ASSERT(ppPipes != m_ConfiguredPipes); 768 769 for (iPipe = 0; iPipe < numPipes; iPipe++) { 770 if (ppPipes[iPipe] != NULL) { 771 ppPipes[iPipe]->DeleteFromFailedCreate(); 772 } 773 } 774 775 FxPoolFree(ppPipes); 776 ppPipes = NULL; 777 } 778 } 779 780 return status; 781 } 782 783 VOID 784 FxUsbInterface::FormatSelectSettingUrb( 785 __in_bcount(GET_SELECT_INTERFACE_REQUEST_SIZE(NumEndpoints)) PURB Urb, 786 __in USHORT NumEndpoints, 787 __in UCHAR SettingNumber 788 ) 789 /*++ 790 791 Routine Description: 792 Format a URB for selecting an interface's new setting. Note this will setup 793 the URB header and all pipes' information in the URB's array of pipe infos. 794 795 This function exists as a method of FxUsbDevice instead of FxUsbInterface 796 because in the case of a select config where we manually select setting 0 797 on interfaces 2...N we don't have an FxUsbInterface pointer 798 799 Arguments: 800 Urb - the URB to format. It is assumed the caller allocated a large enough 801 URB to contain NumEndpoints 802 803 NumEndpoints - number of endpoints in the new setting 804 805 InterfaceNum - interface number for the interface 806 807 SettingNumber - setting number on the interface 808 809 --*/ 810 { 811 ULONG defaultMaxTransferSize; 812 USHORT size; 813 UCHAR i; 814 815 size = GET_SELECT_INTERFACE_REQUEST_SIZE(NumEndpoints); 816 817 RtlZeroMemory(Urb, size); 818 819 // 820 // Setup the URB, format the request, and send it 821 // 822 UsbBuildSelectInterfaceRequest(Urb, 823 size, 824 m_UsbDevice->m_ConfigHandle, 825 m_InterfaceNumber, 826 SettingNumber); 827 828 defaultMaxTransferSize = m_UsbDevice->GetDefaultMaxTransferSize(); 829 830 Urb->UrbSelectInterface.Interface.Length = 831 GET_USBD_INTERFACE_SIZE(NumEndpoints); 832 833 Urb->UrbSelectInterface.Interface.NumberOfPipes = NumEndpoints; 834 835 for (i = 0; i < NumEndpoints; i++) { 836 837 // 838 // Make sure that the Interface Length conveys the exact number of EP's 839 // 840 ASSERT( 841 &Urb->UrbSelectInterface.Interface.Pipes[i] < 842 WDF_PTR_ADD_OFFSET(&Urb->UrbSelectInterface.Interface, 843 Urb->UrbSelectInterface.Interface.Length) 844 ); 845 846 Urb->UrbSelectInterface.Interface.Pipes[i].PipeFlags = 0x0; 847 Urb->UrbSelectInterface.Interface.Pipes[i].MaximumTransferSize = 848 defaultMaxTransferSize; 849 } 850 } 851 852 VOID 853 FxUsbInterface::GetEndpointInformation( 854 __in UCHAR SettingIndex, 855 __in UCHAR EndpointIndex, 856 __in PWDF_USB_PIPE_INFORMATION PipeInfo 857 ) 858 /*++ 859 860 Routine Description: 861 The layout of the config descriptor is such that each interface+setting pair 862 is followed by the endpoints for that interface+setting pair. Keep track of 863 the index. 864 865 Arguments: 866 SettingIndex - alternate setting to get info for 867 868 EndpointIndex - index into the number endpoints for this interface+setting 869 870 PipeInfo - Info to return 871 872 Return Value: 873 None 874 875 --*/ 876 { 877 PUCHAR pEnd, pCur; 878 PUSB_INTERFACE_DESCRIPTOR pInterfaceDesc; 879 PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc; 880 UCHAR curEndpointIndex; 881 BOOLEAN endPointFound; 882 883 pInterfaceDesc = NULL; 884 curEndpointIndex = 0; 885 endPointFound = FALSE; 886 887 // 888 // Extract the interface descriptor for the alternate setting for the interface 889 // 890 pInterfaceDesc = GetSettingDescriptor(SettingIndex); 891 892 if (pInterfaceDesc == NULL) { 893 return; 894 } 895 896 pEnd = (PUCHAR) WDF_PTR_ADD_OFFSET( 897 m_UsbDevice->m_ConfigDescriptor, 898 m_UsbDevice->m_ConfigDescriptor->wTotalLength 899 ); 900 901 // 902 // Start from the descriptor after current one 903 // 904 pCur = (PUCHAR) WDF_PTR_ADD_OFFSET(pInterfaceDesc, pInterfaceDesc->bLength); 905 906 // 907 // Iterate through the list of EP descriptors following the interface descriptor 908 // we just found and get the endpoint descriptor which matches the endpoint 909 // index or we hit another interface descriptor 910 // 911 // We have already validated that the descriptor headers are well formed and within 912 // the config descriptor bounds 913 // 914 while (pCur < pEnd) { 915 PUSB_COMMON_DESCRIPTOR pCommonDesc = (PUSB_COMMON_DESCRIPTOR) pCur; 916 917 // 918 // If we hit the next interface no way we can find the EndPoint 919 // 920 if (pCommonDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) { 921 break; 922 } 923 924 if (pCommonDesc->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) { 925 // 926 // Size of pEndpointDesc has been validated by CreateSettings() and 927 // is within the config descriptor 928 // 929 pEndpointDesc = (PUSB_ENDPOINT_DESCRIPTOR) pCommonDesc; 930 931 if (EndpointIndex == curEndpointIndex) { 932 CopyEndpointFieldsFromDescriptor(PipeInfo, 933 pEndpointDesc, 934 SettingIndex); 935 break; 936 } 937 938 curEndpointIndex++; 939 } 940 941 // 942 // Advance past this descriptor 943 // 944 pCur += pCommonDesc->bLength; 945 } 946 } 947 948 ULONG 949 FxUsbInterface::DetermineDefaultMaxTransferSize( 950 VOID 951 ) 952 /*++ 953 954 Routine Description: 955 Returns the maximum transfer size of an endpoint 956 957 Arguments: 958 None 959 960 Return Value: 961 max transfer size 962 963 --*/ 964 { 965 if (m_UsbDevice->m_Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) { 966 return FxUsbPipeHighSpeedMaxTransferSize; 967 } 968 else { 969 return FxUsbPipeLowSpeedMaxTransferSize; 970 } 971 } 972 973 VOID 974 FxUsbInterface::CopyEndpointFieldsFromDescriptor( 975 __in PWDF_USB_PIPE_INFORMATION PipeInfo, 976 __in PUSB_ENDPOINT_DESCRIPTOR EndpointDesc, 977 __in UCHAR SettingIndex 978 ) 979 /*++ 980 981 Routine Description: 982 Copy informatoin out of the usb endpoint descriptor into this object 983 984 Arguments: 985 PipeInfo - information to return 986 987 EndpointDesc - descriptor to copy from 988 989 SettingIndex - alternate setting this information is for 990 991 Return Value: 992 None 993 994 --*/ 995 { 996 PipeInfo->MaximumPacketSize = EndpointDesc->wMaxPacketSize; 997 PipeInfo->EndpointAddress = EndpointDesc->bEndpointAddress; 998 PipeInfo->Interval = EndpointDesc->bInterval; 999 1000 // 1001 // Extract the lower 2 bits which contain the EP type 1002 // 1003 PipeInfo->PipeType = FxUsbPipe::_UsbdPipeTypeToWdf( 1004 (USBD_PIPE_TYPE) (EndpointDesc->bmAttributes & 0x03) 1005 ); 1006 1007 // 1008 // Filling in a default value since the EndpointDescriptor doesn't contain it 1009 // 1010 if (PipeInfo->PipeType == WdfUsbPipeTypeControl) { 1011 PipeInfo->MaximumTransferSize = FxUsbPipeControlMaxTransferSize; 1012 } 1013 else { 1014 PipeInfo->MaximumTransferSize = DetermineDefaultMaxTransferSize(); 1015 } 1016 1017 PipeInfo->SettingIndex = SettingIndex; 1018 } 1019 1020 WDFUSBPIPE 1021 FxUsbInterface::GetConfiguredPipe( 1022 __in UCHAR PipeIndex, 1023 __out_opt PWDF_USB_PIPE_INFORMATION PipeInfo 1024 ) 1025 /*++ 1026 1027 Routine Description: 1028 Return the WDFUSBPIPE for the given index 1029 1030 Arguments: 1031 PipeIndex - index into the number of configured pipes for the interface 1032 1033 PipeInfo - optional information to return about the returned pipe 1034 1035 Return Value: 1036 valid WDFUSBPIPE handle or NULL on error 1037 1038 --*/ 1039 { 1040 if (PipeIndex >= m_NumberOfConfiguredPipes) { 1041 return NULL; 1042 } 1043 else { 1044 if (PipeInfo != NULL) { 1045 m_ConfiguredPipes[PipeIndex]->GetInformation(PipeInfo); 1046 } 1047 1048 return m_ConfiguredPipes[PipeIndex]->GetHandle(); 1049 } 1050 } 1051 1052 VOID 1053 FxUsbInterface::GetDescriptor( 1054 __in PUSB_INTERFACE_DESCRIPTOR UsbInterfaceDescriptor, 1055 __in UCHAR SettingIndex 1056 ) 1057 /*++ 1058 1059 Routine Description: 1060 Copies the descriptor back to the caller 1061 1062 Arguments: 1063 UsbInterfaceDescriptor - descriptor pointer to fill in 1064 1065 SettingIndex - alternate setting that the caller is interested in 1066 1067 Return Value: 1068 None 1069 1070 --*/ 1071 { 1072 if (SettingIndex >= m_NumSettings) { 1073 RtlZeroMemory(UsbInterfaceDescriptor, 1074 sizeof(*UsbInterfaceDescriptor)); 1075 } 1076 else { 1077 RtlCopyMemory(UsbInterfaceDescriptor, 1078 m_Settings[SettingIndex].InterfaceDescriptor, 1079 sizeof(*UsbInterfaceDescriptor)); 1080 } 1081 } 1082 1083 UCHAR 1084 FxUsbInterface::GetConfiguredSettingIndex( 1085 VOID 1086 ) 1087 /*++ 1088 1089 Routine Description: 1090 Returns the currently configured setting index for the interface 1091 1092 Arguments: 1093 None 1094 1095 Return Value: 1096 Currently configured Index 1097 1098 --*/ 1099 1100 { 1101 if (IsInterfaceConfigured()) { 1102 return m_CurAlternateSetting; 1103 } 1104 else { 1105 DoTraceLevelMessage( 1106 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1107 "WDFUSBINTERFACE %p not configured, cannot retrieve configured " 1108 "setting index", GetHandle()); 1109 1110 FxVerifierDbgBreakPoint(GetDriverGlobals()); 1111 1112 return 0; 1113 } 1114 } 1115 1116 UCHAR 1117 FxUsbInterface::GetNumEndpoints( 1118 __in UCHAR SettingIndex 1119 ) 1120 /*++ 1121 1122 Routine Description: 1123 Returns the number of endpoints on a given alternate interface 1124 1125 Arguments: 1126 SettingIndex - index of the alternate setting 1127 1128 Return Value: 1129 Number of endpoints or 0 on error 1130 1131 --*/ 1132 { 1133 if (SettingIndex >= m_NumSettings) { 1134 return 0; 1135 } 1136 else { 1137 return m_Settings[SettingIndex].InterfaceDescriptor->bNumEndpoints; 1138 } 1139 } 1140 1141 PUSB_INTERFACE_DESCRIPTOR 1142 FxUsbInterface::GetSettingDescriptor( 1143 __in UCHAR Setting 1144 ) 1145 /*++ 1146 1147 Routine Description: 1148 Returns the device's interface descriptor for the given alternate setting 1149 1150 Arguments: 1151 Setting - AlternateSetting desired 1152 1153 Return Value: 1154 USB interface descriptor or NULL on failure 1155 1156 --*/ 1157 { 1158 UCHAR i; 1159 1160 for (i = 0; i < m_NumSettings; i++) { 1161 if (m_Settings[i].InterfaceDescriptor->bAlternateSetting == Setting) { 1162 return m_Settings[i].InterfaceDescriptor; 1163 } 1164 } 1165 1166 return NULL; 1167 } 1168 1169