1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxPkgFdo.cpp 8 9 Abstract: 10 11 This module implements the pnp/power package for the driver 12 framework. 13 14 Author: 15 16 17 18 Environment: 19 20 Both kernel and user mode 21 22 Revision History: 23 24 25 26 27 --*/ 28 29 #include "pnppriv.hpp" 30 31 32 //#include <FxIoTarget.hpp> 33 34 #include <initguid.h> 35 #include <wdmguid.h> 36 37 #if defined(EVENT_TRACING) 38 // Tracing support 39 extern "C" { 40 #include "fxpkgfdo.tmh" 41 } 42 #endif 43 44 struct FxFilteredStartContext : public FxStump { 45 FxFilteredStartContext( 46 VOID 47 ) 48 { 49 ResourcesRaw = NULL; 50 ResourcesTranslated = NULL; 51 } 52 53 ~FxFilteredStartContext() 54 { 55 if (ResourcesRaw != NULL) { 56 MxMemory::MxFreePool(ResourcesRaw); 57 } 58 if (ResourcesTranslated != NULL) { 59 MxMemory::MxFreePool(ResourcesTranslated); 60 } 61 } 62 63 FxPkgFdo* PkgFdo; 64 65 PCM_RESOURCE_LIST ResourcesRaw; 66 67 PCM_RESOURCE_LIST ResourcesTranslated; 68 }; 69 70 const PFN_PNP_POWER_CALLBACK FxPkgFdo::m_FdoPnpFunctionTable[IRP_MN_SURPRISE_REMOVAL + 1] = 71 { 72 _PnpStartDevice, // IRP_MN_START_DEVICE 73 _PnpQueryRemoveDevice, // IRP_MN_QUERY_REMOVE_DEVICE 74 _PnpRemoveDevice, // IRP_MN_REMOVE_DEVICE 75 _PnpCancelRemoveDevice, // IRP_MN_CANCEL_REMOVE_DEVICE 76 _PnpStopDevice, // IRP_MN_STOP_DEVICE 77 _PnpQueryStopDevice, // IRP_MN_QUERY_STOP_DEVICE 78 _PnpCancelStopDevice, // IRP_MN_CANCEL_STOP_DEVICE 79 80 _PnpQueryDeviceRelations, // IRP_MN_QUERY_DEVICE_RELATIONS 81 _PnpQueryInterface, // IRP_MN_QUERY_INTERFACE 82 _PnpQueryCapabilities, // IRP_MN_QUERY_CAPABILITIES 83 _PnpPassDown, // IRP_MN_QUERY_RESOURCES 84 _PnpPassDown, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS 85 _PnpPassDown, // IRP_MN_QUERY_DEVICE_TEXT 86 _PnpFilterResourceRequirements, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS 87 88 _PnpPassDown, // 0x0E 89 90 _PnpPassDown, // IRP_MN_READ_CONFIG 91 _PnpPassDown, // IRP_MN_WRITE_CONFIG 92 _PnpPassDown, // IRP_MN_EJECT 93 _PnpPassDown, // IRP_MN_SET_LOCK 94 _PnpPassDown, // IRP_MN_QUERY_ID 95 _PnpQueryPnpDeviceState, // IRP_MN_QUERY_PNP_DEVICE_STATE 96 _PnpPassDown, // IRP_MN_QUERY_BUS_INFORMATION 97 _PnpDeviceUsageNotification, // IRP_MN_DEVICE_USAGE_NOTIFICATION 98 _PnpSurpriseRemoval, // IRP_MN_SURPRISE_REMOVAL 99 100 }; 101 102 const PFN_PNP_POWER_CALLBACK FxPkgFdo::m_FdoPowerFunctionTable[IRP_MN_QUERY_POWER + 1] = 103 { 104 _DispatchWaitWake, // IRP_MN_WAIT_WAKE 105 _PowerPassDown, // IRP_MN_POWER_SEQUENCE 106 _DispatchSetPower, // IRP_MN_SET_POWER 107 _DispatchQueryPower, // IRP_MN_QUERY_POWER 108 }; 109 110 //#if defined(ALLOC_PRAGMA) 111 //#pragma code_seg("PAGE") 112 //#endif 113 114 FxPkgFdo::FxPkgFdo( 115 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 116 __in CfxDevice *Device 117 ) : 118 FxPkgPnp(FxDriverGlobals, Device, FX_TYPE_PACKAGE_FDO) 119 /*++ 120 121 Routine Description: 122 123 This is the constructor for the FxPkgFdo. Don't do any initialization 124 that might fail here. 125 126 Arguments: 127 128 none 129 130 Returns: 131 132 none 133 134 --*/ 135 136 { 137 m_DefaultDeviceList = NULL; 138 m_StaticDeviceList = NULL; 139 140 m_DefaultTarget = NULL; 141 m_SelfTarget = NULL; 142 143 m_BusEnumRetries = 0; 144 145 // 146 // Since we will always have a valid PDO when we are the FDO, we can do 147 // any device interface related activity at any time 148 // 149 m_DeviceInterfacesCanBeEnabled = TRUE; 150 151 m_Filter = FALSE; 152 153 RtlZeroMemory(&m_BusInformation, sizeof(m_BusInformation)); 154 155 RtlZeroMemory(&m_SurpriseRemoveAndReenumerateSelfInterface, 156 sizeof(m_SurpriseRemoveAndReenumerateSelfInterface)); 157 } 158 159 FxPkgFdo::~FxPkgFdo( 160 VOID 161 ) 162 /*++ 163 164 Routine Description: 165 166 This is the destructor for the FxPkgFdo 167 168 Arguments: 169 170 none 171 172 Returns: 173 174 none 175 176 --*/ 177 178 { 179 if (m_DefaultDeviceList != NULL) { 180 m_DefaultDeviceList->RELEASE(this); 181 } 182 if (m_StaticDeviceList != NULL) { 183 m_StaticDeviceList->RELEASE(this); 184 } 185 if (m_SelfTarget != NULL) { 186 m_SelfTarget->RELEASE(this); 187 } 188 if (m_DefaultTarget != NULL) { 189 m_DefaultTarget->RELEASE(this); 190 } 191 } 192 193 _Must_inspect_result_ 194 NTSTATUS 195 FxPkgFdo::_Create( 196 __in PFX_DRIVER_GLOBALS DriverGlobals, 197 __in CfxDevice * Device, 198 __deref_out FxPkgFdo ** PkgFdo 199 ) 200 { 201 NTSTATUS status; 202 FxPkgFdo * fxPkgFdo; 203 FxEventQueue *eventQueue; 204 205 fxPkgFdo = new(DriverGlobals) FxPkgFdo(DriverGlobals, Device); 206 207 if (NULL == fxPkgFdo) { 208 status = STATUS_INSUFFICIENT_RESOURCES; 209 DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 210 "Memory allocation failed: %!STATUS!", status); 211 return status; 212 } 213 214 // 215 // Initialize the event queues in the PnP, power and power policy state 216 // machines 217 // 218 eventQueue = static_cast<FxEventQueue*> (&(fxPkgFdo->m_PnpMachine)); 219 status = eventQueue->Initialize(DriverGlobals); 220 if (!NT_SUCCESS(status)) { 221 goto exit; 222 } 223 224 eventQueue = static_cast<FxEventQueue*> (&(fxPkgFdo->m_PowerMachine)); 225 status = eventQueue->Initialize(DriverGlobals); 226 if (!NT_SUCCESS(status)) { 227 goto exit; 228 } 229 230 eventQueue = static_cast<FxEventQueue*> (&(fxPkgFdo->m_PowerPolicyMachine)); 231 status = eventQueue->Initialize(DriverGlobals); 232 if (!NT_SUCCESS(status)) { 233 goto exit; 234 } 235 236 *PkgFdo = fxPkgFdo; 237 238 exit: 239 if (!NT_SUCCESS(status)) { 240 fxPkgFdo->DeleteFromFailedCreate(); 241 } 242 243 return status; 244 } 245 246 _Must_inspect_result_ 247 NTSTATUS 248 FxPkgFdo::SendIrpSynchronously( 249 __inout FxIrp* Irp 250 ) 251 252 /*++ 253 254 Routine Description: 255 256 Helper function that makes it easy to handle events which need to be 257 done as an IRP comes back up the stack. 258 259 Arguments: 260 261 Irp - The request 262 263 Returns: 264 265 results from IoCallDriver 266 267 --*/ 268 269 { 270 Irp->CopyCurrentIrpStackLocationToNext(); 271 return Irp->SendIrpSynchronously(m_Device->GetAttachedDevice()); 272 } 273 274 _Must_inspect_result_ 275 NTSTATUS 276 FxPkgFdo::FireAndForgetIrp( 277 __inout FxIrp *Irp 278 ) 279 280 /*++ 281 282 Routine Description: 283 284 Virtual override which sends the request down the stack and forgets about it. 285 286 Arguments: 287 288 Irp - The request 289 290 Returns: 291 292 results from IoCallDriver 293 294 --*/ 295 296 { 297 if (Irp->GetMajorFunction() == IRP_MJ_POWER) { 298 return _PowerPassDown(this, Irp); 299 } 300 else { 301 return _PnpPassDown(this, Irp); 302 } 303 } 304 305 _Must_inspect_result_ 306 NTSTATUS 307 FxPkgFdo::_PnpPassDown( 308 __in FxPkgPnp* This, 309 __inout FxIrp* Irp 310 ) 311 /*++ 312 313 Routine Description: 314 Functionally equivalent to FireAndForgetIrp except this isn't a virtual 315 call 316 317 Arguments: 318 Irp - The request 319 320 Return Value: 321 result from IoCallDriver 322 323 --*/ 324 { 325 NTSTATUS status; 326 FxDevice* device; 327 MdIrp pIrp; 328 329 device = ((FxPkgFdo*)This)->m_Device; 330 pIrp = Irp->GetIrp(); 331 332 Irp->CopyCurrentIrpStackLocationToNext(); 333 status = Irp->CallDriver( 334 ((FxPkgFdo*)This)->m_Device->GetAttachedDevice()); 335 336 Mx::MxReleaseRemoveLock(device->GetRemoveLock(), 337 pIrp 338 ); 339 340 return status; 341 } 342 343 _Must_inspect_result_ 344 NTSTATUS 345 FxPkgFdo::_PnpSurpriseRemoval( 346 __inout FxPkgPnp* This, 347 __inout FxIrp *Irp 348 ) 349 /*++ 350 351 Routine Description: 352 353 This method is called in response to a PnP SurpriseRemoval IRP. 354 355 Arguments: 356 357 Device - a pointer to the FxDevice 358 359 Irp - a pointer to the FxIrp 360 361 Returns: 362 363 NTSTATUS 364 365 --*/ 366 { 367 return ((FxPkgFdo*) This)->PnpSurpriseRemoval(Irp); 368 } 369 370 _Must_inspect_result_ 371 NTSTATUS 372 FxPkgFdo::_PnpQueryDeviceRelations( 373 __inout FxPkgPnp* This, 374 __inout FxIrp *Irp 375 ) 376 /*++ 377 378 Routine Description: 379 380 This method is called in response to a PnP QDR. 381 382 Arguments: 383 384 Device - a pointer to the FxDevice 385 386 Irp - a pointer to the FxIrp 387 388 Returns: 389 390 NTSTATUS 391 392 --*/ 393 { 394 return ((FxPkgFdo*) This)->PnpQueryDeviceRelations(Irp); 395 } 396 397 _Must_inspect_result_ 398 NTSTATUS 399 FxPkgFdo::PnpQueryDeviceRelations( 400 __inout FxIrp *Irp 401 ) 402 403 /*++ 404 405 Routine Description: 406 407 This routine is called in response to a QueryDeviceRelations IRP. 408 409 Arguments: 410 411 Device - a pointer to the FxDevice 412 413 Irp - a pointer to the FxIrp 414 415 Returns: 416 417 NSTATUS 418 419 --*/ 420 421 { 422 NTSTATUS status; 423 DEVICE_RELATION_TYPE type; 424 425 type = Irp->GetParameterQDRType(); 426 427 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 428 "Entering QueryDeviceRelations handler, " 429 "type %!DEVICE_RELATION_TYPE!", 430 type); 431 432 status = STATUS_SUCCESS; 433 434 435 // 436 // Set up the type of relations. 437 // 438 switch (type) { 439 case BusRelations: 440 status = HandleQueryBusRelations(Irp); 441 442 // 443 // STATUS_NOT_SUPPORTED is a special value. It means that 444 // HandleQueryBusRelations did not modify the irp at all and it should 445 // be sent off as is. 446 // 447 if (status == STATUS_NOT_SUPPORTED) { 448 // 449 // We set status to STATUS_SUCCESS so that we send the requqest down 450 // the stack in the comparison below. 451 // 452 status = STATUS_SUCCESS; 453 } 454 break; 455 456 case RemovalRelations: 457 status = HandleQueryDeviceRelations(Irp, m_RemovalDeviceList); 458 459 // 460 // STATUS_NOT_SUPPORTED is a special value. It means that 461 // HandleQueryDeviceRelations did not modify the irp at all and it should 462 // be sent off as is. 463 // 464 if (status == STATUS_NOT_SUPPORTED) { 465 // 466 // We set status to STATUS_SUCCESS so that we send the requqest down 467 // the stack in the comparison below. 468 // 469 status = STATUS_SUCCESS; 470 } 471 break; 472 } 473 474 if (NT_SUCCESS(status)) { 475 status = _PnpPassDown(this, Irp); 476 } 477 else { 478 CompletePnpRequest(Irp, status); 479 } 480 481 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 482 "Exiting QueryDeviceRelations handler, status %!STATUS!", 483 status); 484 485 return status; 486 } 487 488 _Must_inspect_result_ 489 NTSTATUS 490 FxPkgFdo::_PnpQueryInterface( 491 __inout FxPkgPnp* This, 492 __inout FxIrp *Irp 493 ) 494 /*++ 495 496 Routine Description: 497 498 This method is invoked in response to a Pnp QueryInterface IRP. 499 500 Arguments: 501 502 This - The package 503 504 Irp - a pointer to the FxIrp 505 506 Returns: 507 508 NTSTATUS 509 510 --*/ 511 { 512 FxPkgFdo* pThis; 513 NTSTATUS status; 514 BOOLEAN completeIrp; 515 516 pThis = (FxPkgFdo*) This; 517 518 DoTraceLevelMessage(pThis->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 519 "Entering QueryInterface handler"); 520 521 status = pThis->HandleQueryInterface(Irp, &completeIrp); 522 523 DoTraceLevelMessage(pThis->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 524 "Exiting QueryInterface handler, %!STATUS!", 525 status); 526 // 527 // If we understand the irp, we'll complete it. Otherwise we 528 // pass it down. 529 // 530 if (completeIrp == FALSE) { 531 status = _PnpPassDown(pThis, Irp); 532 } 533 else { 534 Irp->SetInformation(NULL); 535 pThis->CompletePnpRequest(Irp, status); 536 } 537 538 // 539 // Remlock is released in _PnpPassDown and CompletePnpRequest. If this 540 // irp is racing with remove on another thread, it's possible for the device 541 // to get deleted right after the lock is released and before anything 542 // after this point is executed. So make sure to not touch any memory in 543 // the return path. 544 // 545 546 return status; 547 } 548 549 _Must_inspect_result_ 550 NTSTATUS 551 FxPkgFdo::_PnpQueryCapabilities( 552 __inout FxPkgPnp* This, 553 __inout FxIrp *Irp 554 ) 555 { 556 557 558 559 560 561 562 563 564 565 566 567 568 return ((FxPkgFdo*) This)->PnpQueryCapabilities(Irp); 569 } 570 571 VOID 572 FxPkgFdo::HandleQueryCapabilities( 573 __inout FxIrp *Irp 574 ) 575 { 576 PDEVICE_CAPABILITIES pCaps; 577 LONG pnpCaps; 578 579 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 580 "Entering QueryCapabilities handler"); 581 582 pCaps = Irp->GetParameterDeviceCapabilities(); 583 584 pnpCaps = GetPnpCapsInternal(); 585 586 // 587 // Add Capabilities. These need to be done as the IRP goes down, since 588 // lower drivers need to see them. 589 // 590 if ((pCaps->Size >= sizeof(DEVICE_CAPABILITIES)) && (pCaps->Version == 1)) { 591 SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, LockSupported); 592 SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, EjectSupported); 593 SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, Removable); 594 SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, DockDevice); 595 SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, SurpriseRemovalOK); 596 SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, NoDisplayInUI); 597 // 598 // If the driver has declared a wake capable interrupt, 599 // we need to set this bit in the capabilities so that 600 // ACPI will relinquish control of wake responsiblity 601 // 602 if (SupportsWakeInterrupt()) { 603 pCaps->WakeFromInterrupt = TRUE; 604 } 605 } 606 607 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 608 "Exiting QueryCapabilities handler"); 609 return; 610 } 611 612 VOID 613 FxPkgFdo::HandleQueryCapabilitiesCompletion( 614 __inout FxIrp *Irp 615 ) 616 { 617 PDEVICE_CAPABILITIES pCaps; 618 LONG pnpCaps; 619 ULONG i; 620 621 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 622 "Entering QueryCapabilities completion handler"); 623 624 pCaps = Irp->GetParameterDeviceCapabilities(); 625 626 pnpCaps = GetPnpCapsInternal(); 627 628 // 629 // Confirm this is a valid DeviceCapabilities structure. 630 // 631 ASSERT(pCaps->Size >= sizeof(DEVICE_CAPABILITIES)); 632 ASSERT(pCaps->Version >= 1); 633 634 if ((pCaps->Size >= sizeof(DEVICE_CAPABILITIES)) && 635 (pCaps->Version == 1)) { 636 ULONG states; 637 638 // 639 // Remove Capabilities 640 // 641 642 // 643 // Re-add SOME capibilties that the bus driver may have accidentally 644 // stomped. 645 646 647 648 649 650 SET_PNP_CAP_IF_FALSE(pnpCaps, pCaps, LockSupported); 651 SET_PNP_CAP_IF_FALSE(pnpCaps, pCaps, EjectSupported); 652 SET_PNP_CAP_IF_FALSE(pnpCaps, pCaps, DockDevice); 653 654 SET_PNP_CAP(pnpCaps, pCaps, Removable); 655 SET_PNP_CAP(pnpCaps, pCaps, SurpriseRemovalOK); 656 657 // 658 // The DeviceState array contains a table of D states that correspond 659 // to a given S state. If the driver writer initialized entries of the 660 // array, and if the new value is a deeper sleep state than the 661 // original, we will use the new driver supplied value. 662 // 663 states = m_PowerCaps.States; 664 665 for (i = PowerSystemWorking; i < PowerSystemMaximum; i++) { 666 DEVICE_POWER_STATE state; 667 668 // 669 // PowerDeviceMaximum indicates to use the default value 670 // 671 // We are only allowed to deepen the D states, not lighten them, 672 // hence the > compare. 673 // 674 state = _GetPowerCapState(i, states); 675 676 if (state != PowerDeviceMaximum && state > pCaps->DeviceState[i]) { 677 pCaps->DeviceState[i] = state; 678 } 679 } 680 681 // 682 // If the driver supplied SystemWake value is lighter than the current 683 // value, then use the driver supplied value. 684 // 685 // PowerSystemMaximum indicates to use the default value 686 // 687 // We are only allowed to lighten the S state, not deepen it, hence 688 // the < compare. 689 // 690 if (m_PowerCaps.SystemWake != PowerSystemMaximum && 691 m_PowerCaps.SystemWake < pCaps->SystemWake) { 692 pCaps->SystemWake = (SYSTEM_POWER_STATE) m_PowerCaps.SystemWake; 693 } 694 695 // 696 // Same for DeviceWake 697 // 698 if (m_PowerCaps.DeviceWake != PowerDeviceMaximum && 699 m_PowerCaps.DeviceWake < pCaps->DeviceWake) { 700 pCaps->DeviceWake = (DEVICE_POWER_STATE) m_PowerCaps.DeviceWake; 701 } 702 703 // 704 // Set the Device wake up latencies. A value of -1 indicates to 705 // use the default values provided by the lower stack. 706 // 707 if (m_PowerCaps.D1Latency != (ULONG) -1 && 708 m_PowerCaps.D1Latency > pCaps->D1Latency) { 709 pCaps->D1Latency = m_PowerCaps.D1Latency; 710 } 711 712 if (m_PowerCaps.D2Latency != (ULONG) -1 && 713 m_PowerCaps.D2Latency > pCaps->D2Latency) { 714 pCaps->D2Latency = m_PowerCaps.D2Latency; 715 } 716 717 if (m_PowerCaps.D3Latency != (ULONG) -1 && 718 m_PowerCaps.D3Latency > pCaps->D3Latency) { 719 pCaps->D3Latency = m_PowerCaps.D3Latency; 720 } 721 722 // 723 // Set the Address and the UI number values. A value of -1 indicates 724 // to use the default values provided by the lower stack. 725 // 726 if (m_PnpCapsAddress != (ULONG) -1) { 727 pCaps->Address = m_PnpCapsAddress; 728 } 729 730 if (m_PnpCapsUINumber != (ULONG) -1) { 731 pCaps->UINumber= m_PnpCapsUINumber; 732 } 733 } 734 735 // 736 // CompletePnpRequest is called after return from this function 737 // so it is safe to log here 738 // 739 740 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 741 "Exiting QueryCapabilities completion handler"); 742 743 return; 744 } 745 746 _Must_inspect_result_ 747 NTSTATUS 748 FxPkgFdo::_PnpFilterResourceRequirements( 749 __inout FxPkgPnp* This, 750 __inout FxIrp *Irp 751 ) 752 { 753 return ((FxPkgFdo*) This)->PnpFilterResourceRequirements(Irp); 754 } 755 756 757 758 759 760 761 762 VOID 763 FxPkgFdo::HandleQueryPnpDeviceStateCompletion( 764 __inout FxIrp *Irp 765 ) 766 { 767 PNP_DEVICE_STATE pnpDeviceState; 768 769 DoTraceLevelMessage( 770 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 771 "Entering QueryPnpDeviceState completion handler"); 772 773 pnpDeviceState = HandleQueryPnpDeviceState( 774 (PNP_DEVICE_STATE) Irp->GetInformation() 775 ); 776 777 Irp->SetInformation((ULONG_PTR) pnpDeviceState); 778 779 DoTraceLevelMessage( 780 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 781 "WDFDEVICE 0x%p !devobj 0x%p returning PNP_DEVICE_STATE 0x%d IRP 0x%p", 782 m_Device->GetHandle(), 783 m_Device->GetDeviceObject(), 784 pnpDeviceState, 785 Irp->GetIrp()); 786 787 DoTraceLevelMessage( 788 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 789 "Exiting QueryPnpDeviceState completion handler"); 790 791 return; 792 } 793 794 _Must_inspect_result_ 795 NTSTATUS 796 FxPkgFdo::RegisterCallbacks( 797 __in PWDF_FDO_EVENT_CALLBACKS DispatchTable 798 ) 799 { 800 // 801 // Walk the table, and only update the pkg table *if* the dispatch 802 // table has a non-null entry. 803 // 804 m_DeviceFilterAddResourceRequirements.m_Method = 805 DispatchTable->EvtDeviceFilterAddResourceRequirements; 806 m_DeviceFilterRemoveResourceRequirements.m_Method = 807 DispatchTable->EvtDeviceFilterRemoveResourceRequirements; 808 m_DeviceRemoveAddedResources.m_Method = 809 DispatchTable->EvtDeviceRemoveAddedResources; 810 811 return STATUS_SUCCESS; 812 } 813 814 _Must_inspect_result_ 815 NTSTATUS 816 FxPkgFdo::CreateDefaultDeviceList( 817 __in PWDF_CHILD_LIST_CONFIG ListConfig, 818 __in PWDF_OBJECT_ATTRIBUTES ListAttributes 819 ) 820 821 /*++ 822 823 Routine Description: 824 825 826 827 Arguments: 828 829 830 Returns: 831 832 NTSTATUS 833 834 --*/ 835 836 { 837 PFX_DRIVER_GLOBALS pFxDriverGlobals; 838 WDFCHILDLIST hList; 839 size_t totalDescriptionSize = 0; 840 NTSTATUS status; 841 842 pFxDriverGlobals = GetDriverGlobals(); 843 844 ASSERT(m_EnumInfo != NULL); 845 846 // 847 // This should not fail, we already validated the total size when we 848 // validated the config (we just had no place to store the total size, so 849 // we recompute it again). 850 // 851 status = FxChildList::_ComputeTotalDescriptionSize( 852 pFxDriverGlobals, 853 ListConfig, 854 &totalDescriptionSize 855 ); 856 if (!NT_SUCCESS(status)) { 857 return status; 858 } 859 860 status = FxChildList::_CreateAndInit(&m_DefaultDeviceList, 861 pFxDriverGlobals, 862 ListAttributes, 863 totalDescriptionSize, 864 m_Device, 865 ListConfig); 866 if (!NT_SUCCESS(status)) { 867 return status; 868 } 869 870 status = m_DefaultDeviceList->Commit(ListAttributes, 871 (WDFOBJECT*)&hList, 872 m_Device); 873 874 if (!NT_SUCCESS(status)) { 875 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 876 "Could not convert object to handle"); 877 m_DefaultDeviceList->DeleteFromFailedCreate(); 878 m_DefaultDeviceList = NULL; 879 return status; 880 } 881 882 // 883 // This will be released in the destructor 884 // 885 m_DefaultDeviceList->ADDREF(this); 886 887 return status; 888 } 889 890 _Must_inspect_result_ 891 NTSTATUS 892 FxPkgFdo::SetFilter( 893 __in BOOLEAN Value 894 ) 895 896 /*++ 897 898 Routine Description: 899 900 The Framework behaves differently depending on whether this device is a 901 filter in the stack. This method is the way we keep track. 902 903 Arguments: 904 905 Value - Filter or not 906 907 Returns: 908 909 NTSTATUS 910 911 --*/ 912 913 { 914 m_Filter = Value; 915 return STATUS_SUCCESS; 916 } 917 918 BOOLEAN 919 FxPkgFdo::PnpSendStartDeviceDownTheStackOverload( 920 VOID 921 ) 922 /*++ 923 924 Routine Description: 925 Send the start irp down the stack. 926 927 Arguments: 928 None 929 930 Return Value: 931 FALSE, the transition will occur in the irp's completion routine. 932 933 --*/ 934 { 935 // 936 // We will re-set the pending pnp irp when the start irp returns 937 // 938 FxIrp irp(ClearPendingPnpIrp()); 939 PCM_RESOURCE_LIST pWdmRaw, pWdmTranslated; 940 NTSTATUS status; 941 BOOLEAN setFilteredCompletion = FALSE; 942 FxFilteredStartContext* pContext = NULL; 943 944 pWdmRaw = irp.GetParameterAllocatedResources(); 945 pWdmTranslated = irp.GetParameterAllocatedResourcesTranslated(); 946 947 // 948 // Always setup the irp to be sent down the stack. In case of an error, 949 // this does no harm and it keeps everything simple. 950 // 951 irp.CopyCurrentIrpStackLocationToNext(); 952 953 // 954 // If the driver registered for a callback to remove its added resources 955 // and there are resources to remove, call the driver and set the next 956 // stack location to the filtered resources lists 957 // 958 if (m_DeviceRemoveAddedResources.m_Method != NULL && 959 pWdmRaw != NULL && pWdmTranslated != NULL) { 960 961 // 962 // Since we reuse these 2 fields for both the removal and the normal 963 // reporting (and can then be subsequently reused on a restart), we 964 // set the changed status back to FALSE. 965 // 966 m_ResourcesRaw->m_Changed = FALSE; 967 m_Resources->m_Changed = FALSE; 968 969 status = m_ResourcesRaw->BuildFromWdmList(pWdmRaw, 970 FxResourceAllAccessAllowed); 971 972 if (NT_SUCCESS(status)) { 973 status = m_Resources->BuildFromWdmList(pWdmTranslated, 974 FxResourceAllAccessAllowed); 975 } 976 977 if (NT_SUCCESS(status)) { 978 status = m_DeviceRemoveAddedResources.Invoke( 979 m_Device->GetHandle(), 980 m_ResourcesRaw->GetHandle(), 981 m_Resources->GetHandle() 982 ); 983 } 984 985 if (NT_SUCCESS(status) && 986 (m_ResourcesRaw->IsChanged() || m_Resources->IsChanged())) { 987 988 pContext = new(GetDriverGlobals()) FxFilteredStartContext(); 989 990 if (pContext != NULL) { 991 pContext->PkgFdo = this; 992 993 // 994 // Allocate the raw and translated resources. Upon failure for 995 // either, fail the start irp. We allocate from NonPagedPool 996 // because we are going to free the list in a completion routine 997 // which maybe running at an IRQL > PASSIVE_LEVEL. 998 // 999 if (m_ResourcesRaw->Count() > 0) { 1000 pContext->ResourcesRaw = 1001 m_ResourcesRaw->CreateWdmList(NonPagedPool); 1002 1003 if (pContext->ResourcesRaw == NULL) { 1004 status = STATUS_INSUFFICIENT_RESOURCES; 1005 } 1006 } 1007 1008 if (NT_SUCCESS(status) && m_Resources->Count() > 0) { 1009 pContext->ResourcesTranslated = 1010 m_Resources->CreateWdmList(NonPagedPool); 1011 1012 if (pContext->ResourcesTranslated == NULL) { 1013 status = STATUS_INSUFFICIENT_RESOURCES; 1014 } 1015 } 1016 1017 if (NT_SUCCESS(status)) { 1018 // 1019 // We copied to the next stack location at the start 1020 // 1021 irp.SetParameterAllocatedResources( 1022 pContext->ResourcesRaw); 1023 irp.SetParameterAllocatedResourcesTranslated( 1024 pContext->ResourcesTranslated); 1025 1026 // 1027 // Completion routine will free the resource list 1028 // allocations. 1029 // 1030 setFilteredCompletion = TRUE; 1031 } 1032 else { 1033 // 1034 // Allocation failure. The destructor will free any 1035 // outstanding allocations. 1036 // 1037 delete pContext; 1038 } 1039 } 1040 } 1041 } 1042 else { 1043 status = STATUS_SUCCESS; 1044 } 1045 1046 if (NT_SUCCESS(status)) { 1047 // 1048 // The completion of the start irp will move the state machine into a new 1049 // state. 1050 // 1051 // After calling IoSetCompletionRoutineEx the driver must call 1052 // IoCallDriver, otherwise a memory leak would occur. So call this API 1053 // as close to IoCallDriver as possible to avoid failure paths. 1054 // 1055 if (setFilteredCompletion) { 1056 ASSERT(pContext != NULL); 1057 irp.SetCompletionRoutineEx( 1058 m_Device->GetDeviceObject(), 1059 _PnpFilteredStartDeviceCompletionRoutine, 1060 pContext); 1061 } 1062 else { 1063 irp.SetCompletionRoutineEx( 1064 m_Device->GetDeviceObject(), 1065 _PnpStartDeviceCompletionRoutine, 1066 this); 1067 } 1068 1069 irp.CallDriver(m_Device->GetAttachedDevice()); 1070 } 1071 else { 1072 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1073 "PNP start preprocessing failed with %!STATUS!", 1074 status); 1075 1076 // 1077 // Move the state machine to the failed state. 1078 // 1079 // Process the event *before* completing the irp so that this even is in 1080 // the queue before the device remove event which will be be processed 1081 // right after the start irp has been completed. 1082 // 1083 PnpProcessEvent(PnpEventStartDeviceFailed); 1084 1085 // 1086 // All states which handle the PnpEventStartDeviceFailed event 1087 // transition do not expect a pended start irp. 1088 // 1089 CompletePnpRequest(&irp, status); 1090 } 1091 1092 // 1093 // Indicate to the caller that the transition is asynchronous. 1094 // 1095 return FALSE; 1096 } 1097 1098 WDF_DEVICE_PNP_STATE 1099 FxPkgFdo::PnpEventEjectHardwareOverload( 1100 VOID 1101 ) 1102 1103 /*++ 1104 1105 Routine Description: 1106 1107 This method implements the Eject Hardware state in the PnP State Machine. 1108 Since FDO and PDO behavior is different, this is overloaded. In fact, 1109 this state shouldn't be reachable for FDOs, as the FDO should have been 1110 torn off the stack before the device was cleanly ejected. 1111 1112 Arguments: 1113 1114 none 1115 1116 Returns: 1117 1118 WdfDevStatePnpEjectedWaitingForRemove 1119 1120 --*/ 1121 1122 { 1123 ASSERT(!"This should only be reachable for PDOs."); 1124 1125 // 1126 // Do something safe. Act like the device got 1127 // ejected. 1128 // 1129 return WdfDevStatePnpEjectedWaitingForRemove; 1130 } 1131 1132 WDF_DEVICE_PNP_STATE 1133 FxPkgFdo::PnpEventCheckForDevicePresenceOverload( 1134 VOID 1135 ) 1136 1137 /*++ 1138 1139 Routine Description: 1140 1141 This method implements the Check For Device Presence state in the PnP State 1142 Machine. Since FDO and PDO behavior is different, this is overloaded. In 1143 fact, this state shouldn't be reachable for FDOs, as the FDO should have 1144 been torn off the stack before the device was cleanly ejected. 1145 1146 Arguments: 1147 1148 none 1149 1150 Returns: 1151 1152 WdfDevStatePnpFinal 1153 1154 --*/ 1155 1156 { 1157 ASSERT(!"This should only be implemented for PDOs."); 1158 1159 // 1160 // Do something safe. Act like the device is not 1161 // present. 1162 // 1163 return WdfDevStatePnpFinal; 1164 } 1165 1166 WDF_DEVICE_PNP_STATE 1167 FxPkgFdo::PnpEventPdoRemovedOverload( 1168 VOID 1169 ) 1170 1171 /*++ 1172 1173 Routine Description: 1174 1175 This method implements the PDO Removed state in the PnP State Machine. 1176 Since FDO and PDO behavior is different, this is overloaded. In fact, 1177 this state shouldn't be reachable for FDOs, as the FDO should have been 1178 torn off the stack before the PDO is removed. 1179 1180 Arguments: 1181 1182 none 1183 1184 Returns: 1185 1186 none 1187 1188 --*/ 1189 1190 { 1191 ASSERT(!"This should only be implemented for PDOs."); 1192 1193 return WdfDevStatePnpFinal; 1194 } 1195 1196 WDF_DEVICE_PNP_STATE 1197 FxPkgFdo::PnpGetPostRemoveState( 1198 VOID 1199 ) 1200 1201 /*++ 1202 1203 Routine Description: 1204 1205 This method implements the Removed state in the PnP State Machine. 1206 Since FDO and PDO behavior is different, this is overloaded. This state 1207 just moves us toward the FDO-specific removal states. 1208 1209 Arguments: 1210 1211 none 1212 1213 Returns: 1214 1215 none 1216 1217 --*/ 1218 1219 { 1220 return WdfDevStatePnpFdoRemoved; 1221 } 1222 1223 WDF_DEVICE_PNP_STATE 1224 FxPkgFdo::PnpEventFdoRemovedOverload( 1225 VOID 1226 ) 1227 /*++ 1228 1229 Routine Description: 1230 FDO is being removed, see if there are any children that need to be removed 1231 1232 Arguments: 1233 None 1234 1235 Return Value: 1236 New device pnp state 1237 1238 --*/ 1239 { 1240 // 1241 // Do that which all device stacks need to do upon removal. 1242 // 1243 PnpEventRemovedCommonCode(); 1244 1245 return WdfDevStatePnpFinal; 1246 } 1247 1248 _Must_inspect_result_ 1249 NTSTATUS 1250 FxPkgFdo::ProcessRemoveDeviceOverload( 1251 __inout FxIrp* Irp 1252 ) 1253 { 1254 NTSTATUS status; 1255 1256 // 1257 // After this is called, any irp dispatched to FxDevice::DispatchWithLock 1258 // will fail with STATUS_INVALID_DEVICE_REQUEST. 1259 // 1260 Mx::MxReleaseRemoveLockAndWait(m_Device->GetRemoveLock(), 1261 Irp->GetIrp()); 1262 1263 // 1264 // Cleanup the state machines and release the power thread. 1265 // 1266 CleanupStateMachines(TRUE); 1267 1268 Irp->CopyCurrentIrpStackLocationToNext(); 1269 status = Irp->CallDriver(m_Device->GetAttachedDevice()); 1270 1271 // 1272 // Detach and delete the device object. 1273 // 1274 DeleteDevice(); 1275 1276 return status; 1277 } 1278 1279 VOID 1280 FxPkgFdo::DeleteSymbolicLinkOverload( 1281 __in BOOLEAN GracefulRemove 1282 ) 1283 /*++ 1284 1285 Routine Description: 1286 Role specific virtual function which determines if the symbolic link for a 1287 device should be deleted. 1288 1289 Arguments: 1290 None 1291 1292 Return Value: 1293 None 1294 1295 --*/ 1296 { 1297 UNREFERENCED_PARAMETER(GracefulRemove); 1298 1299 // 1300 // We always remove the symbolic link for an FDO since there is no presence 1301 // state to check. 1302 // 1303 m_Device->DeleteSymbolicLink(); 1304 } 1305 1306 VOID 1307 FxPkgFdo::QueryForReenumerationInterface( 1308 VOID 1309 ) 1310 { 1311 PREENUMERATE_SELF_INTERFACE_STANDARD pInterface; 1312 NTSTATUS status; 1313 1314 pInterface = &m_SurpriseRemoveAndReenumerateSelfInterface; 1315 1316 if (pInterface->SurpriseRemoveAndReenumerateSelf != NULL) { 1317 // 1318 // Already got it, just return. This function can be called again during 1319 // stop -> start, so we must check. 1320 // 1321 return; 1322 } 1323 1324 RtlZeroMemory(pInterface, sizeof(*pInterface)); 1325 pInterface->Size = sizeof(*pInterface); 1326 pInterface->Version = 1; 1327 1328 // 1329 // Since there are some stacks that are not PnP re-entrant 1330 1331 // we specify that the QI goes only to our attached device and 1332 // not to the top of the stack as a normal QI irp would. For the 1333 // reenumerate self interface, having someone on top of us filter the 1334 // IRP makes no sense anyways. 1335 // 1336 // We also do this as a preventative measure for other stacks we don't know 1337 // about internally and do not have access to when testing. 1338 // 1339 status = m_Device->QueryForInterface(&GUID_REENUMERATE_SELF_INTERFACE_STANDARD, 1340 (PINTERFACE) pInterface, 1341 sizeof(*pInterface), 1342 1, 1343 NULL, 1344 m_Device->GetAttachedDevice() 1345 ); 1346 1347 // 1348 // Failure to get this interface is not fatal. 1349 // Note that an implicit reference has been taken on the interface. We 1350 // must release the reference when we are done with the interface. 1351 // 1352 UNREFERENCED_PARAMETER(status); // for analyis tools. 1353 } 1354 1355 VOID 1356 FxPkgFdo::ReleaseReenumerationInterface( 1357 VOID 1358 ) 1359 /*++ 1360 1361 Routine Description: 1362 1363 Releases the implicit reference taken on REENUMERATE_SELF interface. 1364 NOOP for PDO. 1365 1366 Arguments: 1367 None 1368 1369 Return Value: 1370 VOID 1371 1372 --*/ 1373 { 1374 PREENUMERATE_SELF_INTERFACE_STANDARD pInterface; 1375 1376 pInterface = &m_SurpriseRemoveAndReenumerateSelfInterface; 1377 1378 pInterface->SurpriseRemoveAndReenumerateSelf = NULL; 1379 1380 if (pInterface->InterfaceDereference != NULL) { 1381 pInterface->InterfaceDereference(pInterface->Context); 1382 } 1383 } 1384 1385 _Must_inspect_result_ 1386 NTSTATUS 1387 FxPkgFdo::QueryForPowerThread( 1388 VOID 1389 ) 1390 /*++ 1391 1392 Routine Description: 1393 Sends a query for a power thread down the stack. If it can't query for one, 1394 it attempts to create one on its own. 1395 1396 Arguments: 1397 None 1398 1399 Return Value: 1400 NTSTATUS 1401 1402 --*/ 1403 { 1404 NTSTATUS status; 1405 1406 // 1407 // Query down the stack to see if a lower device already created a thread. 1408 // Do NOT send this to the top of the stack, it is sent to the attached 1409 // device b/c we need the thread from a device below us b/c its lifetime 1410 // will outlast this device's. 1411 // 1412 status = m_Device->QueryForInterface(&GUID_POWER_THREAD_INTERFACE, 1413 &m_PowerThreadInterface.Interface, 1414 sizeof(m_PowerThreadInterface), 1415 1, 1416 NULL, 1417 m_Device->GetAttachedDevice()); 1418 1419 if (NT_SUCCESS(status)) { 1420 // 1421 // A lower thread exists, use it 1422 // 1423 m_HasPowerThread = TRUE; 1424 } 1425 else { 1426 // 1427 // No thread exists yet, attempt to create our own 1428 // 1429 status = CreatePowerThread(); 1430 } 1431 1432 return status; 1433 } 1434 1435 _Must_inspect_result_ 1436 NTSTATUS 1437 FxPkgFdo::_PnpFilteredStartDeviceCompletionRoutine( 1438 __in MdDeviceObject DeviceObject, 1439 __inout MdIrp Irp, 1440 __inout PVOID Context 1441 ) 1442 { 1443 FxFilteredStartContext *pContext; 1444 FxPkgFdo* pPkgFdo; 1445 1446 pContext = (FxFilteredStartContext*) Context; 1447 1448 // 1449 // Save off the package so we can use it after we free the context 1450 // 1451 pPkgFdo = pContext->PkgFdo; 1452 1453 delete pContext; 1454 1455 return _PnpStartDeviceCompletionRoutine(DeviceObject, Irp, pPkgFdo); 1456 } 1457 1458 _Must_inspect_result_ 1459 NTSTATUS 1460 FxPkgFdo::_PnpStartDeviceCompletionRoutine( 1461 __in MdDeviceObject DeviceObject, 1462 __inout MdIrp Irp, 1463 __inout PVOID Context 1464 ) 1465 { 1466 FxPkgFdo* pThis; 1467 FxIrp irp(Irp); 1468 1469 UNREFERENCED_PARAMETER(DeviceObject); 1470 1471 pThis = (FxPkgFdo*) Context; 1472 1473 if (NT_SUCCESS(irp.GetStatus())) { 1474 pThis->SetPendingPnpIrp(&irp); 1475 1476 // 1477 // Only raise irql if we are the power policy owner. Only the p.p.o. 1478 // does this so that we only have one driver in the device stack moving 1479 // to another thread. 1480 // 1481 if (pThis->IsPowerPolicyOwner()) { 1482 KIRQL irql; 1483 1484 // 1485 // By raising to dispatch level we are forcing the pnp state machine 1486 // to move to another thread. On NT 6.0 PnP supports asynchronous 1487 // starts, so this will other starts to proceed while WDF processes 1488 // this device starting. 1489 // 1490 Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); 1491 pThis->PnpProcessEvent(PnpEventStartDeviceComplete); 1492 Mx::MxLowerIrql(irql); 1493 } 1494 else { 1495 pThis->PnpProcessEvent(PnpEventStartDeviceComplete); 1496 } 1497 } 1498 else { 1499 // 1500 // Just complete the request, the current pnp state can handle the remove 1501 // which will be sent b/c of the failed start. 1502 // 1503 DoTraceLevelMessage( 1504 pThis->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1505 "PNP start failed with %!STATUS!", irp.GetStatus()); 1506 1507 // 1508 // Process the event *before* completing the irp so that this even is in 1509 // the queue before the device remove event which will be be processed 1510 // right after the start irp has been completed. 1511 // 1512 pThis->PnpProcessEvent(PnpEventStartDeviceFailed); 1513 1514 pThis->CompletePnpRequest(&irp, irp.GetStatus()); 1515 } 1516 1517 return STATUS_MORE_PROCESSING_REQUIRED; 1518 } 1519 1520 _Must_inspect_result_ 1521 NTSTATUS 1522 FxPkgFdo::PostCreateDeviceInitialize( 1523 VOID 1524 ) 1525 { 1526 NTSTATUS status; 1527 1528 status = FxPkgPnp::PostCreateDeviceInitialize(); // __super call 1529 if (!NT_SUCCESS(status)) { 1530 return status; 1531 } 1532 1533 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 1534 // 1535 // Allow device simulation framework to hook interrupt routines. 1536 // 1537 if (GetDriverGlobals()->FxDsfOn) { 1538 status = QueryForDsfInterface(); 1539 if (!NT_SUCCESS(status)) { 1540 return status; 1541 } 1542 } 1543 1544 #endif 1545 1546 status = m_Device->AllocateTarget(&m_DefaultTarget, 1547 FALSE /*SelfTarget=FALSE*/); 1548 if (NT_SUCCESS(status)) { 1549 // 1550 // This will be released in the destructor 1551 // 1552 m_DefaultTarget->ADDREF(this); 1553 } 1554 1555 if (m_Device->m_SelfIoTargetNeeded) { 1556 status = m_Device->AllocateTarget((FxIoTarget**)&m_SelfTarget, 1557 TRUE /*SelfTarget*/); 1558 if (NT_SUCCESS(status)) { 1559 // 1560 // This will be released in the destructor 1561 // 1562 m_SelfTarget->ADDREF(this); 1563 } 1564 } 1565 1566 1567 return status; 1568 } 1569 1570