1 /*++ 2 3 Copyright (c) Microsoft. All rights reserved. 4 5 Module Name: 6 7 PnpStateMachine.cpp 8 9 Abstract: 10 11 This module implements the PnP state machine for the driver framework. 12 This code was split out from FxPkgPnp.cpp. 13 14 Author: 15 16 17 18 19 Environment: 20 21 Both kernel and user mode 22 23 Revision History: 24 25 26 27 --*/ 28 29 #include "pnppriv.hpp" 30 #include <wdmguid.h> 31 32 #include<ntstrsafe.h> 33 34 extern "C" { 35 #if defined(EVENT_TRACING) 36 #include "PnpStateMachine.tmh" 37 #endif 38 } 39 40 41 // 42 // The PnP State Machine 43 // 44 // This state machine responds to several PnP events: 45 // 46 // AddDevice -- Always targets the same state 47 // IRP_MN_START_DEVICE 48 // IRP_MN_START_DEVICE Complete -- Handled on the way up the stack 49 // IRP_MN_QUERY_REMOVE_DEVICE 50 // IRP_MN_QUERY_STOP_DEVICE 51 // IRP_MN_CANCEL_REMOVE_DEVICE 52 // IRP_MN_CANCEL_STOP_DEVICE 53 // IRP_MN_STOP_DEVICE 54 // IRP_MN_REMOVE_DEVICE 55 // IRP_MN_SURPRISE_REMOVE_DEVICE -- Always targets the same state 56 // IRP_MN_EJECT 57 // 58 // Each state has an entry for each of these events, listing the 59 // target state for each of them. 60 // 61 62 #if FX_STATE_MACHINE_VERIFY 63 #define VALIDATE_PNP_STATE(_CurrentState, _NewState) \ 64 ValidatePnpStateEntryFunctionReturnValue((_CurrentState), (_NewState)) 65 #else 66 #define VALIDATE_PNP_STATE(_CurrentState, _NewState) (0) 67 #endif //FX_STATE_MACHINE_VERIFY 68 69 // @@SMVERIFY_SPLIT_BEGIN 70 71 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpInitOtherStates[] = 72 { 73 { PnpEventQueryRemove, WdfDevStatePnpInitQueryRemove DEBUGGED_EVENT }, 74 { PnpEventRemove, WdfDevStatePnpRemoved DEBUGGED_EVENT }, 75 { PnpEventParentRemoved, WdfDevStatePnpRemoved DEBUGGED_EVENT }, 76 { PnpEventSurpriseRemove, WdfDevStatePnpInitSurpriseRemoved DEBUGGED_EVENT }, 77 { PnpEventEject, WdfDevStatePnpEjectHardware DEBUGGED_EVENT }, 78 { PnpEventNull, WdfDevStatePnpNull }, 79 }; 80 81 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpInitStartingOtherStates[] = 82 { 83 { PnpEventStartDeviceFailed, WdfDevStatePnpInit DEBUGGED_EVENT }, 84 { PnpEventNull, WdfDevStatePnpNull }, 85 }; 86 87 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpHardwareAvailableOtherStates[] = 88 { 89 { PnpEventPwrPolStartFailed, WdfDevStatePnpHardwareAvailablePowerPolicyFailed DEBUGGED_EVENT }, 90 { PnpEventNull, WdfDevStatePnpNull }, 91 }; 92 93 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpQueryStopPendingOtherStates[] = 94 { 95 { PnpEventCancelStop, WdfDevStatePnpQueryCanceled DEBUGGED_EVENT }, 96 { PnpEventSurpriseRemove, WdfDevStatePnpQueriedSurpriseRemove TRAP_ON_EVENT }, 97 { PnpEventNull, WdfDevStatePnpNull }, 98 }; 99 100 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpRemovedPdoWaitOtherStates[] = 101 { 102 { PnpEventStartDevice, WdfDevStatePnpPdoRestart DEBUGGED_EVENT }, 103 { PnpEventRemove, WdfDevStatePnpCheckForDevicePresence DEBUGGED_EVENT }, 104 { PnpEventParentRemoved, WdfDevStatePnpPdoRemoved DEBUGGED_EVENT }, 105 { PnpEventSurpriseRemove, WdfDevStatePnpRemovedPdoSurpriseRemoved DEBUGGED_EVENT }, 106 { PnpEventNull, WdfDevStatePnpNull }, 107 }; 108 109 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpRestartingOtherStates[] = 110 { 111 { PnpEventPwrPolStartFailed, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, 112 { PnpEventNull, WdfDevStatePnpNull }, 113 }; 114 115 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStartedOtherStates[] = 116 { 117 { PnpEventQueryStop, WdfDevStatePnpQueryStopStaticCheck DEBUGGED_EVENT }, 118 { PnpEventCancelStop, WdfDevStatePnpStartedCancelStop DEBUGGED_EVENT }, 119 { PnpEventCancelRemove, WdfDevStatePnpStartedCancelRemove DEBUGGED_EVENT }, 120 { PnpEventRemove, WdfDevStatePnpStartedRemoving DEBUGGED_EVENT }, 121 { PnpEventSurpriseRemove, WdfDevStatePnpSurpriseRemoveIoStarted DEBUGGED_EVENT }, 122 { PnpEventPowerUpFailed, WdfDevStatePnpFailedIoStarting DEBUGGED_EVENT }, 123 { PnpEventPowerDownFailed, WdfDevStatePnpFailedPowerDown DEBUGGED_EVENT }, 124 { PnpEventStartDevice, WdfDevStatePnpRestart DEBUGGED_EVENT }, 125 { PnpEventNull, WdfDevStatePnpNull }, 126 }; 127 128 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpQueryRemovePendingOtherStates[] = 129 { 130 { PnpEventCancelRemove, WdfDevStatePnpQueryCanceled DEBUGGED_EVENT }, 131 { PnpEventSurpriseRemove, WdfDevStatePnpQueriedSurpriseRemove TRAP_ON_EVENT }, 132 { PnpEventNull, WdfDevStatePnpNull }, 133 }; 134 135 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpQueriedRemovingOtherStates[] = 136 { 137 { PnpEventPwrPolStopFailed, WdfDevStatePnpRemovingDisableInterfaces DEBUGGED_EVENT }, 138 { PnpEventNull, WdfDevStatePnpNull }, 139 }; 140 141 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpInitQueryRemoveOtherStates[] = 142 { 143 { PnpEventCancelRemove, WdfDevStatePnpInitQueryRemoveCanceled DEBUGGED_EVENT }, 144 { PnpEventNull, WdfDevStatePnpNull }, 145 }; 146 147 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStoppedOtherStates[] = 148 { 149 { PnpEventSurpriseRemove, WdfDevStatePnpSurpriseRemove DEBUGGED_EVENT }, 150 { PnpEventNull, WdfDevStatePnpNull }, 151 }; 152 153 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStoppedWaitForStartCompletionOtherStates[] = 154 { 155 { PnpEventStartDeviceFailed, WdfDevStatePnpFailed TRAP_ON_EVENT }, 156 { PnpEventNull, WdfDevStatePnpNull }, 157 }; 158 159 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStartedStoppingOtherStates[] = 160 { 161 { PnpEventPwrPolStopFailed, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, 162 { PnpEventNull, WdfDevStatePnpNull }, 163 }; 164 165 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStartedStoppingFailedOtherStates[] = 166 { 167 { PnpEventPwrPolStopFailed, WdfDevStatePnpFailedOwnHardware TRAP_ON_EVENT }, 168 { PnpEventNull, WdfDevStatePnpNull }, 169 }; 170 171 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpEjectFailedOtherStates[] = 172 { 173 { PnpEventSurpriseRemove, WdfDevStatePnpSurpriseRemove TRAP_ON_EVENT }, 174 { PnpEventNull, WdfDevStatePnpNull }, 175 }; 176 177 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStartedRemovingOtherStates[] = 178 { 179 { PnpEventPwrPolStopFailed, WdfDevStatePnpRemovingDisableInterfaces DEBUGGED_EVENT }, 180 { PnpEventNull, WdfDevStatePnpNull }, 181 }; 182 183 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpFailedPowerDownOtherStates[] = 184 { 185 { PnpEventPwrPolStopFailed, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, 186 { PnpEventNull, WdfDevStatePnpNull }, 187 }; 188 189 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpFailedIoStartingOtherStates[] = 190 { 191 { PnpEventPwrPolStopFailed, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, 192 { PnpEventNull, WdfDevStatePnpNull }, 193 }; 194 195 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpFailedWaitForRemoveOtherStates[] = 196 { 197 { PnpEventSurpriseRemove, WdfDevStatePnpFailedSurpriseRemoved DEBUGGED_EVENT }, 198 { PnpEventStartDevice, WdfDevStatePnpFailedStarted TRAP_ON_EVENT }, 199 { PnpEventNull, WdfDevStatePnpNull }, 200 }; 201 202 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpRestartOtherStates[] = 203 { 204 { PnpEventPwrPolStopFailed, WdfDevStatePnpHardwareAvailablePowerPolicyFailed DEBUGGED_EVENT }, 205 { PnpEventNull, WdfDevStatePnpNull }, 206 }; 207 208 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpRestartReleaseHardware[] = 209 { 210 { PnpEventStartDeviceFailed, WdfDevStatePnpFailed TRAP_ON_EVENT }, 211 { PnpEventNull, WdfDevStatePnpNull }, 212 }; 213 214 const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpRestartHardwareAvailableOtherStates[] = 215 { 216 { PnpEventPwrPolStartFailed, WdfDevStatePnpHardwareAvailablePowerPolicyFailed DEBUGGED_EVENT }, 217 { PnpEventNull, WdfDevStatePnpNull }, 218 }; 219 220 const PNP_STATE_TABLE FxPkgPnp::m_WdfPnpStates[] = { 221 // State function 222 // First transition event & state 223 // Other transition events & states 224 // state info 225 226 // WdfDevStatePnpObjectCreated 227 { NULL, 228 { PnpEventAddDevice, WdfDevStatePnpInit DEBUGGED_EVENT }, 229 NULL, 230 { TRUE, 231 0 }, 232 }, 233 234 // WdfDevStatePnpCheckForDevicePresence 235 { FxPkgPnp::PnpEventCheckForDevicePresence, 236 { PnpEventNull, WdfDevStatePnpNull }, 237 NULL, 238 { FALSE, 239 0 }, 240 }, 241 242 // WdfDevStatePnpEjectFailed 243 { NULL, 244 { PnpEventStartDevice, WdfDevStatePnpPdoRestart DEBUGGED_EVENT }, 245 FxPkgPnp::m_PnpEjectFailedOtherStates, 246 { TRUE, 247 0 }, 248 }, 249 250 // WdfDevStatePnpEjectHardware 251 { FxPkgPnp::PnpEventEjectHardware, 252 { PnpEventNull, WdfDevStatePnpNull }, 253 NULL, 254 { FALSE, 255 0 }, 256 }, 257 258 // WdfDevStatePnpEjectedWaitingForRemove 259 { NULL, 260 { PnpEventRemove, WdfDevStatePnpPdoRemoved DEBUGGED_EVENT }, 261 NULL, 262 { TRUE, 263 PnpEventSurpriseRemove }, // can receive this if parent is surprise 264 // removed while the ejected pdo is waiting 265 // for remove. 266 }, 267 268 // WdfDevStatePnpInit 269 { NULL, 270 { PnpEventStartDevice, WdfDevStatePnpInitStarting DEBUGGED_EVENT }, 271 FxPkgPnp::m_PnpInitOtherStates, 272 { TRUE, 273 PnpEventStartDevice }, 274 }, 275 276 // WdfDevStatePnpInitStarting 277 { FxPkgPnp::PnpEventInitStarting, 278 { PnpEventStartDeviceComplete, WdfDevStatePnpHardwareAvailable DEBUGGED_EVENT }, 279 FxPkgPnp::m_PnpInitStartingOtherStates, 280 { TRUE, 281 0 }, 282 }, 283 284 // WdfDevStatePnpInitSurpriseRemoved 285 { FxPkgPnp::PnpEventInitSurpriseRemoved, 286 { PnpEventNull, WdfDevStatePnpNull }, 287 NULL, 288 { FALSE, 289 0 }, 290 }, 291 292 // WdfDevStatePnpHardwareAvailable 293 { FxPkgPnp::PnpEventHardwareAvailable, 294 { PnpEventPwrPolStarted, WdfDevStatePnpEnableInterfaces DEBUGGED_EVENT }, 295 FxPkgPnp::m_PnpHardwareAvailableOtherStates, 296 { FALSE, 297 PnpEventPowerUpFailed 298 }, 299 }, 300 301 // WdfDevStatePnpEnableInterfaces 302 { FxPkgPnp::PnpEventEnableInterfaces, 303 { PnpEventNull, WdfDevStatePnpNull }, 304 NULL, 305 { FALSE, 306 0 }, 307 }, 308 309 // WdfDevStatePnpHardwareAvailablePowerPolicyFailed 310 { FxPkgPnp::PnpEventHardwareAvailablePowerPolicyFailed, 311 { PnpEventNull, WdfDevStatePnpNull }, 312 NULL, 313 { FALSE, 314 0 }, 315 }, 316 317 // WdfDevStatePnpQueryRemoveAskDriver 318 { FxPkgPnp::PnpEventQueryRemoveAskDriver, 319 { PnpEventNull, WdfDevStatePnpNull }, 320 NULL, 321 { FALSE, 322 0 }, 323 }, 324 325 // WdfDevStatePnpQueryRemovePending 326 { FxPkgPnp::PnpEventQueryRemovePending, 327 { PnpEventRemove, WdfDevStatePnpQueriedRemoving DEBUGGED_EVENT }, 328 FxPkgPnp::m_PnpQueryRemovePendingOtherStates, 329 { TRUE, 330 0, 331 }, 332 }, 333 334 // WdfDevStatePnpQueryRemoveStaticCheck 335 { FxPkgPnp::PnpEventQueryRemoveStaticCheck, 336 { PnpEventNull, WdfDevStatePnpNull }, 337 NULL, 338 { FALSE, 339 0 }, 340 }, 341 342 // WdfDevStatePnpQueriedRemoving, 343 { FxPkgPnp::PnpEventQueriedRemoving, 344 { PnpEventPwrPolStopped, WdfDevStatePnpRemovingDisableInterfaces DEBUGGED_EVENT }, 345 FxPkgPnp::m_PnpQueriedRemovingOtherStates, 346 { FALSE, 347 PnpEventPowerDownFailed | // We ignore these power failed events because 348 PnpEventPowerUpFailed // they will be translated into failed power 349 // policy events. 350 }, 351 }, 352 353 // WdfDevStatePnpQueryStopAskDriver 354 { FxPkgPnp::PnpEventQueryStopAskDriver, 355 { PnpEventNull, WdfDevStatePnpNull }, 356 NULL, 357 { FALSE, 358 0 }, 359 }, 360 361 // WdfDevStatePnpQueryStopPending 362 { FxPkgPnp::PnpEventQueryStopPending, 363 { PnpEventStop, WdfDevStatePnpStartedStopping DEBUGGED_EVENT }, 364 FxPkgPnp::m_PnpQueryStopPendingOtherStates, 365 { TRUE, 366 0, 367 }, 368 }, 369 370 // WdfDevStatePnpQueryStopStaticCheck 371 { FxPkgPnp::PnpEventQueryStopStaticCheck, 372 { PnpEventNull, WdfDevStatePnpNull }, 373 NULL, 374 { FALSE, 375 0 }, 376 }, 377 378 // WdfDevStatePnpQueryCanceled, 379 { FxPkgPnp::PnpEventQueryCanceled, 380 { PnpEventNull, WdfDevStatePnpNull }, 381 NULL, 382 { FALSE, 383 0 }, 384 }, 385 386 // WdfDevStatePnpRemoved 387 { FxPkgPnp::PnpEventRemoved, 388 { PnpEventNull, WdfDevStatePnpNull }, 389 NULL, 390 { FALSE, 391 0 }, 392 }, 393 394 // WdfDevStatePnpPdoRemoved 395 { FxPkgPnp::PnpEventPdoRemoved, 396 { PnpEventNull, WdfDevStatePnpNull }, 397 NULL, 398 { FALSE, 399 0 }, 400 }, 401 402 // WdfDevStatePnpRemovedPdoWait 403 { FxPkgPnp::PnpEventRemovedPdoWait, 404 { PnpEventEject, WdfDevStatePnpEjectHardware DEBUGGED_EVENT }, 405 FxPkgPnp::m_PnpRemovedPdoWaitOtherStates, 406 { TRUE, 407 PnpEventCancelRemove | // Amazingly enough, you can get a cancel q.r. 408 // on a PDO without seeing the query remove if 409 // the stack is partially built 410 PnpEventQueryRemove | // Can get a query remove from the removed state 411 // when installing a PDO that is disabled 412 PnpEventPowerDownFailed // We may get this for a PDO if implicit power 413 // down callbacks were failed. The failed power 414 // policy stop event took care of rundown. 415 }, 416 }, 417 418 // WdfDevStatePnpRemovedPdoSurpriseRemoved 419 { FxPkgPnp::PnpEventRemovedPdoSurpriseRemoved, 420 { PnpEventNull, WdfDevStatePnpNull }, 421 NULL, 422 { FALSE, 423 0 }, 424 }, 425 426 // WdfDevStatePnpRemovingDisableInterfaces 427 { FxPkgPnp::PnpEventRemovingDisableInterfaces, 428 { PnpEventPwrPolRemoved, WdfDevStatePnpRemoved DEBUGGED_EVENT }, 429 NULL, 430 { FALSE, 431 0 }, 432 }, 433 434 // WdfDevStatePnpRestarting 435 { FxPkgPnp::PnpEventRestarting, 436 { PnpEventPwrPolStarted, WdfDevStatePnpStarted DEBUGGED_EVENT }, 437 FxPkgPnp::m_PnpRestartingOtherStates, 438 { FALSE, 439 PnpEventPowerUpFailed 440 }, 441 }, 442 443 // WdfDevStatePnpStarted 444 { FxPkgPnp::PnpEventStarted, 445 { PnpEventQueryRemove, WdfDevStatePnpQueryRemoveStaticCheck DEBUGGED_EVENT }, 446 FxPkgPnp::m_PnpStartedOtherStates, 447 { TRUE, 448 0, 449 }, 450 }, 451 452 // WdfDevStatePnpStartedCancelStop 453 { FxPkgPnp::PnpEventStartedCancelStop, 454 { PnpEventNull, WdfDevStatePnpNull }, 455 NULL, 456 { FALSE, 457 0 }, 458 }, 459 460 // WdfDevStatePnpStartedCancelRemove 461 { FxPkgPnp::PnpEventStartedCancelRemove, 462 { PnpEventNull, WdfDevStatePnpNull }, 463 NULL, 464 { FALSE, 465 0 }, 466 }, 467 468 // WdfDevStatePnpStartedRemoving 469 { FxPkgPnp::PnpEventStartedRemoving, 470 { PnpEventPwrPolStopped, WdfDevStatePnpRemovingDisableInterfaces DEBUGGED_EVENT }, 471 FxPkgPnp::m_PnpStartedRemovingOtherStates, 472 { TRUE, 473 PnpEventPowerUpFailed | // device was idled out and in Dx when we got removed 474 // and this event is due to the power up that occured 475 // to move it into D0 so it could be disarmed 476 PnpEventPowerDownFailed 477 }, 478 }, 479 480 // WdfDevStatePnpStartingFromStopped 481 { FxPkgPnp::PnpEventStartingFromStopped, 482 { PnpEventNull, WdfDevStatePnpNull }, 483 NULL, 484 { FALSE, 485 0 }, 486 }, 487 488 // WdfDevStatePnpStopped 489 { FxPkgPnp::PnpEventStopped, 490 { PnpEventStartDevice, WdfDevStatePnpStoppedWaitForStartCompletion DEBUGGED_EVENT }, 491 FxPkgPnp::m_PnpStoppedOtherStates, 492 { TRUE, 493 0, 494 }, 495 }, 496 497 // WdfDevStatePnpStoppedWaitForStartCompletion 498 { FxPkgPnp::PnpEventStoppedWaitForStartCompletion, 499 { PnpEventStartDeviceComplete, WdfDevStatePnpStartingFromStopped DEBUGGED_EVENT }, 500 FxPkgPnp::m_PnpStoppedWaitForStartCompletionOtherStates, 501 { TRUE, 502 0 }, 503 }, 504 505 // WdfDevStatePnpStartedStopping 506 { FxPkgPnp::PnpEventStartedStopping, 507 { PnpEventPwrPolStopped, WdfDevStatePnpStopped DEBUGGED_EVENT }, 508 FxPkgPnp::m_PnpStartedStoppingOtherStates, 509 { TRUE, 510 PnpEventPowerUpFailed | // device was idled out and in Dx when we got stopped 511 // and this event is due to the power up that occured 512 // to move it into D0 so it could be disarmed 513 PnpEventPowerDownFailed 514 }, 515 }, 516 517 // The function is named PnpEventSurpriseRemoved with a 'd' because 518 // PnpEventSurpriseRemove (no 'd') is an event name 519 520 // WdfDevStatePnpSurpriseRemove 521 { FxPkgPnp::PnpEventSurpriseRemoved, 522 { PnpEventNull, WdfDevStatePnpNull }, 523 NULL, 524 { FALSE, 525 0 }, 526 }, 527 528 // WdfDevStatePnpInitQueryRemove 529 { FxPkgPnp::PnpEventInitQueryRemove, 530 { PnpEventRemove, WdfDevStatePnpRemoved DEBUGGED_EVENT }, 531 FxPkgPnp::m_PnpInitQueryRemoveOtherStates, 532 { TRUE, 533 0 }, 534 }, 535 536 // WdfDevStatePnpInitQueryRemoveCanceled 537 { FxPkgPnp::PnpEventInitQueryRemoveCanceled, 538 { PnpEventNull, WdfDevStatePnpNull }, 539 NULL, 540 { TRUE, 541 0 }, 542 }, 543 544 // WdfDevStatePnpFdoRemoved 545 { FxPkgPnp::PnpEventFdoRemoved, 546 { PnpEventNull, WdfDevStatePnpNull }, 547 NULL, 548 { FALSE, 549 0 }, 550 }, 551 552 // WdfDevStatePnpRemovedWaitForChildren 553 { NULL, 554 { PnpEventChildrenRemovalComplete, WdfDevStatePnpRemovedChildrenRemoved DEBUGGED_EVENT }, 555 NULL, 556 { TRUE, 557 PnpEventPowerDownFailed // device power down even from processing remove 558 }, 559 }, 560 561 // WdfDevStatePnpQueriedSurpriseRemove 562 { FxPkgPnp::PnpEventQueriedSurpriseRemove, 563 { PnpEventNull, WdfDevStatePnpNull }, 564 NULL, 565 { FALSE, 566 0 }, 567 }, 568 569 // WdfDevStatePnpSurpriseRemoveIoStarted 570 { FxPkgPnp::PnpEventSurpriseRemoveIoStarted, 571 { PnpEventNull, WdfDevStatePnpNull }, 572 NULL, 573 { FALSE, 574 0 }, 575 }, 576 577 // WdfDevStatePnpFailedPowerDown 578 { FxPkgPnp::PnpEventFailedPowerDown, 579 { PnpEventPwrPolStopped, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, 580 FxPkgPnp::m_PnpFailedPowerDownOtherStates, 581 { FALSE, 582 PnpEventPowerDownFailed , 583 }, 584 }, 585 586 // WdfDevStatePnpFailedIoStarting 587 { FxPkgPnp::PnpEventFailedIoStarting, 588 { PnpEventPwrPolStopped, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, 589 FxPkgPnp::m_PnpFailedIoStartingOtherStates, 590 { FALSE, 591 PnpEventPowerDownFailed | 592 593 PnpEventPowerUpFailed // if the device idled out and then failed 594 // d0 entry, the power up failed can be passed 595 // up by the IoInvalidateDeviceRelations and 596 // subsequence surprise remove event. 597 }, 598 }, 599 600 // WdfDevStatePnpFailedOwnHardware 601 { FxPkgPnp::PnpEventFailedOwnHardware, 602 { PnpEventNull, WdfDevStatePnpNull }, 603 NULL, 604 { FALSE, 605 0 }, 606 }, 607 608 // WdfDevStatePnpFailed 609 { FxPkgPnp::PnpEventFailed, 610 { PnpEventPwrPolRemoved, WdfDevStatePnpFailedPowerPolicyRemoved DEBUGGED_EVENT }, 611 NULL, 612 { FALSE, 613 0, 614 }, 615 }, 616 617 // WdfDevStatePnpFailedSurpriseRemoved 618 { FxPkgPnp::PnpEventFailedSurpriseRemoved, 619 { PnpEventNull, WdfDevStatePnpNull }, 620 NULL, 621 { FALSE, 622 0, }, 623 }, 624 625 // WdfDevStatePnpFailedStarted 626 { FxPkgPnp::PnpEventFailedStarted, 627 { PnpEventNull, WdfDevStatePnpNull }, 628 NULL, 629 { FALSE, 630 0, }, 631 }, 632 633 // WdfDevStatePnpFailedWaitForRemove, 634 { NULL, 635 { PnpEventRemove, WdfDevStatePnpRemoved DEBUGGED_EVENT }, 636 FxPkgPnp::m_PnpFailedWaitForRemoveOtherStates, 637 { TRUE, 638 PnpEventPowerUpFailed | // initial power up failed, power policy start 639 // failed event moved the state machine to the 640 // failed state first 641 PnpEventPowerDownFailed | // implicitD3 power down failed 642 PnpEventQueryRemove | // start succeeded, but we still get a query in 643 // the removed case 644 PnpEventCancelStop | // power down failure while processing query stop 645 // and q.s. irp completed with error 646 PnpEventCancelRemove // power down failure while processing query remove 647 // and q.r. irp completed with error 648 }, 649 }, 650 651 // WdfDevStatePnpFailedInit 652 { FxPkgPnp::PnpEventFailedInit, 653 { PnpEventNull, WdfDevStatePnpNull }, 654 NULL, 655 { FALSE, 656 0 }, 657 }, 658 659 // WdfDevStatePnpPdoInitFailed 660 { FxPkgPnp::PnpEventPdoInitFailed, 661 { PnpEventNull, WdfDevStatePnpNull }, 662 NULL, 663 { FALSE, 664 0 }, 665 }, 666 667 // WdfDevStatePnpRestart 668 { FxPkgPnp::PnpEventRestart, 669 { PnpEventPwrPolStopped, WdfDevStatePnpRestartReleaseHardware DEBUGGED_EVENT }, 670 FxPkgPnp::m_PnpRestartOtherStates, 671 { FALSE, 672 PnpEventPowerUpFailed | // when stopping power policy, device was in 673 // Dx and bringing it to D0 succeeded or failed 674 PnpEventPowerDownFailed // same as power up 675 }, 676 }, 677 678 // WdfDevStatePnpRestartReleaseHardware 679 { FxPkgPnp::PnpEventRestartReleaseHardware, 680 { PnpEventStartDeviceComplete, WdfDevStatePnpRestartHardwareAvailable DEBUGGED_EVENT }, 681 FxPkgPnp::m_PnpRestartReleaseHardware, 682 { TRUE, 683 PnpEventPowerDownFailed // the previous pwr policy stop 684 // in WdfDevStaePnpRestart will 685 // cause these events to show up here 686 }, 687 }, 688 689 // WdfDevStatePnpRestartHardwareAvailable 690 { FxPkgPnp::PnpEventRestartHardwareAvailable, 691 { PnpEventPwrPolStarted, WdfDevStatePnpStarted DEBUGGED_EVENT }, 692 FxPkgPnp::m_PnpRestartHardwareAvailableOtherStates, 693 { TRUE, 694 PnpEventPowerUpFailed 695 }, 696 }, 697 698 // WdfDevStatePnpPdoRestart 699 { FxPkgPnp::PnpEventPdoRestart, 700 { PnpEventNull, WdfDevStatePnpNull }, 701 NULL, 702 { FALSE, 703 0 }, 704 }, 705 706 // WdfDevStatePnpFinal 707 { FxPkgPnp::PnpEventFinal, 708 { PnpEventNull, WdfDevStatePnpNull }, 709 NULL, 710 { TRUE, 711 PnpEventPowerDownFailed, // on the final implicit power down, a 712 // callback returned !NT_SUCCESS 713 }, 714 }, 715 716 // WdfDevStatePnpRemovedChildrenRemoved 717 { FxPkgPnp::PnpEventRemovedChildrenRemoved, 718 { PnpEventNull, WdfDevStatePnpNull }, 719 NULL, 720 { TRUE, 721 0 } , 722 }, 723 724 // WdfDevStatePnpQueryRemoveEnsureDeviceAwake 725 { FxPkgPnp::PnpEventQueryRemoveEnsureDeviceAwake, 726 { PnpEventDeviceInD0, WdfDevStatePnpQueryRemovePending DEBUGGED_EVENT }, 727 NULL, 728 { FALSE, 729 0 }, 730 }, 731 732 // WdfDevStatePnpQueryStopEnsureDeviceAwake 733 { FxPkgPnp::PnpEventQueryStopEnsureDeviceAwake, 734 { PnpEventDeviceInD0, WdfDevStatePnpQueryStopPending DEBUGGED_EVENT }, 735 NULL, 736 { FALSE, 737 0 }, 738 }, 739 740 // WdfDevStatePnpFailedPowerPolicyRemoved 741 { FxPkgPnp::PnpEventFailedPowerPolicyRemoved, 742 { PnpEventNull, WdfDevStatePnpNull }, 743 NULL, 744 { FALSE, 745 0 } , 746 }, 747 }; 748 749 // @@SMVERIFY_SPLIT_END 750 751 VOID 752 FxPkgPnp::PnpCheckAssumptions( 753 VOID 754 ) 755 /*++ 756 757 Routine Description: 758 This routine is never actually called by running code, it just has 759 WDFCASSERTs who upon failure, would not allow this file to be compiled. 760 761 DO NOT REMOVE THIS FUNCTION just because it is not callec by any running 762 code. 763 764 Arguments: 765 None 766 767 Return Value: 768 None 769 770 --*/ 771 { 772 WDFCASSERT(sizeof(FxPnpStateInfo) == sizeof(ULONG)); 773 774 WDFCASSERT((sizeof(m_WdfPnpStates)/sizeof(m_WdfPnpStates[0])) 775 == 776 (WdfDevStatePnpNull - WdfDevStatePnpObjectCreated)); 777 778 // we assume these are the same length when we update the history index 779 WDFCASSERT((sizeof(m_PnpMachine.m_Queue)/sizeof(m_PnpMachine.m_Queue[0])) 780 == 781 (sizeof(m_PnpMachine.m_States.History)/ 782 sizeof(m_PnpMachine.m_States.History[0]))); 783 } 784 785 /*++ 786 787 The locking model for the PnP state machine requires that events be enqueued 788 possibly at DISPATCH_LEVEL. It also requires that the PnP state machine be 789 runnable at PASSIVE_LEVEL. Consequently, we have two locks, one DISPATCH_LEVEL 790 lock that guards the event queue and one PASSIVE_LEVEL lock that guards the 791 state machine itself. 792 793 Algorithm: 794 795 1) Acquire the PnP queue lock. 796 2) Enqueue the request. Requests are put at the end of the queue, except if 797 they are PowerUp, or PowerDown, in which case they are put at the head of 798 the queue. 799 3) Drop the PnP queue lock. 800 4) If the thread is running at PASSIVE_LEVEL, skip to step 6. 801 5) Queue a work item onto any work queue. 802 6) Attempt to acquire the state machine lock, with a near-zero-length timeout. 803 7) If successful, skip to step 10. 804 8) Queue a work item onto any work queue. 805 9) Acquire the state machine lock. 806 10) Acquire the PnP queue lock. 807 11) Attempt to dequeue an event. 808 12) Drop the PnP queue lock. 809 13) If there was no event to dequeue, drop the state machine lock and exit. 810 14) Execute the state handler. This may involve taking one of the other state 811 machine queue locks, briefly, to deliver an event. 812 15) Go to Step 10. 813 814 Implementing this algorithm requires three functions. 815 816 PnpProcessEvent -- Implements steps 1-8. 817 _PnpProcessEventInner -- Implements step 9. 818 PnpProcessEventInner -- Implements steps 10-15. 819 820 --*/ 821 822 VOID 823 FxPkgPnp::PnpProcessEvent( 824 __in FxPnpEvent Event, 825 __in BOOLEAN ProcessOnDifferentThread 826 ) 827 /*++ 828 829 Routine Description: 830 This function implements steps 1-8 of the algorithm described above. 831 832 Arguments: 833 Event - Current PnP event 834 835 Return Value: 836 837 NTSTATUS 838 839 --*/ 840 { 841 NTSTATUS status; 842 KIRQL oldIrql; 843 844 // 845 // Take the lock, raising to DISPATCH_LEVEL. 846 // 847 m_PnpMachine.Lock(&oldIrql); 848 849 if (m_PnpMachine.IsFull()) { 850 DoTraceLevelMessage( 851 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 852 "WDFDEVICE 0x%p !devobj 0x%p current pnp state %!WDF_DEVICE_PNP_STATE! " 853 "dropping event %!FxPnpEvent! because of a full queue", 854 m_Device->GetHandle(), 855 m_Device->GetDeviceObject(), 856 m_Device->GetDevicePnpState(), 857 Event); 858 859 // 860 // The queue is full. Bail. 861 // 862 m_PnpMachine.Unlock(oldIrql); 863 864 ASSERT(!"The PnP queue is full. This shouldn't be able to happen."); 865 return; 866 } 867 868 if (m_PnpMachine.IsClosedLocked()) { 869 DoTraceLevelMessage( 870 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 871 "WDFDEVICE 0x%p !devobj 0x%p current pnp state %!WDF_DEVICE_PNP_STATE! " 872 "dropping event %!FxPnpEvent! because of a closed queue", 873 m_Device->GetHandle(), 874 m_Device->GetDeviceObject(), 875 m_Device->GetDevicePnpState(), 876 Event); 877 878 // 879 // The queue is closed. Bail 880 // 881 m_PnpMachine.Unlock(oldIrql); 882 883 return; 884 } 885 886 // 887 // Enqueue the event. Whether the event goes on the front 888 // or the end of the queue depends on which event it is. 889 // 890 if (Event & PnpPriorityEventsMask) { 891 // 892 // Stick it on the front of the queue, making it the next 893 // event that will be processed. 894 // 895 m_PnpMachine.m_Queue[m_PnpMachine.InsertAtHead()] = Event; 896 } 897 else { 898 // 899 // Stick it on the end of the queue. 900 // 901 m_PnpMachine.m_Queue[m_PnpMachine.InsertAtTail()] = Event; 902 } 903 904 // 905 // Drop the lock. 906 // 907 m_PnpMachine.Unlock(oldIrql); 908 909 // 910 // Now, if we are running at PASSIVE_LEVEL, attempt to run the state 911 // machine on this thread. If we can't do that, then queue a work item. 912 // 913 914 if (FALSE == ShouldProcessPnpEventOnDifferentThread( 915 oldIrql, 916 ProcessOnDifferentThread 917 )) { 918 919 LONGLONG timeout = 0; 920 921 status = m_PnpMachine.m_StateMachineLock.AcquireLock(GetDriverGlobals(), 922 &timeout); 923 924 if (FxWaitLockInternal::IsLockAcquired(status)) { 925 FxPostProcessInfo info; 926 927 // 928 // We now hold the state machine lock. So call the function that 929 // dispatches the next state. 930 // 931 PnpProcessEventInner(&info); 932 933 m_PnpMachine.m_StateMachineLock.ReleaseLock(GetDriverGlobals()); 934 935 info.Evaluate(this); 936 return; 937 } 938 } 939 940 // 941 // For one reason or another, we couldn't run the state machine on this 942 // thread. So queue a work item to do it. If m_PnPWorkItemEnqueuing 943 // is non-zero, that means that the work item is already being enqueued 944 // on another thread. This is significant, since it means that we can't do 945 // anything with the work item on this thread, but it's okay, since the 946 // work item will pick up our work and do it. 947 // 948 m_PnpMachine.QueueToThread(); 949 } 950 951 VOID 952 FxPkgPnp::_PnpProcessEventInner( 953 __inout FxPkgPnp* This, 954 __inout FxPostProcessInfo* Info, 955 __in PVOID WorkerContext 956 ) 957 { 958 UNREFERENCED_PARAMETER(WorkerContext); 959 960 // 961 // Take the state machine lock. 962 // 963 This->m_PnpMachine.m_StateMachineLock.AcquireLock( 964 This->GetDriverGlobals() 965 ); 966 967 // 968 // Call the function that will actually run the state machine. 969 // 970 This->PnpProcessEventInner(Info); 971 972 // 973 // We are being called from the work item and m_WorkItemRunning is > 0, so 974 // we cannot be deleted yet. 975 // 976 ASSERT(Info->SomethingToDo() == FALSE); 977 978 // 979 // Now release the lock 980 // 981 This->m_PnpMachine.m_StateMachineLock.ReleaseLock( 982 This->GetDriverGlobals() 983 ); 984 } 985 986 VOID 987 FxPkgPnp::PnpProcessEventInner( 988 __inout FxPostProcessInfo* Info 989 ) 990 /*++ 991 992 Routine Description: 993 This routine runs the state machine. It implements steps 10-15 of the 994 algorithm described above. 995 996 --*/ 997 { 998 WDF_DEVICE_PNP_STATE newState; 999 CPPNP_STATE_TABLE entry; 1000 FxPnpEvent event; 1001 KIRQL oldIrql; 1002 1003 // 1004 // Process as many events as we can. 1005 // 1006 for ( ; ; ) { 1007 entry = GetPnpTableEntry(m_Device->GetDevicePnpState()); 1008 1009 // 1010 // Get an event from the queue. 1011 // 1012 m_PnpMachine.Lock(&oldIrql); 1013 1014 if (m_PnpMachine.IsEmpty()) { 1015 m_PnpMachine.GetFinishedState(Info); 1016 1017 if (m_PnpMachine.m_FireAndForget) { 1018 m_PnpMachine.m_FireAndForget = FALSE; 1019 Info->m_FireAndForgetIrp = ClearPendingPnpIrp(); 1020 1021 ASSERT(Info->m_FireAndForgetIrp != NULL); 1022 } 1023 1024 Info->m_SetRemovedEvent = m_SetDeviceRemoveProcessed; 1025 m_SetDeviceRemoveProcessed = FALSE; 1026 1027 // 1028 // The queue is empty. 1029 // 1030 m_PnpMachine.Unlock(oldIrql); 1031 1032 return; 1033 } 1034 1035 event = m_PnpMachine.m_Queue[m_PnpMachine.GetHead()]; 1036 1037 // 1038 // At this point, we need to determine whether we can process this 1039 // event. 1040 // 1041 if (event & PnpPriorityEventsMask) { 1042 // 1043 // These are always possible to handle. 1044 // 1045 DO_NOTHING(); 1046 } 1047 else { 1048 // 1049 // Check to see if this state can handle new events. 1050 // 1051 if (entry->StateInfo.Bits.QueueOpen == FALSE) { 1052 // 1053 // This state can't handle new events. 1054 // 1055 m_PnpMachine.Unlock(oldIrql); 1056 return; 1057 } 1058 } 1059 1060 m_PnpMachine.IncrementHead(); 1061 m_PnpMachine.Unlock(oldIrql); 1062 1063 // 1064 // Find the entry in the PnP state table that corresponds 1065 // to this event. 1066 // 1067 newState = WdfDevStatePnpNull; 1068 1069 if (entry->FirstTargetState.PnpEvent == event) { 1070 newState = entry->FirstTargetState.TargetState; 1071 1072 DO_EVENT_TRAP(&entry->FirstTargetState); 1073 } 1074 else if (entry->OtherTargetStates != NULL) { 1075 ULONG i = 0; 1076 1077 for (i = 0; 1078 entry->OtherTargetStates[i].PnpEvent != PnpEventNull; 1079 i++) { 1080 if (entry->OtherTargetStates[i].PnpEvent == event) { 1081 newState = entry->OtherTargetStates[i].TargetState; 1082 DO_EVENT_TRAP(&entry->OtherTargetStates[i]); 1083 break; 1084 } 1085 } 1086 } 1087 1088 if (newState == WdfDevStatePnpNull) { 1089 DoTraceLevelMessage( 1090 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 1091 "WDFDEVICE 0x%p !devobj 0x%p current pnp state " 1092 "%!WDF_DEVICE_PNP_STATE! dropping event %!FxPnpEvent!", 1093 m_Device->GetHandle(), 1094 m_Device->GetDeviceObject(), 1095 m_Device->GetDevicePnpState(), 1096 event); 1097 1098 if ((entry->StateInfo.Bits.KnownDroppedEvents & event) == 0) { 1099 COVERAGE_TRAP(); 1100 1101 DoTraceLevelMessage( 1102 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, 1103 "WDFDEVICE 0x%p !devobj %p current state " 1104 "%!WDF_DEVICE_PNP_STATE!, policy event %!FxPnpEvent! is not" 1105 " a known dropped event, known dropped events are " 1106 "%!FxPnpEvent!", 1107 m_Device->GetHandle(), 1108 m_Device->GetDeviceObject(), 1109 m_Device->GetDevicePnpState(), 1110 event, 1111 entry->StateInfo.Bits.KnownDroppedEvents); 1112 1113 // DIAG: add diag code here 1114 } 1115 1116 // 1117 // This state doesn't respond to the Event. Make sure we do not 1118 // drop an event which pends a pnp irp on the floor though. 1119 // 1120 if (event & PnpEventPending) { 1121 // 1122 // In the case of a previous power up/down failure, the following 1123 // can happen 1124 // 1 invalidate device relations 1125 // 2 failure event is posted to pnp state machine 1126 // 3 process power failure event first, but while processing, 1127 // query device state is completed, and failed /removed is reported 1128 // 4 surprise remove comes, the irp is queued, the event is queued 1129 // 5 processing of power failure event continues, gets to 1130 // Failed and completes the s.r irp 1131 // 6 the surprise remove event is processed (the current value 1132 // of the local var event), but since we are already in the 1133 // Failed state, we ignore this event and end up 1134 // here. 1135 // 1136 // This means that if we are processing surprise remove, we cannot 1137 // 100% expect that an irp has been pended. 1138 // 1139 PnpFinishProcessingIrp( 1140 (event == PnpEventSurpriseRemove) ? FALSE : TRUE); 1141 } 1142 else { 1143 DO_NOTHING(); 1144 } 1145 } 1146 else { 1147 // 1148 // Now enter the new state. 1149 // 1150 PnpEnterNewState(newState); 1151 } 1152 } 1153 } 1154 1155 VOID 1156 FxPkgPnp::PnpEnterNewState( 1157 __in WDF_DEVICE_PNP_STATE State 1158 ) 1159 /*++ 1160 1161 Routine Description: 1162 This function looks up the handler for a state and 1163 then calls it. 1164 1165 Arguments: 1166 Event - Current PnP event 1167 1168 Return Value: 1169 None. 1170 1171 --*/ 1172 { 1173 CPPNP_STATE_TABLE entry; 1174 WDF_DEVICE_PNP_STATE currentState, newState; 1175 WDF_DEVICE_PNP_NOTIFICATION_DATA data; 1176 1177 currentState = m_Device->GetDevicePnpState(); 1178 newState = State; 1179 1180 while (newState != WdfDevStatePnpNull) { 1181 DoTraceLevelMessage( 1182 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES, 1183 "WDFDEVICE 0x%p !devobj 0x%p entering PnP State " 1184 "%!WDF_DEVICE_PNP_STATE! from %!WDF_DEVICE_PNP_STATE!", 1185 m_Device->GetHandle(), 1186 m_Device->GetDeviceObject(), 1187 newState, 1188 currentState); 1189 1190 if (m_PnpStateCallbacks != NULL) { 1191 // 1192 // Callback for leaving the old state 1193 // 1194 RtlZeroMemory(&data, sizeof(data)); 1195 1196 data.Type = StateNotificationLeaveState; 1197 data.Data.LeaveState.CurrentState = currentState; 1198 data.Data.LeaveState.NewState = newState; 1199 1200 m_PnpStateCallbacks->Invoke(currentState, 1201 StateNotificationLeaveState, 1202 m_Device->GetHandle(), 1203 &data); 1204 } 1205 1206 m_PnpMachine.m_States.History[m_PnpMachine.IncrementHistoryIndex()] = 1207 (USHORT) newState; 1208 1209 if (m_PnpStateCallbacks != NULL) { 1210 // 1211 // Callback for entering the new state 1212 // 1213 RtlZeroMemory(&data, sizeof(data)); 1214 1215 data.Type = StateNotificationEnterState; 1216 data.Data.EnterState.CurrentState = currentState; 1217 data.Data.EnterState.NewState = newState; 1218 1219 m_PnpStateCallbacks->Invoke(newState, 1220 StateNotificationEnterState, 1221 m_Device->GetHandle(), 1222 &data); 1223 } 1224 1225 m_Device->SetDevicePnpState(newState); 1226 currentState = newState; 1227 1228 entry = GetPnpTableEntry(currentState); 1229 1230 // 1231 // Call the state handler if one is present and record our new state 1232 // 1233 if (entry->StateFunc != NULL) { 1234 newState = entry->StateFunc(this); 1235 1236 // 1237 // Validate the return value if FX_STATE_MACHINE_VERIFY is enabled 1238 // 1239 VALIDATE_PNP_STATE(currentState, newState); 1240 } 1241 else { 1242 newState = WdfDevStatePnpNull; 1243 } 1244 1245 if (m_PnpStateCallbacks != NULL) { 1246 // 1247 // Callback for post processing the new state 1248 // 1249 RtlZeroMemory(&data, sizeof(data)); 1250 1251 data.Type = StateNotificationPostProcessState; 1252 data.Data.PostProcessState.CurrentState = currentState; 1253 1254 m_PnpStateCallbacks->Invoke(currentState, 1255 StateNotificationPostProcessState, 1256 m_Device->GetHandle(), 1257 &data); 1258 } 1259 } 1260 } 1261 1262 WDF_DEVICE_PNP_STATE 1263 FxPkgPnp::PnpEventCheckForDevicePresence( 1264 __inout FxPkgPnp* This 1265 ) 1266 /*++ 1267 1268 Routine Description: 1269 This function implements the Check For Device 1270 Presence state. This is a state that is specific 1271 to PDOs, so this function should be overloaded by 1272 the PDO class and never called. 1273 1274 Arguments: 1275 none 1276 1277 Return Value: 1278 1279 VOID 1280 1281 --*/ 1282 { 1283 return This->PnpEventCheckForDevicePresenceOverload(); 1284 } 1285 1286 WDF_DEVICE_PNP_STATE 1287 FxPkgPnp::PnpEventEjectHardware( 1288 __inout FxPkgPnp* This 1289 ) 1290 /*++ 1291 1292 Routine Description: 1293 This function implements the Eject Hardware state. 1294 This is a state that is specific to PDOs, so this 1295 function should be overloaded by the PDO class 1296 and never called. 1297 1298 Arguments: 1299 none 1300 1301 Return Value: 1302 1303 VOID 1304 1305 --*/ 1306 { 1307 return This->PnpEventEjectHardwareOverload(); 1308 } 1309 1310 WDF_DEVICE_PNP_STATE 1311 FxPkgPnp::PnpEventInitStarting( 1312 __inout FxPkgPnp* This 1313 ) 1314 /*++ 1315 1316 Routine Description: 1317 The device is recieving a start for the first time. The start is on the way 1318 down the stack. 1319 1320 Arguments: 1321 This - instance of the state machine 1322 1323 Return Value: 1324 new machine state 1325 1326 --*/ 1327 { 1328 if (This->PnpSendStartDeviceDownTheStackOverload() == FALSE) { 1329 // 1330 // Start was sent asynchronously down the stack, the irp's completion 1331 // routine will move the state machine to the new state. 1332 // 1333 return WdfDevStatePnpNull; 1334 } 1335 1336 return WdfDevStatePnpHardwareAvailable; 1337 } 1338 1339 WDF_DEVICE_PNP_STATE 1340 FxPkgPnp::PnpEventInitSurpriseRemoved( 1341 __inout FxPkgPnp* This 1342 ) 1343 /*++ 1344 1345 Routine Description: 1346 This transition should only occur for a PDO. 1347 1348 The device was initialized, but then it's parent bus was surprise removed. 1349 Complete the surprise remove and wait for the remove. 1350 1351 Arguments: 1352 This - instance of the state machine 1353 1354 Return Value: 1355 WdfDevStatePnpInit 1356 1357 --*/ 1358 { 1359 This->PnpFinishProcessingIrp(TRUE); 1360 1361 return WdfDevStatePnpInit; 1362 } 1363 1364 WDF_DEVICE_PNP_STATE 1365 FxPkgPnp::PnpEventHardwareAvailable( 1366 __inout FxPkgPnp* This 1367 ) 1368 /*++ 1369 1370 Routine Description: 1371 This function implements the Hardware Available state. 1372 1373 Arguments: 1374 none 1375 1376 Return Value: 1377 1378 VOID 1379 1380 --*/ 1381 { 1382 NTSTATUS status; 1383 BOOLEAN matched; 1384 1385 status = STATUS_SUCCESS; 1386 matched = FALSE; 1387 1388 This->QueryForReenumerationInterface(); 1389 1390 status = This->CreatePowerThreadIfNeeded(); 1391 1392 if (NT_SUCCESS(status)) { 1393 status = This->PnpPrepareHardware(&matched); 1394 } 1395 1396 if (!NT_SUCCESS(status)) { 1397 if (matched == FALSE) { 1398 // 1399 // NOTE: consider going to WdfDevStatePnpFailed instead of yet 1400 // another failed state out of start device handling. 1401 // 1402 1403 // 1404 // We can handle remove out of the init state, revert back to that 1405 // state. 1406 // 1407 return WdfDevStatePnpFailedInit; 1408 } 1409 else { 1410 // 1411 // EvtDevicePrepareHardware is what failed, goto a state where we 1412 // undo that call. 1413 // 1414 return WdfDevStatePnpFailedOwnHardware; 1415 } 1416 } 1417 1418 // 1419 // We only query for the capabilities for the power policy owner because 1420 // we use the capabilities to determine the right Dx state when we want to 1421 // wake from S0 or Sx. Since only the power policy owner can enable wake 1422 // behavior, only the owner needs to query for the information. 1423 // 1424 // ALSO, if we are a filter, there are issues in stacks wrt pnp reentrancy. 1425 1426 1427 1428 1429 1430 1431 1432 // 1433 if (This->IsPowerPolicyOwner()) { 1434 // 1435 // Query the stack for capabilities before telling the stack hw is 1436 // available 1437 // 1438 status = This->QueryForCapabilities(); 1439 1440 if (!NT_SUCCESS(status)) { 1441 DoTraceLevelMessage( 1442 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1443 "could not query caps for stack, %!STATUS!", status); 1444 1445 This->SetPendingPnpIrpStatus(status); 1446 return WdfDevStatePnpFailedOwnHardware; 1447 } 1448 1449 This->m_CapsQueried = TRUE; 1450 } 1451 1452 This->PnpPowerPolicyStart(); 1453 1454 return WdfDevStatePnpNull; 1455 } 1456 1457 WDF_DEVICE_PNP_STATE 1458 FxPkgPnp::PnpEventEnableInterfaces( 1459 __inout FxPkgPnp* This 1460 ) 1461 /*++ 1462 1463 Routine Description: 1464 The device has powered up and fully started, now enable the device 1465 interfaces and WMI. We wait until the last possible moment because on 1466 win2k WMI registration is not synchronized with the completion of start 1467 device, so if we register WMI early in start device processing, we could get 1468 wmi requests while we are initializing, which is a race condition we want 1469 to eliminate. 1470 1471 Arguments: 1472 This - instance of the state machine 1473 1474 Return Value: 1475 new state 1476 1477 --*/ 1478 { 1479 NTSTATUS status; 1480 1481 status = This->PnpEnableInterfacesAndRegisterWmi(); 1482 1483 if (!NT_SUCCESS(status)) { 1484 // 1485 // Upon failure, PnpEnableInterfacesAndRegisterWmi already marked the 1486 // irp as failed and recorded an internal error. 1487 // 1488 // FailedPowerDown will gracefully tear down the stack and bring it out 1489 // of D0. 1490 // 1491 return WdfDevStatePnpFailedPowerDown; 1492 } 1493 1494 return WdfDevStatePnpStarted; 1495 } 1496 1497 WDF_DEVICE_PNP_STATE 1498 FxPkgPnp::PnpEventHardwareAvailablePowerPolicyFailed( 1499 __inout FxPkgPnp* This 1500 ) 1501 /*++ 1502 1503 Routine Description: 1504 Our previous state called PowerPolicyStart or PowerPolicyStopRemove and the 1505 power state machine could not perform the requested action. We still have 1506 a start irp pending, so set its status and then proceed down the start failure 1507 path. 1508 1509 Arguments: 1510 This - instance of the state machien 1511 1512 Return Value: 1513 WdfDevStatePnpFailedOwnHardware 1514 1515 --*/ 1516 { 1517 This->SetPendingPnpIrpStatus(STATUS_DEVICE_POWER_FAILURE); 1518 1519 return WdfDevStatePnpFailedOwnHardware; 1520 } 1521 1522 WDF_DEVICE_PNP_STATE 1523 FxPkgPnp::PnpEventQueryRemoveAskDriver( 1524 __inout FxPkgPnp* This 1525 ) 1526 /*++ 1527 1528 Routine Description: 1529 This function implements the Query Remove Ask Driver 1530 state. It's job is to invoke EvtDeviceQueryRemove and then complete the 1531 QueryRemove IRP if needed. 1532 1533 Arguments: 1534 This - instance of the state machine 1535 1536 Return Value: 1537 new state 1538 1539 --*/ 1540 { 1541 WDF_DEVICE_PNP_STATE state; 1542 NTSTATUS status; 1543 1544 // 1545 // First, call the driver. If it succeeds, look at whether 1546 // it managed to stop its stuff. 1547 // 1548 status = This->m_DeviceQueryRemove.Invoke(This->m_Device->GetHandle()); 1549 1550 if (NT_SUCCESS(status)) { 1551 // 1552 // The driver has stopped all of its self managed io. Proceed to 1553 // stop everything before passing the request down the stack. 1554 // 1555 state = WdfDevStatePnpQueryRemoveEnsureDeviceAwake; 1556 } 1557 else { 1558 // 1559 // The callback didn't manage to stop. Go back to the Started state 1560 // where we will complete the pended pnp irp 1561 // 1562 DoTraceLevelMessage( 1563 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1564 "EvtDeviceQueryRemove failed, %!STATUS!", status); 1565 1566 if (status == STATUS_NOT_SUPPORTED) { 1567 DoTraceLevelMessage( 1568 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1569 "EvtDeviceQueryRemove returned an invalid status " 1570 "STATUS_NOT_SUPPORTED"); 1571 1572 if (This->GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) { 1573 FxVerifierDbgBreakPoint(This->GetDriverGlobals()); 1574 } 1575 } 1576 1577 state = WdfDevStatePnpStarted; 1578 } 1579 1580 This->SetPendingPnpIrpStatus(status); 1581 1582 return state; 1583 } 1584 1585 WDF_DEVICE_PNP_STATE 1586 FxPkgPnp::PnpEventQueryRemoveEnsureDeviceAwake( 1587 __inout FxPkgPnp *This 1588 ) 1589 /*++ 1590 Routine Description: 1591 This function brings the device to a working state if it is idle. If the 1592 device is already in working state, it ensures that it does not idle out. 1593 1594 Arguments: 1595 This - instance of the state machine 1596 1597 Return Value: 1598 new state 1599 --*/ 1600 { 1601 NTSTATUS status; 1602 WDF_DEVICE_PNP_STATE state; 1603 1604 // 1605 // Make sure that the device is powered on before we send the query remove 1606 // on its way. If we do this after we send the query remove, we could race 1607 // with the remove which removes the reference and we want the device 1608 // powered on when processing remove. 1609 // 1610 status = This->PnpPowerReferenceDuringQueryPnp(); 1611 if (STATUS_PENDING == status) { 1612 // 1613 // Device is transitioning to D0. The Pnp state machine will wait in 1614 // the current state until the transition is complete 1615 // 1616 state = WdfDevStatePnpNull; 1617 } 1618 else if (NT_SUCCESS(status)) { 1619 // 1620 // Already in D0 1621 // 1622 state = WdfDevStatePnpQueryRemovePending; 1623 } 1624 else { 1625 DoTraceLevelMessage( 1626 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1627 "StopIdle on WDFDEVICE %p failed, %!STATUS!, failing query remove", 1628 This->m_Device->GetHandle(), status); 1629 1630 This->SetPendingPnpIrpStatus(status); 1631 1632 // 1633 // The Started state will complete the irp when it sees the failure 1634 // status set on the irp. 1635 // 1636 state = WdfDevStatePnpStarted; 1637 } 1638 1639 return state; 1640 } 1641 1642 WDF_DEVICE_PNP_STATE 1643 FxPkgPnp::PnpEventQueryRemovePending( 1644 __inout FxPkgPnp* This 1645 ) 1646 /*++ 1647 1648 Routine Description: 1649 The device has fully stopped. Let go of the query remove irp. 1650 1651 Arguments: 1652 This - instance of the state machine for this device 1653 1654 Return Value: 1655 WdfDevStatePnpNull 1656 1657 --*/ 1658 1659 { 1660 FxIrp irp; 1661 1662 irp.SetIrp(This->ClearPendingPnpIrp()); 1663 (void) This->FireAndForgetIrp(&irp); 1664 return WdfDevStatePnpNull; 1665 } 1666 1667 WDF_DEVICE_PNP_STATE 1668 FxPkgPnp::PnpEventQueryRemoveStaticCheck( 1669 __inout FxPkgPnp* This 1670 ) 1671 /*++ 1672 1673 Routine Description: 1674 This function implements the Query Remove Static Check 1675 state. It's job is to determine whether this device, 1676 in general, can stop. If it can, then we proceed on 1677 to Query Remove Ask Driver. If not, then we go to 1678 back to Started. 1679 1680 Arguments: 1681 none 1682 1683 Return Value: 1684 1685 VOID 1686 1687 --*/ 1688 { 1689 NTSTATUS status; 1690 BOOLEAN completeQuery; 1691 1692 completeQuery = TRUE; 1693 1694 if (This->m_DeviceStopCount != 0) { 1695 DoTraceLevelMessage( 1696 This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 1697 "Failing QueryRemoveDevice because the driver " 1698 "has indicated that it cannot be stopped, count %d", 1699 This->m_DeviceStopCount); 1700 1701 status = STATUS_INVALID_DEVICE_STATE; 1702 } 1703 else if (This->IsInSpecialUse()) { 1704 DoTraceLevelMessage( 1705 This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 1706 "Failing QueryRemoveDevice due to open special file counts " 1707 "(paging %d, hiber %d, dump %d, boot %d)", 1708 This->GetUsageCount(WdfSpecialFilePaging), 1709 This->GetUsageCount(WdfSpecialFileHibernation), 1710 This->GetUsageCount(WdfSpecialFileDump), 1711 This->GetUsageCount(WdfSpecialFileBoot)); 1712 1713 status = STATUS_DEVICE_NOT_READY; 1714 } 1715 else { 1716 // 1717 // Go on to next state in the "remove" progression. 1718 // 1719 completeQuery = FALSE; 1720 status = STATUS_SUCCESS; 1721 } 1722 1723 if (completeQuery) { 1724 // 1725 // Store the status which Started will complete 1726 // 1727 This->SetPendingPnpIrpStatus(status); 1728 1729 // 1730 // Revert to started 1731 // 1732 return WdfDevStatePnpStarted; 1733 } 1734 else { 1735 // 1736 // Wait for the other state machines to stop 1737 // 1738 return WdfDevStatePnpQueryRemoveAskDriver; 1739 } 1740 } 1741 1742 WDF_DEVICE_PNP_STATE 1743 FxPkgPnp::PnpEventQueriedRemoving( 1744 __inout FxPkgPnp* This 1745 ) 1746 /*++ 1747 1748 Routine Description: 1749 The device was query removed and is now in the removed state. 1750 1751 Arguments: 1752 This - instance of the state machine 1753 1754 Return Value: 1755 WdfDevStatePnpNull 1756 1757 --*/ 1758 { 1759 // 1760 // It is important to stop power policy before releasing the reference. 1761 // If the reference was released first, we could get into a situation where 1762 // we immediately go idle and then we must send a D0 irp when in the remove. 1763 // If there are devices on top of this device and we send a D0 irp during 1764 // remove processing, the upper devices will be sent an irp after getting a 1765 // pnp remove (and either crash or fail the power irp upon receiving it). 1766 // 1767 This->PnpPowerPolicyStop(); 1768 This->PnpPowerDereferenceSelf(); 1769 1770 return WdfDevStatePnpNull; 1771 } 1772 1773 WDF_DEVICE_PNP_STATE 1774 FxPkgPnp::PnpEventQueryStopAskDriver( 1775 __inout FxPkgPnp* This 1776 ) 1777 /*++ 1778 1779 Routine Description: 1780 This function implements the Query Stop Ask Driver 1781 state. It's job is to invoke the EvtDeviceQueryStop 1782 callback and then complete the QueryStop IRP if needed. 1783 1784 Arguments: 1785 This - instance of the state machine 1786 1787 Return Value: 1788 new state 1789 1790 --*/ 1791 { 1792 WDF_DEVICE_PNP_STATE state; 1793 NTSTATUS status; 1794 1795 // 1796 // First, call the driver. If it succeeds, look at whether 1797 // it managed to stop its stuff. 1798 // 1799 status = This->m_DeviceQueryStop.Invoke(This->m_Device->GetHandle()); 1800 1801 if (NT_SUCCESS(status)) { 1802 // 1803 // Tell the other state machines to stop 1804 // 1805 state = WdfDevStatePnpQueryStopEnsureDeviceAwake; 1806 } 1807 else { 1808 DoTraceLevelMessage( 1809 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1810 "EvtDeviceQueryStop failed, %!STATUS!", status); 1811 1812 if (status == STATUS_NOT_SUPPORTED) { 1813 DoTraceLevelMessage( 1814 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1815 "EvtDeviceQueryStop returned an invalid status " 1816 "STATUS_NOT_SUPPORTED"); 1817 1818 if (This->GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) { 1819 FxVerifierDbgBreakPoint(This->GetDriverGlobals()); 1820 } 1821 } 1822 1823 // 1824 // The callback didn't manage to stop. Go back to the Started state. 1825 // 1826 state = WdfDevStatePnpStarted; 1827 } 1828 1829 This->SetPendingPnpIrpStatus(status); 1830 1831 return state; 1832 } 1833 1834 WDF_DEVICE_PNP_STATE 1835 FxPkgPnp::PnpEventQueryStopEnsureDeviceAwake( 1836 __inout FxPkgPnp *This 1837 ) 1838 /*++ 1839 Routine Description: 1840 This function brings the device to a working state if it is idle. If the 1841 device is already in working state, it ensures that it does not idle out. 1842 1843 Arguments: 1844 This - instance of the state machine 1845 1846 Return Value: 1847 new state 1848 --*/ 1849 { 1850 NTSTATUS status; 1851 WDF_DEVICE_PNP_STATE state; 1852 1853 // 1854 // Make sure that the device is powered on before we send the query stop 1855 // on its way. If we do this after we send the query stop, we could race 1856 // with the stop and we want the device powered on when processing stop. 1857 // 1858 status = This->PnpPowerReferenceDuringQueryPnp(); 1859 if (STATUS_PENDING == status) { 1860 // 1861 // Device is transitioning to D0. The Pnp state machine will wait in 1862 // the current state until the transition is complete 1863 // 1864 state = WdfDevStatePnpNull; 1865 } 1866 else if (NT_SUCCESS(status)) { 1867 // 1868 // Already in D0 1869 // 1870 state = WdfDevStatePnpQueryStopPending; 1871 } 1872 else { 1873 DoTraceLevelMessage( 1874 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1875 "StopIdle on WDFDEVICE %p failed, %!STATUS!, failing query stop", 1876 This->m_Device->GetHandle(), status); 1877 1878 This->SetPendingPnpIrpStatus(status); 1879 1880 // 1881 // The Started state will complete the irp when it sees the failure 1882 // status set on the irp. 1883 // 1884 state = WdfDevStatePnpStarted; 1885 } 1886 1887 return state; 1888 } 1889 1890 WDF_DEVICE_PNP_STATE 1891 FxPkgPnp::PnpEventQueryStopPending( 1892 __inout FxPkgPnp* This 1893 ) 1894 /*++ 1895 1896 Routine Description: 1897 Everything in the device has stopped due to the stop device irp. Complete 1898 it now 1899 1900 Arguments: 1901 This - instance of the state machine 1902 1903 Return Value: 1904 WdfDevStatePnpNull 1905 1906 --*/ 1907 1908 { 1909 FxIrp irp; 1910 1911 irp.SetIrp(This->ClearPendingPnpIrp()); 1912 (void) This->FireAndForgetIrp(&irp); 1913 return WdfDevStatePnpNull; 1914 } 1915 1916 WDF_DEVICE_PNP_STATE 1917 FxPkgPnp::PnpEventQueryStopStaticCheck( 1918 __inout FxPkgPnp* This 1919 ) 1920 /*++ 1921 1922 Routine Description: 1923 This function implements the Query Stop Static Check state. It's job is to 1924 determine whether this device, in general, can stop. If it can, then we 1925 proceed on to Query Stop Ask Driver. Otherwise we will return to the 1926 Started state. If the driver has set that the state machine should ignore 1927 query stop/remove, the query will succeed, otherwise it will fail 1928 1929 Arguments: 1930 This - instance of the state machine 1931 1932 Return Value: 1933 new machine state 1934 1935 --*/ 1936 { 1937 NTSTATUS status; 1938 BOOLEAN completeQuery = TRUE; 1939 1940 if (This->m_DeviceStopCount != 0) { 1941 DoTraceLevelMessage( 1942 This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 1943 "Failing QueryStopDevice because the driver " 1944 "has indicated that it cannot be stopped, count %d", 1945 This->m_DeviceStopCount); 1946 1947 status = STATUS_INVALID_DEVICE_STATE; 1948 } 1949 else if (This->IsInSpecialUse()) { 1950 DoTraceLevelMessage( 1951 This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 1952 "Failing QueryStopDevice due to open special file counts (paging %d," 1953 " hiber %d, dump %d, boot %d)", 1954 This->GetUsageCount(WdfSpecialFilePaging), 1955 This->GetUsageCount(WdfSpecialFileHibernation), 1956 This->GetUsageCount(WdfSpecialFileDump), 1957 This->GetUsageCount(WdfSpecialFileBoot)); 1958 1959 status = STATUS_DEVICE_NOT_READY; 1960 } 1961 else { 1962 // 1963 // Go on to next state in the "stop" progression. 1964 // 1965 status = STATUS_SUCCESS; 1966 completeQuery = FALSE; 1967 } 1968 1969 if (completeQuery) { 1970 // 1971 // Set the state which started will complete the request with 1972 // 1973 This->SetPendingPnpIrpStatus(status); 1974 1975 // 1976 // Revert to started 1977 // 1978 return WdfDevStatePnpStarted; 1979 } 1980 else { 1981 // 1982 // Go ask power what the self managed io state is 1983 // 1984 return WdfDevStatePnpQueryStopAskDriver; 1985 } 1986 } 1987 1988 VOID 1989 FxPkgPnp::PnpEventRemovedCommonCode( 1990 VOID 1991 ) 1992 /*++ 1993 1994 Routine Description: 1995 This function implements the Removed state. 1996 1997 Arguments: 1998 none 1999 2000 Return Value: 2001 2002 VOID 2003 2004 --*/ 2005 { 2006 // 2007 // Purge non power managed queues now 2008 // 2009 m_Device->m_PkgIo->StopProcessingForPower( 2010 FxIoStopProcessingForPowerPurgeNonManaged 2011 ); 2012 2013 if (m_SelfManagedIoMachine != NULL) { 2014 m_SelfManagedIoMachine->Cleanup(); 2015 } 2016 2017 // 2018 // Cleanup WMI *after* EvtDeviceSelfManagedIoCleanup b/c we want to cleanup 2019 // after a well known and documented time. The WMI docs state that you can 2020 // register providers and instances all the way through 2021 // EvtDeviceSelfManagedIoCleanup, so we mark WMI as cleaned up after that 2022 // call. 2023 // 2024 m_Device->WmiPkgCleanup(); 2025 2026 // 2027 // Mark the device as removed. 2028 // 2029 m_PnpStateAndCaps.Value &= ~FxPnpStateRemovedMask; 2030 m_PnpStateAndCaps.Value |= FxPnpStateRemovedTrue; 2031 2032 // 2033 // Now call the driver and tell it to cleanup all its software state. 2034 // 2035 // We do the dispose early here before deleting the object 2036 // since the PNP remove event is the main trigger for 2037 // the Dispose chain in the framework. 2038 // 2039 // (Almost everything in the driver is rooted on the device object) 2040 // 2041 2042 m_Device->EarlyDispose(); 2043 2044 // 2045 // All the children are in the disposed state, destroy them all. m_Device 2046 // is not destroyed in this call. 2047 // 2048 2049 m_Device->DestroyChildren(); 2050 2051 // 2052 // Wait for all children to drain out and cleanup. 2053 // 2054 2055 m_Device->m_DisposeList->WaitForEmpty(); 2056 2057 } 2058 2059 WDF_DEVICE_PNP_STATE 2060 FxPkgPnp::PnpEventQueryCanceled( 2061 __inout FxPkgPnp* This 2062 ) 2063 /*++ 2064 2065 Routine Description: 2066 The device was in the queried state (remove or stop) and the query was 2067 canceled. Remove the power reference taken and return to the started state. 2068 2069 Arguments: 2070 This - instance of the state machine 2071 2072 Return Value: 2073 WdfDevStatePnpStarted 2074 2075 --*/ 2076 { 2077 This->PnpPowerDereferenceSelf(); 2078 2079 return WdfDevStatePnpStarted; 2080 } 2081 2082 WDF_DEVICE_PNP_STATE 2083 FxPkgPnp::PnpEventRemoved( 2084 __inout FxPkgPnp* This 2085 ) 2086 /*++ 2087 2088 Routine Description: 2089 This function implements the Removed state. It tears down any remaining 2090 children and the moves into a role (FDO/PDO) specific state. 2091 2092 Arguments: 2093 This - instance of the state machine 2094 2095 Return Value: 2096 new machine state 2097 2098 --*/ 2099 { 2100 // 2101 // Remove any child PDOs which may still be lingering around. We do 2102 // the cleanup here so that we do it only once for the PDO which is being 2103 // removed (but may stick around) b/c it was not reported as missing. 2104 // 2105 // 2106 // Iterate over all of the reported children 2107 // 2108 This->ChildListNotifyRemove(&This->m_PendingChildCount); 2109 2110 // 2111 // Decrement our bias from when the device was (re)started. If all of the 2112 // children removed themselves synchronously, we just move to the cleanup 2113 // state, otherwise wait for all the children to fully process the remove 2114 // before remove the parent so that ordering of removal between parent and 2115 // child is guaranteed (where the order is that all children are cleaned 2116 // up before the parent is cleaned up). 2117 // 2118 if (InterlockedDecrement(&This->m_PendingChildCount) > 0) { 2119 return WdfDevStatePnpRemovedWaitForChildren; 2120 } 2121 else { 2122 return WdfDevStatePnpRemovedChildrenRemoved; 2123 } 2124 } 2125 2126 WDF_DEVICE_PNP_STATE 2127 FxPkgPnp::PnpEventPdoRemoved( 2128 __inout FxPkgPnp* This 2129 ) 2130 /*++ 2131 2132 Routine Description: 2133 This function implements the PDO Removed state. This function is called 2134 when the PDO is actually reported missing to the OS or the FDO is removed. 2135 2136 Arguments: 2137 none 2138 2139 Return Value: 2140 new state 2141 2142 --*/ 2143 { 2144 return This->PnpEventPdoRemovedOverload(); 2145 } 2146 2147 WDF_DEVICE_PNP_STATE 2148 FxPkgPnp::PnpEventRemovedPdoWait( 2149 __inout FxPkgPnp* This 2150 ) 2151 /*++ 2152 2153 Routine Description: 2154 Indicates to the remove path that remove processing is done and we will 2155 wait for additional PNP events to arrive at this state machine 2156 2157 Arguments: 2158 This - Instance of the state machine 2159 2160 Return Value: 2161 WdfDevStatePnpNull 2162 2163 --*/ 2164 { 2165 if (This->m_DeviceRemoveProcessed != NULL) { 2166 This->m_SetDeviceRemoveProcessed = TRUE; 2167 } 2168 2169 return WdfDevStatePnpNull; 2170 } 2171 2172 WDF_DEVICE_PNP_STATE 2173 FxPkgPnp::PnpEventRemovedPdoSurpriseRemoved( 2174 __inout FxPkgPnp* This 2175 ) 2176 /*++ 2177 2178 Routine Description: 2179 PDO has been removed (could have been disabled in user mode) and is now 2180 surprise removed by the underlying bus. 2181 2182 Arguments: 2183 This - instance of the state machine 2184 2185 Return Value: 2186 WdfDevStatePnpRemovedPdoWait 2187 2188 --*/ 2189 { 2190 // 2191 // Invoke EvtDeviceSurpriseRemove 2192 // 2193 This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle()); 2194 2195 // 2196 // Call the overloaded surprise remove handler since 2197 // PnpEventSurpriseRemovePendingOverload will not get called 2198 // 2199 This->PnpEventSurpriseRemovePendingOverload(); 2200 2201 // 2202 // The surprise remove irp was pended, complete it now 2203 // 2204 This->PnpFinishProcessingIrp(); 2205 2206 return WdfDevStatePnpRemovedPdoWait; 2207 } 2208 2209 VOID 2210 FxPkgPnp::PnpCleanupForRemove( 2211 __in BOOLEAN GracefulRemove 2212 ) 2213 /*++ 2214 2215 Routine Description: 2216 This is a common worker function between surprise remove and the graceful 2217 remove path to do common cleanup. This involves deregistering from WMI, 2218 device interfaces, symbolic links and stopping power managed i/o. 2219 2220 Arguments: 2221 GracefulRemove - if TRUE, we are in the graceful remove path, otherwise we 2222 are in the surprise remove path. 2223 2224 Return Value: 2225 None 2226 2227 --*/ 2228 { 2229 // 2230 // Disable WMI. 2231 // 2232 m_Device->WmiPkgDeregister(); 2233 2234 // 2235 // Disable any device interfaces. 2236 // 2237 PnpDisableInterfaces(); 2238 2239 DeleteSymbolicLinkOverload(GracefulRemove); 2240 2241 2242 2243 2244 2245 2246 2247 2248 // Flush/purge top-edge queues 2249 m_Device->m_PkgIo->StopProcessingForPower( 2250 FxIoStopProcessingForPowerPurgeManaged 2251 ); 2252 2253 // 2254 // Invoke EvtDeviceSelfManagedIoFlush 2255 // 2256 if (m_SelfManagedIoMachine != NULL) { 2257 m_SelfManagedIoMachine->Flush(); 2258 } 2259 2260 // 2261 // Tell all the resource objects that they no longer own anything. 2262 // 2263 NotifyResourceobjectsToReleaseResources(); 2264 2265 // 2266 // Flush persistent state to permanent storage. We do this in the failed 2267 // state for the surprise removed case. By storing the state when we are 2268 // surprise removed, if the stack is reenumerated, it will pick up the saved 2269 // state that was just committed. If the state was saved during remove 2270 // device it can be too late because the new instance of the same device 2271 // could already be up and running and not pick up the saved state. 2272 // 2273 // It is important to save the state before completing the (potentially) 2274 // pended pnp irp. Completing the pnp irp will allow a new instance of the 2275 // device to be enumerated and we want to save state before that happens. 2276 // 2277 SaveState(FALSE); 2278 2279 if (m_SharedPower.m_WaitWakeOwner) { 2280 // 2281 // Don't care about the return code, just blindly try to complete the 2282 // wake request. The function can handle the case where there is no 2283 // irp to complete. 2284 // 2285 (void) PowerIndicateWaitWakeStatus(STATUS_NO_SUCH_DEVICE); 2286 } 2287 } 2288 2289 WDF_DEVICE_PNP_STATE 2290 FxPkgPnp::PnpEventRemovingDisableInterfaces( 2291 __inout FxPkgPnp* This 2292 ) 2293 /*++ 2294 2295 Routine Description: 2296 This function implements the Removing Disable 2297 Interfaces state. It disables any device interfaces 2298 and then tells the power policy state machine to prepare for device removal. 2299 2300 Arguments: 2301 none 2302 2303 Return Value: 2304 2305 WdfDevStatePnpNull 2306 2307 --*/ 2308 { 2309 NTSTATUS status; 2310 2311 // 2312 // Surprise remove path releases hardware first then disables the interfaces, 2313 // so do the same in the graceful remove path. 2314 // 2315 2316 // 2317 // Call the driver and tell it to unmap resources. 2318 // 2319 status = This->PnpReleaseHardware(); 2320 if (!NT_SUCCESS(status)) { 2321 // 2322 // The driver failed to unmap resources. Presumably this means that 2323 // there are now some leaked PTEs. Just log the failure. 2324 // 2325 DoTraceLevelMessage( 2326 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2327 "EvtDeviceReleaseHardware %p failed, %!STATUS!", 2328 This->m_Device->GetHandle(), status); 2329 } 2330 2331 This->PnpCleanupForRemove(TRUE); 2332 2333 // 2334 // Tell the power policy state machine to prepare for device removal 2335 // 2336 This->PnpPowerPolicyRemove(); 2337 2338 return WdfDevStatePnpNull; 2339 } 2340 2341 WDF_DEVICE_PNP_STATE 2342 FxPkgPnp::PnpEventStarted( 2343 __inout FxPkgPnp* This 2344 ) 2345 /*++ 2346 2347 Routine Description: 2348 Completes the pending request or sends it on its way. 2349 2350 Arguments: 2351 This - instance of the state machine for the device 2352 2353 Return Value: 2354 WdfDevStatePnpNull 2355 2356 --*/ 2357 { 2358 2359 This->m_AchievedStart = TRUE; 2360 2361 // 2362 // Log Telemetry event for the FDO 2363 // 2364 if (This->m_Device->IsPdo() == FALSE) { 2365 This->m_Device->FxLogDeviceStartTelemetryEvent(); 2366 } 2367 2368 This->PnpFinishProcessingIrp(); 2369 2370 return WdfDevStatePnpNull; 2371 } 2372 2373 WDF_DEVICE_PNP_STATE 2374 FxPkgPnp::PnpEventStartedCancelStop( 2375 __inout FxPkgPnp* This 2376 ) 2377 /*++ 2378 2379 Routine Description: 2380 Cancel stop received from the started state. Just return to the started 2381 state where we will handle the pended irp. 2382 2383 Arguments: 2384 This - Instance of the state machine 2385 2386 Return Value: 2387 WdfDevStatePnpStarted 2388 2389 --*/ 2390 { 2391 UNREFERENCED_PARAMETER(This); 2392 return WdfDevStatePnpStarted; 2393 } 2394 2395 WDF_DEVICE_PNP_STATE 2396 FxPkgPnp::PnpEventStartedCancelRemove( 2397 __inout FxPkgPnp* This 2398 ) 2399 /*++ 2400 2401 Routine Description: 2402 Cancel remove received from the started state. Just return to the started 2403 state where we will handle the pended irp. 2404 2405 Arguments: 2406 This - Instance of the state machine 2407 2408 Return Value: 2409 WdfDevStatePnpStarted 2410 2411 --*/ 2412 { 2413 UNREFERENCED_PARAMETER(This); 2414 2415 return WdfDevStatePnpStarted; 2416 } 2417 2418 WDF_DEVICE_PNP_STATE 2419 FxPkgPnp::PnpEventStartedRemoving( 2420 __inout FxPkgPnp* This 2421 ) 2422 /*++ 2423 2424 Routine Description: 2425 Remove directly from started. Power down the other state machines. 2426 2427 Arguments: 2428 This - instance of the state machine 2429 2430 Return Value: 2431 WdfDevStatePnpNull 2432 2433 --*/ 2434 { 2435 This->PnpPowerPolicyStop(); 2436 2437 return WdfDevStatePnpNull; 2438 } 2439 2440 WDF_DEVICE_PNP_STATE 2441 FxPkgPnp::PnpEventRestarting( 2442 __inout FxPkgPnp* This 2443 ) 2444 /*++ 2445 2446 Routine Description: 2447 This function implements the Cancelling Stop state. 2448 2449 Arguments: 2450 none 2451 2452 Return Value: 2453 2454 VOID 2455 2456 --*/ 2457 { 2458 // 2459 // Send an event to the Power Policy State Machine 2460 // telling it to "Start." 2461 // 2462 This->PnpPowerPolicyStart(); 2463 2464 return WdfDevStatePnpNull; 2465 } 2466 2467 WDF_DEVICE_PNP_STATE 2468 FxPkgPnp::PnpEventStartingFromStopped( 2469 __inout FxPkgPnp* This 2470 ) 2471 /*++ 2472 2473 Routine Description: 2474 This function implements the Restarting From Stopped state. It's job 2475 is to map new resources and then proceed to the Restarting state. 2476 2477 Arguments: 2478 none 2479 2480 Return Value: 2481 2482 VOID 2483 2484 --*/ 2485 { 2486 NTSTATUS status; 2487 BOOLEAN matched; 2488 2489 status = This->PnpPrepareHardware(&matched); 2490 2491 if (!NT_SUCCESS(status)) { 2492 // 2493 // We can handle remove out of the init state, revert back to that state 2494 // 2495 if (matched == FALSE) { 2496 // 2497 // Wait for the remove irp to come in 2498 // 2499 COVERAGE_TRAP(); 2500 return WdfDevStatePnpFailed; 2501 } 2502 else { 2503 // 2504 // EvtDevicePrepareHardware is what failed, goto a state where we 2505 // undo that call. 2506 // 2507 COVERAGE_TRAP(); 2508 return WdfDevStatePnpFailedOwnHardware; 2509 } 2510 } 2511 2512 return WdfDevStatePnpRestarting; 2513 } 2514 2515 WDF_DEVICE_PNP_STATE 2516 FxPkgPnp::PnpEventStopped( 2517 __inout FxPkgPnp* This 2518 ) 2519 /*++ 2520 2521 Routine Description: 2522 This function implements the Stopped state. It's job is to invoke 2523 EvtDeviceReleaseHardware. 2524 2525 Arguments: 2526 none 2527 2528 Return Value: 2529 2530 VOID 2531 2532 --*/ 2533 { 2534 WDF_DEVICE_PNP_STATE state; 2535 NTSTATUS status; 2536 2537 status = This->PnpReleaseHardware(); 2538 if (NT_SUCCESS(status)) { 2539 // 2540 // Tell all the resource objects that they no longer own anything. 2541 // 2542 This->NotifyResourceobjectsToReleaseResources(); 2543 2544 state = WdfDevStatePnpNull; 2545 } 2546 else { 2547 DoTraceLevelMessage(This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 2548 "EvtDeviceReleaseHardware failed - %!STATUS!", 2549 status); 2550 COVERAGE_TRAP(); 2551 2552 This->SetInternalFailure(); 2553 state = WdfDevStatePnpFailed; 2554 } 2555 2556 // 2557 // Send the irp on its merry way. This irp (stop device) cannot be failed 2558 // and must always be sent down the stack. 2559 // 2560 This->PnpFinishProcessingIrp(); 2561 2562 return state; 2563 } 2564 2565 WDF_DEVICE_PNP_STATE 2566 FxPkgPnp::PnpEventStoppedWaitForStartCompletion( 2567 __inout FxPkgPnp* This 2568 ) 2569 /*++ 2570 2571 Routine Description: 2572 The start irp is coming down from the stopped state. Send it down the stack 2573 and transition to the new state if needed. 2574 2575 Arguments: 2576 This - instance of the state machine 2577 2578 Return Value: 2579 new machine state 2580 2581 --*/ 2582 { 2583 if (This->PnpSendStartDeviceDownTheStackOverload() == FALSE) { 2584 // 2585 // The start irp's completion routine will move the state machine into 2586 // the new state. 2587 // 2588 return WdfDevStatePnpNull; 2589 } 2590 2591 return WdfDevStatePnpStartingFromStopped; 2592 } 2593 2594 WDF_DEVICE_PNP_STATE 2595 FxPkgPnp::PnpEventStartedStopping( 2596 __inout FxPkgPnp* This 2597 ) 2598 /*++ 2599 2600 Routine Description: 2601 Received a stop irp. Stop the power policy machine and then wait for it to 2602 complete. 2603 2604 Arguments: 2605 This - instance of the state machine 2606 2607 Return Value: 2608 WdfDevStatePnpNull 2609 2610 --*/ 2611 { 2612 // 2613 // It is important to stop power policy before releasing the reference. 2614 // If the reference was released first, we could get into a situation where 2615 // we immediately go idle and then we must send a D0 irp when in the remove. 2616 // If there are devices on top of this device and we send a D0 irp during 2617 // remove processing, the upper devices will be sent an irp after getting a 2618 // pnp remove (and either crash or fail the power irp upon receiving it). 2619 // 2620 This->PnpPowerPolicyStop(); 2621 This->PnpPowerDereferenceSelf(); 2622 2623 return WdfDevStatePnpNull; 2624 } 2625 2626 WDF_DEVICE_PNP_STATE 2627 FxPkgPnp::PnpEventSurpriseRemoved( 2628 __inout FxPkgPnp* This 2629 ) 2630 /*++ 2631 2632 Routine Description: 2633 We got IRP_MN_SURPRISE_REMOVE_DEVICE while the system was pretty far down 2634 the removal path, or never started. Call EvtDeviceSurpriseRemoval, call the 2635 surprise remove virtual and drop into the Failed path. 2636 2637 Arguments: 2638 This - instance of the state machine 2639 2640 Return Value: 2641 new device pnp state 2642 2643 --*/ 2644 { 2645 // 2646 // Invoke EvtDeviceSurpriseRemove 2647 // 2648 This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle()); 2649 2650 // 2651 // Notify the virtual override of the surprise remove. 2652 // 2653 This->PnpEventSurpriseRemovePendingOverload(); 2654 2655 return WdfDevStatePnpFailed; 2656 } 2657 2658 WDF_DEVICE_PNP_STATE 2659 FxPkgPnp::PnpEventInitQueryRemove( 2660 __inout FxPkgPnp* This 2661 ) 2662 /*++ 2663 2664 Routine Description: 2665 Query remove from the init state. Complete the pended request. 2666 2667 Arguments: 2668 This - instance of th state machine. 2669 2670 Return Value: 2671 WdfDevStatePnpNull 2672 2673 --*/ 2674 { 2675 FxIrp irp(This->ClearPendingPnpIrp()); 2676 2677 irp.SetStatus(STATUS_SUCCESS); 2678 This->FireAndForgetIrp(&irp); 2679 2680 return WdfDevStatePnpNull; 2681 } 2682 2683 WDF_DEVICE_PNP_STATE 2684 FxPkgPnp::PnpEventInitQueryRemoveCanceled( 2685 __inout FxPkgPnp* This 2686 ) 2687 /*++ 2688 2689 Routine Description: 2690 Handle a query remove canceled from the init state. Complete the pended 2691 request. 2692 2693 Arguments: 2694 This - instance of the state machine 2695 2696 Return Value: 2697 WdfDevStatePnpInit 2698 2699 --*/ 2700 { 2701 FxIrp irp(This->ClearPendingPnpIrp()); 2702 2703 This->FireAndForgetIrp(&irp); 2704 2705 return WdfDevStatePnpInit; 2706 } 2707 2708 WDF_DEVICE_PNP_STATE 2709 FxPkgPnp::PnpEventFdoRemoved( 2710 __inout FxPkgPnp* This 2711 ) 2712 /*++ 2713 2714 Routine Description: 2715 FDO is being removed, hand off to the derived pnp package 2716 2717 Arguments: 2718 This - instance of the state machine 2719 2720 Return Value: 2721 new device pnp state 2722 2723 --*/ 2724 { 2725 return This->PnpEventFdoRemovedOverload(); 2726 } 2727 2728 WDF_DEVICE_PNP_STATE 2729 FxPkgPnp::PnpEventQueriedSurpriseRemove( 2730 __inout FxPkgPnp* This 2731 ) 2732 /*++ 2733 2734 Routine Description: 2735 The device was in a queried (either stop or cancel) state and was surprise 2736 removed from it. 2737 2738 Arguments: 2739 This - instance of the state machine 2740 2741 Return Value: 2742 new state, WdfDevStatePnpSurpriseRemoveIoStarted 2743 2744 --*/ 2745 { 2746 COVERAGE_TRAP(); 2747 2748 This->PnpPowerDereferenceSelf(); 2749 2750 return WdfDevStatePnpSurpriseRemoveIoStarted; 2751 } 2752 2753 WDF_DEVICE_PNP_STATE 2754 FxPkgPnp::PnpEventSurpriseRemoveIoStarted( 2755 __inout FxPkgPnp* This 2756 ) 2757 /*++ 2758 2759 Routine Description: 2760 We got IRP_MN_SURPRISE_REMOVE_DEVICE while the system was more or less 2761 running. Start down the Surprise Remove/Device Failed path. This state 2762 calls EvtDeviceSurpriseRemoval, calls the virtual surprise remove overload, 2763 and then drops into the Failed path. 2764 2765 Arguments: 2766 This - instance of the state machine 2767 2768 Return Value: 2769 new device pnp state 2770 2771 --*/ 2772 { 2773 // 2774 // Invoke EvtDeviceSurpriseRemove 2775 // 2776 2777 This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle()); 2778 2779 // 2780 // Notify the virtual override of the surprise remove. 2781 // 2782 This->PnpEventSurpriseRemovePendingOverload(); 2783 2784 return WdfDevStatePnpFailedIoStarting; 2785 } 2786 2787 WDF_DEVICE_PNP_STATE 2788 FxPkgPnp::PnpEventFailedPowerDown( 2789 __inout FxPkgPnp* This 2790 ) 2791 /*++ 2792 2793 Routine Description: 2794 The device was in the started state and failed power down or could not 2795 enable its interfaces. Gracefully power down the device and tear down 2796 the stack. 2797 2798 The difference between this routine and PnpEventFailedIoStarting is that 2799 FailedIoStarting sends a surprise remove to the power state machine. After 2800 surprise remove has been sent to the power state machine, it will not attempt 2801 to put the device into Dx because it assumes the device is no longer present. 2802 In this error case, we still want the device to be powered down, so we send 2803 a normal stop remove. 2804 2805 Arguments: 2806 This - instance of the state machine 2807 2808 Return Value: 2809 new state 2810 2811 --*/ 2812 { 2813 // 2814 // Normal stop so that the power state machine will go through the power off 2815 // path and not skip directly to off like it would if we sent it a surprise 2816 // remove notification. 2817 // 2818 This->PnpPowerPolicyStop(); 2819 2820 return WdfDevStatePnpNull; 2821 } 2822 2823 WDF_DEVICE_PNP_STATE 2824 FxPkgPnp::PnpEventFailedIoStarting( 2825 __inout FxPkgPnp* This 2826 ) 2827 /*++ 2828 2829 Routine Description: 2830 The device failed (or was yanked out of the machine) while it was more 2831 or less running. Tell the driver to stop self-managed I/O and drop into 2832 the next state on the failure path. 2833 2834 Arguments: j 2835 This - instance of the state machine 2836 2837 Return Value: 2838 new device pnp state 2839 2840 --*/ 2841 { 2842 This->PnpPowerPolicySurpriseRemove(); 2843 2844 return WdfDevStatePnpNull; 2845 } 2846 2847 WDF_DEVICE_PNP_STATE 2848 FxPkgPnp::PnpEventFailedOwnHardware( 2849 __inout FxPkgPnp* This 2850 ) 2851 /*++ 2852 2853 Routine Description: 2854 The device failed (or was yanked out of the machine) while it owned access 2855 to the hardware. Tell the driver to release resources and drop into 2856 the next state on the failure path. 2857 2858 Arguments: 2859 This - instance of the state machine 2860 2861 Return Value: 2862 new device pnp state 2863 2864 --*/ 2865 { 2866 // 2867 // Invoke EvtDeviceReleaseHardware 2868 // 2869 (void) This->PnpReleaseHardware(); 2870 2871 return WdfDevStatePnpFailed; 2872 } 2873 2874 WDF_DEVICE_PNP_STATE 2875 FxPkgPnp::PnpEventFailed( 2876 __inout FxPkgPnp* This 2877 ) 2878 /*++ 2879 2880 Routine Description: 2881 The device failed (or was yanked out of the machine). Disable interfaces, 2882 flush queues and tell the driver to clean up random stuff. 2883 Also ask the power policy state machine to prepare for device removal. 2884 2885 Arguments: 2886 This - instance of the state machine 2887 2888 Return Value: 2889 WdfDevStatePnpNull 2890 2891 --*/ 2892 { 2893 This->PnpCleanupForRemove(FALSE); 2894 2895 // 2896 // Tell the power policy state machine to prepare for device removal 2897 // 2898 This->PnpPowerPolicyRemove(); 2899 2900 return WdfDevStatePnpNull; 2901 } 2902 2903 WDF_DEVICE_PNP_STATE 2904 FxPkgPnp::PnpEventFailedPowerPolicyRemoved( 2905 __inout FxPkgPnp* This 2906 ) 2907 /*++ 2908 2909 Routine Description: 2910 The power policy state machine has prepared for device removal. Invalidate 2911 the device state and wait for IRP_MN_REMOVE_DEVICE. 2912 2913 Arguments: 2914 This - instance of the state machine 2915 2916 Return Value: 2917 WdfDevStatePnpFailedWaitForRemove 2918 2919 --*/ 2920 { 2921 // 2922 // Finish processing any pended PnP IRP. Since we can reach this state from 2923 // states where a pnp irp was *not* pended, we do not require a pnp irp to 2924 // have been pended when trying to complete it. 2925 // 2926 This->PnpFinishProcessingIrp(FALSE); 2927 2928 // 2929 // Request reenumeration if the client driver asked for it or if there was 2930 // an internal failure *and* if the client driver didn't specify failure... 2931 // AND if we have not yet exceeded our restart count within a period of time. 2932 // 2933 if ((This->m_FailedAction == WdfDeviceFailedAttemptRestart || 2934 (This->m_FailedAction == WdfDeviceFailedUndefined && This->m_InternalFailure)) 2935 && 2936 This->PnpCheckAndIncrementRestartCount()) { 2937 // 2938 // No need to invalidate state because we are in a state waiting for 2939 // a remove device anyways so failure is imminent. 2940 // 2941 This->AskParentToRemoveAndReenumerate(); 2942 } 2943 2944 if (This->m_FailedAction != WdfDeviceFailedUndefined || This->m_InternalFailure) { 2945 // 2946 // If the failure occurred in this device, then tear down the stack if 2947 // we are in a state in which pnp thinks we are started. If we are 2948 // already in a stopped state, this invalidation will do no harm. 2949 // 2950 MxDeviceObject physicalDeviceObject( 2951 This->m_Device->GetPhysicalDevice() 2952 ); 2953 2954 // 2955 // We need to pass FDO as a parameter as UMDF currently doesn't have 2956 // PDOs and instead needs FDO to invalidate device state. 2957 // 2958 physicalDeviceObject.InvalidateDeviceState( 2959 This->m_Device->GetDeviceObject() //FDO 2960 ); 2961 } 2962 2963 return WdfDevStatePnpFailedWaitForRemove; 2964 } 2965 2966 WDF_DEVICE_PNP_STATE 2967 FxPkgPnp::PnpEventFailedSurpriseRemoved( 2968 __inout FxPkgPnp* This 2969 ) 2970 /*++ 2971 2972 Routine Description: 2973 The device has failed and then received a surprise remove. This can easily 2974 happen on return from low power as following: 2975 2976 1 device attempts to enter D0, D0Entry fails 2977 2 pnp state machine proceeds down failure path and stops at FailedWaitForRemove 2978 3 bus driver finds device missing, reports it as such and a s.r. irp 2979 arrives 2980 2981 Arguments: 2982 This - instance of the state machine 2983 2984 Return Value: 2985 WdfDevStatePnpFailedWaitForRemove 2986 2987 --*/ 2988 { 2989 // 2990 // Invoke EvtDeviceSurpriseRemove 2991 // 2992 This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle()); 2993 2994 // 2995 // Call the overloaded surprise remove handler 2996 // 2997 This->PnpEventSurpriseRemovePendingOverload(); 2998 2999 // 3000 // The surprise remove irp was pended, complete it now. The irp need not 3001 // be present. If we failed before the surprise irp was sent and the irp 3002 // arrived in the middle of processing the failure, we could have completed 3003 // the s.r. irp in FailedWaitForRemove, which is OK. 3004 // 3005 This->PnpFinishProcessingIrp(FALSE); 3006 3007 // 3008 // Return back to the failed state where will wait for remove 3009 // 3010 return WdfDevStatePnpFailedWaitForRemove; 3011 } 3012 3013 WDF_DEVICE_PNP_STATE 3014 FxPkgPnp::PnpEventFailedStarted( 3015 __inout FxPkgPnp* This 3016 ) 3017 /*++ 3018 3019 Routine Description: 3020 Device failed (probably somewhere in the start path) and got another start 3021 request. Fail the start and return to the state where we will wait for a 3022 remove irp. 3023 3024 Arguments: 3025 This - instance of the state machine 3026 3027 Return Value: 3028 WdfDevStatePnpFailedWaitForRemove 3029 3030 --*/ 3031 { 3032 // 3033 // Complete the pended start irp with error 3034 // 3035 This->SetPendingPnpIrpStatus(STATUS_INVALID_DEVICE_STATE); 3036 This->PnpFinishProcessingIrp(); 3037 3038 return WdfDevStatePnpFailedWaitForRemove; 3039 } 3040 3041 WDF_DEVICE_PNP_STATE 3042 FxPkgPnp::PnpEventFailedInit( 3043 __inout FxPkgPnp* This 3044 ) 3045 /*++ 3046 3047 Routine Description: 3048 Processing of the start irp's resources failed. Complete the start irp. 3049 3050 Arguments: 3051 This - instance of the state machine 3052 3053 Return Value: 3054 WdfDevStatePnpNull 3055 3056 --*/ 3057 { 3058 // 3059 // Release the power thread that we may have previously acquired in 3060 // HardwareAvailable. 3061 // 3062 This->ReleasePowerThread(); 3063 3064 // 3065 // Deref the reenumeration interface 3066 // 3067 This->ReleaseReenumerationInterface(); 3068 3069 This->PnpFinishProcessingIrp(); 3070 3071 return WdfDevStatePnpInit; 3072 } 3073 3074 WDF_DEVICE_PNP_STATE 3075 FxPkgPnp::PnpEventPdoInitFailed( 3076 __inout FxPkgPnp* This 3077 ) 3078 /*++ 3079 3080 Routine Description: 3081 The driver failed EvtDeviceSoftwareInit. Run cleanup and die. 3082 3083 Arguments: 3084 This - instance of the state machine 3085 3086 Return Value: 3087 new device pnp state 3088 3089 --*/ 3090 { 3091 COVERAGE_TRAP(); 3092 3093 3094 This->m_Device->EarlyDispose(); 3095 3096 // 3097 // All the children are in the disposed state, destroy them all. m_Device 3098 // is not destroyed in this call. 3099 // 3100 3101 This->m_Device->DestroyChildren(); 3102 3103 return WdfDevStatePnpFinal; 3104 } 3105 3106 WDF_DEVICE_PNP_STATE 3107 FxPkgPnp::PnpEventRestart( 3108 __inout FxPkgPnp* This 3109 ) 3110 /*++ 3111 3112 Routine Description: 3113 A start to start transition has occurred. Go through the normal stop path 3114 first and then restart things. 3115 3116 Arguments: 3117 This - instance of the state machine 3118 3119 Return Value: 3120 WdfDevStateNull or new machine state 3121 3122 --*/ 3123 { 3124 // 3125 // Stop the power policy machine so that we simulate stopping first 3126 // 3127 This->PnpPowerPolicyStop(); 3128 3129 return WdfDevStatePnpNull; 3130 } 3131 3132 WDF_DEVICE_PNP_STATE 3133 FxPkgPnp::PnpEventRestartReleaseHardware( 3134 __inout FxPkgPnp* This 3135 ) 3136 /*++ 3137 3138 Routine Description: 3139 Release the hardware resources and send the start irp down the stack 3140 3141 Arguments: 3142 This - instance of the state machine 3143 3144 Return Value: 3145 new machine state 3146 3147 --*/ 3148 { 3149 NTSTATUS status; 3150 3151 status = This->PnpReleaseHardware(); 3152 if (!NT_SUCCESS(status)) { 3153 DoTraceLevelMessage( 3154 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3155 "EvtDeviceReleaseHardware failed with %!STATUS!", status); 3156 3157 COVERAGE_TRAP(); 3158 3159 This->SetInternalFailure(); 3160 This->SetPendingPnpIrpStatus(status); 3161 3162 return WdfDevStatePnpFailed; 3163 } 3164 3165 if (This->PnpSendStartDeviceDownTheStackOverload() == FALSE) { 3166 // 3167 // The start irp's completion routine will move the state machine into 3168 // the new state. 3169 // 3170 return WdfDevStatePnpNull; 3171 } 3172 3173 // 3174 // Start happened synchronously. Transition to the new state now. 3175 // 3176 return WdfDevStatePnpRestartHardwareAvailable; 3177 } 3178 3179 WDF_DEVICE_PNP_STATE 3180 FxPkgPnp::PnpEventRestartHardwareAvailable( 3181 __inout FxPkgPnp* This 3182 ) 3183 /*++ 3184 3185 Routine Description: 3186 Prepare the hardware and restart the power and power policy state machines 3187 after a successful start -> start transition where the start irp is coming 3188 up the stack. 3189 3190 Arguments: 3191 This - instance of the state machine 3192 3193 Return Value: 3194 new machine state 3195 3196 --*/ 3197 { 3198 NTSTATUS status; 3199 BOOLEAN matched; 3200 3201 status = This->PnpPrepareHardware(&matched); 3202 3203 if (!NT_SUCCESS(status)) { 3204 if (matched == FALSE) { 3205 // 3206 // Wait for the remove irp to come in 3207 // 3208 COVERAGE_TRAP(); 3209 return WdfDevStatePnpFailed; 3210 } 3211 else { 3212 // 3213 // EvtDevicePrepareHardware is what failed, goto a state where we 3214 // undo that call. 3215 // 3216 COVERAGE_TRAP(); 3217 return WdfDevStatePnpFailedOwnHardware; 3218 } 3219 } 3220 3221 This->PnpPowerPolicyStart(); 3222 3223 return WdfDevStatePnpNull; 3224 } 3225 3226 WDF_DEVICE_PNP_STATE 3227 FxPkgPnp::PnpEventPdoRestart( 3228 __inout FxPkgPnp* This 3229 ) 3230 /*++ 3231 3232 Routine Description: 3233 The PDO was in the removed state has received another start irp. Reset state 3234 and then move into the start sequence. 3235 3236 Arguments: 3237 This - instance of the state machine 3238 3239 Return Value: 3240 WdfDevStatePnpHardwareAvailable 3241 3242 --*/ 3243 { 3244 // 3245 // Since this is a PDO and it is being restarted, it could have had an internal 3246 // failure during its previous start. Since we use m_InternalFailure to set 3247 // PNP_DEVICE_FAILED when handling IRP_MN_QUERY_PNP_DEVICE_STATE, it should 3248 // be set to FALSE so we don't immediately fail the device after the start 3249 // has been succeeded. 3250 // 3251 This->m_InternalFailure = FALSE; 3252 This->m_Failed = FALSE; 3253 3254 // 3255 // The PDO is being restarted and could have previous had a power thread 3256 // running. If so, the reference count goes to zero when removed from a 3257 // started state. Reset back to 1. 3258 // 3259 This->m_PowerThreadInterfaceReferenceCount = 1; 3260 3261 // 3262 // The count is decremented on the initial started->removed transition (and 3263 // not subsequent removed -> removed transitiosn). On removed -> restarted, 3264 // we need to set the count back to a bias of 1 so when we process the remove 3265 // again we can know if there are any pending child (of this PDO) removals 3266 // that we must wait for. 3267 // 3268 This->m_PendingChildCount = 1; 3269 3270 // 3271 // Reset WMI state 3272 // 3273 // This->m_Device->m_PkgWmi->ResetStateForPdoRestart(); __REACTOS__ 3274 3275 3276 This->m_Device->m_PkgIo->ResetStateForRestart(); 3277 3278 if (This->IsPowerPolicyOwner()) { 3279 This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Reset(); 3280 } 3281 3282 // 3283 // Set STATUS_SUCCESS in the irp so that the stack will start smoothly after 3284 // we have powered up. 3285 // 3286 This->SetPendingPnpIrpStatus(STATUS_SUCCESS); 3287 3288 // 3289 // This flag is set on the wake-enabled device powering down path, 3290 // but if the device power down failed it may not have been cleared. 3291 // 3292 This->m_WakeInterruptsKeepConnected = FALSE; 3293 3294 3295 // 3296 // This flag is cleared so we can reacquire the start time and state 3297 // 3298 This->m_AchievedStart = FALSE; 3299 3300 return WdfDevStatePnpHardwareAvailable; 3301 } 3302 3303 WDF_DEVICE_PNP_STATE 3304 FxPkgPnp::PnpEventRemovedChildrenRemoved( 3305 __inout FxPkgPnp* This 3306 ) 3307 /*++ 3308 3309 Routine Description: 3310 All of this device's previously enumerated children have been removed. Move 3311 the state machine into its next state based on the device's role. 3312 3313 Arguments: 3314 This - instance of the state machine 3315 3316 Return Value: 3317 new state 3318 3319 --*/ 3320 { 3321 return This->PnpGetPostRemoveState(); 3322 } 3323 3324 WDF_DEVICE_PNP_STATE 3325 FxPkgPnp::PnpEventFinal( 3326 __inout FxPkgPnp* This 3327 ) 3328 /*++ 3329 3330 Routine Description: 3331 The final resting and dead state for the FxDevice that has been removed. We 3332 release our final reference here and destroy the object. 3333 3334 Arguments: 3335 This - This instance of the state machine 3336 3337 Return Value: 3338 WdfDevStatePnpNull 3339 3340 --*/ 3341 { 3342 NTSTATUS status; 3343 3344 // 3345 // We may not have a pnp irp at this stage (esp for PDO which are in the 3346 // removed state and whose parent is being removed) so we use the function 3347 // pointer as the unique tag. 3348 // 3349 // IoReleaseRemoveLockAndWait requires an outstanding reference to release, 3350 // so acquire it before calling it if we are in the case where the PDO is 3351 // being removed with no outstanding PNP remove irp b/c the parent is being 3352 // removed. 3353 // 3354 if (This->m_DeviceRemoveProcessed == NULL) { 3355 status = Mx::MxAcquireRemoveLock( 3356 This->m_Device->GetRemoveLock(), 3357 (PVOID)&FxPkgPnp::PnpEventFinal); 3358 3359 ASSERT(NT_SUCCESS(status)); 3360 UNREFERENCED_PARAMETER(status); 3361 } 3362 3363 // 3364 // Indicate to the parent device that we are removed now (vs the destructor 3365 // of the object where we would never reach because in the case of the PDO 3366 // being removed b/c the parent is going away, the parent has a reference 3367 // on the PDO). 3368 3369 3370 3371 3372 3373 3374 3375 if (This->m_Device->m_ParentWaitingOnChild) { 3376 (This->m_Device->m_ParentDevice->m_PkgPnp)->ChildRemoved(); 3377 } 3378 3379 3380 if (This->m_DeviceRemoveProcessed == NULL) { 3381 // 3382 // We can get into this state w/out an event to set when a PDO (this 3383 // device) is in the removed state and then the parent is removed. 3384 // 3385 3386 // 3387 // After this is called, any irp dispatched to FxDevice::DispatchWithLock 3388 // will fail with STATUS_INVALID_DEVICE_REQUEST. 3389 // 3390 Mx::MxReleaseRemoveLockAndWait( 3391 This->m_Device->GetRemoveLock(), 3392 (PVOID)&FxPkgPnp::PnpEventFinal); 3393 3394 // 3395 // Delete the object when we exit the state machine. Dispose was run 3396 // early in a previous state. 3397 // 3398 This->m_PnpMachine.SetDelayedDeletion(); 3399 } 3400 else { 3401 // 3402 // The thread which received the pnp remove irp will delete the device 3403 // 3404 This->m_SetDeviceRemoveProcessed = TRUE; 3405 } 3406 3407 return WdfDevStatePnpNull; 3408 } 3409 3410 _Must_inspect_result_ 3411 NTSTATUS 3412 FxPkgPnp::PnpEnableInterfacesAndRegisterWmi( 3413 VOID 3414 ) 3415 /*++ 3416 3417 Routine Description: 3418 Enables all of the device interfaces and then registers wmi. 3419 3420 Arguments: 3421 None 3422 3423 Return Value: 3424 NT_SUCCESS if all goes well, !NT_SUCCESS otherwise 3425 3426 --*/ 3427 { 3428 PSINGLE_LIST_ENTRY ple; 3429 NTSTATUS status; 3430 3431 status = STATUS_SUCCESS; 3432 3433 // 3434 // Enable any device interfaces. 3435 // 3436 m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals()); 3437 3438 m_DeviceInterfacesCanBeEnabled = TRUE; 3439 3440 for (ple = m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) { 3441 FxDeviceInterface *pDeviceInterface; 3442 3443 pDeviceInterface = FxDeviceInterface::_FromEntry(ple); 3444 3445 3446 3447 3448 3449 3450 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 3451 // 3452 // By this time, the device interface, no matter what the WDFDEVICE role 3453 // will have been registered. 3454 // 3455 ASSERT(pDeviceInterface->m_SymbolicLinkName.Buffer != NULL); 3456 #endif 3457 pDeviceInterface->SetState(TRUE); 3458 3459 status = STATUS_SUCCESS; 3460 } 3461 3462 m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals()); 3463 3464 if (NT_SUCCESS(status)) { 3465 status = m_Device->WmiPkgRegister(); 3466 } 3467 3468 if (!NT_SUCCESS(status)) { 3469 SetInternalFailure(); 3470 SetPendingPnpIrpStatus(status); 3471 } 3472 3473 return status; 3474 } 3475 3476 __drv_when(!NT_SUCCESS(return), __drv_arg(ResourcesMatched, _Must_inspect_result_)) 3477 NTSTATUS 3478 FxPkgPnp::PnpPrepareHardware( 3479 __inout PBOOLEAN ResourcesMatched 3480 ) 3481 /*++ 3482 3483 Routine Description: 3484 Matches the PNP resources with the WDFINTERRUPT objects registered and then 3485 calls EvtDevicePrepareHardware. All start paths call this function 3486 3487 Arguments: 3488 ResourcesMatched - indicates to the caller what stage failed if !NT_SUCCESS 3489 is returned 3490 3491 Return Value: 3492 NT_SUCCESS if all goes well, !NT_SUCCESS if failure occurrs 3493 3494 --*/ 3495 { 3496 NTSTATUS status; 3497 *ResourcesMatched = FALSE; 3498 3499 // 3500 // FxPnpStateRemoved: 3501 // Mark the device a not removed. This is just so that anybody sending 3502 // a PnP IRP_MN_QUERY_DEVICE_STATE gets a reasonable answer. 3503 // 3504 // FxPnpStateFailed, FxPnpStateResourcesChanged: 3505 // Both of these values can be set to true and cause another start to 3506 // be sent down the stack. Reset these values back to false. If there is 3507 // a need to set these values, the driver can set them in 3508 // EvtDevicePrepareHardware. 3509 // 3510 m_PnpStateAndCaps.Value &= ~(FxPnpStateRemovedMask | 3511 FxPnpStateFailedMask | 3512 FxPnpStateResourcesChangedMask); 3513 m_PnpStateAndCaps.Value |= (FxPnpStateRemovedUseDefault | 3514 FxPnpStateFailedUseDefault | 3515 FxPnpStateResourcesChangedUseDefault); 3516 3517 // 3518 // This will parse the resources and setup all the WDFINTERRUPT handles 3519 // 3520 status = PnpMatchResources(); 3521 3522 if (!NT_SUCCESS(status)) { 3523 *ResourcesMatched = FALSE; 3524 SetInternalFailure(); 3525 SetPendingPnpIrpStatus(status); 3526 return status; 3527 } 3528 3529 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 3530 // 3531 // Build register resource table 3532 // 3533 status = m_Resources->BuildRegisterResourceTable(); 3534 if (!NT_SUCCESS(status)) { 3535 SetInternalFailure(); 3536 SetPendingPnpIrpStatus(status); 3537 goto exit; 3538 } 3539 3540 // 3541 // Build Port resource table 3542 // 3543 status = m_Resources->BuildPortResourceTable(); 3544 if (!NT_SUCCESS(status)) { 3545 SetInternalFailure(); 3546 SetPendingPnpIrpStatus(status); 3547 goto exit; 3548 } 3549 3550 // 3551 // We keep track if the device has any connection resources, 3552 // in which case we allow unrestricted access to interrupts 3553 // regardless of the UmdfDirectHardwareAccess directive. 3554 // 3555 status = m_Resources->CheckForConnectionResources(); 3556 if (!NT_SUCCESS(status)) { 3557 SetInternalFailure(); 3558 SetPendingPnpIrpStatus(status); 3559 goto exit; 3560 } 3561 #endif 3562 3563 *ResourcesMatched = TRUE; 3564 3565 m_Device->SetCallbackFlags( 3566 FXDEVICE_CALLBACK_IN_PREPARE_HARDWARE 3567 ); 3568 3569 status = m_DevicePrepareHardware.Invoke(m_Device->GetHandle(), 3570 m_ResourcesRaw->GetHandle(), 3571 m_Resources->GetHandle()); 3572 3573 m_Device->ClearCallbackFlags( 3574 FXDEVICE_CALLBACK_IN_PREPARE_HARDWARE 3575 ); 3576 3577 if (!NT_SUCCESS(status)) { 3578 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3579 "EvtDevicePrepareHardware failed %!STATUS!", status); 3580 3581 if (status == STATUS_NOT_SUPPORTED) { 3582 DoTraceLevelMessage( 3583 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3584 "EvtDevicePrepareHardware returned an invalid status " 3585 "STATUS_NOT_SUPPORTED"); 3586 3587 if (GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) { 3588 FxVerifierDbgBreakPoint(GetDriverGlobals()); 3589 } 3590 } 3591 3592 SetInternalFailure(); 3593 SetPendingPnpIrpStatus(status); 3594 goto exit; 3595 } 3596 3597 // 3598 // Now that we have assigned the resources to all the interrupts, figure out 3599 // the highest synch irql for each interrupt set which shares a spinlock. 3600 // 3601 PnpAssignInterruptsSyncIrql(); 3602 3603 // 3604 // Do mode-specific work. For KMDF, there is nothing additional to do. 3605 // 3606 status = PnpPrepareHardwareInternal(); 3607 if (!NT_SUCCESS(status)) { 3608 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3609 "PrepareHardware failed %!STATUS!", status); 3610 3611 SetInternalFailure(); 3612 SetPendingPnpIrpStatus(status); 3613 } 3614 3615 exit: 3616 return status; 3617 } 3618 3619 _Must_inspect_result_ 3620 NTSTATUS 3621 FxPkgPnp::PnpReleaseHardware( 3622 VOID 3623 ) 3624 /*++ 3625 3626 Routine Description: 3627 Invokes the driver's release hardware callback if present. 3628 Releases any interrupt resources allocated during the prepare hardware callback. 3629 3630 Arguments: 3631 None 3632 3633 Return Value: 3634 Driver's release hardware callback return status or 3635 STATUS_SUCCESS if callback is not present. 3636 3637 --*/ 3638 { 3639 NTSTATUS status; 3640 FxInterrupt* interrupt; 3641 PLIST_ENTRY le; 3642 3643 // 3644 // Invoke the device's release hardware callback. 3645 // 3646 status = m_DeviceReleaseHardware.Invoke( 3647 m_Device->GetHandle(), 3648 m_Resources->GetHandle()); 3649 3650 if (status == STATUS_NOT_SUPPORTED) { 3651 DoTraceLevelMessage( 3652 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3653 "EvtDeviceReleaseHardware returned an invalid status " 3654 "STATUS_NOT_SUPPORTED"); 3655 3656 if (GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) { 3657 FxVerifierDbgBreakPoint(GetDriverGlobals()); 3658 } 3659 } 3660 3661 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 3662 if (NT_SUCCESS(status)) { 3663 // 3664 // make sure driver has unmapped its resources 3665 // 3666 m_Resources->ValidateResourceUnmap(); 3667 } 3668 3669 // 3670 // delete the register and port resource tables 3671 // 3672 m_Resources->DeleteRegisterResourceTable(); 3673 m_Resources->DeletePortResourceTable(); 3674 #endif 3675 3676 // 3677 // Delete all interrupt objects that were created in the prepare hardware 3678 // callback that the driver did not explicitly delete (in reverse order). 3679 // 3680 le = m_InterruptListHead.Blink; 3681 3682 while(le != &m_InterruptListHead) { 3683 3684 // Find the interrupt object pointer. 3685 interrupt = CONTAINING_RECORD(le, FxInterrupt, m_PnpList); 3686 3687 // Advance the entry before it becomes invalid. 3688 le = le->Blink; 3689 3690 // Let the interrupt know that 'release hardware' was called. 3691 interrupt->OnPostReleaseHardware(); 3692 } 3693 3694 return status; 3695 } 3696 3697 VOID 3698 FxPkgPnp::PnpPowerPolicyStart( 3699 VOID 3700 ) 3701 /*++ 3702 3703 Routine Description: 3704 Informs the power policy state machine that it should start. 3705 3706 Arguments: 3707 None 3708 3709 Return Value: 3710 None 3711 3712 --*/ 3713 { 3714 PowerPolicyProcessEvent(PwrPolStart); 3715 } 3716 3717 VOID 3718 FxPkgPnp::PnpPowerPolicyStop( 3719 VOID 3720 ) 3721 /*++ 3722 3723 Routine Description: 3724 Informs the power and power policy state machines that they should stop. 3725 3726 Arguments: 3727 None 3728 3729 Return Value: 3730 None 3731 3732 --*/ 3733 { 3734 PowerPolicyProcessEvent(PwrPolStop); 3735 } 3736 3737 VOID 3738 FxPkgPnp::PnpPowerPolicySurpriseRemove( 3739 VOID 3740 ) 3741 /*++ 3742 3743 Routine Description: 3744 Informs the policy state machines that it should stop due to the hardware 3745 being surprise removed. 3746 3747 Arguments: 3748 None 3749 3750 Return Value: 3751 None 3752 3753 --*/ 3754 { 3755 PowerPolicyProcessEvent(PwrPolSurpriseRemove); 3756 } 3757 3758 VOID 3759 FxPkgPnp::PnpPowerPolicyRemove( 3760 VOID 3761 ) 3762 /*++ 3763 3764 Routine Description: 3765 Informs the policy state machine that it should prepare for device removal. 3766 3767 Arguments: 3768 None 3769 3770 Return Value: 3771 None 3772 3773 --*/ 3774 { 3775 PowerPolicyProcessEvent(PwrPolRemove); 3776 } 3777 3778 VOID 3779 FxPkgPnp::PnpFinishProcessingIrp( 3780 __in BOOLEAN IrpMustBePresent 3781 ) 3782 /*++ 3783 3784 Routine Description: 3785 Finishes handling a pended pnp irp 3786 3787 Arguments: 3788 None 3789 3790 Return Value: 3791 None 3792 3793 --*/ 3794 { 3795 FxIrp irp; 3796 3797 UNREFERENCED_PARAMETER(IrpMustBePresent); 3798 ASSERT(IrpMustBePresent == FALSE || IsPresentPendingPnpIrp()); 3799 3800 // 3801 // Start device is the only request we handle on the way back up the stack. 3802 // Also, if we fail any pnp irps that we are allowed to fail, we just 3803 // complete them. 3804 // 3805 if (IsPresentPendingPnpIrp()) { 3806 3807 irp.SetIrp(GetPendingPnpIrp()); 3808 if (irp.GetMinorFunction() == IRP_MN_START_DEVICE 3809 || 3810 !NT_SUCCESS(irp.GetStatus())) { 3811 3812 irp.SetIrp(ClearPendingPnpIrp()); 3813 CompletePnpRequest(&irp, irp.GetStatus()); 3814 } 3815 else { 3816 m_PnpMachine.m_FireAndForget = TRUE; 3817 } 3818 } 3819 } 3820 3821 VOID 3822 FxPkgPnp::PnpDisableInterfaces( 3823 VOID 3824 ) 3825 /*++ 3826 3827 Routine Description: 3828 Disables all of the registerd interfaces on the device. 3829 3830 Arguments: 3831 None 3832 3833 Return Value: 3834 None 3835 3836 --*/ 3837 { 3838 PSINGLE_LIST_ENTRY ple; 3839 3840 m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals()); 3841 3842 m_DeviceInterfacesCanBeEnabled = FALSE; 3843 3844 for (ple = m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) { 3845 3846 FxDeviceInterface *pDeviceInterface; 3847 pDeviceInterface = FxDeviceInterface::_FromEntry(ple); 3848 pDeviceInterface->SetState(FALSE); 3849 } 3850 3851 m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals()); 3852 } 3853 3854 VOID 3855 FxPkgPnp::PnpEventSurpriseRemovePendingOverload( 3856 VOID 3857 ) 3858 { 3859 3860 // 3861 // Mark all of the children as missing because the parent has just been 3862 // removed. Note that this will happen after all of the children have 3863 // already received the surprise remove event. This is OK because the 3864 // reported status is inspected during the remove device event which will 3865 // happen after the parent finishes processing the surprise event. 3866 // 3867 if (m_EnumInfo != NULL) { 3868 m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals()); 3869 FxTransactionedEntry* ple; 3870 3871 ple = NULL; 3872 while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) { 3873 FxChildList::_FromEntry(ple)->NotifyDeviceSurpriseRemove(); 3874 } 3875 3876 m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals()); 3877 } 3878 } 3879 3880 _Must_inspect_result_ 3881 NTSTATUS 3882 FxPkgPnp::PnpMatchResources( 3883 VOID 3884 ) 3885 /*++ 3886 3887 Routine Description: 3888 3889 This method is called in response to a PnP StartDevice IRP 3890 coming up the stack. It: 3891 3892 - Captures the device's resources 3893 - Calls out to interested resource objects 3894 - Sends an event to the PnP state machine 3895 3896 Arguemnts: 3897 3898 Irp - a pointer to the FxIrp 3899 3900 Returns: 3901 3902 NTSTATUS 3903 3904 --*/ 3905 { 3906 PCM_RESOURCE_LIST pResourcesRaw; 3907 PCM_RESOURCE_LIST pResourcesTranslated; 3908 FxResourceCm* resCmRaw; 3909 FxResourceCm* resCmTrans; 3910 FxInterrupt* interrupt; 3911 PLIST_ENTRY ple; 3912 NTSTATUS status; 3913 FxCollectionEntry *curRaw, *curTrans, *endTrans; 3914 ULONG messageCount; 3915 FxIrp irp; 3916 3917 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 3918 "Entering PnpMatchResources"); 3919 3920 // 3921 // We must clear these flags before calling into the event handler because 3922 // it might set these states back (which is OK). If we don't clear these 3923 // states and the start succeeds, we would endlessly report that our 3924 // resources have changed and be restarted over and over. 3925 // 3926 m_PnpStateAndCaps.Value &= ~(FxPnpStateFailedMask | 3927 FxPnpStateResourcesChangedMask); 3928 m_PnpStateAndCaps.Value |= (FxPnpStateFailedUseDefault | 3929 FxPnpStateResourcesChangedUseDefault); 3930 3931 irp.SetIrp(m_PendingPnPIrp); 3932 pResourcesRaw = irp.GetParameterAllocatedResources(); 3933 pResourcesTranslated = irp.GetParameterAllocatedResourcesTranslated(); 3934 3935 status = m_ResourcesRaw->BuildFromWdmList(pResourcesRaw, FxResourceNoAccess); 3936 if (!NT_SUCCESS(status)) { 3937 DoTraceLevelMessage( 3938 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3939 "Could not allocate raw resource list for WDFDEVICE 0x%p, %!STATUS!", 3940 m_Device->GetHandle(), status); 3941 goto Done; 3942 } 3943 3944 status = m_Resources->BuildFromWdmList(pResourcesTranslated, FxResourceNoAccess); 3945 if (!NT_SUCCESS(status)) { 3946 DoTraceLevelMessage( 3947 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 3948 "Could not allocate translated resource list for WDFDEVICE 0x%p, %!STATUS!", 3949 m_Device->GetHandle(), status); 3950 goto Done; 3951 } 3952 3953 // 3954 // reset the stored information in all interrupts in the rebalance case 3955 // 3956 for (ple = m_InterruptListHead.Flink; 3957 ple != &m_InterruptListHead; 3958 ple = ple->Flink) { 3959 interrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); 3960 interrupt->Reset(); 3961 } 3962 3963 // 3964 // Now iterate across the resources, looking for ones that correspond 3965 // to objects that we are managing. Tell those objects about the resources 3966 // that were assigned. 3967 // 3968 ple = &m_InterruptListHead; 3969 3970 endTrans = m_Resources->End(); 3971 3972 for (curTrans = m_Resources->Start(), curRaw = m_ResourcesRaw->Start(); 3973 curTrans != endTrans; 3974 curTrans = curTrans->Next(), curRaw = curRaw->Next()) { 3975 3976 ASSERT(curTrans->m_Object->GetType() == FX_TYPE_RESOURCE_CM); 3977 ASSERT(curRaw->m_Object->GetType() == FX_TYPE_RESOURCE_CM); 3978 3979 resCmRaw = (FxResourceCm*) curRaw->m_Object; 3980 3981 if (resCmRaw->m_Descriptor.Type == CmResourceTypeInterrupt) { 3982 // 3983 // We're looking at an interrupt resource. 3984 // 3985 if (ple->Flink == &m_InterruptListHead) { 3986 // 3987 // Oops, there are no more interrupt objects. 3988 // 3989 DoTraceLevelMessage( 3990 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, 3991 "Not enough interrupt objects created by WDFDEVICE 0x%p", 3992 m_Device->GetHandle()); 3993 break; 3994 } 3995 3996 resCmTrans = (FxResourceCm*) curTrans->m_Object; 3997 ASSERT(resCmTrans->m_Descriptor.Type == CmResourceTypeInterrupt); 3998 3999 messageCount = resCmRaw->m_Descriptor.u.MessageInterrupt.Raw.MessageCount; 4000 4001 if (FxInterrupt::_IsMessageInterrupt(resCmTrans->m_Descriptor.Flags) 4002 && 4003 (messageCount > 1)) { 4004 ULONG i; 4005 // 4006 // Multi-message MSI 2.2 needs to be handled differently 4007 // 4008 for (i = 0, ple = ple->Flink; 4009 i < messageCount && ple != &m_InterruptListHead; 4010 i++, ple = ple->Flink) { 4011 4012 // 4013 // Get the next interrupt object. 4014 // 4015 interrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); 4016 4017 // 4018 // Tell the interrupt object what its resources are. 4019 // 4020 interrupt->AssignResources(&resCmRaw->m_Descriptor, 4021 &resCmTrans->m_Descriptor); 4022 } 4023 } 4024 else { 4025 // 4026 // This is either MSI2.2 with 1 message, MSI-X or Line based. 4027 // 4028 ple = ple->Flink; 4029 interrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); 4030 4031 // 4032 // Tell the interrupt object what its resources are. 4033 // 4034 interrupt->AssignResources(&resCmRaw->m_Descriptor, 4035 &resCmTrans->m_Descriptor); 4036 } 4037 } 4038 } 4039 4040 #if FX_IS_KERNEL_MODE 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 // 4051 // If there are any pended I/Os that were sent to the target 4052 // that were pended in the transition to stop, then this will 4053 // resend them. 4054 // 4055 // ISSUE: This has the potential of I/O completing 4056 // before the driver's start callback has been called...but, 4057 // this is the same as the PDO pending a sent irp and completing 4058 // it when the PDO is restarted before the FDO has a change to 4059 // process the start irp which was still pended below. 4060 // 4061 if (m_Device->IsFilter()) { 4062 // 4063 // If this is a filter device, then copy the FILE_REMOVABLE_MEDIA 4064 // characteristic from the lower device. 4065 // 4066 if (m_Device->GetAttachedDevice()->Characteristics & FILE_REMOVABLE_MEDIA) { 4067 ULONG characteristics; 4068 4069 characteristics = 4070 m_Device->GetDeviceObject()->Characteristics | FILE_REMOVABLE_MEDIA; 4071 4072 m_Device->GetDeviceObject()->Characteristics = characteristics; 4073 } 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 m_Device->SetFilterIoType(); 4085 } 4086 4087 #endif // FX_IS_KERNEL_MODE 4088 4089 Done: 4090 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 4091 "Exiting PnpMatchResources %!STATUS!", status); 4092 4093 return status; 4094 } 4095 4096 VOID 4097 FxPkgPnp::PnpAssignInterruptsSyncIrql( 4098 VOID 4099 ) 4100 /*++ 4101 4102 Routine Description: 4103 Figure out the highest synch irql for each interrupt set which shares a 4104 spinlock. 4105 4106 foreach(interrupt assigned to this instance) 4107 determine the max sync irql in the set 4108 set all the associated interrupts to the sync irql 4109 set the sync irql on the first interrupt in the set 4110 4111 Arguments: 4112 None 4113 4114 Return Value: 4115 None 4116 4117 --*/ 4118 { 4119 PLIST_ENTRY ple; 4120 FxInterrupt* pInterrupt; 4121 4122 for (ple = m_InterruptListHead.Flink; 4123 ple != &m_InterruptListHead; 4124 ple = ple->Flink) { 4125 4126 KIRQL syncIrql; 4127 4128 pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); 4129 4130 syncIrql = pInterrupt->GetResourceIrql(); 4131 4132 if (syncIrql == PASSIVE_LEVEL) { 4133 // 4134 // The irql associated with the resources assigned is passive, 4135 // this can happen in the following scenarios: 4136 // 4137 // (1) no resources were assigned. Skip this interrupt b/c it has 4138 // no associated resources. Note: setting the SynchronizeIrql 4139 // to PASSIVE_LEVEL is a no-op. 4140 // 4141 // (2) this interrupt is handled at passive-level. 4142 // Set SynchronizeIrql to passive-level and continue. 4143 // 4144 pInterrupt->SetSyncIrql(PASSIVE_LEVEL); 4145 continue; 4146 } 4147 4148 if (pInterrupt->IsSharedSpinLock() == FALSE) { 4149 // 4150 // If the interrupt spinlock is not shared, it's sync irql is the 4151 // irql assigned to it in the resources. 4152 // 4153 pInterrupt->SetSyncIrql(syncIrql); 4154 } 4155 else if (pInterrupt->IsSyncIrqlSet() == FALSE) { 4156 FxInterrupt* pFwdInterrupt; 4157 PLIST_ENTRY pleFwd; 4158 4159 // 4160 // Find all of the other interrupts which share the lock and compute 4161 // the max sync irql. 4162 // 4163 for (pleFwd = ple->Flink; 4164 pleFwd != &m_InterruptListHead; 4165 pleFwd = pleFwd->Flink) { 4166 4167 pFwdInterrupt = CONTAINING_RECORD(pleFwd, FxInterrupt, m_PnpList); 4168 4169 // 4170 // If the 2 do not share the same lock, they are not in the same 4171 // set. 4172 // 4173 if (pFwdInterrupt->SharesLock(pInterrupt) == FALSE) { 4174 continue; 4175 } 4176 4177 if (pFwdInterrupt->GetResourceIrql() > syncIrql) { 4178 syncIrql = pFwdInterrupt->GetResourceIrql(); 4179 } 4180 } 4181 4182 // 4183 // Now that we found the max sync irql, set it for all interrupts in 4184 // the set which share the lock 4185 // 4186 for (pleFwd = ple->Flink; 4187 pleFwd != &m_InterruptListHead; 4188 pleFwd = pleFwd->Flink) { 4189 4190 pFwdInterrupt = CONTAINING_RECORD(pleFwd, FxInterrupt, m_PnpList); 4191 4192 // 4193 // If the 2 do not share the same lock, they are not in the same 4194 // set. 4195 // 4196 if (pFwdInterrupt->SharesLock(pInterrupt) == FALSE) { 4197 continue; 4198 } 4199 4200 pFwdInterrupt->SetSyncIrql(syncIrql); 4201 } 4202 4203 // 4204 // Set the sync irql for the first interrupt in the set. We have set 4205 // the sync irql for all other interrupts in the set. 4206 // 4207 pInterrupt->SetSyncIrql(syncIrql); 4208 } 4209 else { 4210 // 4211 // If IsSyncIrqlSet is TRUE, we already covered this interrupt in a 4212 // previous pass of this loop when we computed the max sync irql for 4213 // an interrupt set. 4214 // 4215 ASSERT(pInterrupt->GetSyncIrql() > PASSIVE_LEVEL); 4216 DO_NOTHING(); 4217 } 4218 } 4219 } 4220 4221 _Must_inspect_result_ 4222 NTSTATUS 4223 FxPkgPnp::ValidateCmResource( 4224 __inout PCM_PARTIAL_RESOURCE_DESCRIPTOR* CmResourceRaw, 4225 __inout PCM_PARTIAL_RESOURCE_DESCRIPTOR* CmResource 4226 ) 4227 /*++ 4228 4229 Routine Description: 4230 Makes sure the specified resource is valid. 4231 4232 Arguments: 4233 CmResourceRaw - the raw resource to validate. 4234 CmResource - the translated resources to validate. 4235 4236 Return Value: 4237 STATUS_SUCCESS if resource is valid or 4238 NTSTATUS error. 4239 4240 --*/ 4241 { 4242 NTSTATUS status; 4243 FxCollectionEntry* cur; 4244 FxCollectionEntry* curRaw; 4245 FxResourceCm* res; 4246 FxResourceCm* resRaw; 4247 PFX_DRIVER_GLOBALS fxDriverGlobals; 4248 4249 ASSERT(m_ResourcesRaw != NULL); 4250 ASSERT(m_Resources != NULL); 4251 4252 res = NULL; 4253 resRaw = NULL; 4254 4255 fxDriverGlobals = GetDriverGlobals(); 4256 4257 // 4258 // Find the resource in our list. 4259 // 4260 for (cur = m_Resources->Start(), curRaw = m_ResourcesRaw->Start(); 4261 cur != m_Resources->End(); 4262 cur = cur->Next(), curRaw = curRaw->Next()) { 4263 4264 res = (FxResourceCm*) cur->m_Object; 4265 resRaw = (FxResourceCm*) curRaw->m_Object; 4266 4267 if (&res->m_DescriptorClone == *CmResource) { 4268 break; 4269 } 4270 } 4271 4272 // 4273 // Error out if not found. 4274 // 4275 if (cur == m_Resources->End()) { 4276 status = STATUS_INVALID_PARAMETER; 4277 DoTraceLevelMessage( 4278 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 4279 "The translated PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, " 4280 "WDFDEVICE 0x%p, %!STATUS!", 4281 *CmResource, m_Device->GetHandle(), status); 4282 FxVerifierDbgBreakPoint(fxDriverGlobals); 4283 goto Done; 4284 } 4285 4286 // 4287 // Error out if the associated raw resource is not the same. 4288 // 4289 if (&resRaw->m_DescriptorClone != *CmResourceRaw) { 4290 status = STATUS_INVALID_PARAMETER; 4291 DoTraceLevelMessage( 4292 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 4293 "The raw PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, " 4294 "WDFDEVICE 0x%p, %!STATUS!", 4295 *CmResourceRaw, m_Device->GetHandle(), status); 4296 FxVerifierDbgBreakPoint(fxDriverGlobals); 4297 goto Done; 4298 } 4299 4300 // 4301 // Make sure driver didn't change any of the PnP settings. 4302 // 4303 if (sizeof(res->m_Descriptor) != 4304 RtlCompareMemory(&res->m_DescriptorClone, 4305 &res->m_Descriptor, 4306 sizeof(res->m_Descriptor))) { 4307 status = STATUS_INVALID_PARAMETER; 4308 DoTraceLevelMessage( 4309 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 4310 "The translated PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, " 4311 "driver cannot change the assigned PnP resources, WDFDEVICE 0x%p, " 4312 "%!STATUS!", 4313 *CmResource, m_Device->GetHandle(), status); 4314 FxVerifierDbgBreakPoint(fxDriverGlobals); 4315 goto Done; 4316 } 4317 4318 if (sizeof(resRaw->m_Descriptor) != 4319 RtlCompareMemory(&resRaw->m_DescriptorClone, 4320 &resRaw->m_Descriptor, 4321 sizeof(resRaw->m_Descriptor))) { 4322 status = STATUS_INVALID_PARAMETER; 4323 DoTraceLevelMessage( 4324 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 4325 "The raw PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, " 4326 "driver cannot change the assigned PnP resources, WDFDEVICE 0x%p, " 4327 "%!STATUS!", 4328 *CmResourceRaw, m_Device->GetHandle(), status); 4329 FxVerifierDbgBreakPoint(fxDriverGlobals); 4330 goto Done; 4331 } 4332 4333 // 4334 // Return the real descriptor. 4335 // 4336 ASSERT(res != NULL && resRaw != NULL); 4337 *CmResource = &res->m_Descriptor; 4338 *CmResourceRaw = &resRaw->m_Descriptor; 4339 4340 status = STATUS_SUCCESS; 4341 4342 Done: 4343 return status; 4344 } 4345 4346 _Must_inspect_result_ 4347 NTSTATUS 4348 FxPkgPnp::ValidateInterruptResourceCm( 4349 __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResourceRaw, 4350 __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResource, 4351 __in PWDF_INTERRUPT_CONFIG Configuration 4352 ) 4353 /*++ 4354 4355 Routine Description: 4356 Makes sure the specified resource is valid for an interrupt resource. 4357 4358 Arguments: 4359 CmIntResourceRaw - the raw interrupt resource to validate. 4360 CmIntResource - the translated interrupt resource to validate. 4361 4362 Return Value: 4363 STATUS_SUCCESS if resource is valid or 4364 NTSTATUS error. 4365 4366 --*/ 4367 { 4368 NTSTATUS status; 4369 PLIST_ENTRY le; 4370 FxInterrupt* interrupt; 4371 ULONG messageCount; 4372 PFX_DRIVER_GLOBALS fxDriverGlobals; 4373 PCM_PARTIAL_RESOURCE_DESCRIPTOR cmIntResourceRaw; 4374 PCM_PARTIAL_RESOURCE_DESCRIPTOR cmIntResource; 4375 4376 cmIntResourceRaw = CmIntResourceRaw; 4377 cmIntResource = CmIntResource; 4378 fxDriverGlobals = GetDriverGlobals(); 4379 4380 // 4381 // Get the real descriptor not the copy. 4382 // 4383 status = ValidateCmResource(&cmIntResourceRaw, &cmIntResource); 4384 if (!NT_SUCCESS(status)) { 4385 goto Done; 4386 } 4387 4388 // 4389 // Make sure this is an interrupt resource. 4390 // 4391 if (cmIntResourceRaw->Type != CmResourceTypeInterrupt) { 4392 status = STATUS_INVALID_PARAMETER; 4393 DoTraceLevelMessage( 4394 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 4395 "The raw PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not an " 4396 "interrupt resource, WDFDEVICE 0x%p, %!STATUS!", 4397 CmIntResourceRaw, m_Device->GetHandle(), status); 4398 FxVerifierDbgBreakPoint(fxDriverGlobals); 4399 goto Done; 4400 } 4401 4402 if (cmIntResource->Type != CmResourceTypeInterrupt) { 4403 status = STATUS_INVALID_PARAMETER; 4404 DoTraceLevelMessage( 4405 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 4406 "The translated PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not an " 4407 "interrupt resource, WDFDEVICE 0x%p, %!STATUS!", 4408 CmIntResource, m_Device->GetHandle(), status); 4409 FxVerifierDbgBreakPoint(fxDriverGlobals); 4410 goto Done; 4411 } 4412 4413 // 4414 // Make sure resource was not claimed by another interrupt. 4415 // Multi-message MSI 2.2 interrupts: allowed to reuse claimed resources. 4416 // Driver must create them sequentially. 4417 // Line-based interrupts: allowed to reuse claimed resources. 4418 // Driver can create them out-of-order. 4419 // Other MSI: not allowed to reuse claimed resources. 4420 // 4421 messageCount = 0; 4422 4423 for (le = m_InterruptListHead.Flink; 4424 le != &m_InterruptListHead; 4425 le = le->Flink) { 4426 4427 interrupt = CONTAINING_RECORD(le, FxInterrupt, m_PnpList); 4428 4429 if (cmIntResource != interrupt->GetResources()) { 4430 // 4431 // Multi-message MSI 2.2 interrupts must be sequential. 4432 // 4433 if (messageCount != 0) { 4434 status = STATUS_INVALID_PARAMETER; 4435 DoTraceLevelMessage( 4436 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 4437 "Multi-message MSI 2.2 interrupts must be created " 4438 "sequentially, WDFDEVICE 0x%p, %!STATUS!", 4439 m_Device->GetHandle(), status); 4440 FxVerifierDbgBreakPoint(fxDriverGlobals); 4441 goto Done; 4442 } 4443 4444 continue; 4445 } 4446 4447 if (interrupt->IsWakeCapable() && 4448 Configuration->PassiveHandling) { 4449 DoTraceLevelMessage( 4450 fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, 4451 "The PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p was already used " 4452 "to create a wakable interrupt 0x%p, WDFDEVICE 0x%p and " 4453 "any functional interrupt being shared with wakable interrupt " 4454 "can not use passive level handling", 4455 CmIntResource, interrupt->GetHandle(), 4456 m_Device->GetHandle()); 4457 status = STATUS_INVALID_PARAMETER; 4458 goto Done; 4459 } 4460 4461 if (interrupt->IsPassiveHandling() && 4462 Configuration->CanWakeDevice) { 4463 DoTraceLevelMessage( 4464 fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, 4465 "The PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p was already used " 4466 "to create a passive level interrupt 0x%p, WDFDEVICE 0x%p and " 4467 "is now being used to create a wakable interrupt. A functional " 4468 "passive level interrupt can not be shared with wakable interrupt", 4469 CmIntResource, interrupt->GetHandle(), 4470 m_Device->GetHandle()); 4471 status = STATUS_INVALID_PARAMETER; 4472 goto Done; 4473 } 4474 4475 // 4476 // Check for multi-message MSI 2.2 interrupts. These are allowed 4477 // to use the same resource. 4478 // We allow line based interrupts to reuse claimed resources. 4479 // 4480 if (FxInterrupt::_IsMessageInterrupt(cmIntResource->Flags) == FALSE) { 4481 DoTraceLevelMessage( 4482 fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, 4483 "The PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p was already used " 4484 "to create interrupt 0x%p, WDFDEVICE 0x%p", 4485 CmIntResource, interrupt->GetHandle(), 4486 m_Device->GetHandle()); 4487 continue; 4488 } 4489 4490 // 4491 // Only allow the correct # of messages. 4492 // 4493 messageCount++; 4494 if (messageCount > 4495 cmIntResourceRaw->u.MessageInterrupt.Raw.MessageCount) { 4496 4497 status = STATUS_INVALID_PARAMETER; 4498 DoTraceLevelMessage( 4499 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 4500 "All the MSI 2.2 interrupts for " 4501 "PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p are already created, " 4502 "WDFDEVICE 0x%p, %!STATUS!", 4503 CmIntResource, m_Device->GetHandle(), status); 4504 FxVerifierDbgBreakPoint(fxDriverGlobals); 4505 goto Done; 4506 } 4507 } 4508 4509 status = STATUS_SUCCESS; 4510 4511 Done: 4512 return status; 4513 } 4514 4515 #define RESTART_START_ACHIEVED_NAME L"StartAchieved" 4516 #define RESTART_START_TIME_NAME L"StartTime" 4517 #define RESTART_COUNT_NAME L"Count" 4518 4519 const PWCHAR FxPkgPnp::m_RestartStartAchievedName = RESTART_START_ACHIEVED_NAME; 4520 const PWCHAR FxPkgPnp::m_RestartStartTimeName = RESTART_START_TIME_NAME; 4521 const PWCHAR FxPkgPnp::m_RestartCountName = RESTART_COUNT_NAME; 4522 4523 const ULONG FxPkgPnp::m_RestartTimePeriodMaximum = 60; 4524 const ULONG FxPkgPnp::m_RestartCountMaximum = 5; 4525 4526 BOOLEAN 4527 FxPkgPnp::PnpIncrementRestartCountLogic( 4528 _In_ HANDLE RestartKey, 4529 _In_ BOOLEAN CreatedNewKey 4530 ) 4531 /*++ 4532 4533 Routine Description: 4534 This routine determines if this device should ask the bus driver to 4535 reenumerate the device. This is determined by how many times the entire 4536 stack has asked for a restart within a given period. This is stack wide 4537 because the settings are stored in a key in the device node itself (which all 4538 devices share). 4539 4540 The period and number of times a restart are attempted are defined as constants 4541 (m_RestartTimePeriodMaximum, m_RestartCountMaximum)in this class. They are 4542 current defined as a period of 60 seconds and a restart max count of 5. 4543 4544 The settings are stored in a volatile key so that they do not persist across 4545 machine reboots. Persisting across reboots makes no sense if we restrict the 4546 number of restarts w/in a period. 4547 4548 The rules are as follows 4549 1) if the key does not exist, treat this as the beginning of the period 4550 and ask for a reenumeration 4551 2) if the key exists 4552 a) if the beginning of the period and the restart count cannot be read 4553 do not ask for a reenumeration 4554 b) if the beginning of the period is after the current time, either the 4555 current tick count has wrapped or the key has somehow survived a 4556 reboot. Either way, treat this as a reset of the period and ask 4557 for a reenumeration 4558 c) if the current time is after the period start time and within the 4559 restart period, increment the restart count. if the count is <= 4560 the max restart count, ask for a reenumeration. If it exceeds the 4561 max, do not ask for a reenumeration. 4562 d) if the current time is after the period stat time and exceeds the 4563 maximum period, and if the device as reached the started state, 4564 reset the period, count, and started state, then ask for a 4565 reenumeration. 4566 4567 Considerations: 4568 There is a reenumeration loop that a device can get caught in. If a device 4569 takes more than m_RestartTimePeriodMaximum to fail m_RestartCountMaximum 4570 times then the device will be caught in this loop. If it is failing on the 4571 way to PnpEventStarted then the device will likely cause a 9F bugcheck. 4572 This is because they hold a power lock while in this loop. If the device 4573 fails after PnpEventStarted then pnp can progress and the device can loop 4574 here indefinitely. We have shipped with this behavior for several releases, 4575 so we are hesitant to completely change this behavior. The concern is that 4576 a device out there relies on this behavior. 4577 4578 Arguments: 4579 RestartKey - opened handle to the Restart registry key 4580 CreatedNewKey - TRUE if the Restart key was created just now 4581 4582 Return Value: 4583 TRUE if a restart should be requested. 4584 4585 --*/ 4586 { 4587 NTSTATUS status = STATUS_SUCCESS; 4588 ULONG count; 4589 LARGE_INTEGER currentTickCount, startTickCount; 4590 BOOLEAN started, writeTick, writeCount, writeStarted; 4591 4592 DECLARE_CONST_UNICODE_STRING(valueNameStartTime, RESTART_START_TIME_NAME); 4593 DECLARE_CONST_UNICODE_STRING(valueNameCount, RESTART_COUNT_NAME); 4594 DECLARE_CONST_UNICODE_STRING(valueNameStartAchieved, RESTART_START_ACHIEVED_NAME); 4595 4596 count = 0; 4597 started = FALSE; 4598 writeTick = FALSE; 4599 writeCount = FALSE; 4600 writeStarted = FALSE; 4601 4602 Mx::MxQueryTickCount(¤tTickCount); 4603 4604 started = m_AchievedStart; 4605 if (started) { 4606 // 4607 // Save the fact the driver started without failing 4608 // 4609 writeStarted = TRUE; 4610 } 4611 4612 4613 // 4614 // If the key was created right now, there is nothing to check, just write out 4615 // the data. 4616 // 4617 if (CreatedNewKey) { 4618 writeTick = TRUE; 4619 writeCount = TRUE; 4620 4621 // 4622 // First restart 4623 // 4624 count = 1; 4625 } 4626 else { 4627 ULONG length, type; 4628 4629 // 4630 // First try to get the start time of when we first attempted a restart 4631 // 4632 status = FxRegKey::_QueryValue(GetDriverGlobals(), 4633 RestartKey, 4634 &valueNameStartTime, 4635 sizeof(startTickCount.QuadPart), 4636 &startTickCount.QuadPart, 4637 &length, 4638 &type); 4639 4640 if (NT_SUCCESS(status) && 4641 length == sizeof(startTickCount.QuadPart) && type == REG_BINARY) { 4642 4643 // 4644 // Now try to get the last restart count 4645 // 4646 status = FxRegKey::_QueryULong(RestartKey, 4647 &valueNameCount, 4648 &count); 4649 4650 if (status == STATUS_OBJECT_NAME_NOT_FOUND) { 4651 // 4652 // We read the start time, but not the count. Assume there was 4653 // at least one previous restart. 4654 // 4655 count = 1; 4656 status = STATUS_SUCCESS; 4657 } 4658 } 4659 4660 if (NT_SUCCESS(status)) { 4661 if (currentTickCount.QuadPart < startTickCount.QuadPart) { 4662 // 4663 // Somehow the key survived a reboot or the clock overflowed 4664 // and the current time is less then the last time we started 4665 // timing restarts. Either way, just treat this as the first 4666 // time we are restarting. 4667 // 4668 writeTick = TRUE; 4669 writeCount = TRUE; 4670 count = 1; 4671 } 4672 else { 4673 LONGLONG delta; 4674 4675 // 4676 // Compute the difference in time in 100 ns units 4677 // 4678 delta = (currentTickCount.QuadPart - startTickCount.QuadPart) * 4679 Mx::MxQueryTimeIncrement(); 4680 4681 if (delta <= WDF_ABS_TIMEOUT_IN_SEC(m_RestartTimePeriodMaximum)) { 4682 // 4683 // We are within the time limit, see if we are within the 4684 // count limit 4685 count++; 4686 4687 // 4688 // The count starts at one, so include the maximum in the 4689 // compare. 4690 // 4691 if (count <= m_RestartCountMaximum) { 4692 writeCount = TRUE; 4693 } 4694 else { 4695 // 4696 // Exceeded the restart count, do not attempt to restart 4697 // the device. 4698 // 4699 status = STATUS_UNSUCCESSFUL; 4700 } 4701 } 4702 else { 4703 if (started == FALSE) { 4704 ULONG length, type, value; 4705 status = FxRegKey::_QueryValue(GetDriverGlobals(), 4706 RestartKey, 4707 &valueNameStartAchieved, 4708 sizeof(value), 4709 &value, 4710 &length, 4711 &type); 4712 if (!NT_SUCCESS(status) || length != sizeof(value) || 4713 type != REG_DWORD) { 4714 value = 0; 4715 } 4716 started = value != 0; 4717 status = STATUS_SUCCESS; 4718 } 4719 4720 if (started) { 4721 // 4722 // Exceeded the time limit. This is treated as a reset of 4723 // the time limit, so we will try to restart and reset the 4724 // start time and restart count. 4725 // 4726 writeTick = TRUE; 4727 writeCount = TRUE; 4728 count = 1; 4729 4730 // 4731 // Erase the fact the driver once started and 4732 // make it do it again to get another 5 attempts to 4733 // restart. 4734 // 4735 writeStarted = TRUE; 4736 started = FALSE; 4737 } 4738 else { 4739 // 4740 // Device never started 4741 // 4742 status = STATUS_UNSUCCESSFUL; 4743 } 4744 } 4745 } 4746 } 4747 } 4748 4749 if (writeTick) { 4750 // 4751 // Write out the time and the count 4752 // 4753 NTSTATUS status2; 4754 status2 = FxRegKey::_SetValue(RestartKey, 4755 (PUNICODE_STRING)&valueNameStartTime, 4756 REG_BINARY, 4757 ¤tTickCount.QuadPart, 4758 sizeof(currentTickCount.QuadPart)); 4759 // 4760 // Don't let status report success if it was an error prior to _SetValue 4761 // 4762 if(NT_SUCCESS(status)) { 4763 status = status2; 4764 } 4765 } 4766 4767 if (NT_SUCCESS(status) && writeCount) { 4768 status = FxRegKey::_SetValue(RestartKey, 4769 (PUNICODE_STRING)&valueNameCount, 4770 REG_DWORD, 4771 &count, 4772 sizeof(count)); 4773 } 4774 4775 if (writeStarted) { 4776 NTSTATUS status2; 4777 DWORD value = started; 4778 status2 = FxRegKey::_SetValue(RestartKey, 4779 (PUNICODE_STRING)&valueNameStartAchieved, 4780 REG_DWORD, 4781 &value, 4782 sizeof(value)); 4783 // 4784 // Don't let status report success if it was an error prior to _SetValue 4785 // 4786 if(NT_SUCCESS(status)) { 4787 status = status2; 4788 } 4789 } 4790 4791 return NT_SUCCESS(status) ? TRUE : FALSE; 4792 } 4793 4794