1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxUsbDevice.cpp 8 9 Abstract: 10 11 Author: 12 13 Environment: 14 15 kernel mode only 16 17 Revision History: 18 19 --*/ 20 21 extern "C" { 22 #include <initguid.h> 23 } 24 25 #include "fxusbpch.hpp" 26 27 28 extern "C" { 29 #include "FxUsbDevice.tmh" 30 } 31 32 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 33 #define UCHAR_MAX (0xff) 34 #endif 35 36 FxUsbDeviceControlContext::FxUsbDeviceControlContext( 37 __in FX_URB_TYPE FxUrbType 38 ) : 39 FxUsbRequestContext(FX_RCT_USB_CONTROL_REQUEST) 40 { 41 m_PartialMdl = NULL; 42 m_UnlockPages = FALSE; 43 m_USBDHandle = NULL; 44 45 if (FxUrbType == FxUrbTypeLegacy) { 46 m_Urb = &m_UrbLegacy; 47 } 48 else { 49 m_Urb = NULL; 50 } 51 } 52 53 FxUsbDeviceControlContext::~FxUsbDeviceControlContext( 54 VOID 55 ) 56 { 57 if (m_Urb && (m_Urb != &m_UrbLegacy)) { 58 USBD_UrbFree(m_USBDHandle, (PURB)m_Urb); 59 } 60 m_Urb = NULL; 61 m_USBDHandle = NULL; 62 } 63 64 __checkReturn 65 NTSTATUS 66 FxUsbDeviceControlContext::AllocateUrb( 67 __in USBD_HANDLE USBDHandle 68 ) 69 { 70 NTSTATUS status; 71 72 ASSERT(USBDHandle != NULL); 73 ASSERT(m_Urb == NULL); 74 75 status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb); 76 77 if (!NT_SUCCESS(status)) { 78 goto Done; 79 } 80 81 m_USBDHandle = USBDHandle; 82 83 Done: 84 return status; 85 } 86 87 VOID 88 FxUsbDeviceControlContext::Dispose( 89 VOID 90 ) 91 { 92 if (m_Urb && (m_Urb != &m_UrbLegacy)){ 93 USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); 94 m_Urb = NULL; 95 m_USBDHandle = NULL; 96 } 97 } 98 99 VOID 100 FxUsbDeviceControlContext::CopyParameters( 101 __in FxRequestBase* Request 102 ) 103 { 104 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 105 m_CompletionParams.IoStatus.Information = m_Urb->TransferBufferLength; 106 m_UsbParameters.Parameters.DeviceControlTransfer.Length = m_Urb->TransferBufferLength; 107 #elif (FX_CORE_MODE == FX_CORE_USER_MODE) 108 m_CompletionParams.IoStatus.Information = m_UmUrb.UmUrbControlTransfer.TransferBufferLength; 109 m_UsbParameters.Parameters.DeviceControlTransfer.Length = m_UmUrb.UmUrbControlTransfer.TransferBufferLength; 110 #endif 111 FxUsbRequestContext::CopyParameters(Request); // __super call 112 } 113 114 VOID 115 FxUsbDeviceControlContext::ReleaseAndRestore( 116 __in FxRequestBase* Request 117 ) 118 { 119 // 120 // Check now because Init will NULL out the field 121 // 122 if (m_PartialMdl != NULL) { 123 if (m_UnlockPages) { 124 Mx::MxUnlockPages(m_PartialMdl); 125 m_UnlockPages = FALSE; 126 } 127 128 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 129 FxMdlFree(Request->GetDriverGlobals(), m_PartialMdl); 130 #endif 131 m_PartialMdl = NULL; 132 } 133 134 FxUsbRequestContext::ReleaseAndRestore(Request); // __super call 135 } 136 137 USBD_STATUS 138 FxUsbDeviceControlContext::GetUsbdStatus( 139 VOID 140 ) 141 { 142 return m_Urb->Hdr.Status; 143 } 144 145 FxUsbDeviceStringContext::FxUsbDeviceStringContext( 146 __in FX_URB_TYPE FxUrbType 147 ) : 148 FxUsbRequestContext(FX_RCT_USB_STRING_REQUEST) 149 { 150 m_USBDHandle = NULL; 151 m_StringDescriptor = NULL; 152 m_StringDescriptorLength = 0; 153 RtlZeroMemory(&m_UrbLegacy, sizeof(m_UrbLegacy)); 154 155 if (FxUrbType == FxUrbTypeLegacy) { 156 m_Urb = &m_UrbLegacy; 157 m_Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; 158 m_Urb->Hdr.Length = sizeof(*m_Urb); 159 m_Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE; 160 } 161 else { 162 m_Urb = NULL; 163 } 164 } 165 166 FxUsbDeviceStringContext::~FxUsbDeviceStringContext( 167 VOID 168 ) 169 { 170 if (m_StringDescriptor != NULL) { 171 FxPoolFree(m_StringDescriptor); 172 m_StringDescriptor = NULL; 173 } 174 175 if (m_Urb && (m_Urb != &m_UrbLegacy)){ 176 USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); 177 } 178 m_Urb = NULL; 179 m_USBDHandle = NULL; 180 } 181 182 __checkReturn 183 NTSTATUS 184 FxUsbDeviceStringContext::AllocateUrb( 185 __in USBD_HANDLE USBDHandle 186 ) 187 { 188 NTSTATUS status; 189 190 ASSERT(USBDHandle != NULL); 191 ASSERT(m_Urb == NULL); 192 193 status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb); 194 195 if (!NT_SUCCESS(status)) { 196 goto Done; 197 } 198 199 m_USBDHandle = USBDHandle; 200 201 m_Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; 202 m_Urb->Hdr.Length = sizeof(*m_Urb); 203 m_Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE; 204 205 Done: 206 return status; 207 } 208 209 VOID 210 FxUsbDeviceStringContext::Dispose( 211 VOID 212 ) 213 { 214 if (m_Urb && (m_Urb != &m_UrbLegacy)){ 215 USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); 216 m_Urb = NULL; 217 m_USBDHandle = NULL; 218 } 219 220 } 221 222 VOID 223 FxUsbDeviceStringContext::CopyParameters( 224 __in FxRequestBase* Request 225 ) 226 { 227 // 228 // Make sure we got an even number of bytes and that we got a header 229 // 230 if ((m_StringDescriptor->bLength & 0x1) || 231 m_StringDescriptor->bLength < sizeof(USB_COMMON_DESCRIPTOR)) { 232 m_CompletionParams.IoStatus.Status = STATUS_DEVICE_DATA_ERROR; 233 } 234 else if (NT_SUCCESS(Request->GetSubmitFxIrp()->GetStatus())) { 235 // 236 // No matter what, indicate the required size to the caller 237 // 238 m_UsbParameters.Parameters.DeviceString.RequiredSize = 239 m_StringDescriptor->bLength - sizeof(USB_COMMON_DESCRIPTOR); 240 241 if (m_UsbParameters.Parameters.DeviceString.RequiredSize > 242 m_RequestMemory->GetBufferSize()) { 243 // 244 // Too much string to fit into the buffer supplied by the client. 245 // Morph the status into a warning. Copy as much as we can. 246 // 247 m_CompletionParams.IoStatus.Status = STATUS_BUFFER_OVERFLOW; 248 RtlCopyMemory(m_RequestMemory->GetBuffer(), 249 &m_StringDescriptor->bString[0], 250 m_RequestMemory->GetBufferSize()); 251 } 252 else { 253 // 254 // Everything fits, copy it over 255 // 256 m_CompletionParams.IoStatus.Information = 257 m_UsbParameters.Parameters.DeviceString.RequiredSize; 258 259 RtlCopyMemory(m_RequestMemory->GetBuffer(), 260 &m_StringDescriptor->bString[0], 261 m_UsbParameters.Parameters.DeviceString.RequiredSize); 262 } 263 } 264 265 FxUsbRequestContext::CopyParameters(Request); // __super call 266 } 267 268 VOID 269 FxUsbDeviceStringContext::SetUrbInfo( 270 __in UCHAR StringIndex, 271 __in USHORT LangID 272 ) 273 { 274 SetUsbType(WdfUsbRequestTypeDeviceString); 275 276 ASSERT(m_StringDescriptor != NULL && m_StringDescriptorLength != 0); 277 278 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 279 m_Urb->TransferBuffer = m_StringDescriptor; 280 m_Urb->TransferBufferLength = m_StringDescriptorLength; 281 282 m_Urb->Index = StringIndex; 283 m_Urb->LanguageId = LangID; 284 #elif (FX_CORE_MODE == FX_CORE_USER_MODE) 285 m_UmUrb.UmUrbDescriptorRequest.Buffer = m_StringDescriptor; 286 m_UmUrb.UmUrbDescriptorRequest.BufferLength = m_StringDescriptorLength; 287 288 m_UmUrb.UmUrbDescriptorRequest.Index = StringIndex; 289 m_UmUrb.UmUrbDescriptorRequest.LanguageID = LangID; 290 #endif 291 } 292 293 USBD_STATUS 294 FxUsbDeviceStringContext::GetUsbdStatus( 295 VOID 296 ) 297 { 298 return m_Urb->Hdr.Status; 299 } 300 301 _Must_inspect_result_ 302 NTSTATUS 303 FxUsbDeviceStringContext::AllocateDescriptor( 304 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 305 __in size_t BufferSize 306 ) 307 { 308 PUSB_STRING_DESCRIPTOR pDescriptor; 309 size_t length; 310 NTSTATUS status; 311 312 if (BufferSize <= m_StringDescriptorLength) { 313 return STATUS_SUCCESS; 314 } 315 316 length = sizeof(USB_STRING_DESCRIPTOR) - sizeof(pDescriptor->bString[0]) + 317 BufferSize; 318 319 pDescriptor = (PUSB_STRING_DESCRIPTOR) FxPoolAllocate( 320 FxDriverGlobals, 321 NonPagedPool, 322 length); 323 324 if (pDescriptor == NULL) { 325 return STATUS_INSUFFICIENT_RESOURCES; 326 } 327 328 if (m_StringDescriptor != NULL) { 329 FxPoolFree(m_StringDescriptor); 330 } 331 332 RtlZeroMemory(pDescriptor, length); 333 334 m_StringDescriptor = pDescriptor; 335 336 status = RtlSizeTToULong(length, &m_StringDescriptorLength); 337 338 return status; 339 } 340 341 FxUsbUrb::FxUsbUrb( 342 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 343 __in USBD_HANDLE USBDHandle, 344 __in_bcount(BufferSize) PVOID Buffer, 345 __in size_t BufferSize 346 ) : 347 FxMemoryBufferPreallocated(FxDriverGlobals, sizeof(*this), Buffer, BufferSize), 348 m_USBDHandle(USBDHandle) 349 { 350 MarkDisposeOverride(); 351 } 352 353 FxUsbUrb::~FxUsbUrb() 354 { 355 } 356 357 BOOLEAN 358 FxUsbUrb::Dispose( 359 VOID 360 ) 361 { 362 ASSERT(m_USBDHandle != NULL); 363 ASSERT(m_pBuffer != NULL); 364 USBD_UrbFree(m_USBDHandle, (PURB)m_pBuffer); 365 m_pBuffer = NULL; 366 m_USBDHandle = NULL; 367 368 return FxMemoryBufferPreallocated::Dispose(); // __super call 369 } 370 371 FxUsbDevice::FxUsbDevice( 372 __in PFX_DRIVER_GLOBALS FxDriverGlobals 373 ) : 374 FxIoTarget(FxDriverGlobals, sizeof(FxUsbDevice), FX_TYPE_IO_TARGET_USB_DEVICE) 375 { 376 RtlZeroMemory(&m_DeviceDescriptor, sizeof(m_DeviceDescriptor)); 377 RtlZeroMemory(&m_UsbdVersionInformation, sizeof(m_UsbdVersionInformation)); 378 379 m_OnUSBD = FALSE; 380 m_Interfaces = NULL;; 381 m_NumInterfaces = 0; 382 383 m_Traits = 0; 384 m_HcdPortCapabilities = 0; 385 m_ControlPipe = NULL; 386 m_QueryBusTime = NULL; 387 m_BusInterfaceContext = NULL; 388 m_BusInterfaceDereference = NULL; 389 m_ConfigHandle = NULL; 390 m_ConfigDescriptor = NULL; 391 392 m_MismatchedInterfacesInConfigDescriptor = FALSE; 393 394 m_USBDHandle = NULL; 395 m_UrbType = FxUrbTypeLegacy; 396 397 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 398 m_pHostTargetFile = NULL; 399 m_WinUsbHandle = NULL; 400 #endif 401 402 MarkDisposeOverride(ObjectDoNotLock); 403 } 404 405 BOOLEAN 406 FxUsbDevice::Dispose( 407 VOID 408 ) 409 { 410 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) 411 KeFlushQueuedDpcs(); 412 #endif 413 414 if (m_USBDHandle) { 415 USBD_CloseHandle(m_USBDHandle); 416 m_USBDHandle = NULL; 417 } 418 419 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 420 IWudfDevice* device = NULL; 421 IWudfDeviceStack* devstack = NULL; 422 423 device = m_DeviceBase->GetDeviceObject(); 424 devstack = device->GetDeviceStackInterface(); 425 426 if (m_pHostTargetFile) { 427 devstack->CloseFile(m_pHostTargetFile); 428 SAFE_RELEASE(m_pHostTargetFile); 429 } 430 #endif 431 432 return FxIoTarget::Dispose(); // __super call 433 } 434 435 FxUsbDevice::~FxUsbDevice() 436 { 437 UCHAR i; 438 439 if (m_BusInterfaceDereference != NULL) { 440 m_BusInterfaceDereference(m_BusInterfaceContext); 441 m_BusInterfaceDereference = NULL; 442 } 443 444 if (m_ConfigDescriptor != NULL) { 445 FxPoolFree(m_ConfigDescriptor); 446 m_ConfigDescriptor = NULL; 447 } 448 449 for (i = 0; i < m_NumInterfaces; i++) { 450 ASSERT(m_Interfaces[i] == NULL); 451 } 452 453 if (m_Interfaces != NULL){ 454 FxPoolFree(m_Interfaces); 455 m_Interfaces = NULL; 456 } 457 458 m_NumInterfaces = 0; 459 } 460 461 VOID 462 FxUsbDevice::RemoveDeletedInterface( 463 __in FxUsbInterface* Interface 464 ) 465 { 466 UCHAR i; 467 468 if (m_Interfaces == NULL) { 469 return; 470 } 471 472 for (i = 0; i < m_NumInterfaces; i++) { 473 if (m_Interfaces[i] == Interface) { 474 m_Interfaces[i] = NULL; 475 return; 476 } 477 } 478 } 479 480 VOID 481 FxUsbDevice::GetInformation( 482 __out PWDF_USB_DEVICE_INFORMATION Information 483 ) 484 { 485 Information->Traits = m_Traits; 486 Information->HcdPortCapabilities = m_HcdPortCapabilities; 487 488 RtlCopyMemory(&Information->UsbdVersionInformation, 489 &m_UsbdVersionInformation, 490 sizeof(m_UsbdVersionInformation)); 491 } 492 493 ULONG 494 FxUsbDevice::GetDefaultMaxTransferSize( 495 VOID 496 ) 497 /*++ 498 499 Routine Description: 500 Determines the default max transfer size based on the usb host controller 501 and OS we are running on. What it boils down to is that on XP and later 502 the usb core ignores the default max transfer size, but it does use the 503 value on Windows 2000. To make life fun, there is only one definition of 504 USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE whose value changes depending on header 505 versioning. Since we are versioned for the latest OS, we do not pick up the 506 Win2k value by using the #define, rather we have to use the value that we 507 *would* have picked up if we were header versioned for Win2k. 508 509 NOTE: we could be on win2k with a usbport serviced stack. in this case, 510 usbport doesn't care about max transfer sizes 511 512 Arguments: 513 None 514 515 Return Value: 516 usb core and OS appropriate default max transfer size. 517 518 --*/ 519 { 520 // 521 // On a usbport serviced stack (which can be running on Win2k) or on a 522 // usbd stack on XP and later. In any case, always use the current max 523 // transfer size definition. 524 // 525 return USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; 526 } 527 528 _Must_inspect_result_ 529 NTSTATUS 530 FxUsbDevice::Start( 531 VOID 532 ) 533 { 534 NTSTATUS status; 535 536 status = FxIoTarget::Start(); 537 538 if (NT_SUCCESS(status)) { 539 FxRequestBase* pRequest; 540 LIST_ENTRY head, *ple; 541 ULONG i, iInterface; 542 FxUsbInterface *pUsbInterface; 543 KIRQL irql; 544 545 InitializeListHead(&head); 546 547 Lock(&irql); 548 549 // 550 // Iterate over all of the interfaces. For each pipe on each interface, 551 // grab all pended i/o for later submission. 552 // 553 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++){ 554 555 pUsbInterface = m_Interfaces[iInterface]; 556 557 for (i = 0; i < pUsbInterface->m_NumberOfConfiguredPipes; i++) { 558 pUsbInterface->m_ConfiguredPipes[i]->GotoStartState(&head); 559 } 560 } 561 Unlock(irql); 562 563 // 564 // Since we are going to reference the FxUsbPipe's outside of the 565 // lock and the interface can go away in the meantime, add a reference 566 // (multiple times perhaps) to each FxUsbPipe to make sure it sticks 567 // around. 568 // 569 for (ple = head.Flink; ple != &head; ple = ple->Flink) { 570 pRequest = FxRequestBase::_FromListEntry(ple); 571 pRequest->GetTarget()->ADDREF(this); 572 } 573 574 // 575 // Drain the list of pended requests. 576 // 577 while (!IsListEmpty(&head)) { 578 FxIoTarget* pTarget; 579 580 ple = RemoveHeadList(&head); 581 582 pRequest = FxRequestBase::_FromListEntry(ple); 583 584 pTarget = pRequest->GetTarget(); 585 586 pTarget->SubmitPendedRequest(pRequest); 587 588 // 589 // Release the reference taken above when accumulating pended i/o. 590 // 591 pTarget->RELEASE(this); 592 } 593 } 594 595 return status; 596 } 597 598 #define STOP_TAG (PVOID) 'pots' 599 600 VOID 601 FxUsbDevice::Stop( 602 __in WDF_IO_TARGET_SENT_IO_ACTION Action 603 ) 604 { 605 FxUsbInterface *pUsbInterface; 606 SINGLE_LIST_ENTRY head; 607 ULONG iPipe, iInterface; 608 KIRQL irql; 609 610 head.Next = NULL; 611 612 // 613 // Stop all of our own I/O first 614 // 615 FxIoTarget::Stop(Action); 616 617 // 618 // if we are just canceling i/o, then we just acquire the spin lock b/c 619 // we can be called at dispatch level for this action code. 620 // 621 if (Action != WdfIoTargetLeaveSentIoPending) { 622 ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); 623 624 AcquireInterfaceIterationLock(); 625 } 626 627 // 628 // Since we don't have to synchronize on the I/O already sent, just set 629 // each pipe's state to stop. 630 // 631 Lock(&irql); 632 633 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) { 634 pUsbInterface = m_Interfaces[iInterface]; 635 636 if (pUsbInterface->m_ConfiguredPipes != NULL) { 637 for (iPipe = 0; 638 iPipe < pUsbInterface->m_NumberOfConfiguredPipes; 639 iPipe++) { 640 641 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { 642 BOOLEAN wait; 643 644 wait = FALSE; 645 646 pUsbInterface->m_ConfiguredPipes[iPipe]->GotoStopState( 647 Action, 648 &head, 649 &wait, 650 TRUE 651 ); 652 } 653 } 654 } 655 } 656 Unlock(irql); 657 658 // 659 // If we are leaving sent IO pending, the io target will set the IO 660 // completion event during stop even if there is still outstanding IO. 661 // 662 663 if (head.Next != NULL) { 664 _CancelSentRequests(&head); 665 } 666 667 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) { 668 pUsbInterface = m_Interfaces[iInterface]; 669 670 if (pUsbInterface->m_ConfiguredPipes != NULL) { 671 // 672 // Iterate over the pipes and clean each one up 673 // 674 for (iPipe = 0; 675 iPipe < pUsbInterface->m_NumberOfConfiguredPipes; 676 iPipe++) { 677 // 678 // Same reason as above 679 // 680 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { 681 pUsbInterface->m_ConfiguredPipes[iPipe]-> 682 WaitForSentIoToComplete(); 683 } 684 } 685 } 686 } 687 688 if (Action != WdfIoTargetLeaveSentIoPending) { 689 ReleaseInterfaceIterationLock(); 690 } 691 } 692 693 VOID 694 FxUsbDevice::Purge( 695 __in WDF_IO_TARGET_PURGE_IO_ACTION Action 696 ) 697 { 698 FxUsbInterface *pUsbInterface; 699 SINGLE_LIST_ENTRY sentHead; 700 ULONG iPipe, iInterface; 701 KIRQL irql; 702 703 sentHead.Next = NULL; 704 705 // 706 // Purge all of our own I/O first 707 // 708 FxIoTarget::Purge(Action); 709 710 // 711 // if we are just canceling i/o, then we just acquire the spin lock b/c 712 // we can be called at dispatch level for this action code. 713 // 714 if (Action != WdfIoTargetPurgeIo) { 715 ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); 716 717 AcquireInterfaceIterationLock(); 718 } 719 720 // 721 // Since we don't have to synchronize on the I/O already sent, just set 722 // each pipe's state to purged. 723 // 724 Lock(&irql); 725 726 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) { 727 pUsbInterface = m_Interfaces[iInterface]; 728 729 if (pUsbInterface->m_ConfiguredPipes != NULL) { 730 for (iPipe = 0; 731 iPipe < pUsbInterface->m_NumberOfConfiguredPipes; 732 iPipe++) { 733 734 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { 735 BOOLEAN wait; 736 LIST_ENTRY pendedHead; 737 738 wait = FALSE; 739 InitializeListHead(&pendedHead); 740 741 pUsbInterface->m_ConfiguredPipes[iPipe]->GotoPurgeState( 742 Action, 743 &pendedHead, 744 &sentHead, 745 &wait, 746 TRUE 747 ); 748 749 // 750 // Complete any requests pulled off from this pipe. 751 // 752 pUsbInterface->m_ConfiguredPipes[iPipe]-> 753 CompletePendedRequestList(&pendedHead); 754 } 755 } 756 } 757 } 758 Unlock(irql); 759 760 // 761 // Cancel all sent requests. 762 // 763 _CancelSentRequests(&sentHead); 764 765 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) { 766 pUsbInterface = m_Interfaces[iInterface]; 767 768 if (pUsbInterface->m_ConfiguredPipes != NULL) { 769 // 770 // Iterate over the pipes and clean each one up 771 // 772 for (iPipe = 0; 773 iPipe < pUsbInterface->m_NumberOfConfiguredPipes; 774 iPipe++) { 775 // 776 // Same reason as above 777 // 778 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { 779 pUsbInterface->m_ConfiguredPipes[iPipe]-> 780 WaitForSentIoToComplete(); 781 } 782 } 783 } 784 } 785 786 if (Action != WdfIoTargetPurgeIo) { 787 ReleaseInterfaceIterationLock(); 788 } 789 } 790 791 VOID 792 FxUsbDevice::_CleanupPipesRequests( 793 __in PLIST_ENTRY PendHead, 794 __in PSINGLE_LIST_ENTRY SentHead 795 ) 796 { 797 while (!IsListEmpty(PendHead)) { 798 PLIST_ENTRY ple; 799 FxRequestBase* pRequest; 800 801 ple = RemoveHeadList(PendHead); 802 803 InitializeListHead(ple); 804 805 pRequest = FxRequestBase::_FromListEntry(ple); 806 pRequest->GetTarget()->CompletePendedRequest(pRequest); 807 } 808 809 _CancelSentRequests(SentHead); 810 } 811 812 VOID 813 FxUsbDevice::PipesGotoRemoveState( 814 __in BOOLEAN ForceRemovePipes 815 ) 816 { 817 SINGLE_LIST_ENTRY sentHead; 818 LIST_ENTRY pendHead, interfaceHead; 819 FxUsbInterface* pUsbInterface; 820 ULONG iPipe, intfIndex; 821 KIRQL irql; 822 823 sentHead.Next = NULL; 824 InitializeListHead(&pendHead); 825 InitializeListHead(&interfaceHead); 826 827 AcquireInterfaceIterationLock(); 828 829 Lock(&irql); 830 for (intfIndex = 0; intfIndex < m_NumInterfaces; intfIndex++ ) { 831 pUsbInterface = m_Interfaces[intfIndex]; 832 833 if (pUsbInterface->m_ConfiguredPipes != NULL) { 834 for (iPipe = 0; 835 iPipe < pUsbInterface->m_NumberOfConfiguredPipes; 836 iPipe++) { 837 BOOLEAN wait; 838 839 wait = FALSE; 840 841 // 842 // Pipe can be NULL if the interface is half initialized 843 // 844 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { 845 pUsbInterface->m_ConfiguredPipes[iPipe]->GotoRemoveState( 846 WdfIoTargetDeleted, 847 &pendHead, 848 &sentHead, 849 TRUE, 850 &wait); 851 852 } 853 } 854 } 855 } 856 Unlock(irql); 857 858 // 859 // We cleanup requests no matter what the new state is because we complete all 860 // pended requests in the surprise removed case. 861 // 862 _CleanupPipesRequests(&pendHead, &sentHead); 863 864 // 865 // Only destroy child pipe objects when the parent is going away or the 866 // caller indicates that this is the desired action. 867 // 868 if (m_State == WdfIoTargetDeleted || ForceRemovePipes) { 869 for (intfIndex = 0; intfIndex < m_NumInterfaces; intfIndex++) { 870 pUsbInterface = m_Interfaces[intfIndex]; 871 872 if (pUsbInterface->m_ConfiguredPipes != NULL) { 873 // 874 // Iterate over the pipes and clean each one up 875 // 876 for (iPipe = 0; 877 iPipe < pUsbInterface->m_NumberOfConfiguredPipes; 878 iPipe++) { 879 // 880 // Same reason as above 881 // 882 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { 883 pUsbInterface->m_ConfiguredPipes[iPipe]-> 884 WaitForSentIoToComplete(); 885 } 886 } 887 } 888 889 pUsbInterface->CleanUpAndDelete(FALSE); 890 } 891 } 892 893 ReleaseInterfaceIterationLock(); 894 } 895 896 _Must_inspect_result_ 897 NTSTATUS 898 FxUsbDevice::CreateInterfaces( 899 VOID 900 ) 901 { 902 PFX_DRIVER_GLOBALS pFxDriverGlobals; 903 UCHAR descCountBitMap[UCHAR_MAX / sizeof(UCHAR)]; 904 PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor; 905 UCHAR iInterface, numFound; 906 NTSTATUS status; 907 ULONG size; 908 ULONG totalLength; 909 910 pFxDriverGlobals = GetDriverGlobals(); 911 status = STATUS_SUCCESS; 912 totalLength = m_ConfigDescriptor->wTotalLength; 913 914 // 915 // Make sure each PCOMMON_DESCRIPTOR_HEADER within the entire config descriptor is well formed. 916 // If successful, we can walk the config descriptor using common headers without any more top 917 // level error checking. Task specific checking of the specialized header types must still occur. 918 // 919 status = FxUsbValidateConfigDescriptorHeaders( 920 pFxDriverGlobals, 921 m_ConfigDescriptor, 922 m_ConfigDescriptor->wTotalLength 923 ); 924 925 if (!NT_SUCCESS(status)) { 926 DoTraceLevelMessage( 927 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 928 "Validation of the config descriptor failed due to a bad common descriptor header, %!STATUS!", 929 status); 930 return status; 931 } 932 933 // 934 // Validate all interface descriptors in config descriptor are at least 935 // sizeof(USB_INTERFACE_DESCRIPTOR). 936 // 937 938 939 940 941 942 status = FxUsbValidateDescriptorType( 943 pFxDriverGlobals, 944 m_ConfigDescriptor, 945 m_ConfigDescriptor, 946 WDF_PTR_ADD_OFFSET(m_ConfigDescriptor, m_ConfigDescriptor->wTotalLength), 947 USB_INTERFACE_DESCRIPTOR_TYPE, 948 sizeof(USB_INTERFACE_DESCRIPTOR), 949 FxUsbValidateDescriptorOpAtLeast, 950 0 951 ); 952 953 if (!NT_SUCCESS(status)) { 954 DoTraceLevelMessage( 955 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 956 "Validation of interface descriptors in config descriptor failed, %!STATUS!", 957 status); 958 959 return status; 960 } 961 962 if (m_ConfigDescriptor->bNumInterfaces == 0) { 963 // 964 // Use an array of one in the zero case 965 // 966 size = sizeof(FxUsbInterface*); 967 } 968 else { 969 size = sizeof(FxUsbInterface*) * m_ConfigDescriptor->bNumInterfaces; 970 } 971 972 // 973 // Allocate an array large enough to hold pointers to interfaces 974 // 975 m_Interfaces = (FxUsbInterface**) 976 FxPoolAllocate(pFxDriverGlobals, NonPagedPool, size); 977 978 if (m_Interfaces == NULL) { 979 status = STATUS_INSUFFICIENT_RESOURCES; 980 981 DoTraceLevelMessage( 982 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 983 "Could not allocate memory for %d interfaces, %!STATUS!", 984 m_ConfigDescriptor->bNumInterfaces, status); 985 986 goto Done; 987 } 988 989 RtlZeroMemory(m_Interfaces, size); 990 m_NumInterfaces = m_ConfigDescriptor->bNumInterfaces; 991 992 // 993 // Iterate over the desciptors again, this time allocating an FxUsbInterface 994 // for each one and capturing the interface information. 995 // 996 RtlZeroMemory(descCountBitMap, sizeof(descCountBitMap)); 997 iInterface = 0; 998 numFound = 0; 999 1000 pInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( 1001 m_ConfigDescriptor, 1002 m_ConfigDescriptor->wTotalLength, 1003 m_ConfigDescriptor, 1004 USB_INTERFACE_DESCRIPTOR_TYPE 1005 ); 1006 1007 while (pInterfaceDescriptor != NULL && 1008 iInterface < m_ConfigDescriptor->bNumInterfaces) { 1009 1010 // 1011 // This function will retun false if the bit wasn't already set 1012 // 1013 if (FxBitArraySet(descCountBitMap, 1014 pInterfaceDescriptor->bInterfaceNumber) == FALSE) { 1015 FxUsbInterface* pInterface; 1016 1017 pInterface = new (GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES) 1018 FxUsbInterface(pFxDriverGlobals, 1019 this, 1020 pInterfaceDescriptor); 1021 1022 if (pInterface == NULL) { 1023 status = STATUS_INSUFFICIENT_RESOURCES; 1024 DoTraceLevelMessage( 1025 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1026 "Could not allocate memory for interface object #%d, %!STATUS!", 1027 iInterface, status); 1028 goto Done; 1029 } 1030 1031 status = pInterface->Commit(WDF_NO_OBJECT_ATTRIBUTES, NULL, this); 1032 1033 // 1034 // This should never fail 1035 // 1036 ASSERT(NT_SUCCESS(status)); 1037 1038 if (!NT_SUCCESS(status)) { 1039 goto Done; 1040 } 1041 1042 status = pInterface->CreateSettings(); 1043 if (!NT_SUCCESS(status)) { 1044 goto Done; 1045 } 1046 1047 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 1048 status = pInterface->SetWinUsbHandle(iInterface); 1049 if (!NT_SUCCESS(status)) { 1050 goto Done; 1051 } 1052 1053 status = pInterface->MakeAndConfigurePipes(WDF_NO_OBJECT_ATTRIBUTES, 1054 pInterfaceDescriptor->bNumEndpoints); 1055 if (!NT_SUCCESS(status)) { 1056 goto Done; 1057 } 1058 #endif 1059 1060 m_Interfaces[iInterface] = pInterface; 1061 1062 iInterface++; 1063 } 1064 1065 pInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( 1066 m_ConfigDescriptor, 1067 totalLength, 1068 WDF_PTR_ADD_OFFSET(pInterfaceDescriptor, 1069 pInterfaceDescriptor->bLength), 1070 USB_INTERFACE_DESCRIPTOR_TYPE 1071 ); 1072 } 1073 1074 // 1075 // We cannot check for the error case of 1076 // 1077 // pInterfaceDescriptor != NULL && 1078 // iInterface == m_ConfigDescriptor->bNumInterfaces 1079 // 1080 // Because if there are multiple alternative settings for the last interface 1081 // in the config descriptor, we will have hit the limit of interfaces 1082 // (correctly), but have found another pInterfaceDescriptor (the next alt 1083 // setting). 1084 // 1085 1086 // 1087 // We already logged and found the case where iInterface >= m_NumInterfaces. 1088 // Check for the case where we found too few interfaces and when we found 1089 // no interfaces even though the config descriptor says otherwise. 1090 // 1091 // 1092 if (iInterface == 0 && m_NumInterfaces > 0) { 1093 status = STATUS_INVALID_DEVICE_REQUEST; 1094 1095 DoTraceLevelMessage( 1096 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1097 "Config descriptor indicated there were %d interfaces, but did not " 1098 "find any interface descriptors in config descriptor %p, %!STATUS!", 1099 m_NumInterfaces, m_ConfigDescriptor, status); 1100 } 1101 else if (pInterfaceDescriptor != NULL && m_NumInterfaces == 0) { 1102 DoTraceLevelMessage( 1103 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIOTARGET, 1104 "Config descriptor indicated there were 0 interfaces, but an interface " 1105 "descriptor was found"); 1106 1107 m_MismatchedInterfacesInConfigDescriptor = TRUE; 1108 } 1109 else if (iInterface < m_NumInterfaces) { 1110 DoTraceLevelMessage( 1111 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1112 "Config descriptor indicated there were %d interfaces, only found " 1113 "%d interfaces", m_NumInterfaces, iInterface); 1114 1115 // 1116 // Instead of considering this an error, just use the number found. 1117 // This will not have an adverse affect elsewhere and since the framework 1118 // is probably more strict then previous USB code, this would have not 1119 // been found earlier by a WDM driver. 1120 // 1121 m_NumInterfaces = iInterface; 1122 } 1123 1124 Done: 1125 return status; 1126 } 1127 1128 1129 _Must_inspect_result_ 1130 NTSTATUS 1131 FxUsbDevice::GetPortStatus( 1132 __out PULONG PortStatus 1133 ) 1134 { 1135 NTSTATUS status; 1136 1137 FxInternalIoctlOthersContext context; 1138 FxRequestBuffer args[FX_REQUEST_NUM_OTHER_PARAMS]; 1139 FxSyncRequest syncRequest(GetDriverGlobals(), &context); 1140 1141 // 1142 // FxSyncRequest always succeesds for KM. 1143 // 1144 status = syncRequest.Initialize(); 1145 if (!NT_SUCCESS(status)) { 1146 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1147 "Failed to initialize FxSyncRequest"); 1148 return status; 1149 } 1150 1151 *PortStatus = 0; 1152 args[0].SetBuffer(PortStatus, 0); 1153 args[1].SetBuffer(NULL, 0); 1154 args[2].SetBuffer(NULL, 0); 1155 1156 status = FormatInternalIoctlOthersRequest(syncRequest.m_TrueRequest, 1157 IOCTL_INTERNAL_USB_GET_PORT_STATUS, 1158 args); 1159 1160 if (NT_SUCCESS(status)) { 1161 WDF_REQUEST_SEND_OPTIONS options; 1162 1163 WDF_REQUEST_SEND_OPTIONS_INIT( 1164 &options, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); 1165 1166 status = SubmitSync(syncRequest.m_TrueRequest, &options); 1167 } 1168 1169 return status; 1170 } 1171 1172 1173 1174 BOOLEAN 1175 FxUsbDevice::IsEnabled( 1176 VOID 1177 ) 1178 { 1179 NTSTATUS status; 1180 ULONG portStatus; 1181 BOOLEAN enabled; 1182 1183 enabled = TRUE; 1184 status = GetPortStatus(&portStatus); 1185 1186 // 1187 // Inability to get STATUS_SUCCESS from GetPortStatus is more likely a resource 1188 // issue rather than a device issue so return FALSE from this function only if 1189 // we were able to read the PortStatus and the port was disabled. 1190 // What you don't want is to continuosly reset the device (by returning FALSE) 1191 // instead of resetting pipe (by returning TRUE) under low memory conditions. 1192 // 1193 if (NT_SUCCESS(status) && (portStatus & USBD_PORT_ENABLED) == 0) { 1194 enabled = FALSE; 1195 } 1196 1197 return enabled; 1198 } 1199 1200 _Must_inspect_result_ 1201 NTSTATUS 1202 FxUsbDevice::IsConnected( 1203 VOID 1204 ) 1205 { 1206 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 1207 1208 1209 1210 1211 return STATUS_UNSUCCESSFUL; 1212 #elif (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 1213 NTSTATUS status; 1214 ULONG portStatus; 1215 1216 status = GetPortStatus(&portStatus); 1217 if (NT_SUCCESS(status) && (portStatus & USBD_PORT_CONNECTED) == 0) { 1218 status = STATUS_DEVICE_DOES_NOT_EXIST; 1219 } 1220 1221 return status; 1222 #endif 1223 } 1224 1225 _Must_inspect_result_ 1226 NTSTATUS 1227 FxUsbDevice::CyclePort( 1228 VOID 1229 ) 1230 { 1231 FxIoContext context; 1232 FxSyncRequest request(GetDriverGlobals(), &context); 1233 NTSTATUS status; 1234 1235 // 1236 // FxSyncRequest always succeesds for KM. 1237 // 1238 status = request.Initialize(); 1239 if (!NT_SUCCESS(status)) { 1240 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1241 "Failed to initialize FxSyncRequest"); 1242 return status; 1243 } 1244 1245 status = FormatCycleRequest(request.m_TrueRequest); 1246 1247 if (NT_SUCCESS(status)) { 1248 CancelSentIo(); 1249 status = SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, NULL); 1250 // 1251 // NOTE: CyclePort causes the device to be removed and re-enumerated so 1252 // don't do anymore operations after this point. 1253 // 1254 } 1255 1256 return status; 1257 } 1258 1259 _Must_inspect_result_ 1260 NTSTATUS 1261 FxUsbDevice::FormatCycleRequest( 1262 __in FxRequestBase* Request 1263 ) 1264 { 1265 FxRequestBuffer emptyBuffer; 1266 1267 return FormatIoctlRequest(Request, 1268 IOCTL_INTERNAL_USB_CYCLE_PORT, 1269 TRUE, 1270 &emptyBuffer, 1271 &emptyBuffer); 1272 } 1273 1274 _Must_inspect_result_ 1275 NTSTATUS 1276 FxUsbDevice::GetConfigDescriptor( 1277 __out PVOID ConfigDescriptor, 1278 __inout PUSHORT ConfigDescriptorLength 1279 ) 1280 { 1281 NTSTATUS status; 1282 USHORT copyLength; 1283 1284 if (ConfigDescriptor == NULL) { 1285 // 1286 // Caller wants length to allocate 1287 // 1288 *ConfigDescriptorLength = m_ConfigDescriptor->wTotalLength; 1289 return STATUS_BUFFER_TOO_SMALL; 1290 } 1291 1292 if (*ConfigDescriptorLength < m_ConfigDescriptor->wTotalLength) { 1293 // 1294 // Valid ConfigDescriptor passed in, but its too small. Copy as many 1295 // bytes as we can. 1296 // 1297 copyLength = *ConfigDescriptorLength; 1298 status = STATUS_BUFFER_TOO_SMALL; 1299 } 1300 else { 1301 copyLength = m_ConfigDescriptor->wTotalLength; 1302 status = STATUS_SUCCESS; 1303 } 1304 1305 // 1306 // Always indicate to the caller the number of required bytes or the 1307 // number of bytes we copied. 1308 // 1309 RtlCopyMemory(ConfigDescriptor, m_ConfigDescriptor, copyLength); 1310 *ConfigDescriptorLength = m_ConfigDescriptor->wTotalLength; 1311 1312 return status; 1313 } 1314 1315 _Must_inspect_result_ 1316 NTSTATUS 1317 FxUsbDevice::SelectConfigDescriptor( 1318 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, 1319 __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params 1320 ) 1321 { 1322 PUSBD_INTERFACE_LIST_ENTRY pInterfaces; 1323 PURB urb; 1324 NTSTATUS status; 1325 ULONG i, size; 1326 PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor; 1327 PUSB_INTERFACE_DESCRIPTOR* interfaceDescriptors; 1328 ULONG numInterfaces; 1329 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1330 1331 pFxDriverGlobals = GetDriverGlobals(); 1332 1333 configurationDescriptor = Params->Types.Descriptor.ConfigurationDescriptor; 1334 interfaceDescriptors = Params->Types.Descriptor.InterfaceDescriptors; 1335 numInterfaces = Params->Types.Descriptor.NumInterfaceDescriptors; 1336 1337 for (i = 0; i < numInterfaces; i++) { 1338 if (interfaceDescriptors[i] == NULL) { 1339 return STATUS_INVALID_PARAMETER; 1340 } 1341 } 1342 1343 // 1344 // eventually size = sizeof(USBD_INTERFACE_LIST_ENTRY) * (numInterfaces + 1) 1345 // 1346 status = RtlULongAdd(numInterfaces, 1, &size); 1347 if (!NT_SUCCESS(status)) { 1348 return status; 1349 } 1350 1351 status = RtlULongMult(size, sizeof(USBD_INTERFACE_LIST_ENTRY), &size); 1352 if (!NT_SUCCESS(status)) { 1353 return status; 1354 } 1355 1356 pInterfaces = (PUSBD_INTERFACE_LIST_ENTRY) FxPoolAllocate( 1357 pFxDriverGlobals, NonPagedPool, size); 1358 1359 if (pInterfaces == NULL) { 1360 status = STATUS_INSUFFICIENT_RESOURCES; 1361 1362 DoTraceLevelMessage( 1363 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1364 "Could not allocate array of USBD_INTERFACE_LIST_ENTRY, %!STATUS!", 1365 status); 1366 1367 return status; 1368 } 1369 1370 RtlZeroMemory(pInterfaces, size); 1371 1372 for (i = 0; i < numInterfaces; i++) { 1373 pInterfaces[i].InterfaceDescriptor = interfaceDescriptors[i]; 1374 } 1375 1376 if (configurationDescriptor == NULL) { 1377 configurationDescriptor = m_ConfigDescriptor; 1378 } 1379 1380 // 1381 // NOTE: 1382 // 1383 // Creating a config request using the caller's config descriptor does not 1384 // currently work if the provided config descriptor is not the same as the 1385 // descriptor reported by the device. It does not work because we try to 1386 // validate the interface number in the URB against an existing 1387 // FxUsbInterface (which is based on the config descriptor described by the 1388 // device, not the provided one), and if that validation fails, we return 1389 // !NT_SUCCESS from SelectConfig(). 1390 // 1391 urb = FxUsbCreateConfigRequest(GetDriverGlobals(), 1392 configurationDescriptor, 1393 pInterfaces, 1394 GetDefaultMaxTransferSize()); 1395 if (urb == NULL) { 1396 status = STATUS_INSUFFICIENT_RESOURCES; 1397 } 1398 else { 1399 status = SelectConfig(PipesAttributes, urb, FxUrbTypeLegacy, NULL); 1400 FxPoolFree(urb); 1401 urb = NULL; 1402 } 1403 1404 FxPoolFree(pInterfaces); 1405 pInterfaces = NULL; 1406 1407 return status; 1408 } 1409 1410 struct FxInterfacePipeInformation { 1411 // 1412 // Array of pipes 1413 // 1414 FxUsbPipe** Pipes; 1415 1416 // 1417 // Number of entries in Pipes 1418 // 1419 ULONG NumPipes; 1420 }; 1421 1422 _Must_inspect_result_ 1423 NTSTATUS 1424 FxUsbDevice::SelectConfig( 1425 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, 1426 __in PURB Urb, 1427 __in FX_URB_TYPE FxUrbType, 1428 __out_opt PUCHAR NumConfiguredInterfaces 1429 ) 1430 /*++ 1431 1432 Routine Description: 1433 Selects the configuration as described by the parameter Urb. If there is a 1434 previous active configuration, the WDFUSBPIPEs for it are stopped and 1435 destroyed before the new configuration is selected 1436 1437 Arguments: 1438 PipesAttributes - object attributes to apply to each created WDFUSBPIPE 1439 1440 Urb - the URB describing the configuration to select 1441 1442 Return Value: 1443 NTSTATUS 1444 1445 --*/ 1446 { 1447 WDF_REQUEST_SEND_OPTIONS options; 1448 PUCHAR pCur, pEnd; 1449 PUSBD_INTERFACE_INFORMATION pIface; 1450 FxUsbPipe* pPipe; 1451 PURB pSelectUrb; 1452 NTSTATUS status; 1453 ULONG iPipe; 1454 USHORT maxNumPipes, size; 1455 UCHAR numPipes; 1456 FxInterfacePipeInformation* pPipeInfo; 1457 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1458 FxUsbInterface * pUsbInterface ; 1459 UCHAR intfIndex; 1460 FxIrp* irp; 1461 1462 pFxDriverGlobals = GetDriverGlobals(); 1463 FxSyncRequest request(GetDriverGlobals(), NULL); 1464 1465 pIface = NULL; 1466 maxNumPipes = 0; 1467 size = 0; 1468 pPipeInfo = NULL; 1469 pSelectUrb = NULL; 1470 1471 // 1472 // Callers to this function have guaranteed that there are interfaces 1473 // reported on this device. 1474 // 1475 ASSERT(m_NumInterfaces != 0); 1476 1477 if (NumConfiguredInterfaces != NULL) { 1478 *NumConfiguredInterfaces = 0; 1479 } 1480 1481 // 1482 // FxSyncRequest always succeesds for KM but can fail for UM. 1483 // 1484 status = request.Initialize(); 1485 if (!NT_SUCCESS(status)) { 1486 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1487 "Failed to initialize FxSyncRequest"); 1488 goto Done; 1489 } 1490 1491 // 1492 // Allocate a PIRP for the select config and possible select interface(s) 1493 // 1494 status = request.m_TrueRequest->ValidateTarget(this); 1495 if (!NT_SUCCESS(status)) { 1496 goto Done; 1497 } 1498 1499 // 1500 // Allocate a pool for storing the FxUsbPipe ** before we 1501 // assign them to the Interfaces just in case all doesn't go well. 1502 // 1503 if (m_NumInterfaces == 0) { 1504 // 1505 // Use one in the zero case to make the logic simpler 1506 // 1507 size = sizeof(FxInterfacePipeInformation); 1508 } 1509 else { 1510 size = m_NumInterfaces * sizeof(FxInterfacePipeInformation); 1511 } 1512 1513 pPipeInfo = (FxInterfacePipeInformation*) FxPoolAllocate( 1514 pFxDriverGlobals, NonPagedPool, size 1515 ); 1516 1517 if (pPipeInfo == NULL) { 1518 status = STATUS_INSUFFICIENT_RESOURCES; 1519 DoTraceLevelMessage( 1520 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1521 "Could not internal allocate tracking info for selecting a config on " 1522 "WDFUSBDEVICE 0x%p, %!STATUS!", GetHandle(), status); 1523 goto Done; 1524 } 1525 1526 RtlZeroMemory(pPipeInfo, size); 1527 1528 // 1529 // The following code and the one in select setting have a lot in common 1530 // but can't leverage on that as that sends the select interface URB down 1531 // Our goal is allocate the resources -- the pipes and the select setting URB 1532 // before sending down the select config URB so that the tear down is simpler. 1533 // 1534 1535 // 1536 // Each FxUsbInterface will need a FxUsbPipe* for each pipe contained in 1537 // the interface. 1538 // 1539 pCur = (PUCHAR) &Urb->UrbSelectConfiguration.Interface; 1540 pEnd = ((PUCHAR) Urb) + Urb->UrbSelectConfiguration.Hdr.Length; 1541 intfIndex = 0; 1542 1543 for ( ; pCur < pEnd; pCur += pIface->Length, intfIndex++) { 1544 FxUsbPipe** ppPipes; 1545 1546 pIface = (PUSBD_INTERFACE_INFORMATION) pCur; 1547 if (pIface->NumberOfPipes > UCHAR_MAX) { 1548 status = STATUS_INVALID_DEVICE_REQUEST; 1549 DoTraceLevelMessage( 1550 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1551 "WDFUSBDEVICE supports a maximum of %d pipes per interface, " 1552 "USBD_INTERFACE_INFORMATION %p specified %d, %!STATUS!", 1553 UCHAR_MAX, pIface, pIface->NumberOfPipes, status); 1554 goto Done; 1555 } 1556 1557 pUsbInterface = GetInterfaceFromNumber(pIface->InterfaceNumber); 1558 if (pUsbInterface == NULL) { 1559 status = STATUS_INVALID_DEVICE_REQUEST; 1560 DoTraceLevelMessage( 1561 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1562 "Could not find an instance of an interface descriptor with " 1563 "InterfaceNumber %d, %!STATUS!", 1564 pIface->InterfaceNumber, status); 1565 goto Done; 1566 } 1567 1568 numPipes = (UCHAR) pIface->NumberOfPipes; 1569 1570 // 1571 // Track the maximum number of pipes we have seen in an interface in 1572 // case we need to allocate a select interface URB. 1573 // 1574 if (numPipes > maxNumPipes) { 1575 maxNumPipes = (USHORT) numPipes; 1576 } 1577 1578 if (numPipes > 0) { 1579 size = numPipes * sizeof(FxUsbPipe *); 1580 } 1581 else { 1582 // 1583 // It is valid to have an interface with zero pipes in it. In that 1584 // case, we just allocate one entry so that we have a valid array 1585 // and keep the remaining code simple. 1586 // 1587 size = sizeof(FxUsbPipe*); 1588 } 1589 1590 ppPipes = (FxUsbPipe**) FxPoolAllocate( 1591 pFxDriverGlobals, 1592 NonPagedPool, 1593 size 1594 ); 1595 1596 if (ppPipes == NULL) { 1597 status = STATUS_INSUFFICIENT_RESOURCES; 1598 DoTraceLevelMessage( 1599 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1600 "Could not allocate memory for Pipes " 1601 "InterfaceNumber %d, %!STATUS!", 1602 pIface->InterfaceNumber, status); 1603 goto Done; 1604 } 1605 1606 RtlZeroMemory(ppPipes, size); 1607 1608 // 1609 // We store the pointer to the newly allocated arary in a temporary b/c 1610 // we can still fail and we don't want a half baked interface. 1611 // 1612 1613 pPipeInfo[intfIndex].Pipes = ppPipes; 1614 pPipeInfo[intfIndex].NumPipes = numPipes; 1615 1616 for (iPipe = 0; iPipe < numPipes; iPipe++) { 1617 ppPipes[iPipe] = new (GetDriverGlobals(), PipesAttributes) 1618 FxUsbPipe(GetDriverGlobals(),this); 1619 1620 if (ppPipes[iPipe] == NULL) { 1621 status = STATUS_INSUFFICIENT_RESOURCES; 1622 DoTraceLevelMessage( 1623 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1624 "Could not allocate a pipe object, %!STATUS!", status); 1625 goto Done; 1626 } 1627 1628 pPipe = ppPipes[iPipe]; 1629 status = pPipe->Init(m_Device); 1630 if (!NT_SUCCESS(status)) { 1631 DoTraceLevelMessage( 1632 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1633 "Could not Init the pipe object, %!STATUS!", status); 1634 goto Done; 1635 } 1636 1637 status = pPipe->Commit(PipesAttributes, NULL, pUsbInterface); 1638 if (!NT_SUCCESS(status)) { 1639 DoTraceLevelMessage( 1640 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1641 "Could not commit the pipe object, %!STATUS!", status); 1642 goto Done; 1643 } 1644 } 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 if (pUsbInterface->IsInterfaceConfigured()) { 1655 CleanupInterfacePipesAndDelete(pUsbInterface); 1656 } 1657 } 1658 1659 // 1660 // If we are selecting more then one interface and at least one of them 1661 // has pipes in them, allocate a select interface URB that will be used 1662 // after the select config to select each interface. The select interface 1663 // URB will be big enough to select the largest interface in the group. 1664 // 1665 // The select interface URB is allocated before the select config so that 1666 // we know once the select config has completed successfully, we can be 1667 // guaranteed that we can select the interfaces we want and not have to 1668 // handle undoing the select config upon URB allocation failure. 1669 // 1670 if (m_NumInterfaces > 1 && maxNumPipes > 0) { 1671 size = GET_SELECT_INTERFACE_REQUEST_SIZE(maxNumPipes); 1672 1673 pSelectUrb = (PURB) FxPoolAllocate(GetDriverGlobals(), 1674 NonPagedPool, 1675 size 1676 ); 1677 1678 if (pSelectUrb == NULL) { 1679 status = STATUS_INSUFFICIENT_RESOURCES; 1680 DoTraceLevelMessage( 1681 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1682 "Could not allocate a select interface URB, %!STATUS!", status); 1683 goto Done; 1684 } 1685 1686 RtlZeroMemory(pSelectUrb, size); 1687 } 1688 1689 // 1690 // Send the select config to the usb core 1691 // 1692 WDF_REQUEST_SEND_OPTIONS_INIT(&options, 1693 WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); 1694 WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(2)); 1695 1696 FxFormatUsbRequest(request.m_TrueRequest, Urb, FxUrbType, m_USBDHandle); 1697 status = SubmitSync(request.m_TrueRequest, &options); 1698 1699 if (NT_SUCCESS(status)) { 1700 // 1701 // Save the config handle and store off all the pipes 1702 // 1703 m_ConfigHandle = Urb->UrbSelectConfiguration.ConfigurationHandle; 1704 1705 // 1706 // Initialize the first interface 1707 // 1708 pIface = &Urb->UrbSelectConfiguration.Interface; 1709 1710 pUsbInterface = GetInterfaceFromNumber(pIface->InterfaceNumber); 1711 pUsbInterface->SetNumConfiguredPipes((UCHAR)pIface->NumberOfPipes); 1712 1713 // 1714 // The interface now owns the array of pipes 1715 // 1716 pUsbInterface->SetConfiguredPipes(pPipeInfo[0].Pipes); 1717 pPipeInfo[0].Pipes = NULL; 1718 pPipeInfo[0].NumPipes = 0; 1719 1720 pUsbInterface->SetInfo(pIface); 1721 1722 // 1723 // Since this could be the only interface, set the index now, so if we 1724 // return the number of configured interfaces, it will be valid for the 1725 // single interface case. 1726 // 1727 intfIndex = 1; 1728 1729 // 1730 // If we have a more then one interface, we must select each of the addtional 1731 // interfaces after the select config because usbccgp (the generic parent 1732 // driver) didn't fill out all of the pipe info for IAD (interface 1733 // association descriptor) devices. The first interface is filled out 1734 // property, it is 2->N that are left blank. 1735 // 1736 // pSelectUrb can be equal to NULL and have more then one interface if 1737 // all interfaces have no pipes associated with them. In that case, we 1738 // still want to iterate over the remaining pipes so that we can 1739 // initialize our structures properly. 1740 // 1741 if (m_NumInterfaces > 1) { 1742 // 1743 // Loop over the interfaces again. 1744 // 1745 pCur = (PUCHAR) &Urb->UrbSelectConfiguration.Interface; 1746 pIface = (PUSBD_INTERFACE_INFORMATION) pCur; 1747 pEnd = ((PUCHAR) Urb) + Urb->UrbSelectConfiguration.Hdr.Length; 1748 1749 // 1750 // Start at the 2nd one since the first is already selected 1751 // 1752 pCur += pIface->Length; 1753 1754 for ( ; pCur < pEnd; pCur += pIface->Length, intfIndex++) { 1755 #pragma prefast(suppress: __WARNING_UNUSED_POINTER_ASSIGNMENT, "pIface is used in the for loop in many places. It looks like a false positive") 1756 pIface = (PUSBD_INTERFACE_INFORMATION) pCur; 1757 ASSERT(pIface->NumberOfPipes <= maxNumPipes); 1758 1759 pUsbInterface = GetInterfaceFromNumber(pIface->InterfaceNumber); 1760 ASSERT(pUsbInterface != NULL); 1761 1762 // 1763 // Valid to have an interface with no pipes. If there are no 1764 // pipes, GET_SELECT_INTERFACE_REQUEST_SIZE will compute value 1765 // too small of a size to pass validation. 1766 // 1767 if (pIface->NumberOfPipes > 0) { 1768 1769 pUsbInterface->FormatSelectSettingUrb( 1770 pSelectUrb, 1771 (USHORT) pIface->NumberOfPipes, 1772 pIface->AlternateSetting 1773 ); 1774 irp = request.m_TrueRequest->GetSubmitFxIrp(); 1775 irp->Reuse(STATUS_SUCCESS); 1776 1777 request.m_TrueRequest->ClearFieldsForReuse(); 1778 FxFormatUsbRequest(request.m_TrueRequest, 1779 pSelectUrb, 1780 FxUrbTypeLegacy, 1781 NULL); 1782 1783 status = SubmitSync(request.m_TrueRequest, &options); 1784 if (!NT_SUCCESS(status)) { 1785 DoTraceLevelMessage( 1786 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1787 "USB core failed Select Interface URB, %!STATUS!", 1788 status); 1789 goto Done; 1790 } 1791 1792 // 1793 // Copy the info back into the original select config URB 1794 // 1795 1796 RtlCopyMemory(pIface, 1797 &pSelectUrb->UrbSelectInterface.Interface, 1798 pSelectUrb->UrbSelectInterface.Interface.Length); 1799 } 1800 1801 // 1802 // Update the pointer to point to the new pipes with the pointer 1803 // to the pipes stored earlier. 1804 // 1805 ASSERT(pPipeInfo[intfIndex].NumPipes == pIface->NumberOfPipes); 1806 pUsbInterface->SetNumConfiguredPipes((UCHAR)pIface->NumberOfPipes); 1807 1808 // 1809 // The interface now owns the array of pipes 1810 // 1811 pUsbInterface->SetConfiguredPipes(pPipeInfo[intfIndex].Pipes); 1812 pPipeInfo[intfIndex].Pipes = NULL; 1813 pPipeInfo[intfIndex].NumPipes = 0; 1814 1815 // 1816 // SetInfo only after a successful select config so that we can 1817 // copy the USBD_PIPE_INFORMATION . 1818 // 1819 pUsbInterface->SetInfo(pIface); 1820 } 1821 } 1822 1823 if (NumConfiguredInterfaces != NULL) { 1824 *NumConfiguredInterfaces = intfIndex; 1825 } 1826 } 1827 else { 1828 DoTraceLevelMessage( 1829 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1830 "USB core failed Select Configuration, %!STATUS!", status); 1831 } 1832 1833 Done: 1834 if (pSelectUrb != NULL) { 1835 FxPoolFree(pSelectUrb); 1836 pSelectUrb = NULL; 1837 } 1838 1839 if (pPipeInfo != NULL) { 1840 // 1841 // Free all arrays that may have been allocated 1842 // 1843 for (intfIndex = 0; intfIndex < m_NumInterfaces; intfIndex++) { 1844 // 1845 // We can have NumPipes == 0 and still have an allocated array, so 1846 // use the array != NULL as the check. 1847 // 1848 if (pPipeInfo[intfIndex].Pipes != NULL) { 1849 // 1850 // Delete any pipes that might have been created 1851 // 1852 for (iPipe = 0; iPipe < pPipeInfo[intfIndex].NumPipes; iPipe++) { 1853 if (pPipeInfo[intfIndex].Pipes[iPipe] != NULL) { 1854 pPipeInfo[intfIndex].Pipes[iPipe]->DeleteFromFailedCreate(); 1855 pPipeInfo[intfIndex].Pipes[iPipe] = NULL; 1856 } 1857 } 1858 1859 // 1860 // Now free the array itself and clear out the count 1861 // 1862 FxPoolFree(pPipeInfo[intfIndex].Pipes); 1863 pPipeInfo[intfIndex].Pipes = NULL; 1864 pPipeInfo[intfIndex].NumPipes = 0; 1865 } 1866 } 1867 1868 FxPoolFree(pPipeInfo); 1869 pPipeInfo = NULL; 1870 } 1871 1872 return status; 1873 } 1874 1875 _Must_inspect_result_ 1876 NTSTATUS 1877 FxUsbDevice::Deconfig( 1878 VOID 1879 ) 1880 { 1881 WDF_REQUEST_SEND_OPTIONS options; 1882 _URB_SELECT_CONFIGURATION urb; 1883 1884 FxSyncRequest request(GetDriverGlobals(), NULL); 1885 NTSTATUS status; 1886 1887 // 1888 // FxSyncRequest always succeesds for KM but can fail for UM. 1889 // 1890 status = request.Initialize(); 1891 if (!NT_SUCCESS(status)) { 1892 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1893 "Failed to initialize FxSyncRequest"); 1894 return status; 1895 } 1896 1897 status = request.m_TrueRequest->ValidateTarget(this); 1898 if (!NT_SUCCESS(status)) { 1899 return status; 1900 } 1901 1902 // 1903 // This will remove and free all interfaces and associated pipes 1904 // 1905 PipesGotoRemoveState(TRUE); 1906 1907 RtlZeroMemory(&urb, sizeof(urb)); 1908 1909 #pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "this annotation change in usb.h is communicated to usb team"); 1910 UsbBuildSelectConfigurationRequest((PURB) &urb, sizeof(urb), NULL); 1911 #pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "this annotation change in usb.h is communicated to usb team"); 1912 FxFormatUsbRequest(request.m_TrueRequest, (PURB) &urb, FxUrbTypeLegacy, NULL); 1913 1914 WDF_REQUEST_SEND_OPTIONS_INIT( 1915 &options, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); 1916 1917 status = SubmitSync(request.m_TrueRequest, &options); 1918 1919 return status; 1920 } 1921 1922 _Must_inspect_result_ 1923 NTSTATUS 1924 FxUsbDevice::SelectConfigInterfaces( 1925 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, 1926 __in PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, 1927 __in_ecount(NumInterfaces) PUSB_INTERFACE_DESCRIPTOR* InterfaceDescriptors, 1928 __in ULONG NumInterfaces 1929 ) 1930 { 1931 PUSBD_INTERFACE_LIST_ENTRY pInterfaces; 1932 PURB urb; 1933 NTSTATUS status; 1934 ULONG i, size; 1935 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1936 1937 pFxDriverGlobals = GetDriverGlobals(); 1938 1939 // 1940 // eventually size = sizeof(USBD_INTERFACE_LIST_ENTRY) * (NumInterfaces + 1) 1941 // 1942 status = RtlULongAdd(NumInterfaces, 1, &size); 1943 if (!NT_SUCCESS(status)) { 1944 return status; 1945 } 1946 1947 status = RtlULongMult(size, sizeof(USBD_INTERFACE_LIST_ENTRY), &size); 1948 if (!NT_SUCCESS(status)) { 1949 return status; 1950 } 1951 1952 for (i = 0; i < NumInterfaces; i++) { 1953 if (InterfaceDescriptors[i] == NULL) { 1954 return STATUS_INVALID_PARAMETER; 1955 } 1956 } 1957 1958 pInterfaces = (PUSBD_INTERFACE_LIST_ENTRY) FxPoolAllocate( 1959 pFxDriverGlobals, 1960 NonPagedPool, 1961 size 1962 ); 1963 1964 if (pInterfaces == NULL) { 1965 status = STATUS_INSUFFICIENT_RESOURCES; 1966 1967 DoTraceLevelMessage( 1968 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1969 "Could not allocate array of USBD_INTERFACE_LIST_ENTRY, %!STATUS!", 1970 status); 1971 1972 return status; 1973 } 1974 1975 RtlZeroMemory(pInterfaces, size); 1976 1977 for (i = 0; i < NumInterfaces; i++) { 1978 pInterfaces[i].InterfaceDescriptor = InterfaceDescriptors[i]; 1979 } 1980 1981 if (ConfigurationDescriptor == NULL) { 1982 ConfigurationDescriptor = m_ConfigDescriptor; 1983 } 1984 1985 urb = FxUsbCreateConfigRequest(GetDriverGlobals(), 1986 ConfigurationDescriptor, 1987 pInterfaces, 1988 GetDefaultMaxTransferSize()); 1989 if (urb == NULL) { 1990 status = STATUS_INSUFFICIENT_RESOURCES; 1991 } 1992 else { 1993 status = SelectConfig(PipesAttributes, urb, FxUrbTypeLegacy, NULL); 1994 FxPoolFree(urb); 1995 urb = NULL; 1996 } 1997 1998 FxPoolFree(pInterfaces); 1999 pInterfaces = NULL; 2000 2001 return status; 2002 } 2003 2004 FxUsbInterface * 2005 FxUsbDevice::GetInterfaceFromIndex( 2006 __in UCHAR InterfaceIndex 2007 ) 2008 { 2009 if (InterfaceIndex < m_NumInterfaces){ 2010 return m_Interfaces[InterfaceIndex]; 2011 } 2012 2013 return NULL; 2014 } 2015 2016 _Must_inspect_result_ 2017 NTSTATUS 2018 FxUsbDevice::GetInterfaceNumberFromInterface( 2019 __in WDFUSBINTERFACE UsbInterface, 2020 __out PUCHAR InterfaceNumber 2021 ) 2022 { 2023 FxUsbInterface * pUsbInterface; 2024 2025 FxObjectHandleGetPtr(GetDriverGlobals(), 2026 UsbInterface, 2027 FX_TYPE_USB_INTERFACE , 2028 (PVOID*) &pUsbInterface); 2029 2030 *InterfaceNumber = pUsbInterface->GetInterfaceNumber(); 2031 2032 return STATUS_SUCCESS; 2033 } 2034 2035 FxUsbInterface * 2036 FxUsbDevice::GetInterfaceFromNumber( 2037 __in UCHAR InterfaceNumber 2038 ) 2039 { 2040 ULONG i; 2041 2042 for (i = 0; i < m_NumInterfaces; i++) { 2043 if (m_Interfaces[i]->GetInterfaceNumber() == InterfaceNumber) { 2044 return m_Interfaces[i]; 2045 } 2046 } 2047 2048 return NULL; 2049 } 2050 2051 VOID 2052 FxUsbDevice::CleanupInterfacePipesAndDelete( 2053 __in FxUsbInterface * UsbInterface 2054 ) 2055 { 2056 SINGLE_LIST_ENTRY sentHead; 2057 LIST_ENTRY pendHead; 2058 ULONG iPipe; 2059 FxUsbPipe *pPipe; 2060 KIRQL irql; 2061 2062 sentHead.Next = NULL; 2063 InitializeListHead(&pendHead); 2064 2065 AcquireInterfaceIterationLock(); 2066 2067 Lock(&irql); 2068 for (iPipe = 0; iPipe < UsbInterface->m_NumberOfConfiguredPipes; iPipe++) { 2069 BOOLEAN wait; 2070 2071 wait = FALSE; 2072 pPipe = UsbInterface->m_ConfiguredPipes[iPipe]; 2073 pPipe->GotoRemoveState( 2074 WdfIoTargetDeleted, 2075 &pendHead, 2076 &sentHead, 2077 TRUE, 2078 &wait); 2079 } 2080 Unlock(irql); 2081 2082 _CleanupPipesRequests(&pendHead, &sentHead); 2083 2084 for (iPipe = 0; iPipe < UsbInterface->m_NumberOfConfiguredPipes; iPipe++) { 2085 pPipe = UsbInterface->m_ConfiguredPipes[iPipe]; 2086 pPipe->WaitForSentIoToComplete(); 2087 } 2088 2089 UsbInterface->CleanUpAndDelete(FALSE); 2090 2091 ReleaseInterfaceIterationLock(); 2092 } 2093 2094 VOID 2095 FxUsbDevice::CancelSentIo( 2096 VOID 2097 ) 2098 { 2099 FxUsbInterface *pUsbInterface; 2100 ULONG iInterface, iPipe; 2101 2102 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) { 2103 pUsbInterface = m_Interfaces[iInterface]; 2104 2105 if (pUsbInterface->m_ConfiguredPipes != NULL) { 2106 for (iPipe = 0; 2107 iPipe < pUsbInterface->m_NumberOfConfiguredPipes; 2108 iPipe++) { 2109 2110 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { 2111 pUsbInterface->m_ConfiguredPipes[iPipe]->CancelSentIo(); 2112 } 2113 2114 } 2115 } 2116 } 2117 FxIoTarget::CancelSentIo(); // __super call 2118 } 2119 2120 __checkReturn 2121 NTSTATUS 2122 FxUsbDevice::CreateUrb( 2123 __in_opt 2124 PWDF_OBJECT_ATTRIBUTES Attributes, 2125 __out 2126 WDFMEMORY* UrbMemory, 2127 __deref_opt_out_bcount(sizeof(URB)) 2128 PURB* Urb 2129 ) 2130 { 2131 NTSTATUS status; 2132 PURB urbLocal = NULL; 2133 PFX_DRIVER_GLOBALS pFxDriverGlobals; 2134 FxUsbUrb * pUrb = NULL; 2135 WDFMEMORY hMemory; 2136 FxObject* pParent; 2137 2138 // 2139 // Get the parent's globals if it is present, else use the ones for FxUsbDevice 2140 // 2141 pFxDriverGlobals = GetDriverGlobals(); 2142 status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, Attributes); 2143 2144 if (NT_SUCCESS(status)) { 2145 2146 FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, 2147 Attributes->ParentObject, 2148 FX_TYPE_OBJECT, 2149 (PVOID*)&pParent, 2150 &pFxDriverGlobals); 2151 2152 if (FALSE == IsObjectDisposedOnRemove(pParent)) { 2153 DoTraceLevelMessage( 2154 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 2155 "Urb must be parented to FxDevice or an IoAllocated Request"); 2156 status = STATUS_INVALID_PARAMETER; 2157 goto Done; 2158 } 2159 2160 } 2161 else if (status == STATUS_WDF_PARENT_NOT_SPECIFIED) { 2162 2163 pFxDriverGlobals = GetDriverGlobals(); 2164 pParent = this; 2165 status = STATUS_SUCCESS; 2166 2167 } 2168 else { 2169 2170 goto Done; 2171 } 2172 2173 status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes); 2174 if (!NT_SUCCESS(status)) { 2175 goto Done; 2176 } 2177 2178 FxPointerNotNull(pFxDriverGlobals, UrbMemory); 2179 2180 *UrbMemory = NULL; 2181 2182 status = USBD_UrbAllocate(m_USBDHandle, &urbLocal); 2183 2184 if (!NT_SUCCESS(status)) { 2185 2186 urbLocal = NULL; 2187 DoTraceLevelMessage( 2188 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 2189 "USBDEVICE Must have been created with Client Contract Version Info, %!STATUS!", 2190 status); 2191 2192 goto Done; 2193 2194 } 2195 2196 pUrb = new(pFxDriverGlobals, Attributes) 2197 FxUsbUrb(pFxDriverGlobals, m_USBDHandle, urbLocal, sizeof(URB)); 2198 2199 if (pUrb == NULL) { 2200 status = STATUS_INSUFFICIENT_RESOURCES; 2201 goto Done; 2202 } 2203 2204 urbLocal = NULL; 2205 2206 status = pUrb->Commit(Attributes, (WDFOBJECT*)&hMemory, pParent); 2207 2208 if (!NT_SUCCESS(status)) { 2209 goto Done; 2210 } 2211 2212 *UrbMemory = hMemory; 2213 2214 if (Urb) { 2215 *Urb = (PURB) pUrb->GetBuffer(); 2216 } 2217 2218 Done: 2219 2220 if (!NT_SUCCESS(status)) { 2221 2222 if (pUrb) { 2223 pUrb->DeleteFromFailedCreate(); 2224 } 2225 2226 if (urbLocal) { 2227 USBD_UrbFree(m_USBDHandle, urbLocal); 2228 } 2229 2230 } 2231 2232 return status; 2233 } 2234 2235 __checkReturn 2236 NTSTATUS 2237 FxUsbDevice::CreateIsochUrb( 2238 __in_opt 2239 PWDF_OBJECT_ATTRIBUTES Attributes, 2240 __in 2241 ULONG NumberOfIsochPackets, 2242 __out 2243 WDFMEMORY* UrbMemory, 2244 __deref_opt_out_bcount(GET_ISOCH_URB_SIZE(NumberOfIsochPackets)) 2245 PURB* Urb 2246 ) 2247 { 2248 NTSTATUS status; 2249 PURB urbLocal = NULL; 2250 PFX_DRIVER_GLOBALS pFxDriverGlobals; 2251 FxUsbUrb * pUrb = NULL; 2252 WDFMEMORY hMemory; 2253 ULONG size; 2254 FxObject* pParent; 2255 2256 // 2257 // Get the parent's globals if it is present, else use the ones for FxUsbDevice 2258 // 2259 pFxDriverGlobals = GetDriverGlobals(); 2260 status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, Attributes); 2261 2262 if (NT_SUCCESS(status)) { 2263 2264 FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, 2265 Attributes->ParentObject, 2266 FX_TYPE_OBJECT, 2267 (PVOID*)&pParent, 2268 &pFxDriverGlobals); 2269 2270 if (FALSE == IsObjectDisposedOnRemove(pParent)) { 2271 DoTraceLevelMessage( 2272 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 2273 "Urb must be parented to FxDevice or IoAllocated Request"); 2274 status = STATUS_INVALID_PARAMETER; 2275 goto Done; 2276 } 2277 2278 } 2279 else if (status == STATUS_WDF_PARENT_NOT_SPECIFIED) { 2280 2281 pFxDriverGlobals = GetDriverGlobals(); 2282 pParent = this; 2283 status = STATUS_SUCCESS; 2284 2285 } 2286 else { 2287 2288 goto Done; 2289 } 2290 2291 status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes); 2292 if (!NT_SUCCESS(status)) { 2293 goto Done; 2294 } 2295 2296 FxPointerNotNull(pFxDriverGlobals, UrbMemory); 2297 2298 *UrbMemory = NULL; 2299 2300 status = USBD_IsochUrbAllocate(m_USBDHandle, NumberOfIsochPackets, &urbLocal); 2301 2302 if (!NT_SUCCESS(status)) { 2303 2304 urbLocal = NULL; 2305 DoTraceLevelMessage( 2306 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 2307 "USBDEVICE Must have been created with Client Contract Version Info, %!STATUS!", 2308 status); 2309 2310 goto Done; 2311 2312 } 2313 2314 size = GET_ISO_URB_SIZE(NumberOfIsochPackets); 2315 2316 pUrb = new(pFxDriverGlobals, Attributes) 2317 FxUsbUrb(pFxDriverGlobals, m_USBDHandle, urbLocal, size); 2318 2319 if (pUrb == NULL) { 2320 status = STATUS_INSUFFICIENT_RESOURCES; 2321 goto Done; 2322 } 2323 2324 urbLocal = NULL; 2325 2326 status = pUrb->Commit(Attributes, (WDFOBJECT*)&hMemory, pParent); 2327 2328 if (!NT_SUCCESS(status)) { 2329 goto Done; 2330 } 2331 2332 *UrbMemory = hMemory; 2333 2334 if (Urb) { 2335 *Urb = (PURB) pUrb->GetBuffer(); 2336 } 2337 2338 Done: 2339 2340 if (!NT_SUCCESS(status)) { 2341 2342 if (pUrb) { 2343 pUrb->DeleteFromFailedCreate(); 2344 } 2345 2346 if (urbLocal) { 2347 USBD_UrbFree(m_USBDHandle, urbLocal); 2348 } 2349 2350 } 2351 2352 return status; 2353 } 2354 2355 BOOLEAN 2356 FxUsbDevice::IsObjectDisposedOnRemove( 2357 __in FxObject* Object 2358 ) 2359 /*++ 2360 2361 Routine Description: 2362 This routine determines if the Object being passed is guranteed to be disposed on a 2363 Pnp remove operation. 2364 2365 The object will be disposed on Pnp remove operation if it is a somewhere in the child 2366 tree of the FxDevice assocaited with this FxUsbDevice object, or in the child tree of an 2367 Io Allocated Request. 2368 2369 Arguments: 2370 2371 Object - The Object being checked 2372 2373 Return Value: 2374 2375 TRUE if the Object is guranteed to be disposed on a pnp remove operation 2376 FALSE otherwise. 2377 2378 --*/ 2379 { 2380 FxObject * obj; 2381 FxObject * parent; 2382 BOOLEAN isObjectDisposedOnRemove = FALSE; 2383 2384 obj = Object; 2385 2386 // 2387 // By adding a reference now, we simulate what GetParentObjectReferenced 2388 // does later, thus allowing simple logic on when/how to release the 2389 // reference on exit. 2390 // 2391 obj->ADDREF(Object); 2392 2393 while (obj != NULL) { 2394 2395 if (obj == (FxObject*) m_Device) { 2396 2397 isObjectDisposedOnRemove = TRUE; 2398 break; 2399 } 2400 2401 if (FxObjectCheckType(obj, FX_TYPE_REQUEST)) { 2402 2403 FxRequestBase* request = (FxRequestBase*) obj; 2404 if (request->IsAllocatedFromIo()) { 2405 2406 isObjectDisposedOnRemove = TRUE; 2407 break; 2408 } 2409 } 2410 2411 parent = obj->GetParentObjectReferenced(Object); 2412 2413 // 2414 // Release the reference previously taken by the top of the function 2415 // or GetParentObjectReferenced in a previous pass in the loop. 2416 // 2417 obj->RELEASE(Object); 2418 obj = parent; 2419 } 2420 2421 if (obj != NULL) { 2422 2423 // 2424 // Release the reference previously taken by the top of the function 2425 // or GetParentObjectReferenced in a last pass in the loop. 2426 // 2427 obj->RELEASE(Object); 2428 } 2429 2430 return isObjectDisposedOnRemove; 2431 } 2432 2433 FX_URB_TYPE 2434 FxUsbDevice::GetFxUrbTypeForRequest( 2435 __in FxRequestBase* Request 2436 ) 2437 /*++ 2438 2439 Routine Description: 2440 This routine essentially determines whether this routine can use a urb allocated by 2441 the USBD_xxxUrbAllocate APIs 2442 2443 The USBD_xxxUrbAllocate APIs are only used for those requests that could be disposed at the 2444 time the client driver devnode is being removed. 2445 2446 If we cannot make that gurantee about that request, FxUrbTypeLegacy is returned and the 2447 USBD_xxxUrbAllocate api's must not be used to allocate an Urb. 2448 2449 Else FxUrbTypeUsbdAllocated is returned. 2450 2451 Arguments: 2452 2453 Request - FxRequest 2454 2455 Return Value: 2456 2457 FxUrbTypeUsbdAllocated, or FxUrbTypeLegacy 2458 2459 --*/ 2460 { 2461 if (m_UrbType == FxUrbTypeLegacy) { 2462 return FxUrbTypeLegacy; 2463 } 2464 2465 if (Request->IsAllocatedFromIo()) { 2466 return FxUrbTypeUsbdAllocated; 2467 } 2468 2469 if (IsObjectDisposedOnRemove((FxObject*) Request)) { 2470 return FxUrbTypeUsbdAllocated; 2471 } 2472 2473 return FxUrbTypeLegacy; 2474 } 2475 2476