1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxUsbDeviceKm.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 "FxUsbDeviceKm.tmh" 30 } 31 32 33 34 35 36 37 38 #define UCHAR_MAX (0xff) 39 40 41 _Must_inspect_result_ 42 NTSTATUS 43 FxUsbDevice::InitDevice( 44 __in ULONG USBDClientContractVersionForWdfClient 45 ) 46 { 47 URB urb; 48 FxSyncRequest request(GetDriverGlobals(), NULL); 49 WDF_REQUEST_SEND_OPTIONS options; 50 NTSTATUS status; 51 ULONG size; 52 53 RtlZeroMemory(&urb, sizeof(urb)); 54 55 if (USBDClientContractVersionForWdfClient != USBD_CLIENT_CONTRACT_VERSION_INVALID) { 56 57 // 58 // Register with USBDEX.lib 59 // 60 status = USBD_CreateHandle(m_InStackDevice, 61 m_TargetDevice, 62 USBDClientContractVersionForWdfClient, 63 GetDriverGlobals()->Tag, 64 &m_USBDHandle); 65 66 if (!NT_SUCCESS(status)) { 67 DoTraceLevelMessage( 68 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 69 "USBD_CreateHandle failed, %!STATUS!", status); 70 goto Done; 71 } 72 73 m_UrbType = FxUrbTypeUsbdAllocated; 74 } 75 76 status = request.m_TrueRequest->ValidateTarget(this); 77 if (!NT_SUCCESS(status)) { 78 goto Done; 79 } 80 81 UsbBuildGetDescriptorRequest(&urb, 82 sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), 83 USB_DEVICE_DESCRIPTOR_TYPE, 84 0, 85 0, 86 &m_DeviceDescriptor, 87 NULL, 88 sizeof(m_DeviceDescriptor), 89 NULL); 90 91 FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL); 92 93 WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0); 94 WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(5)); 95 96 status = SubmitSync(request.m_TrueRequest, &options); 97 if (!NT_SUCCESS(status)) { 98 DoTraceLevelMessage( 99 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 100 "Could not retrieve device descriptor, %!STATUS!", status); 101 goto Done; 102 } 103 104 // 105 // After successfully completing any default control URB, USBD/usbport fills 106 // in the PipeHandle field of the URB (it is the same offset in every URB, 107 // which this CASSERT verifies. Since USBD_DEFAULT_PIPE_TRANSFER is not 108 // supported by USBD (it is by USBPORT), this is the prescribed way of getting 109 // the default control pipe so that you can set the PipeHandle field in 110 // _URB_CONTROL_TRANSFER. 111 // 112 WDFCASSERT(FIELD_OFFSET(_URB_CONTROL_TRANSFER, PipeHandle) == 113 FIELD_OFFSET(_URB_CONTROL_DESCRIPTOR_REQUEST, Reserved)); 114 115 m_ControlPipe = urb.UrbControlDescriptorRequest.Reserved; 116 117 USB_CONFIGURATION_DESCRIPTOR config; 118 119 RtlZeroMemory(&config, sizeof(config)); 120 size = sizeof(config); 121 122 UsbBuildGetDescriptorRequest(&urb, 123 sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), 124 USB_CONFIGURATION_DESCRIPTOR_TYPE, 125 0, 126 0, 127 &config, 128 NULL, 129 size, 130 NULL); 131 132 request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS); 133 request.m_TrueRequest->ClearFieldsForReuse(); 134 FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL); 135 136 status = SubmitSync(request.m_TrueRequest, &options); 137 if (!NT_SUCCESS(status)) { 138 DoTraceLevelMessage( 139 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 140 "Could not retrieve config descriptor size, %!STATUS!", status); 141 goto Done; 142 } 143 else if (urb.UrbControlDescriptorRequest.TransferBufferLength == 0) { 144 // 145 // Not enough info returned 146 // 147 status = STATUS_UNSUCCESSFUL; 148 149 DoTraceLevelMessage( 150 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 151 "Could not retrieve config descriptor size, zero bytes transferred, " 152 " %!STATUS!", status); 153 154 goto Done; 155 } 156 else if (config.wTotalLength < size) { 157 // 158 // Not enough info returned 159 // 160 status = STATUS_UNSUCCESSFUL; 161 162 DoTraceLevelMessage( 163 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 164 "Could not retrieve config descriptor size, config.wTotalLength %d < " 165 "sizeof(config descriptor) (%d), %!STATUS!", 166 config.wTotalLength, size, status); 167 168 goto Done; 169 } 170 171 // 172 // Allocate an additional memory at the end of the buffer so if we 173 // accidentily access fields beyond the end of the buffer we don't crash 174 175 // 176 177 178 179 180 181 size = config.wTotalLength; 182 ULONG paddedSize = size + sizeof(USB_DEVICE_DESCRIPTOR); 183 184 m_ConfigDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) 185 FxPoolAllocate(GetDriverGlobals(), 186 NonPagedPool, 187 paddedSize); 188 189 if (m_ConfigDescriptor == NULL) { 190 status = STATUS_INSUFFICIENT_RESOURCES; 191 192 DoTraceLevelMessage( 193 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 194 "Could not allocate %d bytes for config descriptor, %!STATUS!", 195 paddedSize, status); 196 197 goto Done; 198 } 199 200 RtlZeroMemory(m_ConfigDescriptor, paddedSize); 201 202 UsbBuildGetDescriptorRequest(&urb, 203 sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), 204 USB_CONFIGURATION_DESCRIPTOR_TYPE, 205 0, 206 0, 207 m_ConfigDescriptor, 208 NULL, 209 size, 210 NULL); 211 212 request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS); 213 request.m_TrueRequest->ClearFieldsForReuse(); 214 FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL); 215 216 status = SubmitSync(request.m_TrueRequest, &options); 217 if (!NT_SUCCESS(status)) { 218 DoTraceLevelMessage( 219 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 220 "Could not retrieve config descriptor, %!STATUS!", status); 221 goto Done; 222 } else if(m_ConfigDescriptor->wTotalLength != size) { 223 // 224 // Invalid wTotalLength 225 // 226 status = STATUS_DEVICE_DATA_ERROR; 227 DoTraceLevelMessage( 228 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 229 "Defective USB device reported two different config descriptor " 230 "wTotalLength values: %d and %d, %!STATUS!", 231 size, m_ConfigDescriptor->wTotalLength, status); 232 goto Done; 233 } 234 235 // 236 // Check to see if we are wait wake capable 237 // 238 if (m_ConfigDescriptor->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) { 239 m_Traits |= WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; 240 } 241 242 // 243 // Check to see if we are self or bus powered 244 // 245 USHORT deviceStatus; 246 247 UsbBuildGetStatusRequest(&urb, 248 URB_FUNCTION_GET_STATUS_FROM_DEVICE, 249 0, 250 &deviceStatus, 251 NULL, 252 NULL); 253 254 request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS); 255 request.m_TrueRequest->ClearFieldsForReuse(); 256 FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL); 257 258 status = SubmitSync(request.m_TrueRequest, &options); 259 if (NT_SUCCESS(status) && (deviceStatus & USB_GETSTATUS_SELF_POWERED)) { 260 m_Traits |= WDF_USB_DEVICE_TRAIT_SELF_POWERED; 261 } 262 263 // 264 // Revert back to success b/c we don't care if the usb device get status 265 // fails 266 // 267 status = STATUS_SUCCESS; 268 269 USB_BUS_INTERFACE_USBDI_V1 busIf; 270 271 RtlZeroMemory(&busIf, sizeof(busIf)); 272 273 // 274 // All PNP irps must have this initial status 275 // 276 request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_NOT_SUPPORTED); 277 request.m_TrueRequest->ClearFieldsForReuse(); 278 279 FxQueryInterface::_FormatIrp( 280 request.m_TrueRequest->GetSubmitFxIrp()->GetIrp(), 281 &USB_BUS_INTERFACE_USBDI_GUID, 282 (PINTERFACE) &busIf, 283 sizeof(busIf), 284 USB_BUSIF_USBDI_VERSION_1); 285 286 request.m_TrueRequest->VerifierSetFormatted(); 287 288 status = SubmitSync(request.m_TrueRequest); 289 290 if (!NT_SUCCESS(status)) { 291 // 292 // Retry with the older interface 293 // 294 RtlZeroMemory(&busIf, sizeof(busIf)); 295 296 // 297 // All PNP irps must have this initial status 298 // 299 300 request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_NOT_SUPPORTED); 301 request.m_TrueRequest->ClearFieldsForReuse(); 302 303 FxQueryInterface::_FormatIrp( 304 request.m_TrueRequest->GetSubmitFxIrp()->GetIrp(), 305 &USB_BUS_INTERFACE_USBDI_GUID, 306 (PINTERFACE) &busIf, 307 sizeof(USB_BUS_INTERFACE_USBDI_V0), 308 USB_BUSIF_USBDI_VERSION_0); 309 310 request.m_TrueRequest->VerifierSetFormatted(); 311 312 status = SubmitSync(request.m_TrueRequest); 313 } 314 315 if (NT_SUCCESS(status)) { 316 // 317 // Need to check for NULL b/c we may have only retrieved the V0 interface 318 // 319 if (busIf.IsDeviceHighSpeed != NULL && 320 busIf.IsDeviceHighSpeed(busIf.BusContext)) { 321 m_Traits |= WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED; 322 } 323 324 // 325 // Stash these off for later 326 // 327 m_QueryBusTime = busIf.QueryBusTime; 328 m_BusInterfaceContext = busIf.BusContext; 329 m_BusInterfaceDereference = busIf.InterfaceDereference; 330 331 ASSERT(busIf.GetUSBDIVersion != NULL); 332 busIf.GetUSBDIVersion(busIf.BusContext, 333 &m_UsbdVersionInformation, 334 &m_HcdPortCapabilities); 335 } 336 else if (status == STATUS_NOT_SUPPORTED) { 337 // 338 // We will only use m_ControlPipe on stacks which do not support 339 // USBD_DEFAULT_PIPE_TRANSFER. If all the QIs failed, then we know 340 // definitively that we are running on USBD and we need m_ControlPipe 341 // to be != NULL for later control transfers 342 // 343 ASSERT(m_ControlPipe != NULL); 344 345 m_OnUSBD = TRUE; 346 347 // 348 // The QI failed with not supported, do not return error 349 // 350 status = STATUS_SUCCESS; 351 } 352 else { 353 DoTraceLevelMessage( 354 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 355 "Query Interface for bus returned error, %!STATUS!", status); 356 } 357 358 Done: 359 360 return status; 361 } 362 363 _Must_inspect_result_ 364 NTSTATUS 365 FxUsbDevice::GetString( 366 __in_ecount(*NumCharacters) PUSHORT String, 367 __in PUSHORT NumCharacters, 368 __in UCHAR StringIndex, 369 __in_opt USHORT LangID, 370 __in_opt WDFREQUEST Request, 371 __in_opt PWDF_REQUEST_SEND_OPTIONS Options 372 ) 373 { 374 PUSB_STRING_DESCRIPTOR pDescriptor; 375 PVOID buffer; 376 _URB_CONTROL_DESCRIPTOR_REQUEST urb; 377 WDF_REQUEST_SEND_OPTIONS options, *pOptions; 378 USB_COMMON_DESCRIPTOR common; 379 ULONG length; 380 NTSTATUS status; 381 382 FxSyncRequest request(GetDriverGlobals(), NULL, Request); 383 384 // 385 // FxSyncRequest always succeesds for KM. 386 // 387 status = request.Initialize(); 388 if (!NT_SUCCESS(status)) { 389 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 390 "Failed to initialize FxSyncRequest"); 391 return status; 392 } 393 394 buffer = NULL; 395 396 status = request.m_TrueRequest->ValidateTarget(this); 397 if (!NT_SUCCESS(status)) { 398 goto Done; 399 } 400 401 RtlZeroMemory(&urb, sizeof(urb)); 402 403 if (String != NULL) { 404 length = sizeof(USB_STRING_DESCRIPTOR) + (*NumCharacters - 1) * sizeof(WCHAR); 405 406 buffer = FxPoolAllocate(GetDriverGlobals(), 407 NonPagedPool, 408 length); 409 410 if (buffer == NULL) { 411 status = STATUS_INSUFFICIENT_RESOURCES; 412 goto Done; 413 } 414 415 RtlZeroMemory(buffer, length); 416 pDescriptor = (PUSB_STRING_DESCRIPTOR) buffer; 417 } 418 else { 419 RtlZeroMemory(&common, sizeof(common)); 420 421 length = sizeof(USB_COMMON_DESCRIPTOR); 422 pDescriptor = (PUSB_STRING_DESCRIPTOR) &common; 423 } 424 425 UsbBuildGetDescriptorRequest((PURB) &urb, 426 sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), 427 USB_STRING_DESCRIPTOR_TYPE, 428 StringIndex, 429 LangID, 430 pDescriptor, 431 NULL, 432 length, 433 NULL); 434 435 if (Options != NULL) { 436 pOptions = Options; 437 } 438 else { 439 WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0); 440 WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, 441 WDF_REL_TIMEOUT_IN_SEC(2)); 442 443 pOptions = &options; 444 } 445 #pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "this annotation change in usb.h is communicated to usb team") 446 FxFormatUsbRequest(request.m_TrueRequest, (PURB) &urb, FxUrbTypeLegacy, NULL); 447 status = SubmitSync(request.m_TrueRequest, pOptions); 448 449 if (NT_SUCCESS(status)) { 450 USHORT numChars; 451 452 // 453 // Make sure we got an even number of bytes and that we got a header 454 // 455 if ((pDescriptor->bLength & 0x1) || 456 pDescriptor->bLength < sizeof(USB_COMMON_DESCRIPTOR)) { 457 status = STATUS_DEVICE_DATA_ERROR; 458 } 459 else { 460 // 461 // bLength is the length of the entire descriptor. Subtract off 462 // the descriptor header and then divide by the size of a WCHAR. 463 // 464 numChars = 465 (pDescriptor->bLength - sizeof(USB_COMMON_DESCRIPTOR)) / sizeof(WCHAR); 466 467 if (String != NULL) { 468 if (*NumCharacters >= numChars) { 469 length = numChars * sizeof(WCHAR); 470 } 471 else { 472 length = *NumCharacters * sizeof(WCHAR); 473 status = STATUS_BUFFER_OVERFLOW; 474 } 475 476 *NumCharacters = numChars; 477 RtlCopyMemory(String, pDescriptor->bString, length); 478 } 479 else { 480 *NumCharacters = numChars; 481 } 482 } 483 } 484 485 if (buffer != NULL) { 486 FxPoolFree(buffer); 487 } 488 489 Done: 490 491 return status; 492 } 493 494 _Must_inspect_result_ 495 NTSTATUS 496 FxUsbDevice::FormatStringRequest( 497 __in FxRequestBase* Request, 498 __in FxRequestBuffer *RequestBuffer, 499 __in UCHAR StringIndex, 500 __in USHORT LangID 501 ) 502 /*++ 503 504 Routine Description: 505 Formats a request to retrieve a string from a string descriptor 506 507 Arguments: 508 Request - request to format 509 510 RequestBuffer - Buffer to be filled in when the request has completed 511 512 StringIndex - index of the string 513 514 LandID - language ID of the string to be retrieved 515 516 Return Value: 517 NTSTATUS 518 519 --*/ 520 { 521 FxUsbDeviceStringContext* pContext; 522 NTSTATUS status; 523 FX_URB_TYPE urbType; 524 525 status = Request->ValidateTarget(this); 526 if (!NT_SUCCESS(status)) { 527 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 528 "WDFUSBDEVICE %p, Request %p, setting target failed, " 529 "%!STATUS!", GetHandle(), Request, status); 530 531 return status; 532 } 533 534 if (Request->HasContextType(FX_RCT_USB_STRING_REQUEST)) { 535 pContext = (FxUsbDeviceStringContext*) Request->GetContext(); 536 } 537 else { 538 539 urbType = GetFxUrbTypeForRequest(Request); 540 pContext = new(GetDriverGlobals()) FxUsbDeviceStringContext(urbType); 541 if (pContext == NULL) { 542 return STATUS_INSUFFICIENT_RESOURCES; 543 } 544 545 if (urbType == FxUrbTypeUsbdAllocated) { 546 status = pContext->AllocateUrb(m_USBDHandle); 547 if (!NT_SUCCESS(status)) { 548 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 549 "FxUsbDeviceStringContext::AllocateUrb failed, %!STATUS!", status); 550 delete pContext; 551 return status; 552 } 553 554 // 555 // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is 556 // important to release those resorces before the devnode is removed. Those 557 // resoruces are removed at the time Request is disposed. 558 // 559 Request->EnableContextDisposeNotification(); 560 } 561 562 Request->SetContext(pContext); 563 } 564 565 status = pContext->AllocateDescriptor(GetDriverGlobals(), 566 RequestBuffer->GetBufferLength()); 567 if (!NT_SUCCESS(status)) { 568 return status; 569 } 570 571 pContext->StoreAndReferenceMemory(RequestBuffer); 572 pContext->SetUrbInfo(StringIndex, LangID); 573 574 if (pContext->m_Urb == &pContext->m_UrbLegacy) { 575 urbType = FxUrbTypeLegacy; 576 } 577 else { 578 urbType = FxUrbTypeUsbdAllocated; 579 } 580 581 FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle); 582 583 return STATUS_SUCCESS; 584 } 585 586 _Must_inspect_result_ 587 NTSTATUS 588 FxUsbDevice::FormatControlRequest( 589 __in FxRequestBase* Request, 590 __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, 591 __in FxRequestBuffer *RequestBuffer 592 ) 593 { 594 FxUsbDeviceControlContext* pContext; 595 NTSTATUS status; 596 size_t bufferSize; 597 FX_URB_TYPE urbType; 598 599 bufferSize = RequestBuffer->GetBufferLength(); 600 601 // 602 // We can only transfer 2 bytes worth of data, so if the buffer is larger, 603 // fail here. 604 // 605 if (bufferSize > 0xFFFF) { 606 DoTraceLevelMessage( 607 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 608 "Control transfer buffer is limited to 0xFFFF bytes in size, " 609 "%I64d requested ", bufferSize); 610 611 return STATUS_INVALID_PARAMETER; 612 } 613 614 status = Request->ValidateTarget(this); 615 if (!NT_SUCCESS(status)) { 616 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 617 "WDFUSBDEVICE %p, Request %p, setting target failed, " 618 "%!STATUS!", GetHandle(), Request, status); 619 620 return status; 621 } 622 623 if (Request->HasContextType(FX_RCT_USB_CONTROL_REQUEST)) { 624 pContext = (FxUsbDeviceControlContext*) Request->GetContext(); 625 } 626 else { 627 628 urbType = GetFxUrbTypeForRequest(Request); 629 pContext = new(GetDriverGlobals()) FxUsbDeviceControlContext(urbType); 630 if (pContext == NULL) { 631 return STATUS_INSUFFICIENT_RESOURCES; 632 } 633 634 if (urbType == FxUrbTypeUsbdAllocated) { 635 status = pContext->AllocateUrb(m_USBDHandle); 636 if (!NT_SUCCESS(status)) { 637 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 638 "FxUsbDeviceControlContext::AllocateUrb Failed, %!STATUS!", status); 639 640 delete pContext; 641 return status; 642 } 643 // 644 // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is 645 // important to release those resorces before the devnode is removed. Those 646 // resoruces are removed at the time Request is disposed. 647 // 648 Request->EnableContextDisposeNotification(); 649 } 650 651 Request->SetContext(pContext); 652 } 653 654 if (RequestBuffer->HasMdl()) { 655 PMDL pMdl; 656 657 pMdl = NULL; 658 ASSERT(pContext->m_PartialMdl == NULL); 659 660 status = RequestBuffer->GetOrAllocateMdl(GetDriverGlobals(), 661 &pMdl, 662 &pContext->m_PartialMdl, 663 &pContext->m_UnlockPages, 664 IoModifyAccess); 665 666 if (!NT_SUCCESS(status)) { 667 return status; 668 } 669 670 ASSERT(pMdl != NULL); 671 } 672 673 pContext->StoreAndReferenceMemory(this, RequestBuffer, SetupPacket); 674 675 if (pContext->m_Urb == &pContext->m_UrbLegacy) { 676 urbType = FxUrbTypeLegacy; 677 } 678 else { 679 urbType = FxUrbTypeUsbdAllocated; 680 } 681 682 FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle); 683 684 return STATUS_SUCCESS; 685 } 686 687 VOID 688 FxUsbDeviceControlContext::StoreAndReferenceMemory( 689 __in FxUsbDevice* Device, 690 __in FxRequestBuffer* Buffer, 691 __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket 692 ) 693 { 694 SetUsbType(WdfUsbRequestTypeDeviceControlTransfer); 695 696 RtlZeroMemory(m_Urb, sizeof(*m_Urb)); 697 698 m_Urb->Hdr.Function = URB_FUNCTION_CONTROL_TRANSFER; 699 m_Urb->Hdr.Length = sizeof(*m_Urb); 700 701 __super::StoreAndReferenceMemory(Buffer); 702 703 // 704 // Set the values using what is stored in the buffer 705 // 706 Buffer->AssignValues(&m_Urb->TransferBuffer, 707 &m_Urb->TransferBufferMDL, 708 &m_Urb->TransferBufferLength); 709 710 RtlCopyMemory(&m_Urb->SetupPacket[0], 711 &SetupPacket->Generic.Bytes[0], 712 sizeof(m_Urb->SetupPacket)); 713 714 // 715 // also indicate the length of the buffer in the header 716 // 717 ((PWDF_USB_CONTROL_SETUP_PACKET) &m_Urb->SetupPacket[0])->Packet.wLength = 718 (USHORT) m_Urb->TransferBufferLength; 719 720 // 721 // Control transfers are always short OK. USBD_TRANSFER_DIRECTION_IN may 722 // be OR'ed in later. 723 // 724 m_Urb->TransferFlags = USBD_SHORT_TRANSFER_OK; 725 726 // 727 // Get the direction out of the setup packet 728 // 729 if (SetupPacket->Packet.bm.Request.Dir == BMREQUEST_DEVICE_TO_HOST) { 730 m_Urb->TransferFlags |= USBD_TRANSFER_DIRECTION_IN; 731 } 732 733 if (Device->OnUSBD()) { 734 m_Urb->PipeHandle = Device->GetControlPipeHandle(); 735 } 736 else { 737 // 738 // USBPORT supports this flag 739 // 740 m_Urb->TransferFlags |= USBD_DEFAULT_PIPE_TRANSFER; 741 } 742 743 // 744 // If we have built a partial MDL, use that instead. TransferBufferLength 745 // is still valid because the Offsets or length in Buffer will have been 746 // used to create this PartialMdl by the caller. 747 // 748 if (m_PartialMdl != NULL) { 749 m_Urb->TransferBufferMDL = m_PartialMdl; 750 } 751 } 752 753 _Must_inspect_result_ 754 NTSTATUS 755 FxUsbDevice::QueryUsbCapability( 756 __in 757 CONST GUID* CapabilityType, 758 __in 759 ULONG CapabilityBufferLength, 760 __drv_when(CapabilityBufferLength == 0, __out_opt) 761 __drv_when(CapabilityBufferLength != 0 && ResultLength == NULL, __out_bcount(CapabilityBufferLength)) 762 __drv_when(CapabilityBufferLength != 0 && ResultLength != NULL, __out_bcount_part_opt(CapabilityBufferLength, *ResultLength)) 763 PVOID CapabilityBuffer, 764 __out_opt 765 __drv_when(ResultLength != NULL,__deref_out_range(<=,CapabilityBufferLength)) 766 PULONG ResultLength 767 ) 768 { 769 NTSTATUS status; 770 771 if (ResultLength != NULL) { 772 *ResultLength = 0; 773 } 774 775 if (GetUSBDHandle() == NULL) { 776 status = STATUS_INVALID_DEVICE_STATE; 777 778 DoTraceLevelMessage( 779 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 780 "WDFUSBDEVICE must have been created using WdfUsbTargetDeviceCreateWithParameters, %!STATUS!", 781 status); 782 783 return status; 784 } 785 786 status = USBD_QueryUsbCapability(m_USBDHandle, 787 CapabilityType, 788 CapabilityBufferLength, 789 (PUCHAR) CapabilityBuffer, 790 ResultLength); 791 792 if (!NT_SUCCESS(status)) { 793 DoTraceLevelMessage( 794 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 795 "Could not retrieve capability %!GUID!, %!STATUS!", 796 CapabilityType, status); 797 goto exit; 798 } 799 800 exit: 801 return status; 802 } 803 804 _Must_inspect_result_ 805 NTSTATUS 806 FxUsbDevice::SelectConfigSingle( 807 __in PWDF_OBJECT_ATTRIBUTES PipeAttributes, 808 __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params 809 ) 810 /*++ 811 812 Routine Description: 813 This will configure the single inteface case and pick up the first available 814 setting. If there are multiple settings on a single interface device 815 and the driver wants to pick one then the driver should use the multinterface 816 option to initialize. 817 818 This takes care of the simplest case only. Configuring a multi interface 819 device as a single interface device would be treated as an error. There is 820 duplication of code with the multi case but it is better to keep these two 821 separate especially if more gets added. 822 823 Arguments: 824 825 826 Return Value: 827 NTSTATUS 828 829 --*/ 830 { 831 // 832 // The array needs an extra element which is zero'd out to mark the end 833 // 834 USBD_INTERFACE_LIST_ENTRY listEntry[2]; 835 PURB urb; 836 NTSTATUS status; 837 838 RtlZeroMemory(&Params->Types.SingleInterface, 839 sizeof(Params->Types.SingleInterface)); 840 841 if (m_NumInterfaces > 1) { 842 status = STATUS_INVALID_PARAMETER; 843 844 DoTraceLevelMessage( 845 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 846 "WDFUSBDEVICE %p cannot be auto configured for a single interface " 847 "since there are %d interfaces on the device, %!STATUS!", 848 GetHandle(), m_NumInterfaces, status); 849 850 return status; 851 } 852 853 RtlZeroMemory(&listEntry[0], sizeof(listEntry)); 854 855 // 856 // Use AlternateSetting 0 by default 857 // 858 listEntry[0].InterfaceDescriptor = m_Interfaces[0]->GetSettingDescriptor(0); 859 860 if (listEntry[0].InterfaceDescriptor == NULL) { 861 DoTraceLevelMessage( 862 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 863 "WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for " 864 "bInterfaceNumber %d", GetHandle(), 865 m_Interfaces[0]->m_InterfaceNumber); 866 867 return STATUS_INVALID_PARAMETER; 868 } 869 870 urb = FxUsbCreateConfigRequest(GetDriverGlobals(), 871 m_ConfigDescriptor, 872 &listEntry[0], 873 GetDefaultMaxTransferSize()); 874 875 if (urb == NULL) { 876 status = STATUS_INSUFFICIENT_RESOURCES; 877 } 878 else { 879 status = SelectConfig(PipeAttributes, urb, FxUrbTypeLegacy, NULL); 880 881 if (NT_SUCCESS(status)) { 882 Params->Types.SingleInterface.NumberConfiguredPipes = 883 m_Interfaces[0]->GetNumConfiguredPipes(); 884 885 Params->Types.SingleInterface.ConfiguredUsbInterface = 886 m_Interfaces[0]->GetHandle(); 887 } 888 889 FxPoolFree(urb); 890 urb = NULL; 891 } 892 893 return status; 894 } 895 896 _Must_inspect_result_ 897 NTSTATUS 898 FxUsbDevice::SelectConfigMulti( 899 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, 900 __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params 901 ) 902 /*++ 903 904 Routine Description: 905 Selects the configuration as described by the parameter Params. If there is a 906 previous active configuration, the WDFUSBPIPEs for it are stopped and 907 destroyed before the new configuration is selected 908 909 Arguments: 910 PipesAttributes - object attributes to apply to each created WDFUSBPIPE 911 912 Params - 913 914 Return Value: 915 NTSTATUS 916 917 --*/ 918 { 919 PUSBD_INTERFACE_LIST_ENTRY pList; 920 PURB urb; 921 NTSTATUS status; 922 ULONG size; 923 UCHAR i; 924 PFX_DRIVER_GLOBALS pFxDriverGlobals; 925 926 pFxDriverGlobals = GetDriverGlobals(); 927 928 Params->Types.MultiInterface.NumberOfConfiguredInterfaces = 0; 929 930 // 931 // The array needs an extra element which is zero'd out to mark the end 932 // 933 size = sizeof(USBD_INTERFACE_LIST_ENTRY) * (m_NumInterfaces + 1); 934 pList = (PUSBD_INTERFACE_LIST_ENTRY) FxPoolAllocate( 935 pFxDriverGlobals, 936 NonPagedPool, 937 size 938 ); 939 940 if (pList == NULL) { 941 return STATUS_INSUFFICIENT_RESOURCES; 942 } 943 944 RtlZeroMemory(pList, size); 945 946 if (Params->Type == WdfUsbTargetDeviceSelectConfigTypeMultiInterface) { 947 for (i = 0; i < m_NumInterfaces; i++) { 948 pList[i].InterfaceDescriptor = 949 m_Interfaces[i]->GetSettingDescriptor(0); 950 951 if (pList[i].InterfaceDescriptor == NULL) { 952 DoTraceLevelMessage( 953 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 954 "WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for " 955 "bInterfaceNumber %d", GetHandle(), 956 m_Interfaces[i]->m_InterfaceNumber); 957 958 status = STATUS_INVALID_PARAMETER; 959 goto Done; 960 } 961 } 962 } 963 else { 964 // 965 // Type is WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs 966 // 967 UCHAR interfacePairsNum = 0; 968 UCHAR bitArray[UCHAR_MAX/sizeof(UCHAR)]; 969 970 // 971 // initialize the bit array 972 // 973 RtlZeroMemory(bitArray, sizeof(bitArray)); 974 // 975 // Build a list of descriptors from the Setting pairs 976 // passed in by the user. There could be interfaces not 977 // covered in the setting/interface pairs array passed. 978 // If that is the case return STATUS_INVALID_PARAMETER 979 // 980 for (i = 0; i < Params->Types.MultiInterface.NumberInterfaces ; i++) { 981 PWDF_USB_INTERFACE_SETTING_PAIR settingPair; 982 UCHAR interfaceNumber; 983 UCHAR altSettingIndex; 984 985 settingPair = &Params->Types.MultiInterface.Pairs[i]; 986 987 status = GetInterfaceNumberFromInterface( 988 settingPair->UsbInterface, 989 &interfaceNumber 990 ); 991 992 // 993 //convert the interface handle to interface number 994 // 995 if (NT_SUCCESS(status)) { 996 altSettingIndex = settingPair->SettingIndex; 997 998 // 999 // do the following only if the bit is not already set 1000 // 1001 if (FxBitArraySet(&bitArray[0], interfaceNumber) == FALSE) { 1002 pList[interfacePairsNum].InterfaceDescriptor = 1003 FxUsbParseConfigurationDescriptor( 1004 m_ConfigDescriptor, 1005 interfaceNumber, 1006 altSettingIndex 1007 ); 1008 1009 if (pList[interfacePairsNum].InterfaceDescriptor == NULL) { 1010 status = STATUS_INVALID_PARAMETER; 1011 DoTraceLevelMessage( 1012 GetDriverGlobals(), TRACE_LEVEL_ERROR, 1013 TRACINGIOTARGET, 1014 "WDFUSBDEVICE %p could not retrieve " 1015 "AlternateSetting %d for " 1016 "bInterfaceNumber %d, returning %!STATUS!", 1017 GetHandle(), 1018 altSettingIndex, interfaceNumber, status); 1019 goto Done; 1020 } 1021 1022 interfacePairsNum++; 1023 } 1024 } 1025 else { 1026 goto Done; 1027 } 1028 } 1029 1030 // 1031 // Check if there are any interfaces not specified by the array. If 1032 // there are, then select setting 0 for them. 1033 // 1034 if (m_NumInterfaces > interfacePairsNum) { 1035 status = STATUS_INVALID_PARAMETER; 1036 DoTraceLevelMessage( 1037 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1038 "WDFUSBDEVICE %p interface pairs set (%d) is not equal to actual " 1039 "# of interfaces (%d) reported by the device, %!STATUS!", 1040 GetObjectHandle(), interfacePairsNum, m_NumInterfaces, status); 1041 goto Done; 1042 } 1043 } //WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs 1044 1045 urb = FxUsbCreateConfigRequest( 1046 GetDriverGlobals(), 1047 m_ConfigDescriptor, 1048 pList, 1049 GetDefaultMaxTransferSize() 1050 ); 1051 1052 if (urb == NULL) { 1053 status = STATUS_INSUFFICIENT_RESOURCES; 1054 } 1055 else { 1056 status = SelectConfig( 1057 PipesAttributes, 1058 urb, 1059 FxUrbTypeLegacy, 1060 &Params->Types.MultiInterface.NumberOfConfiguredInterfaces); 1061 1062 FxPoolFree(urb); 1063 urb = NULL; 1064 } 1065 1066 Done: 1067 FxPoolFree(pList); 1068 pList = NULL; 1069 1070 return status; 1071 } 1072 1073 _Must_inspect_result_ 1074 NTSTATUS 1075 FxUsbDevice::Reset( 1076 VOID 1077 ) 1078 { 1079 FxIoContext context; 1080 FxSyncRequest request(GetDriverGlobals(), &context); 1081 FxRequestBuffer emptyBuffer; 1082 NTSTATUS status; 1083 1084 // 1085 // FxSyncRequest always succeesds for KM. 1086 // 1087 status = request.Initialize(); 1088 if (!NT_SUCCESS(status)) { 1089 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1090 "Failed to initialize FxSyncRequest"); 1091 return status; 1092 } 1093 1094 status = FormatIoctlRequest(request.m_TrueRequest, 1095 IOCTL_INTERNAL_USB_RESET_PORT, 1096 TRUE, 1097 &emptyBuffer, 1098 &emptyBuffer); 1099 if (NT_SUCCESS(status)) { 1100 CancelSentIo(); 1101 status = SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, NULL); 1102 } 1103 1104 return status; 1105 } 1106 1107 1108