1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxPkgPdo.cpp 8 9 Abstract: 10 11 This module implements the Pnp package for Pdo devices. 12 13 Author: 14 15 16 17 Environment: 18 19 Both kernel and user mode 20 21 Revision History: 22 23 24 25 26 --*/ 27 28 #include "pnppriv.hpp" 29 #include <wdmguid.h> 30 31 // Tracing support 32 #if defined(EVENT_TRACING) 33 extern "C" { 34 #include "FxPkgPdo.tmh" 35 } 36 #endif 37 38 const PFN_PNP_POWER_CALLBACK FxPkgPdo::m_PdoPnpFunctionTable[IRP_MN_SURPRISE_REMOVAL + 1] = 39 { 40 _PnpStartDevice, // IRP_MN_START_DEVICE 41 _PnpQueryRemoveDevice, // IRP_MN_QUERY_REMOVE_DEVICE 42 _PnpRemoveDevice, // IRP_MN_REMOVE_DEVICE 43 _PnpCancelRemoveDevice, // IRP_MN_CANCEL_REMOVE_DEVICE 44 _PnpStopDevice, // IRP_MN_STOP_DEVICE 45 _PnpQueryStopDevice, // IRP_MN_QUERY_STOP_DEVICE 46 _PnpCancelStopDevice, // IRP_MN_CANCEL_STOP_DEVICE 47 48 _PnpQueryDeviceRelations, // IRP_MN_QUERY_DEVICE_RELATIONS 49 _PnpQueryInterface, // IRP_MN_QUERY_INTERFACE 50 _PnpQueryCapabilities, // IRP_MN_QUERY_CAPABILITIES 51 _PnpQueryResources, // IRP_MN_QUERY_RESOURCES 52 _PnpQueryResourceRequirements, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS 53 _PnpQueryDeviceText, // IRP_MN_QUERY_DEVICE_TEXT 54 _PnpFilterResourceRequirements, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS 55 56 _PnpCompleteIrp, // 0x0E 57 58 _PnpCompleteIrp, // IRP_MN_READ_CONFIG 59 _PnpCompleteIrp, // IRP_MN_WRITE_CONFIG 60 _PnpEject, // IRP_MN_EJECT 61 _PnpSetLock, // IRP_MN_SET_LOCK 62 _PnpQueryId, // IRP_MN_QUERY_ID 63 _PnpQueryPnpDeviceState, // IRP_MN_QUERY_PNP_DEVICE_STATE 64 _PnpQueryBusInformation, // IRP_MN_QUERY_BUS_INFORMATION 65 _PnpDeviceUsageNotification, // IRP_MN_DEVICE_USAGE_NOTIFICATION 66 _PnpSurpriseRemoval, // IRP_MN_SURPRISE_REMOVAL 67 }; 68 69 const PFN_PNP_POWER_CALLBACK FxPkgPdo::m_PdoPowerFunctionTable[IRP_MN_QUERY_POWER + 1] = 70 { 71 _DispatchWaitWake, // IRP_MN_WAIT_WAKE 72 _DispatchPowerSequence, // IRP_MN_POWER_SEQUENCE 73 _DispatchSetPower, // IRP_MN_SET_POWER 74 _DispatchQueryPower, // IRP_MN_QUERY_POWER 75 }; 76 77 //#if defined(ALLOC_PRAGMA) 78 //#pragma code_seg("PAGE") 79 //#endif 80 81 FxPkgPdo::FxPkgPdo( 82 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 83 __in CfxDevice *Device 84 ) : 85 FxPkgPnp(FxDriverGlobals, Device, FX_TYPE_PACKAGE_PDO) 86 /*++ 87 88 Routine Description: 89 90 This is the constructor for the FxPkgPdo. Don't do any initialization 91 that might fail here. 92 93 Arguments: 94 95 none 96 97 Returns: 98 99 none 100 101 --*/ 102 103 { 104 m_DeviceTextHead.Next = NULL; 105 106 m_DeviceID = NULL; 107 m_InstanceID = NULL; 108 m_HardwareIDs = NULL; 109 m_CompatibleIDs = NULL; 110 m_ContainerID = NULL; 111 m_IDsAllocation = NULL; 112 113 m_RawOK = FALSE; 114 m_Static = FALSE; 115 m_AddedToStaticList = FALSE; 116 117 // 118 // By default the PDO is the owner of wait wake irps (only case where this 119 // wouldn't be the case is for a bus filter to be sitting above us). 120 // 121 m_SharedPower.m_WaitWakeOwner = TRUE; 122 123 m_Description = NULL; 124 m_OwningChildList = NULL; 125 126 m_EjectionDeviceList = NULL; 127 m_DeviceEjectProcessed = NULL; 128 129 m_CanBeDeleted = FALSE; 130 m_EnableWakeAtBusInvoked = FALSE; 131 } 132 133 FxPkgPdo::~FxPkgPdo( 134 VOID 135 ) 136 /*++ 137 138 Routine Description: 139 140 This is the destructor for the FxPkgPdo 141 142 Arguments: 143 144 none 145 146 Returns: 147 148 none 149 150 --*/ 151 { 152 // 153 // If IoCreateDevice fails on a dynamically created PDO, m_Description will 154 // be != NULL b/c we will not go through the pnp state machine in its entirety 155 // for cleanup. FxChildList will need a valid m_Description to cleanup upon 156 // failure from EvtChildListDeviceCrate, so we just leave m_Description alone 157 // here if != NULL. 158 // 159 // ASSERT(m_Description == NULL); 160 161 FxDeviceText::_CleanupList(&m_DeviceTextHead); 162 163 // 164 // This will free the underlying memory for m_DeviceID, m_InstanceID, 165 // m_HardwareIDs, m_CompatibleIDs and m_ContainerID 166 // 167 if (m_IDsAllocation != NULL) { 168 FxPoolFree(m_IDsAllocation); 169 m_IDsAllocation = NULL; 170 } 171 172 if (m_OwningChildList != NULL) { 173 m_OwningChildList->RELEASE(this); 174 } 175 176 if (m_EjectionDeviceList != NULL) { 177 delete m_EjectionDeviceList; 178 m_EjectionDeviceList = NULL; 179 } 180 } 181 182 _Must_inspect_result_ 183 NTSTATUS 184 FxPkgPdo::Initialize( 185 __in PWDFDEVICE_INIT DeviceInit 186 ) 187 /*++ 188 189 Routine Description: 190 191 Do initialization that might fail here. 192 193 Arguemnts: 194 195 DeviceInit - the structure the driver passed in with initialization data 196 197 Returns: 198 199 NTSTATUS 200 201 --*/ 202 { 203 NTSTATUS status; 204 size_t cbLength, cbStrLength; 205 PWSTR pCur; 206 PdoInit* pPdo; 207 208 status = FxPkgPnp::Initialize(DeviceInit); 209 if (!NT_SUCCESS(status)) { 210 return status; 211 } 212 213 cbLength = 0; 214 215 // 216 // Compute the total number of bytes required for all strings and then 217 // make one allocation and remember pointers w/in the string so we can 218 // retrieve them individually later. 219 // 220 pPdo = &DeviceInit->Pdo; 221 cbLength += FxCalculateTotalStringSize(&pPdo->HardwareIDs); 222 cbLength += FxCalculateTotalStringSize(&pPdo->CompatibleIDs); 223 224 if (pPdo->DeviceID != NULL) { 225 cbLength += pPdo->DeviceID->ByteLength(TRUE); 226 } 227 if (pPdo->InstanceID != NULL) { 228 cbLength += pPdo->InstanceID->ByteLength(TRUE); 229 } 230 if (pPdo->ContainerID != NULL) { 231 cbLength += pPdo->ContainerID->ByteLength(TRUE); 232 } 233 234 m_IDsAllocation = (PWSTR) FxPoolAllocate(GetDriverGlobals(), 235 PagedPool, 236 cbLength); 237 238 if (m_IDsAllocation == NULL) { 239 status = STATUS_INSUFFICIENT_RESOURCES; 240 241 DoTraceLevelMessage( 242 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 243 "DeviceInit %p could not allocate string for device IDs " 244 "(length %I64d), %!STATUS!", DeviceInit, cbLength, status); 245 246 return status; 247 } 248 249 pCur = m_IDsAllocation; 250 251 m_HardwareIDs = pCur; 252 pCur = FxCopyMultiSz(m_HardwareIDs, &pPdo->HardwareIDs); 253 254 m_CompatibleIDs = pCur; 255 pCur = FxCopyMultiSz(m_CompatibleIDs, &pPdo->CompatibleIDs); 256 257 if (pPdo->DeviceID != NULL) { 258 m_DeviceID = pCur; 259 260 // 261 // Copy the bytes and then null terminate the buffer 262 // 263 cbStrLength = pPdo->DeviceID->ByteLength(FALSE); 264 265 RtlCopyMemory(m_DeviceID, 266 pPdo->DeviceID->Buffer(), 267 cbStrLength); 268 269 m_DeviceID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL; 270 271 pCur = (PWSTR) WDF_PTR_ADD_OFFSET(m_DeviceID, 272 cbStrLength + sizeof(UNICODE_NULL)); 273 } 274 275 if (pPdo->InstanceID != NULL) { 276 m_InstanceID = pCur; 277 278 // 279 // Copy the bytes and then null terminate the buffer 280 // 281 cbStrLength = pPdo->InstanceID->ByteLength(FALSE); 282 283 RtlCopyMemory(m_InstanceID, 284 pPdo->InstanceID->Buffer(), 285 cbStrLength); 286 287 m_InstanceID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL; 288 289 pCur = (PWSTR) WDF_PTR_ADD_OFFSET(m_InstanceID, 290 cbStrLength + sizeof(UNICODE_NULL)); 291 } 292 293 if (pPdo->ContainerID != NULL) { 294 m_ContainerID = pCur; 295 296 // 297 // Copy the bytes and then null terminate the buffer 298 // 299 cbStrLength = pPdo->ContainerID->ByteLength(FALSE); 300 301 RtlCopyMemory(m_ContainerID, 302 pPdo->ContainerID->Buffer(), 303 cbStrLength); 304 305 m_ContainerID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL; 306 } 307 308 m_Static = pPdo->Static; 309 310 if (m_Static) { 311 // 312 // Statically enumerated children do not support reenumeration requests 313 // from the stack on top of them. 314 // 315 316 // 317 // The only way we can have static children is if an FDO enumerates them. 318 // 319 320 321 322 323 324 Mx::MxAssert(m_Device->m_ParentDevice->IsFdo()); 325 m_OwningChildList = m_Device->m_ParentDevice->GetFdoPkg()->m_StaticDeviceList; 326 327 m_OwningChildList->ADDREF(this); 328 } 329 else { 330 m_Description = pPdo->DescriptionEntry; 331 332 m_OwningChildList = m_Description->GetParentList(); 333 m_OwningChildList->ADDREF(this); 334 } 335 336 return STATUS_SUCCESS; 337 } 338 339 VOID 340 FxPkgPdo::FinishInitialize( 341 __in PWDFDEVICE_INIT DeviceInit 342 ) 343 { 344 PdoInit* pdoInit; 345 346 pdoInit = &DeviceInit->Pdo; 347 348 m_DefaultLocale = pdoInit->DefaultLocale; 349 m_DeviceTextHead.Next = pdoInit->DeviceText.Next; 350 pdoInit->DeviceText.Next = NULL; 351 352 // 353 // Important to do this last since this will cause a pnp state machine 354 // transition 355 // 356 FxPkgPnp::FinishInitialize(DeviceInit); // __super call 357 } 358 359 _Must_inspect_result_ 360 NTSTATUS 361 FxPkgPdo::SendIrpSynchronously( 362 __in FxIrp* Irp 363 ) 364 /*++ 365 366 Routine Description: 367 Virtual override for synchronously sending a request down the stack and 368 catching it on the way back up. For PDOs, we are the bottom, so this is a 369 no-op. 370 371 Arguments: 372 Irp - The request 373 374 Return Value: 375 Status in the Irp 376 377 --*/ 378 { 379 return Irp->GetStatus(); 380 } 381 382 _Must_inspect_result_ 383 NTSTATUS 384 FxPkgPdo::FireAndForgetIrp( 385 __inout FxIrp *Irp 386 ) 387 /*++ 388 389 Routine Description: 390 391 Virtual override for sending a request down the stack and forgetting about 392 it. Since we are the bottom of the stack, just complete the request. 393 394 Arguments: 395 396 Return Value: 397 398 --*/ 399 { 400 NTSTATUS status; 401 402 status = Irp->GetStatus(); 403 404 if (Irp->GetMajorFunction() == IRP_MJ_POWER) { 405 return CompletePowerRequest(Irp, status); 406 } 407 else { 408 return CompletePnpRequest(Irp, status); 409 } 410 } 411 412 _Must_inspect_result_ 413 NTSTATUS 414 FxPkgPdo::_PnpCompleteIrp( 415 __in FxPkgPnp* This, 416 __inout FxIrp *Irp 417 ) 418 { 419 return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, Irp->GetStatus()); 420 } 421 422 _Must_inspect_result_ 423 NTSTATUS 424 FxPkgPdo::_PnpQueryDeviceRelations( 425 __in FxPkgPnp* This, 426 __inout FxIrp *Irp 427 ) 428 { 429 return ((FxPkgPdo*) This)->PnpQueryDeviceRelations(Irp); 430 } 431 432 _Must_inspect_result_ 433 NTSTATUS 434 FxPkgPdo::PnpQueryDeviceRelations( 435 __inout FxIrp *Irp 436 ) 437 /*++ 438 439 Routine Description: 440 441 This method is called in response to a PnP QDR. PDOs handle Ejection 442 Relations and Target Relations. 443 444 Arguments: 445 446 Irp - a pointer to the FxIrp 447 448 Returns: 449 450 NTSTATUS 451 452 --*/ 453 { 454 PDEVICE_RELATIONS pDeviceRelations; 455 NTSTATUS status; 456 DEVICE_RELATION_TYPE type; 457 PFX_DRIVER_GLOBALS pFxDriverGlobals; 458 459 status = Irp->GetStatus(); 460 pFxDriverGlobals = GetDriverGlobals(); 461 462 type = Irp->GetParameterQDRType(); 463 switch (type) { 464 case BusRelations: 465 status = HandleQueryBusRelations(Irp); 466 break; 467 468 case EjectionRelations: 469 case RemovalRelations: 470 status = HandleQueryDeviceRelations( 471 Irp, 472 (type == RemovalRelations) ? m_RemovalDeviceList 473 : m_EjectionDeviceList); 474 475 // 476 // STATUS_NOT_SUPPORTED is a special value. It means that 477 // HandleQueryDeviceRelations did not modify the irp at all and it 478 // should be sent off as is. 479 // 480 if (status == STATUS_NOT_SUPPORTED) { 481 // 482 // Complete the request with the status it was received with 483 // 484 status = Irp->GetStatus(); 485 } 486 break; 487 488 case TargetDeviceRelation: 489 pDeviceRelations = (PDEVICE_RELATIONS) MxMemory::MxAllocatePoolWithTag( 490 PagedPool, sizeof(DEVICE_RELATIONS), pFxDriverGlobals->Tag); 491 492 if (pDeviceRelations != NULL) { 493 PDEVICE_OBJECT pDeviceObject; 494 495 pDeviceObject = reinterpret_cast<PDEVICE_OBJECT> (m_Device->GetDeviceObject()); 496 497 Mx::MxReferenceObject(pDeviceObject); 498 499 pDeviceRelations->Count = 1; 500 pDeviceRelations->Objects[0] = pDeviceObject; 501 502 Irp->SetInformation((ULONG_PTR) pDeviceRelations); 503 status = STATUS_SUCCESS; 504 } 505 else { 506 Irp->SetInformation(NULL); 507 status = STATUS_INSUFFICIENT_RESOURCES; 508 509 DoTraceLevelMessage( 510 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 511 "WDFDEVICE %p failing TargetDeviceRelations, %!STATUS!", 512 m_Device->GetHandle(), status); 513 } 514 break; 515 } 516 517 return CompletePnpRequest(Irp, status); 518 } 519 520 _Must_inspect_result_ 521 NTSTATUS 522 FxPkgPdo::_PnpQueryInterface( 523 IN FxPkgPnp* This, 524 IN FxIrp *Irp 525 ) 526 /*++ 527 528 Routine Description: 529 Query interface handler for the PDO 530 531 Arguments: 532 This - the package 533 534 Irp - the QI request 535 536 Return Value: 537 NTSTATUS 538 539 --*/ 540 { 541 NTSTATUS status; 542 BOOLEAN completeIrp; 543 544 status = ((FxPkgPdo*) This)->HandleQueryInterface(Irp, &completeIrp); 545 546 return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, status); 547 } 548 549 _Must_inspect_result_ 550 NTSTATUS 551 FxPkgPdo::_PnpQueryCapabilities( 552 __inout FxPkgPnp* This, 553 __inout FxIrp *Irp 554 ) 555 { 556 return ((FxPkgPdo*) This)->PnpQueryCapabilities(Irp); 557 } 558 559 _Must_inspect_result_ 560 NTSTATUS 561 FxPkgPdo::PnpQueryCapabilities( 562 __inout FxIrp *Irp 563 ) 564 565 /*++ 566 567 Routine Description: 568 569 This method is invoked in response to a Pnp QueryCapabilities IRP. 570 571 Arguments: 572 573 Irp - a pointer to the FxIrp 574 575 Returns: 576 577 NTSTATUS 578 579 --*/ 580 581 { 582 PDEVICE_CAPABILITIES pDeviceCapabilities; 583 STACK_DEVICE_CAPABILITIES parentStackCapabilities = {0}; 584 NTSTATUS status; 585 586 status = STATUS_UNSUCCESSFUL; 587 588 pDeviceCapabilities = Irp->GetParameterDeviceCapabilities(); 589 590 // 591 // Confirm this is a valid DeviceCapabilities structure. 592 // 593 ASSERT(pDeviceCapabilities->Size >= sizeof(DEVICE_CAPABILITIES)); 594 ASSERT(pDeviceCapabilities->Version == 1); 595 596 if ((pDeviceCapabilities->Version == 1) && 597 (pDeviceCapabilities->Size >= sizeof(DEVICE_CAPABILITIES))) { 598 599 // 600 // Since query caps must be sent to the parent stack until it reaches 601 // the root, we can quickly run out of stack space. If that happens, 602 // then move to a work item to get a fresh stack with plenty of stack 603 // space. 604 // 605 if (Mx::MxHasEnoughRemainingThreadStack() == FALSE) { 606 MxWorkItem workItem; 607 608 status = workItem.Allocate(m_Device->GetDeviceObject()); 609 610 if (NT_SUCCESS(status)) { 611 // 612 // Store off the work item so we can free it in the worker routine 613 // 614 Irp->SetContext(0, (PVOID)workItem.GetWorkItem()); 615 616 // 617 // Mark the irp as pending because it will be completed in 618 // another thread 619 // 620 Irp->MarkIrpPending(); 621 622 // 623 // Kick off to another thread 624 // 625 workItem.Enqueue(_QueryCapsWorkItem, Irp->GetIrp()); 626 627 return STATUS_PENDING; 628 } 629 else { 630 // 631 // Not enough for a work item, return error 632 // 633 status = STATUS_INSUFFICIENT_RESOURCES; 634 } 635 } 636 else { 637 MxDeviceObject parentDeviceObject; 638 639 parentDeviceObject.SetObject( 640 m_Device->m_ParentDevice->GetDeviceObject()); 641 status = GetStackCapabilities( 642 GetDriverGlobals(), 643 &parentDeviceObject, 644 NULL, // D3ColdInterface 645 &parentStackCapabilities); 646 647 if (NT_SUCCESS(status)) { 648 #pragma prefast(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "prefast is confused") 649 HandleQueryCapabilities(pDeviceCapabilities, 650 &parentStackCapabilities.DeviceCaps); 651 652 // 653 // The check above does not guarantee STATUS_SUCCESS explicitly 654 // (ie the verifier can change the value to something other then 655 // STATUS_SUCCESS) so set it here 656 // 657 status = STATUS_SUCCESS; 658 } 659 } 660 } 661 662 return CompletePnpRequest(Irp, status); 663 } 664 665 VOID 666 FxPkgPdo::HandleQueryCapabilities( 667 __inout PDEVICE_CAPABILITIES ReportedCaps, 668 __in_bcount(ParentCaps->size) PDEVICE_CAPABILITIES ParentCaps 669 ) 670 { 671 LONG pnpCaps; 672 ULONG i; 673 674 // 675 // PowerSystemUnspecified is reserved for system use as per the DDK 676 // 677 for (i = PowerSystemWorking; i < PowerSystemMaximum; i++) { 678 DEVICE_POWER_STATE state; 679 680 state = _GetPowerCapState(i, m_PowerCaps.States); 681 682 if (state == PowerDeviceMaximum) { 683 // 684 // PDO did not specify any value, use parent's cap 685 // 686 #pragma prefast(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "Esp:675") 687 ReportedCaps->DeviceState[i] = ParentCaps->DeviceState[i]; 688 } 689 else { 690 // 691 // Use PDO's reported value 692 // 693 ReportedCaps->DeviceState[i] = state; 694 } 695 } 696 697 pnpCaps = GetPnpCapsInternal(); 698 699 // 700 // Appropriately fill the DeviceCapabilities structure. 701 // 702 SET_PNP_CAP(pnpCaps, ReportedCaps, LockSupported); 703 SET_PNP_CAP(pnpCaps, ReportedCaps, EjectSupported); 704 SET_PNP_CAP(pnpCaps, ReportedCaps, Removable); 705 SET_PNP_CAP(pnpCaps, ReportedCaps, DockDevice); 706 SET_PNP_CAP(pnpCaps, ReportedCaps, UniqueID); 707 708 if ((pnpCaps & FxPnpCapSilentInstallMask) != FxPnpCapSilentInstallUseDefault) { 709 SET_PNP_CAP(pnpCaps, ReportedCaps, SilentInstall); 710 } 711 else if (m_RawOK) { 712 // 713 // By default, we report raw devices as silent install devices 714 // because if they are raw, they don't need any further 715 // installation. 716 // 717 ReportedCaps->SilentInstall = TRUE; 718 } 719 720 SET_PNP_CAP(pnpCaps, ReportedCaps, SurpriseRemovalOK); 721 SET_PNP_CAP(pnpCaps, ReportedCaps, HardwareDisabled); 722 SET_PNP_CAP(pnpCaps, ReportedCaps, NoDisplayInUI); 723 724 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD0); 725 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD1); 726 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD2); 727 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD3); 728 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, DeviceD1); 729 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, DeviceD2); 730 731 if (m_RawOK) { 732 ReportedCaps->RawDeviceOK = TRUE; 733 } 734 735 ReportedCaps->UINumber = m_PnpCapsUINumber; 736 ReportedCaps->Address = m_PnpCapsAddress; 737 738 if (m_PowerCaps.SystemWake != PowerSystemMaximum) { 739 ReportedCaps->SystemWake = (SYSTEM_POWER_STATE) m_PowerCaps.SystemWake; 740 } 741 else { 742 ReportedCaps->SystemWake = ParentCaps->SystemWake; 743 } 744 745 // 746 // Set the least-powered device state from which the device can 747 // wake the system. 748 // 749 if (m_PowerCaps.DeviceWake != PowerDeviceMaximum) { 750 ReportedCaps->DeviceWake = (DEVICE_POWER_STATE) m_PowerCaps.DeviceWake; 751 } 752 else { 753 ReportedCaps->DeviceWake = ParentCaps->DeviceWake; 754 } 755 756 // 757 // Set the Device wake up latencies. 758 // 759 if (m_PowerCaps.D1Latency != (ULONG) -1) { 760 ReportedCaps->D1Latency = m_PowerCaps.D1Latency; 761 } 762 else { 763 ReportedCaps->D1Latency = 0; 764 } 765 766 if (m_PowerCaps.D2Latency != (ULONG) -1) { 767 ReportedCaps->D2Latency = m_PowerCaps.D2Latency; 768 } 769 else { 770 ReportedCaps->D2Latency = 0; 771 } 772 773 if (m_PowerCaps.D3Latency != (ULONG) -1) { 774 ReportedCaps->D3Latency = m_PowerCaps.D3Latency; 775 } 776 } 777 778 VOID 779 FxPkgPdo::_QueryCapsWorkItem( 780 __in MdDeviceObject DeviceObject, 781 __in PVOID Context 782 ) 783 { 784 STACK_DEVICE_CAPABILITIES parentCapabilities; 785 MdWorkItem pItem; 786 FxPkgPdo* pPkgPdo; 787 FxIrp irp; 788 NTSTATUS status; 789 MxDeviceObject parentDeviceObject; 790 791 irp.SetIrp((MdIrp)Context); 792 pItem = (MdWorkItem) irp.GetContext(0); 793 794 pPkgPdo = FxDevice::GetFxDevice(DeviceObject)->GetPdoPkg(); 795 796 parentDeviceObject.SetObject( 797 pPkgPdo->m_Device->m_ParentDevice->GetDeviceObject()); 798 799 status = GetStackCapabilities( 800 pPkgPdo->m_Device->GetDriverGlobals(), 801 &parentDeviceObject, 802 NULL, // D3ColdInterface 803 &parentCapabilities); 804 805 if (NT_SUCCESS(status)) { 806 #pragma prefast(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "prefast is confused") 807 pPkgPdo->HandleQueryCapabilities( 808 irp.GetParameterDeviceCapabilities(), 809 &parentCapabilities.DeviceCaps 810 ); 811 status = STATUS_SUCCESS; 812 } 813 814 pPkgPdo->CompletePnpRequest(&irp, status); 815 816 MxWorkItem::_Free(pItem); 817 } 818 819 FxDeviceText * 820 FindObjectForGivenLocale( 821 __in PSINGLE_LIST_ENTRY Head, 822 __in LCID LocaleId 823 ) 824 825 /*++ 826 827 Routine Description: 828 829 830 831 Arguments: 832 833 Returns: 834 835 --*/ 836 837 { 838 PSINGLE_LIST_ENTRY ple; 839 840 for (ple = Head->Next; ple != NULL; ple = ple->Next) { 841 FxDeviceText *pDeviceText; 842 843 pDeviceText= FxDeviceText::_FromEntry(ple); 844 845 if (pDeviceText->m_LocaleId == LocaleId) { 846 // 847 // We found our object! 848 // 849 return pDeviceText; 850 } 851 } 852 853 return NULL; 854 } 855 856 _Must_inspect_result_ 857 NTSTATUS 858 FxPkgPdo::_PnpQueryDeviceText( 859 __inout FxPkgPnp* This, 860 __inout FxIrp *Irp 861 ) 862 863 /*++ 864 865 Routine Description: 866 867 This method is invoked in response to a Pnp QueryDeviceText IRP. 868 We return the decription or the location. 869 870 Arguments: 871 872 Irp - a pointer to the FxIrp 873 874 Returns: 875 876 NTSTATUS 877 878 --*/ 879 880 { 881 FxPkgPdo* pThis; 882 LCID localeId; 883 FxDeviceText *pDeviceTextObject; 884 NTSTATUS status; 885 PFX_DRIVER_GLOBALS pFxDriverGlobals; 886 887 pThis = (FxPkgPdo*) This; 888 pFxDriverGlobals = pThis->GetDriverGlobals(); 889 890 localeId = Irp->GetParameterQueryDeviceTextLocaleId(); 891 status = Irp->GetStatus(); 892 893 // 894 // The PDO package maintains a collection of "DeviceText" objects. We 895 // will look up the item in the collection with the "appropriate" locale. 896 // 897 // If no entries are found in the collection for the given locale, then 898 // we will use the "default locale" property of the PDO and use the 899 // entry for the "default locale". 900 // 901 902 // 903 // Try to find the FxDeviceText object for the given locale. 904 // 905 pDeviceTextObject = FindObjectForGivenLocale( 906 &pThis->m_DeviceTextHead, localeId); 907 908 if (pDeviceTextObject == NULL) { 909 pDeviceTextObject = FindObjectForGivenLocale( 910 &pThis->m_DeviceTextHead, pThis->m_DefaultLocale); 911 } 912 913 if (pDeviceTextObject != NULL) { 914 PWCHAR pInformation; 915 916 pInformation = NULL; 917 918 switch (Irp->GetParameterQueryDeviceTextType()) { 919 case DeviceTextDescription: 920 pInformation = pDeviceTextObject->m_Description; 921 break; 922 923 case DeviceTextLocationInformation: 924 pInformation = pDeviceTextObject->m_LocationInformation; 925 break; 926 } 927 928 // 929 // Information should now point to a valid unicode string. 930 // 931 if (pInformation != NULL) { 932 PWCHAR pBuffer; 933 size_t length; 934 935 length = (wcslen(pInformation) + 1) * sizeof(WCHAR); 936 937 // 938 // Make sure the information field of the IRP isn't already set. 939 // 940 ASSERT(Irp->GetInformation() == NULL); 941 942 pBuffer = (PWCHAR) MxMemory::MxAllocatePoolWithTag( 943 PagedPool, length, pFxDriverGlobals->Tag); 944 945 if (pBuffer != NULL) { 946 RtlCopyMemory(pBuffer, pInformation, length); 947 Irp->SetInformation((ULONG_PTR) pBuffer); 948 949 status = STATUS_SUCCESS; 950 } 951 else { 952 status = STATUS_INSUFFICIENT_RESOURCES; 953 954 DoTraceLevelMessage( 955 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 956 "WDFDEVICE %p failing Query Device Text, type %d, %!STATUS!", 957 pThis->m_Device->GetHandle(), 958 Irp->GetParameterQueryDeviceTextType(), status); 959 } 960 } 961 } 962 963 return pThis->CompletePnpRequest(Irp, status); 964 } 965 966 _Must_inspect_result_ 967 NTSTATUS 968 FxPkgPdo::_PnpEject( 969 __inout FxPkgPnp* This, 970 __inout FxIrp *Irp 971 ) 972 /*++ 973 974 Routine Description: 975 976 Ejection is handled by the PnP state machine. Handle it synchronously. 977 Don't pend it since PnP manager does not serilaize it with other state 978 changing pnp irps if handled asynchronously. 979 980 Arguments: 981 982 This - the package 983 984 Irp - the request 985 986 Return Value: 987 988 NTSTATUS 989 990 --*/ 991 { 992 MxEvent event; 993 FxPkgPdo* pdoPkg; 994 NTSTATUS status; 995 996 pdoPkg = (FxPkgPdo*)This; 997 998 // 999 // This will make sure no new state changing pnp irps arrive while 1000 // we are still processing this one. Also, note that irp is not being 1001 // marked pending. 1002 // 1003 pdoPkg->SetPendingPnpIrp(Irp, FALSE); 1004 1005 status = event.Initialize(SynchronizationEvent, FALSE); 1006 if (!NT_SUCCESS(status)) { 1007 1008 DoTraceLevelMessage( 1009 pdoPkg->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1010 "Event allocation failed while processing eject for WDFDEVICE %p," 1011 " %!STATUS!", 1012 pdoPkg->m_Device->GetHandle(), status); 1013 } 1014 else { 1015 ASSERT(pdoPkg->m_DeviceEjectProcessed == NULL); 1016 pdoPkg->m_DeviceEjectProcessed = event.GetSelfPointer(); 1017 1018 // 1019 // let state machine process eject 1020 // 1021 pdoPkg->PnpProcessEvent(PnpEventEject); 1022 1023 // 1024 // No need to wait in a critical region because we are in the context of a 1025 // pnp request which is in the system context. 1026 // 1027 event.WaitFor(Executive, KernelMode, FALSE, NULL); 1028 1029 pdoPkg->m_DeviceEjectProcessed = NULL; 1030 1031 status = Irp->GetStatus(); 1032 } 1033 1034 // 1035 // complete request 1036 // 1037 1038 pdoPkg->ClearPendingPnpIrp(); 1039 pdoPkg->CompletePnpRequest(Irp, status); 1040 1041 return status; 1042 } 1043 1044 WDF_DEVICE_PNP_STATE 1045 FxPkgPdo::PnpEventEjectHardwareOverload( 1046 VOID 1047 ) 1048 /*++ 1049 1050 Routine Description: 1051 1052 This function implements the EjectHardware state. This 1053 function overloads the base PnP State machine handler. Its 1054 job is to call EvtDeviceEject. If that succeeds, then we 1055 transition immediately to EjectedWaitingForRemove. If not, 1056 then to EjectFailed. 1057 1058 Arguments: 1059 1060 none 1061 1062 Return Value: 1063 1064 NTSTATUS 1065 1066 --*/ 1067 { 1068 NTSTATUS status; 1069 WDF_DEVICE_PNP_STATE state; 1070 1071 status = m_DeviceEject.Invoke(m_Device->GetHandle()); 1072 1073 if (NT_SUCCESS(status)) { 1074 1075 // 1076 // Upon a successful eject, mark the child as missing so that when we 1077 // get another QDR, it is not re-reported. 1078 // 1079 FxChildList* pList; 1080 MxEvent* event; 1081 1082 pList = m_Description->GetParentList(); 1083 1084 status = pList->UpdateAsMissing(m_Description->GetId()); 1085 if (NT_SUCCESS(status)) { 1086 DoTraceLevelMessage( 1087 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 1088 "PDO WDFDEVICE %p !devobj %p marked missing as a result of eject", 1089 m_Device->GetHandle(), m_Device->GetDeviceObject()); 1090 } 1091 else { 1092 DoTraceLevelMessage( 1093 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1094 "Failed to mark PDO WDFDEVICE %p !devobj %p missing after eject %!STATUS!", 1095 m_Device->GetHandle(), m_Device->GetDeviceObject(), 1096 status); 1097 } 1098 1099 // 1100 // We must wait for any pending scans to finish so that the previous 1101 // update as missing is enacted into the list and reported to the 1102 // OS. Otherwise, if we don't wait we could be in the middle of a 1103 // scan, complete the eject, report the child again and it will be 1104 // reenumerated. 1105 // 1106 event = pList->GetScanEvent(); 1107 1108 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 1109 "waiting on event %p for device to finish scanning", 1110 &event); 1111 1112 // 1113 // No need to wait in a crtical region because we are in the context of a 1114 // pnp request which is in the system context. 1115 // 1116 event->WaitFor(Executive, KernelMode, FALSE, NULL); 1117 1118 // 1119 // Change the state. 1120 // 1121 state = WdfDevStatePnpEjectedWaitingForRemove; 1122 } 1123 else { 1124 state = WdfDevStatePnpEjectFailed; 1125 DoTraceLevelMessage( 1126 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1127 "Eject failed since driver's EvtDeviceEject returned %!STATUS!", status); 1128 1129 if (status == STATUS_NOT_SUPPORTED) { 1130 DoTraceLevelMessage( 1131 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, 1132 "EvtDeviceEject returned an invalid status STATUS_NOT_SUPPORTED"); 1133 1134 if (GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) { 1135 FxVerifierDbgBreakPoint(GetDriverGlobals()); 1136 } 1137 } 1138 } 1139 1140 // 1141 // set irp status 1142 // 1143 SetPendingPnpIrpStatus(status); 1144 1145 // 1146 // Pnp dispatch routine is waiting on this event, and it will complete 1147 // the Eject irp 1148 // 1149 m_DeviceEjectProcessed->Set(); 1150 1151 return state; 1152 } 1153 1154 WDF_DEVICE_PNP_STATE 1155 FxPkgPdo::PnpEventCheckForDevicePresenceOverload( 1156 VOID 1157 ) 1158 /*++ 1159 1160 Routine Description: 1161 1162 This function implements the CheckForDevicePresence state. This 1163 function overloads the base PnP State machine handler. It's 1164 job is to figure out whether the removed device is actually 1165 still attached. It then changes state based on that result. 1166 1167 Arguments: 1168 1169 none 1170 1171 Return Value: 1172 1173 NTSTATUS 1174 1175 --*/ 1176 1177 { 1178 if (m_Description != NULL) { 1179 if (m_Description->IsDeviceRemoved()) { 1180 // 1181 // The description freed itself now that the device has been reported 1182 // missing. 1183 // 1184 return WdfDevStatePnpPdoRemoved; 1185 } 1186 else { 1187 // 1188 // Device was not reported as missing, keep it alive 1189 // 1190 return WdfDevStatePnpRemovedPdoWait; 1191 } 1192 } 1193 else { 1194 // 1195 // Only static children can get this far without having an m_Description 1196 // 1197 ASSERT(m_Static); 1198 1199 // 1200 // The description freed itself now that the device has been reported 1201 // missing. 1202 // 1203 return WdfDevStatePnpPdoRemoved; 1204 } 1205 } 1206 1207 WDF_DEVICE_PNP_STATE 1208 FxPkgPdo::PnpEventPdoRemovedOverload( 1209 VOID 1210 ) 1211 /*++ 1212 1213 Routine Description: 1214 1215 This function implements the Removed state. This 1216 function overloads the base PnP State machine handler. 1217 1218 Arguments: 1219 1220 none 1221 1222 Return Value: 1223 1224 NTSTATUS 1225 1226 --*/ 1227 { 1228 m_CanBeDeleted = TRUE; 1229 1230 // 1231 // Unconditionally delete the symbolic link now (vs calling 1232 // DeleteSymbolicLinkOverload()) because we know that the device has been 1233 // reported as missing. 1234 // 1235 m_Device->DeleteSymbolicLink(); 1236 1237 // 1238 // Do that which all device stacks need to do upon removal. 1239 // 1240 PnpEventRemovedCommonCode(); 1241 1242 // 1243 // m_Device is Release()'ed in FxPkgPnp::PnpEventFinal 1244 // 1245 if (m_Description != NULL) { 1246 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 1247 "Removing entry reference %p on FxPkgPnp %p", 1248 m_Description, this); 1249 1250 m_Description->ProcessDeviceRemoved(); 1251 m_Description = NULL; 1252 } 1253 1254 return WdfDevStatePnpFinal; 1255 } 1256 1257 WDF_DEVICE_PNP_STATE 1258 FxPkgPdo::PnpGetPostRemoveState( 1259 VOID 1260 ) 1261 { 1262 // 1263 // Transition to the check for device presence state. 1264 // 1265 return WdfDevStatePnpCheckForDevicePresence; 1266 } 1267 1268 WDF_DEVICE_PNP_STATE 1269 FxPkgPdo::PnpEventFdoRemovedOverload( 1270 VOID 1271 ) 1272 { 1273 ASSERT(!"This should only be implemented for FDOs."); 1274 1275 // 1276 // Do something safe. Act like the device is not present. 1277 // 1278 return WdfDevStatePnpFinal; 1279 } 1280 1281 VOID 1282 FxPkgPdo::PnpEventSurpriseRemovePendingOverload( 1283 VOID 1284 ) 1285 { 1286 if (m_Description != NULL) { 1287 m_Description->DeviceSurpriseRemoved(); 1288 } 1289 1290 FxPkgPnp::PnpEventSurpriseRemovePendingOverload(); 1291 } 1292 1293 BOOLEAN 1294 FxPkgPdo::PnpSendStartDeviceDownTheStackOverload( 1295 VOID 1296 ) 1297 /*++ 1298 1299 Routine Description: 1300 Process the start irp on the way down the stack during a start. 1301 1302 Since the PDO is the bottom, just move to the new state where we 1303 are processing the irp up the stack. 1304 1305 Arguments: 1306 None 1307 1308 Return Value: 1309 TRUE, the completion of the start irp down the stack was synchronous 1310 1311 --*/ 1312 { 1313 // 1314 // We are successful so far, indicate this in the irp. 1315 // 1316 SetPendingPnpIrpStatus(STATUS_SUCCESS); 1317 1318 return TRUE; 1319 } 1320 1321 _Must_inspect_result_ 1322 NTSTATUS 1323 FxPkgPdo::_PnpSetLock( 1324 __inout FxPkgPnp* This, 1325 __inout FxIrp *Irp 1326 ) 1327 /*++ 1328 1329 Routine Description: 1330 Set lock 1331 1332 Arguments: 1333 This - the package 1334 1335 Irp - the irp 1336 1337 Return Value: 1338 NTSTATUS 1339 1340 --*/ 1341 { 1342 NTSTATUS status; 1343 BOOLEAN lock; 1344 1345 lock = Irp->GetParameterSetLockLock(); 1346 1347 status = ((FxPkgPdo*) This)->m_DeviceSetLock.Invoke( 1348 ((FxPkgPdo*) This)->m_Device->GetHandle(), lock); 1349 1350 if (NT_SUCCESS(status)) { 1351 Irp->SetInformation(NULL); 1352 } 1353 1354 return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, status); 1355 } 1356 1357 _Must_inspect_result_ 1358 NTSTATUS 1359 FxPkgPdo::_PnpQueryId( 1360 __inout FxPkgPnp* This, 1361 __inout FxIrp *Irp 1362 ) 1363 { 1364 FxPkgPdo* pThis; 1365 NTSTATUS status; 1366 PWCHAR pBuffer; 1367 PCWSTR pSrc; 1368 size_t cbLength; 1369 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1370 BUS_QUERY_ID_TYPE queryIdType; 1371 1372 pThis = (FxPkgPdo*) This; 1373 pFxDriverGlobals = pThis->GetDriverGlobals(); 1374 status = Irp->GetStatus(); 1375 cbLength = 0; 1376 1377 queryIdType = Irp->GetParameterQueryIdType(); 1378 1379 switch (queryIdType) { 1380 case BusQueryDeviceID: 1381 case BusQueryInstanceID: 1382 case BusQueryContainerID: 1383 if (queryIdType == BusQueryDeviceID) { 1384 pSrc = pThis->m_DeviceID; 1385 } 1386 else if (queryIdType == BusQueryInstanceID) { 1387 pSrc = pThis->m_InstanceID; 1388 } 1389 else { 1390 pSrc = pThis->m_ContainerID; 1391 } 1392 1393 if (pSrc != NULL) { 1394 cbLength = (wcslen(pSrc) + 1) * sizeof(WCHAR); 1395 1396 pBuffer = (PWCHAR) MxMemory::MxAllocatePoolWithTag( 1397 PagedPool, cbLength, pFxDriverGlobals->Tag); 1398 } 1399 else { 1400 status = Irp->GetStatus(); 1401 break; 1402 } 1403 1404 if (pBuffer != NULL) { 1405 1406 // 1407 // This will copy the NULL terminator too 1408 // 1409 RtlCopyMemory(pBuffer, pSrc, cbLength); 1410 Irp->SetInformation((ULONG_PTR) pBuffer); 1411 status = STATUS_SUCCESS; 1412 } 1413 else { 1414 status = STATUS_INSUFFICIENT_RESOURCES; 1415 } 1416 break; 1417 1418 case BusQueryHardwareIDs: 1419 case BusQueryCompatibleIDs: 1420 if (queryIdType == BusQueryHardwareIDs) { 1421 pSrc = pThis->m_HardwareIDs; 1422 } 1423 else { 1424 pSrc = pThis->m_CompatibleIDs; 1425 } 1426 1427 if (pSrc != NULL) { 1428 cbLength = FxCalculateTotalMultiSzStringSize(pSrc); 1429 } 1430 else { 1431 // 1432 // Must return an empty list 1433 // 1434 cbLength = 2 * sizeof(UNICODE_NULL); 1435 } 1436 1437 pBuffer = (PWCHAR) MxMemory::MxAllocatePoolWithTag( 1438 PagedPool, cbLength, pFxDriverGlobals->Tag); 1439 1440 if (pBuffer != NULL) { 1441 if (pSrc != NULL) { 1442 RtlCopyMemory(pBuffer, pSrc, cbLength); 1443 } 1444 else { 1445 RtlZeroMemory(pBuffer, cbLength); 1446 } 1447 1448 Irp->SetInformation((ULONG_PTR) pBuffer); 1449 status = STATUS_SUCCESS; 1450 } 1451 else { 1452 status = STATUS_INSUFFICIENT_RESOURCES; 1453 } 1454 break; 1455 } 1456 1457 if (!NT_SUCCESS(status)) { 1458 Irp->SetInformation(NULL); 1459 1460 if (status == STATUS_NOT_SUPPORTED) { 1461 DoTraceLevelMessage( 1462 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1463 "WDFDEVICE %p does not have a string for PnP query IdType " 1464 "%!BUS_QUERY_ID_TYPE!, %!STATUS!", 1465 pThis->m_Device->GetHandle(), 1466 queryIdType, status); 1467 } 1468 else { 1469 DoTraceLevelMessage( 1470 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1471 "WDFDEVICE %p could not alloc string for PnP query IdType " 1472 "%!BUS_QUERY_ID_TYPE!, %!STATUS!", 1473 pThis->m_Device->GetHandle(), 1474 queryIdType, status); 1475 } 1476 } 1477 1478 return ((FxPkgPdo*) pThis)->CompletePnpRequest(Irp, status); 1479 } 1480 1481 _Must_inspect_result_ 1482 NTSTATUS 1483 FxPkgPdo::_PnpQueryPnpDeviceState( 1484 __inout FxPkgPnp* This, 1485 __inout FxIrp *Irp 1486 ) 1487 /*++ 1488 1489 Routine Description: 1490 indicates the current device state 1491 1492 Arguments: 1493 This - the package 1494 1495 Irp - the request 1496 1497 Return Value: 1498 NTSTATUS 1499 1500 --*/ 1501 { 1502 PNP_DEVICE_STATE pnpDeviceState; 1503 PFX_DRIVER_GLOBALS FxDriverGlobals = This->GetDriverGlobals(); 1504 1505 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, 1506 "Entering QueryPnpDeviceState handler"); 1507 1508 pnpDeviceState = ((FxPkgPdo*) This)->HandleQueryPnpDeviceState( 1509 (PNP_DEVICE_STATE) Irp->GetInformation()); 1510 1511 Irp->SetInformation((ULONG_PTR) pnpDeviceState); 1512 1513 DoTraceLevelMessage( 1514 FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, 1515 "WDFDEVICE 0x%p !devobj 0x%p returning PNP_DEVICE_STATE 0x%d IRP 0x%p", 1516 This->GetDevice()->GetHandle(), 1517 This->GetDevice()->GetDeviceObject(), 1518 pnpDeviceState, 1519 Irp->GetIrp()); 1520 1521 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, 1522 "Exiting QueryPnpDeviceState handler"); 1523 1524 return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, STATUS_SUCCESS); 1525 } 1526 1527 _Must_inspect_result_ 1528 NTSTATUS 1529 FxPkgPdo::_PnpQueryBusInformation( 1530 __inout FxPkgPnp* This, 1531 __inout FxIrp *Irp 1532 ) 1533 /*++ 1534 1535 Routine Description: 1536 Returns the bus information for this child 1537 1538 Arguments: 1539 This - the package 1540 1541 Irp - the request 1542 1543 Return Value: 1544 NTSTATUS 1545 1546 --*/ 1547 { 1548 FxPkgPdo* pThis; 1549 NTSTATUS status; 1550 1551 pThis = (FxPkgPdo*) This; 1552 1553 status = pThis->m_Device->m_ParentDevice->m_PkgPnp-> 1554 HandleQueryBusInformation(Irp); 1555 1556 return pThis->CompletePnpRequest(Irp, status); 1557 } 1558 1559 _Must_inspect_result_ 1560 NTSTATUS 1561 FxPkgPdo::_PnpSurpriseRemoval( 1562 __inout FxPkgPnp* This, 1563 __inout FxIrp *Irp 1564 ) 1565 { 1566 FxPkgPdo* pThis; 1567 1568 pThis = (FxPkgPdo*) This; 1569 1570 pThis->m_Description->DeviceSurpriseRemoved(); 1571 1572 return pThis->PnpSurpriseRemoval(Irp); 1573 } 1574 1575 VOID 1576 FxPkgPdo::RegisterCallbacks( 1577 __in PWDF_PDO_EVENT_CALLBACKS DispatchTable 1578 ) 1579 { 1580 m_DeviceResourcesQuery.m_Method = DispatchTable->EvtDeviceResourcesQuery; 1581 m_DeviceResourceRequirementsQuery.m_Method = DispatchTable->EvtDeviceResourceRequirementsQuery; 1582 m_DeviceEject.m_Method = DispatchTable->EvtDeviceEject; 1583 m_DeviceSetLock.m_Method = DispatchTable->EvtDeviceSetLock; 1584 1585 m_DeviceEnableWakeAtBus.m_Method = DispatchTable->EvtDeviceEnableWakeAtBus; 1586 m_DeviceDisableWakeAtBus.m_Method = DispatchTable->EvtDeviceDisableWakeAtBus; 1587 1588 // 1589 // this callback was added in V1.11 1590 // 1591 if (DispatchTable->Size > sizeof(WDF_PDO_EVENT_CALLBACKS_V1_9)) { 1592 m_DeviceReportedMissing.m_Method = DispatchTable->EvtDeviceReportedMissing; 1593 } 1594 } 1595 1596 _Must_inspect_result_ 1597 NTSTATUS 1598 FxPkgPdo::AskParentToRemoveAndReenumerate( 1599 VOID 1600 ) 1601 /*++ 1602 1603 Routine Description: 1604 This routine asks the PDO to ask its parent bus driver to Surprise-Remove 1605 and re-enumerate the PDO. This will be done only at the point of 1606 catastrophic software failure, and occasionally after catastrophic hardware 1607 failure. 1608 1609 Arguments: 1610 None 1611 1612 Return Value: 1613 status 1614 1615 --*/ 1616 { 1617 // 1618 // Static children do not support reenumeration. 1619 // 1620 if (m_Description != NULL && m_Static == FALSE) { 1621 m_Description->GetParentList()->ReenumerateEntry(m_Description); 1622 return STATUS_SUCCESS; 1623 } 1624 1625 return STATUS_NOT_FOUND; 1626 } 1627 1628 1629 VOID 1630 FxPkgPdo::DeleteSymbolicLinkOverload( 1631 __in BOOLEAN GracefulRemove 1632 ) 1633 /*++ 1634 1635 Routine Description: 1636 Role specific virtual function which determines if the symbolic link for a 1637 device should be deleted. 1638 1639 Arguments: 1640 None 1641 1642 Return Value: 1643 None 1644 1645 --*/ 1646 { 1647 if (GracefulRemove) { 1648 // 1649 // We will remove the symbolic link when we determine if the PDO was 1650 // reported missing or not. 1651 // 1652 return; 1653 } 1654 else if (m_Description->IsDeviceReportedMissing()) { 1655 // 1656 // Surprise removed and we have reported the PDO as missing 1657 // 1658 1659 m_Device->DeleteSymbolicLink(); 1660 } 1661 } 1662 1663 1664 VOID 1665 FxPkgPdo::_RemoveAndReenumerateSelf( 1666 __in PVOID Context 1667 ) 1668 /*++ 1669 1670 Routine Description: 1671 This routine is passed out to higher-level drivers as part of the 1672 re-enumeration interface. 1673 1674 Arguments: 1675 This 1676 1677 Return Value: 1678 void 1679 1680 --*/ 1681 { 1682 ((FxPkgPdo*) Context)->AskParentToRemoveAndReenumerate(); 1683 } 1684 1685 _Must_inspect_result_ 1686 NTSTATUS 1687 FxPkgPdo::HandleQueryInterfaceForReenumerate( 1688 __in FxIrp* Irp, 1689 __out PBOOLEAN CompleteRequest 1690 ) 1691 /*++ 1692 1693 Routine Description: 1694 Handles a query interface on the PDO for the self reenumeration interface. 1695 1696 Arguments: 1697 Irp - the request containing the QI 1698 1699 CompleteRequest - whether the caller should complete the request when this 1700 call returns 1701 1702 Return Value: 1703 status to complete the irp with 1704 1705 --*/ 1706 { 1707 PREENUMERATE_SELF_INTERFACE_STANDARD pInterface; 1708 NTSTATUS status; 1709 1710 *CompleteRequest = TRUE; 1711 1712 if (m_Static) { 1713 // 1714 // Return the embedded status in the irp since this is a statically 1715 // enumerated child. Only dynamically enuemrated child support self 1716 // reenumeration. 1717 // 1718 return Irp->GetStatus(); 1719 } 1720 1721 if (Irp->GetParameterQueryInterfaceVersion() == 1 && 1722 Irp->GetParameterQueryInterfaceSize() >= sizeof(*pInterface)) { 1723 1724 pInterface = (PREENUMERATE_SELF_INTERFACE_STANDARD) 1725 Irp->GetParameterQueryInterfaceInterface(); 1726 1727 // 1728 // Expose the interface to the requesting driver. 1729 // 1730 pInterface->Version = 1; 1731 pInterface->Size = sizeof(*pInterface); 1732 pInterface->Context = this; 1733 pInterface->InterfaceReference = FxDevice::_InterfaceReferenceNoOp; 1734 pInterface->InterfaceDereference = FxDevice::_InterfaceDereferenceNoOp; 1735 pInterface->SurpriseRemoveAndReenumerateSelf = &FxPkgPdo::_RemoveAndReenumerateSelf; 1736 1737 status = STATUS_SUCCESS; 1738 1739 // 1740 // Caller assumes a reference has been taken. 1741 // 1742 pInterface->InterfaceReference(pInterface->Context); 1743 } 1744 else { 1745 status = STATUS_INVALID_BUFFER_SIZE; 1746 } 1747 1748 return status; 1749 } 1750 1751 _Must_inspect_result_ 1752 NTSTATUS 1753 FxPkgPdo::ProcessRemoveDeviceOverload( 1754 __inout FxIrp* Irp 1755 ) 1756 { 1757 if (m_CanBeDeleted) { 1758 // 1759 // After this is called, any irp dispatched to FxDevice::DispatchWithLock 1760 // will fail with STATUS_INVALID_DEVICE_REQUEST. 1761 // 1762 1763 1764 1765 1766 1767 1768 1769 Mx::MxReleaseRemoveLockAndWait( 1770 m_Device->GetRemoveLock(), 1771 Irp->GetIrp() 1772 ); 1773 1774 // 1775 // Cleanup the state machines and release the power thread. 1776 // 1777 CleanupStateMachines(TRUE); 1778 1779 // 1780 // Detach and delete the device object. 1781 // 1782 DeleteDevice(); 1783 1784 // 1785 // Can't call CompletePnpRequest because we just released the tag in 1786 // IoReleaseRemoveLockAndWait above. 1787 // 1788 Irp->CompleteRequest(IO_NO_INCREMENT); 1789 1790 return STATUS_SUCCESS; 1791 } 1792 else { 1793 // 1794 // This was a PDO which was not reported missing, so do not free the 1795 // memory and clear out our stack local address. 1796 // 1797 m_DeviceRemoveProcessed = NULL; 1798 return CompletePnpRequest(Irp, Irp->GetStatus()); 1799 } 1800 } 1801 1802 _Must_inspect_result_ 1803 NTSTATUS 1804 FxPkgPdo::QueryForPowerThread( 1805 VOID 1806 ) 1807 /*++ 1808 1809 Routine Description: 1810 Since the PDO is the lowest device in the stack, it does not have to send 1811 a query down the stack. Rather, it just creates the thread and returns. 1812 1813 Arguments: 1814 None 1815 1816 Return Value: 1817 NTSTATUS 1818 1819 --*/ 1820 { 1821 return CreatePowerThread(); 1822 } 1823 1824 _Must_inspect_result_ 1825 NTSTATUS 1826 FxPkgPdo::AddEjectionDevice( 1827 __in MdDeviceObject DependentDevice 1828 ) 1829 { 1830 FxRelatedDevice* pRelated; 1831 NTSTATUS status; 1832 1833 if (m_EjectionDeviceList == NULL) { 1834 KIRQL irql; 1835 1836 Lock(&irql); 1837 if (m_EjectionDeviceList == NULL) { 1838 m_EjectionDeviceList = new (GetDriverGlobals()) FxRelatedDeviceList(); 1839 1840 if (m_EjectionDeviceList != NULL) { 1841 status = STATUS_SUCCESS; 1842 } 1843 else { 1844 status = STATUS_INSUFFICIENT_RESOURCES; 1845 DoTraceLevelMessage( 1846 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1847 "Could not allocate ejection device list for PDO WDFDEVICE %p", 1848 1849 m_Device->GetHandle()); 1850 } 1851 } 1852 else { 1853 // 1854 // another thread allocated the list already 1855 // 1856 status = STATUS_SUCCESS; 1857 } 1858 Unlock(irql); 1859 1860 if (!NT_SUCCESS(status)) { 1861 return status; 1862 } 1863 } 1864 1865 pRelated = new(GetDriverGlobals()) 1866 FxRelatedDevice(DependentDevice, GetDriverGlobals()); 1867 1868 if (pRelated == NULL) { 1869 return STATUS_INSUFFICIENT_RESOURCES; 1870 } 1871 1872 status = m_EjectionDeviceList->Add(GetDriverGlobals(), pRelated); 1873 1874 if (NT_SUCCESS(status)) { 1875 // 1876 // EjectRelations are queried automatically by PnP when the device is 1877 // going to be ejected. No need to tell pnp that the list changed 1878 // until it needs to query for it. 1879 // 1880 DO_NOTHING(); 1881 } 1882 else { 1883 pRelated->DeleteFromFailedCreate(); 1884 } 1885 1886 return status; 1887 } 1888 1889 VOID 1890 FxPkgPdo::RemoveEjectionDevice( 1891 __in MdDeviceObject DependentDevice 1892 ) 1893 { 1894 if (m_EjectionDeviceList != NULL) { 1895 m_EjectionDeviceList->Remove(GetDriverGlobals(), DependentDevice); 1896 } 1897 1898 // 1899 // EjectRelations are queried automatically by PnP when the device is 1900 // going to be ejected. No need to tell pnp that the list changed 1901 // until it needs to query for it. 1902 // 1903 } 1904 1905 VOID 1906 FxPkgPdo::ClearEjectionDevicesList( 1907 VOID 1908 ) 1909 { 1910 FxRelatedDevice* pEntry; 1911 1912 if (m_EjectionDeviceList != NULL) { 1913 m_EjectionDeviceList->LockForEnum(GetDriverGlobals()); 1914 while ((pEntry = m_EjectionDeviceList->GetNextEntry(NULL)) != NULL) { 1915 m_EjectionDeviceList->Remove(GetDriverGlobals(), 1916 pEntry->GetDevice()); 1917 } 1918 m_EjectionDeviceList->UnlockFromEnum(GetDriverGlobals()); 1919 } 1920 1921 // 1922 // EjectRelations are queried automatically by PnP when the device is 1923 // going to be ejected. No need to tell pnp that the list changed 1924 // until it needs to query for it. 1925 // 1926 } 1927