1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxInterruptApi.cpp 8 9 Abstract: 10 11 This implements the WDFINTERRUPT API's 12 13 Author: 14 15 16 17 18 Environment: 19 20 Both kernel and user mode 21 22 Revision History: 23 24 25 --*/ 26 27 #include "pnppriv.hpp" 28 29 extern "C" { 30 // #include "FxInterruptApi.tmh" 31 } 32 33 // 34 // At this time we are unable to include wdf19.h in the share code, thus for 35 // now we simply cut and paste the needed structures. 36 // 37 typedef struct _WDF_INTERRUPT_CONFIG_V1_9 { 38 ULONG Size; 39 40 // 41 // If this interrupt is to be synchronized with other interrupt(s) assigned 42 // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the 43 // WDFINTERRUPTs config. 44 // 45 WDFSPINLOCK SpinLock; 46 47 WDF_TRI_STATE ShareVector; 48 49 BOOLEAN FloatingSave; 50 51 // 52 // Automatic Serialization of the DpcForIsr 53 // 54 BOOLEAN AutomaticSerialization; 55 56 // Event Callbacks 57 PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; 58 59 PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; 60 61 PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; 62 63 PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; 64 65 } WDF_INTERRUPT_CONFIG_V1_9, *PWDF_INTERRUPT_CONFIG_V1_9; 66 67 // 68 // The interrupt config structure has changed post win8-Beta. This is a 69 // temporary definition to allow beta drivers to load on post-beta builds. 70 // Note that size of win8-beta and win8-postbeta structure is different only on 71 // non-x64 platforms, but the fact that size is same on amd64 is harmless because 72 // the struture gets zero'out by init macro, and the default value of the new 73 // field is 0 on amd64. 74 // 75 typedef struct _WDF_INTERRUPT_CONFIG_V1_11_BETA { 76 ULONG Size; 77 78 // 79 // If this interrupt is to be synchronized with other interrupt(s) assigned 80 // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the 81 // WDFINTERRUPTs config. 82 // 83 WDFSPINLOCK SpinLock; 84 85 WDF_TRI_STATE ShareVector; 86 87 BOOLEAN FloatingSave; 88 89 // 90 // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr. 91 // Passive-level handling: automatic serialization of all callbacks. 92 // 93 BOOLEAN AutomaticSerialization; 94 95 // 96 // Event Callbacks 97 // 98 PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; 99 PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; 100 PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; 101 PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; 102 PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem; 103 104 // 105 // These fields are only used when interrupt is created in 106 // EvtDevicePrepareHardware callback. 107 // 108 PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw; 109 PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated; 110 111 // 112 // Optional passive lock for handling interrupts at passive-level. 113 // 114 WDFWAITLOCK WaitLock; 115 116 // 117 // TRUE: handle interrupt at passive-level. 118 // FALSE: handle interrupt at DIRQL level. This is the default. 119 // 120 BOOLEAN PassiveHandling; 121 122 } WDF_INTERRUPT_CONFIG_V1_11_BETA, *PWDF_INTERRUPT_CONFIG_V1_11_BETA; 123 124 // 125 // Interrupt Configuration Structure 126 // 127 typedef struct _WDF_INTERRUPT_CONFIG_V1_11 { 128 ULONG Size; 129 130 // 131 // If this interrupt is to be synchronized with other interrupt(s) assigned 132 // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the 133 // WDFINTERRUPTs config. 134 // 135 WDFSPINLOCK SpinLock; 136 137 WDF_TRI_STATE ShareVector; 138 139 BOOLEAN FloatingSave; 140 141 // 142 // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr. 143 // Passive-level handling: automatic serialization of all callbacks. 144 // 145 BOOLEAN AutomaticSerialization; 146 147 // 148 // Event Callbacks 149 // 150 PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; 151 PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; 152 PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; 153 PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; 154 PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem; 155 156 // 157 // These fields are only used when interrupt is created in 158 // EvtDevicePrepareHardware callback. 159 // 160 PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw; 161 PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated; 162 163 // 164 // Optional passive lock for handling interrupts at passive-level. 165 // 166 WDFWAITLOCK WaitLock; 167 168 // 169 // TRUE: handle interrupt at passive-level. 170 // FALSE: handle interrupt at DIRQL level. This is the default. 171 // 172 BOOLEAN PassiveHandling; 173 174 // 175 // TRUE: Interrupt is reported inactive on explicit power down 176 // instead of disconnecting it. 177 // FALSE: Interrupt is disconnected instead of reporting inactive 178 // on explicit power down. 179 // DEFAULT: Framework decides the right value. 180 // 181 WDF_TRI_STATE ReportInactiveOnPowerDown; 182 183 } WDF_INTERRUPT_CONFIG_V1_11, *PWDF_INTERRUPT_CONFIG_V1_11; 184 185 // 186 // extern "C" the entire file 187 // 188 extern "C" { 189 190 _Must_inspect_result_ 191 __drv_maxIRQL(DISPATCH_LEVEL) 192 NTSTATUS 193 STDCALL 194 WDFEXPORT(WdfInterruptCreate)( 195 __in 196 PWDF_DRIVER_GLOBALS DriverGlobals, 197 __in 198 WDFDEVICE Device, 199 __in 200 PWDF_INTERRUPT_CONFIG Configuration, 201 __in_opt 202 PWDF_OBJECT_ATTRIBUTES Attributes, 203 __out 204 WDFINTERRUPT* Interrupt 205 ) 206 207 /*++ 208 209 Routine Description: 210 211 Create an Interrupt object along with its associated DpcForIsr. 212 213 Arguments: 214 215 Object - Handle to a WDFDEVICE or WDFQUEUE to associate the interrupt with. 216 217 pConfiguration - WDF_INTERRUPT_CONFIG structure. 218 219 pAttributes - Optional WDF_OBJECT_ATTRIBUTES to request a context 220 memory allocation, and a DestroyCallback. 221 222 pInterrupt - Pointer to location to return the resulting WDFINTERRUPT handle. 223 224 Returns: 225 226 STATUS_SUCCESS - A WDFINTERRUPT handle has been created. 227 228 --*/ 229 230 { 231 DDI_ENTRY(); 232 233 PFX_DRIVER_GLOBALS pFxDriverGlobals; 234 FxInterrupt* pFxInterrupt; 235 FxDevice* pDevice; 236 FxObject* pParent; 237 NTSTATUS status; 238 WDF_DEVICE_PNP_STATE devicePnpState; 239 ULONG expectedConfigSize; 240 WDF_INTERRUPT_CONFIG intConfig; 241 242 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 243 Device, 244 FX_TYPE_DEVICE, 245 (PVOID*)&pDevice, 246 &pFxDriverGlobals); 247 248 FxPointerNotNull(pFxDriverGlobals, Configuration); 249 FxPointerNotNull(pFxDriverGlobals, Interrupt); 250 251 if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13)) { 252 expectedConfigSize = sizeof(WDF_INTERRUPT_CONFIG); 253 } else if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) { 254 expectedConfigSize = sizeof(WDF_INTERRUPT_CONFIG_V1_11); 255 } else { 256 expectedConfigSize = sizeof(WDF_INTERRUPT_CONFIG_V1_9); 257 } 258 259 260 // 261 // We could check if Configuration->Size != expectedConfigSize, but 262 // logic below allows me to installing old WDF drivers v1.11 on new WDF. 263 // 264 if (Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG) && 265 Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG_V1_11) && 266 Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG_V1_11_BETA) && 267 Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG_V1_9)) { 268 269 DoTraceLevelMessage( 270 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 271 "WDF_INTERRUPT_CONFIG size 0x%x incorrect, expected 0x%x", 272 Configuration->Size, expectedConfigSize); 273 274 return STATUS_INFO_LENGTH_MISMATCH; 275 } 276 277 // 278 // Normalize WDF_INTERRUPT_CONFIG structure. 279 // 280 if (Configuration->Size < sizeof(WDF_INTERRUPT_CONFIG)) { 281 // 282 // Init new fields to default values. 283 // 284 WDF_INTERRUPT_CONFIG_INIT(&intConfig, 285 Configuration->EvtInterruptIsr, 286 Configuration->EvtInterruptDpc); 287 // 288 // Copy over existing fields and readjust the struct size. 289 // 290 RtlCopyMemory(&intConfig, Configuration, Configuration->Size); 291 intConfig.Size = sizeof(intConfig); 292 293 // 294 // Use new config structure from now on. 295 // 296 Configuration = &intConfig; 297 } 298 299 // 300 // Parameter validation. 301 // 302 303 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 304 // 305 // Ensure access to interrupts is allowed 306 // 307 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), 308 CHECK(ERROR_STRING_HW_ACCESS_NOT_ALLOWED, 309 (pDevice->IsInterruptAccessAllowed() == TRUE)), 310 DriverGlobals->DriverName); 311 312 // 313 // PassiveHandling member must be set to TRUE. INIT macro does that for 314 // UMDF. This check ensures the field is not overriden by caller. 315 // 316 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), 317 CHECK("PassiveHandling not set to TRUE in WDF_INTERRUPT_CONFIG structure", 318 (Configuration->PassiveHandling == TRUE)), 319 DriverGlobals->DriverName); 320 #endif 321 322 if (Configuration->EvtInterruptIsr == NULL) { 323 DoTraceLevelMessage( 324 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 325 "NULL EvtInterruptIsr in WDF_INTERRUPT_CONFIG structure 0x%p" 326 " passed", Configuration); 327 return STATUS_INVALID_PARAMETER; 328 } 329 330 // 331 // Driver can specify a parent only in the AutomaticSerialization case. 332 // 333 status = FxValidateObjectAttributes( 334 pFxDriverGlobals, 335 Attributes, 336 Configuration->AutomaticSerialization ? 337 FX_VALIDATE_OPTION_NONE_SPECIFIED : 338 FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); 339 if (!NT_SUCCESS(status)) { 340 return status; 341 } 342 343 if (Attributes != NULL && Attributes->ParentObject != NULL) { 344 FxObjectHandleGetPtr(pFxDriverGlobals, 345 Attributes->ParentObject, 346 FX_TYPE_OBJECT, 347 (PVOID*)&pParent); 348 } 349 else { 350 pParent = (FxObject*)pDevice; 351 } 352 353 devicePnpState = pDevice->GetDevicePnpState(); 354 355 if (devicePnpState != WdfDevStatePnpInit && 356 0x0 == (pDevice->GetCallbackFlags() & 357 FXDEVICE_CALLBACK_IN_PREPARE_HARDWARE)) { 358 359 status = STATUS_INVALID_DEVICE_STATE; 360 361 DoTraceLevelMessage( 362 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 363 "WDFINTERRUPTs can only be created during: " 364 "(1) EvtDriverDeviceAdd when the WDFDEVICE %p is initially created, or " 365 "(2) EvtDevicePrepareHardware, %!STATUS!", Device, status); 366 367 return status; 368 } 369 370 // 371 // Interrupts created in EvtDriverDeviceAdd must not specify any 372 // CM resources b/c driver doesn't known them yet. 373 // 374 if (devicePnpState == WdfDevStatePnpInit) { 375 376 if (Configuration->InterruptRaw != NULL || 377 Configuration->InterruptTranslated != NULL) { 378 379 status = STATUS_INVALID_PARAMETER; 380 381 DoTraceLevelMessage( 382 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 383 "Not NULL InterruptRaw or InterruptTranslated in " 384 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", 385 Configuration, status); 386 387 return status; 388 } 389 390 // 391 // Wake Interrupts can not be created in AddDevice as it is 392 // not known if they are actually marked as wake capable 393 // 394 if (Configuration->CanWakeDevice) { 395 status = STATUS_INVALID_PARAMETER; 396 397 DoTraceLevelMessage( 398 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 399 "CanWakeDevice set in WDF_INTERRUPT_CONFIG structure 0x%p" 400 "during EvtDriverDeviceAdd, %!STATUS!", 401 Configuration, status); 402 403 return status; 404 } 405 } 406 407 // 408 // Checks for interrupt created in EvtDevicePrepareHardware. 409 // 410 if (devicePnpState != WdfDevStatePnpInit) { 411 // 412 // CM resources must be specified. 413 // 414 if (Configuration->InterruptRaw == NULL || 415 Configuration->InterruptTranslated == NULL) { 416 417 status = STATUS_INVALID_DEVICE_STATE; 418 419 DoTraceLevelMessage( 420 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 421 "NULL InterruptRaw or InterruptTranslated in " 422 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", 423 Configuration, status); 424 425 return status; 426 } 427 428 // 429 // Share vector must be default. 430 // 431 if (Configuration->ShareVector != WdfUseDefault) { 432 status = STATUS_INVALID_DEVICE_STATE; 433 434 DoTraceLevelMessage( 435 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 436 "Driver cannot specify ShareVector different from " 437 "WdfUseDefault in EvtDevicePrepareHardware callback," 438 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", 439 Configuration, status); 440 441 return status; 442 } 443 444 } 445 446 if (Configuration->CanWakeDevice) { 447 if (FxInterrupt::_IsWakeHintedInterrupt( 448 Configuration->InterruptTranslated->Flags) == FALSE) { 449 450 status = STATUS_INVALID_PARAMETER; 451 DoTraceLevelMessage( 452 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 453 "Driver cannot specify an interrupt as CanWakeDevice if " 454 "the CM_RESOURCE_INTERRUPT_WAKE_HINT is not present." 455 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", 456 Configuration, status); 457 458 return status; 459 } 460 461 // 462 // Driver is allowed to create wake interrupt only if it 463 // is the power policy owner so that the we can wake the 464 // stack when the interrupt fires 465 // 466 if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) { 467 status = STATUS_INVALID_PARAMETER; 468 DoTraceLevelMessage( 469 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 470 "Driver cannot specify an interrupt as CanWakeDevice if " 471 "it is not power policy powner. WDF_INTERRUPT_CONFIG " 472 "structure 0x%p passed, %!STATUS!", 473 Configuration, status); 474 475 return status; 476 } 477 478 // 479 // Declaring an interrupt as wake capable allows it to 480 // take ownership of interrupt from ACPI. It does not 481 // make sense for a PDO 482 // 483 if (pDevice->IsPdo()) { 484 status = STATUS_INVALID_PARAMETER; 485 DoTraceLevelMessage( 486 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 487 "Driver cannot specify an interrupt as CanWakeDevice for a PDO " 488 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", 489 Configuration, status); 490 491 return status; 492 } 493 } 494 495 if (Configuration->EvtInterruptDpc != NULL && 496 Configuration->EvtInterruptWorkItem != NULL) { 497 status = STATUS_INVALID_PARAMETER; 498 DoTraceLevelMessage( 499 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 500 "Driver can provide either EvtInterruptDpc or " 501 "EvtInterruptWorkItem callback but not both. " 502 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", 503 Configuration, status); 504 505 return status; 506 } 507 508 if (Configuration->PassiveHandling == FALSE) { 509 // 510 // DIRQL handling validations. 511 // 512 if (Configuration->WaitLock) { 513 status = STATUS_INVALID_PARAMETER; 514 DoTraceLevelMessage( 515 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 516 "Driver cannot specify WaitLock when handling interrupts at " 517 "DIRQL, WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", 518 Configuration, status); 519 520 return status; 521 } 522 // 523 // Wake interrupts should be passive level so that the stack 524 // can be sychronously bring the device back to D0 form within 525 // the ISR 526 // 527 if (Configuration->CanWakeDevice) { 528 status = STATUS_INVALID_PARAMETER; 529 530 DoTraceLevelMessage( 531 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 532 "CanWakeDevice set in WDF_INTERRUPT_CONFIG structure for an" 533 "interrupt not marked as passive 0x%p, %!STATUS!", 534 Configuration, status); 535 536 return status; 537 } 538 } 539 else { 540 // 541 // Passive-level handling validations. 542 // 543 if (FxIsPassiveLevelInterruptSupported() == FALSE) { 544 status = STATUS_NOT_SUPPORTED; 545 DoTraceLevelMessage( 546 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 547 "The current version of Windows does not support the handling " 548 "of interrupts at passive-level, WDF_INTERRUPT_CONFIG " 549 "structure 0x%p passed, %!STATUS!", Configuration, status); 550 551 return status; 552 } 553 554 if (Configuration->SpinLock) { 555 status = STATUS_INVALID_PARAMETER; 556 DoTraceLevelMessage( 557 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 558 "Driver cannot specify SpinLock when handling interrupts at " 559 "passive-level, WDF_INTERRUPT_CONFIG structure 0x%p passed, " 560 "%!STATUS!", Configuration, status); 561 562 return status; 563 } 564 565 566 // 567 // For UMDF reflector decides whether to handle the interrupt 568 // at passive or DIRQL. Driver has no choice. Therefore this check 569 // is applicable only for KMDF. 570 // 571 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 572 if (Configuration->InterruptTranslated != NULL && 573 FxInterrupt::_IsMessageInterrupt( 574 Configuration->InterruptTranslated->Flags)) { 575 status = STATUS_INVALID_PARAMETER; 576 DoTraceLevelMessage( 577 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 578 "Driver cannot specify PassiveHandling for MSI interrupts, " 579 "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", 580 Configuration, status); 581 582 return status; 583 } 584 #endif 585 } 586 587 // 588 // Make sure the specified resources are valid. 589 // Do this check only under verifier b/c if the driver has a lot of 590 // interrupts/resources, this verification can slow down power up. 591 // Note that if InterruptRaw is != NULL, it implies that 592 // InterruptTranslated is != NULL from the checks above. 593 // 594 if (pFxDriverGlobals->FxVerifierOn) { 595 if (Configuration->InterruptRaw != NULL ) { 596 status = pDevice->m_PkgPnp->ValidateInterruptResourceCm( 597 Configuration->InterruptRaw, 598 Configuration->InterruptTranslated, 599 Configuration); 600 if (!NT_SUCCESS(status)) { 601 return status; 602 } 603 } 604 } 605 606 status = FxInterrupt::_CreateAndInit( 607 pFxDriverGlobals, 608 pDevice, 609 pParent, 610 Attributes, 611 Configuration, 612 &pFxInterrupt); 613 614 if (NT_SUCCESS(status)) { 615 *Interrupt = (WDFINTERRUPT) pFxInterrupt->GetObjectHandle(); 616 } 617 618 return status; 619 } 620 621 BOOLEAN 622 STDCALL 623 WDFEXPORT(WdfInterruptQueueDpcForIsr)( 624 __in 625 PWDF_DRIVER_GLOBALS DriverGlobals, 626 __in 627 WDFINTERRUPT Interrupt 628 ) 629 630 /*++ 631 632 Routine Description: 633 634 Queue the DPC for the ISR 635 636 Arguments: 637 638 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 639 640 Returns: 641 642 TRUE - If the DPC has been enqueued. 643 644 FALSE - If the DPC has already been enqueued. 645 646 --*/ 647 648 { 649 DDI_ENTRY(); 650 651 FxInterrupt* pFxInterrupt; 652 653 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 654 Interrupt, 655 FX_TYPE_INTERRUPT, 656 (PVOID*)&pFxInterrupt); 657 658 return pFxInterrupt->QueueDeferredRoutineForIsr(); 659 } 660 661 BOOLEAN 662 STDCALL 663 WDFEXPORT(WdfInterruptQueueWorkItemForIsr)( 664 __in 665 PWDF_DRIVER_GLOBALS DriverGlobals, 666 __in 667 WDFINTERRUPT Interrupt 668 ) 669 670 /*++ 671 672 Routine Description: 673 674 Queue the interrupt's work-item for the ISR. 675 676 Arguments: 677 678 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 679 680 Returns: 681 682 TRUE - If the work-item has been enqueued. 683 684 FALSE - If the work-item has already been enqueued. 685 686 687 --*/ 688 689 { 690 DDI_ENTRY(); 691 692 FxInterrupt* pFxInterrupt; 693 694 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 695 Interrupt, 696 FX_TYPE_INTERRUPT, 697 (PVOID*)&pFxInterrupt); 698 699 return pFxInterrupt->QueueWorkItemForIsr(); 700 } 701 702 __drv_maxIRQL(DISPATCH_LEVEL) 703 BOOLEAN 704 STDCALL 705 WDFEXPORT(WdfInterruptSynchronize)( 706 __in 707 PWDF_DRIVER_GLOBALS DriverGlobals, 708 __in 709 WDFINTERRUPT Interrupt, 710 __in 711 PFN_WDF_INTERRUPT_SYNCHRONIZE Callback, 712 __in 713 WDFCONTEXT Context 714 ) 715 716 /*++ 717 718 Routine Description: 719 720 Synchronize execution with the interrupt handler 721 722 Arguments: 723 724 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 725 726 Callback - PWDF_INTERRUPT_SYNCHRONIZE callback function to invoke 727 728 Context - Context to pass to the PFN_WDF_INTERRUPT_SYNCHRONIZE callback 729 730 Returns: 731 732 BOOLEAN result from user PFN_WDF_INTERRUPT_SYNCHRONIZE callback 733 734 --*/ 735 736 { 737 DDI_ENTRY(); 738 739 FxInterrupt* pFxInterrupt; 740 NTSTATUS status; 741 742 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 743 Interrupt, 744 FX_TYPE_INTERRUPT, 745 (PVOID*)&pFxInterrupt); 746 747 if (pFxInterrupt->IsPassiveHandling()) { 748 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), 749 PASSIVE_LEVEL); 750 if (!NT_SUCCESS(status)) { 751 return FALSE; 752 } 753 } 754 755 FxPointerNotNull(pFxInterrupt->GetDriverGlobals(), Callback); 756 757 return pFxInterrupt->Synchronize(Callback, Context); 758 } 759 760 __drv_maxIRQL(DISPATCH_LEVEL) 761 VOID 762 STDCALL 763 WDFEXPORT(WdfInterruptAcquireLock)( 764 __in 765 PWDF_DRIVER_GLOBALS DriverGlobals, 766 __in 767 _Requires_lock_not_held_(_Curr_) 768 _Acquires_lock_(_Curr_) 769 WDFINTERRUPT Interrupt 770 ) 771 772 /*++ 773 774 Routine Description: 775 776 Begin synchronization to the interrupts IRQL level 777 778 Arguments: 779 780 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 781 782 Returns: 783 784 --*/ 785 786 { 787 DDI_ENTRY(); 788 789 FxInterrupt* pFxInterrupt; 790 NTSTATUS status; 791 792 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 793 Interrupt, 794 FX_TYPE_INTERRUPT, 795 (PVOID*)&pFxInterrupt); 796 797 if (pFxInterrupt->IsPassiveHandling()) { 798 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), 799 PASSIVE_LEVEL); 800 if (!NT_SUCCESS(status)) { 801 return; 802 } 803 } 804 805 pFxInterrupt->AcquireLock(); 806 } 807 808 __drv_maxIRQL(DISPATCH_LEVEL + 1) 809 VOID 810 STDCALL 811 WDFEXPORT(WdfInterruptReleaseLock)( 812 __in 813 PWDF_DRIVER_GLOBALS DriverGlobals, 814 __in 815 _Requires_lock_held_(_Curr_) 816 _Releases_lock_(_Curr_) 817 WDFINTERRUPT Interrupt 818 ) 819 820 /*++ 821 822 Routine Description: 823 824 End synchronization to the interrupts IRQL level 825 826 Arguments: 827 828 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 829 830 Returns: 831 832 --*/ 833 834 { 835 DDI_ENTRY(); 836 837 FxInterrupt* pFxInterrupt; 838 NTSTATUS status; 839 840 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 841 Interrupt, 842 FX_TYPE_INTERRUPT, 843 (PVOID*)&pFxInterrupt); 844 845 if (pFxInterrupt->IsPassiveHandling()) { 846 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), 847 PASSIVE_LEVEL); 848 if (!NT_SUCCESS(status)) { 849 return; 850 } 851 } 852 853 pFxInterrupt->ReleaseLock(); 854 } 855 856 __drv_maxIRQL(PASSIVE_LEVEL) 857 VOID 858 STDCALL 859 WDFEXPORT(WdfInterruptEnable)( 860 __in 861 PWDF_DRIVER_GLOBALS DriverGlobals, 862 __in 863 WDFINTERRUPT Interrupt 864 ) 865 866 /*++ 867 868 Routine Description: 869 870 Request that the interrupt be enabled in the hardware. 871 872 Arguments: 873 874 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 875 876 Returns: 877 878 --*/ 879 880 { 881 DDI_ENTRY(); 882 883 FxInterrupt* pFxInterrupt; 884 NTSTATUS status; 885 886 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 887 Interrupt, 888 FX_TYPE_INTERRUPT, 889 (PVOID*)&pFxInterrupt); 890 891 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), 892 PASSIVE_LEVEL); 893 if (!NT_SUCCESS(status)) { 894 return; 895 } 896 897 // 898 // Okay to ignore error status. Called function prints error messages. 899 // 900 (VOID) pFxInterrupt->ForceReconnect(); 901 } 902 903 __drv_maxIRQL(PASSIVE_LEVEL) 904 VOID 905 STDCALL 906 WDFEXPORT(WdfInterruptDisable)( 907 __in 908 PWDF_DRIVER_GLOBALS DriverGlobals, 909 __in 910 WDFINTERRUPT Interrupt 911 ) 912 913 /*++ 914 915 Routine Description: 916 917 Request that the interrupt be disabled in the hardware. 918 919 Arguments: 920 921 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 922 923 Returns: 924 925 --*/ 926 927 { 928 DDI_ENTRY(); 929 930 FxInterrupt* pFxInterrupt; 931 NTSTATUS status; 932 933 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 934 Interrupt, 935 FX_TYPE_INTERRUPT, 936 (PVOID*)&pFxInterrupt); 937 938 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), 939 PASSIVE_LEVEL); 940 if (!NT_SUCCESS(status)) { 941 return; 942 } 943 944 // 945 // Okay to ignore error status. Called function prints error messages. 946 // 947 (VOID) pFxInterrupt->ForceDisconnect(); 948 } 949 950 _Must_inspect_result_ 951 struct _KINTERRUPT* 952 STDCALL 953 WDFEXPORT(WdfInterruptWdmGetInterrupt)( 954 __in 955 PWDF_DRIVER_GLOBALS DriverGlobals, 956 __in 957 WDFINTERRUPT Interrupt 958 ) 959 960 /*++ 961 962 Routine Description: 963 964 Return the WDM _KINTERRUPT* 965 966 Arguments: 967 968 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 969 970 Returns: 971 972 --*/ 973 974 { 975 DDI_ENTRY(); 976 977 FxInterrupt* pFxInterrupt; 978 979 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 980 Interrupt, 981 FX_TYPE_INTERRUPT, 982 (PVOID*)&pFxInterrupt); 983 984 return pFxInterrupt->GetInterruptPtr(); 985 } 986 987 __drv_maxIRQL(DISPATCH_LEVEL) 988 VOID 989 STDCALL 990 WDFEXPORT(WdfInterruptGetInfo)( 991 __in 992 PWDF_DRIVER_GLOBALS DriverGlobals, 993 __in 994 WDFINTERRUPT Interrupt, 995 __out 996 PWDF_INTERRUPT_INFO Info 997 ) 998 999 /*++ 1000 1001 Routine Description: 1002 1003 Return the WDF_INTERRUPT_INFO that describes this 1004 particular Message Signaled Interrupt MessageID. 1005 1006 Arguments: 1007 1008 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 1009 1010 Returns: 1011 Nothing 1012 1013 --*/ 1014 { 1015 DDI_ENTRY(); 1016 1017 PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL; 1018 FxInterrupt* pFxInterrupt = NULL; 1019 ULONG size = 0; 1020 1021 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1022 Interrupt, 1023 FX_TYPE_INTERRUPT, 1024 (PVOID*)&pFxInterrupt, 1025 &pFxDriverGlobals); 1026 1027 FxPointerNotNull(pFxDriverGlobals, Info); 1028 1029 if (sizeof(WDF_INTERRUPT_INFO_V1_7) == Info->Size) { 1030 size = sizeof(WDF_INTERRUPT_INFO_V1_7); 1031 } 1032 else if (sizeof(WDF_INTERRUPT_INFO) == Info->Size) { 1033 size = sizeof(WDF_INTERRUPT_INFO); 1034 } 1035 else { 1036 DoTraceLevelMessage( 1037 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1038 "WDF_INTERRUPT_INFO %p Size %d invalid, expected %d", 1039 Interrupt, Info->Size, sizeof(WDF_INTERRUPT_INFO)); 1040 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1041 return; 1042 } 1043 1044 RtlCopyMemory(Info, pFxInterrupt->GetInfo(), size); 1045 1046 Info->Size = size; 1047 } 1048 1049 WDFDEVICE 1050 STDCALL 1051 WDFEXPORT(WdfInterruptGetDevice)( 1052 __in 1053 PWDF_DRIVER_GLOBALS DriverGlobals, 1054 __in 1055 WDFINTERRUPT Interrupt 1056 ) 1057 1058 /*++ 1059 1060 Routine Description: 1061 1062 Get the device that the interrupt is related to. 1063 1064 Arguments: 1065 1066 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 1067 1068 Returns: 1069 1070 WDFDEVICE 1071 1072 --*/ 1073 1074 { 1075 DDI_ENTRY(); 1076 1077 FxInterrupt* pFxInterrupt; 1078 1079 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 1080 Interrupt, 1081 FX_TYPE_INTERRUPT, 1082 (PVOID*)&pFxInterrupt); 1083 1084 return pFxInterrupt->GetDevice()->GetHandle(); 1085 } 1086 1087 __drv_maxIRQL(DISPATCH_LEVEL) 1088 VOID 1089 STDCALL 1090 WDFEXPORT(WdfInterruptSetPolicy)( 1091 __in 1092 PWDF_DRIVER_GLOBALS DriverGlobals, 1093 __in 1094 WDFINTERRUPT Interrupt, 1095 __in 1096 WDF_INTERRUPT_POLICY Policy, 1097 __in 1098 WDF_INTERRUPT_PRIORITY Priority, 1099 __in 1100 KAFFINITY TargetProcessorSet 1101 ) 1102 1103 /*++ 1104 1105 Routine Description: 1106 1107 Interrupts have attributes that a driver might want to influence. This 1108 routine tells the Framework to tell the PnP manager what the driver would 1109 prefer. 1110 1111 Arguments: 1112 1113 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 1114 1115 Returns: 1116 1117 NTSTATUS 1118 1119 --*/ 1120 1121 { 1122 DDI_ENTRY(); 1123 1124 PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL; 1125 FxInterrupt* pFxInterrupt = NULL; 1126 GROUP_AFFINITY processorSet; 1127 1128 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1129 Interrupt, 1130 FX_TYPE_INTERRUPT, 1131 (PVOID*)&pFxInterrupt, 1132 &pFxDriverGlobals); 1133 1134 if (Policy < WdfIrqPolicyMachineDefault || 1135 Policy > WdfIrqPolicySpreadMessagesAcrossAllProcessors) { 1136 DoTraceLevelMessage( 1137 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1138 "Policy %d is out of range", Policy); 1139 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1140 return; 1141 } 1142 1143 if (Priority < WdfIrqPriorityLow || Priority > WdfIrqPriorityHigh) { 1144 DoTraceLevelMessage( 1145 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1146 "Priority %d is out of range", Priority); 1147 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1148 return; 1149 } 1150 1151 RtlZeroMemory(&processorSet, sizeof(processorSet)); 1152 processorSet.Mask = TargetProcessorSet; 1153 1154 pFxInterrupt->SetPolicy(Policy, Priority, &processorSet); 1155 } 1156 1157 __drv_maxIRQL(DISPATCH_LEVEL) 1158 VOID 1159 STDCALL 1160 WDFEXPORT(WdfInterruptSetExtendedPolicy)( 1161 __in 1162 PWDF_DRIVER_GLOBALS DriverGlobals, 1163 __in 1164 WDFINTERRUPT Interrupt, 1165 __in 1166 PWDF_INTERRUPT_EXTENDED_POLICY PolicyAndGroup 1167 ) 1168 1169 /*++ 1170 1171 Routine Description: 1172 1173 Interrupts have attributes that a driver might want to influence. This 1174 routine tells the Framework to tell the PnP manager what the driver would 1175 prefer. 1176 1177 Arguments: 1178 1179 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 1180 1181 PolicyAndGroup - Driver preference for policy, priority and group affinity. 1182 1183 Returns: 1184 1185 NTSTATUS 1186 1187 --*/ 1188 1189 { 1190 DDI_ENTRY(); 1191 1192 PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL; 1193 FxInterrupt* pFxInterrupt = NULL; 1194 PGROUP_AFFINITY processorSet = NULL; 1195 WDF_INTERRUPT_POLICY policy; 1196 WDF_INTERRUPT_PRIORITY priority; 1197 1198 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1199 Interrupt, 1200 FX_TYPE_INTERRUPT, 1201 (PVOID*)&pFxInterrupt, 1202 &pFxDriverGlobals); 1203 1204 if (PolicyAndGroup->Size != sizeof(WDF_INTERRUPT_EXTENDED_POLICY)) { 1205 DoTraceLevelMessage( 1206 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1207 "WDF_INTERRUPT_EXTENDED_POLICY %p Size %d invalid, expected %d", 1208 PolicyAndGroup, 1209 PolicyAndGroup->Size, 1210 sizeof(WDF_INTERRUPT_EXTENDED_POLICY)); 1211 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1212 return; 1213 } 1214 1215 policy = PolicyAndGroup->Policy; 1216 priority = PolicyAndGroup->Priority; 1217 processorSet = &PolicyAndGroup->TargetProcessorSetAndGroup; 1218 1219 if (policy < WdfIrqPolicyMachineDefault || 1220 policy > WdfIrqPolicySpreadMessagesAcrossAllProcessors) { 1221 DoTraceLevelMessage( 1222 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1223 "Policy %d is out of range", policy); 1224 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1225 return; 1226 } 1227 1228 if (priority < WdfIrqPriorityLow || priority > WdfIrqPriorityHigh) { 1229 DoTraceLevelMessage( 1230 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1231 "Priority %d is out of range", priority); 1232 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1233 return; 1234 } 1235 1236 if (processorSet->Reserved[0] != 0 || processorSet->Reserved[1] != 0 || 1237 processorSet->Reserved[2] != 0) { 1238 DoTraceLevelMessage( 1239 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1240 "TargetProcessorSet's reserved fields are not zero"); 1241 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1242 return; 1243 } 1244 1245 pFxInterrupt->SetPolicy(policy, priority, processorSet); 1246 } 1247 1248 _Must_inspect_result_ 1249 _IRQL_requires_max_(PASSIVE_LEVEL) 1250 _Post_satisfies_(return == 1 || return == 0) 1251 BOOLEAN 1252 STDCALL 1253 WDFEXPORT(WdfInterruptTryToAcquireLock)( 1254 __in 1255 PWDF_DRIVER_GLOBALS DriverGlobals, 1256 __in 1257 _Requires_lock_not_held_(_Curr_) 1258 _When_(return!=0, _Acquires_lock_(_Curr_)) 1259 WDFINTERRUPT Interrupt 1260 ) 1261 1262 /*++ 1263 1264 Routine Description: 1265 1266 Try to acquire the interrupt's passive-lock. 1267 1268 Arguments: 1269 1270 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 1271 1272 Returns: 1273 1274 TRUE: function was able to successfully acquire the lock. 1275 1276 FALSE: function was unable to acquire the lock. 1277 1278 --*/ 1279 1280 { 1281 DDI_ENTRY(); 1282 1283 FxInterrupt* pFxInterrupt; 1284 NTSTATUS status; 1285 1286 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 1287 Interrupt, 1288 FX_TYPE_INTERRUPT, 1289 (PVOID*)&pFxInterrupt); 1290 1291 if (pFxInterrupt->GetDriverGlobals()->FxVerifierOn) { 1292 if (pFxInterrupt->IsPassiveHandling() == FALSE) { 1293 DoTraceLevelMessage( 1294 pFxInterrupt->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1295 "WDFINTERRUPT %p is handled at DIRQL. This API is not " 1296 "available for DIQRL interrupt handling.", 1297 Interrupt); 1298 FxVerifierDbgBreakPoint(pFxInterrupt->GetDriverGlobals()); 1299 return FALSE; 1300 } 1301 1302 status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), 1303 PASSIVE_LEVEL); 1304 if (!NT_SUCCESS(status)) { 1305 return FALSE; 1306 } 1307 } 1308 1309 return pFxInterrupt->TryToAcquireLock(); 1310 } 1311 1312 __drv_maxIRQL(DISPATCH_LEVEL) 1313 VOID 1314 STDCALL 1315 WDFEXPORT(WdfInterruptReportActive)( 1316 _In_ 1317 PWDF_DRIVER_GLOBALS DriverGlobals, 1318 _In_ 1319 WDFINTERRUPT Interrupt 1320 ) 1321 1322 /*++ 1323 1324 Routine Description: 1325 1326 This DDI informs the system that the interrupt is active and expecting 1327 interrupt requests on the associated lines. This is typically called after 1328 having reported the lines as inactive via WdfInterruptReportInactive. 1329 The DDI doesn't do anything if this DDI is called before 1330 WdfInterruptReportInactive while the interrupt is connected. 1331 1332 Arguments: 1333 1334 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 1335 1336 Returns: 1337 1338 VOID 1339 1340 --*/ 1341 { 1342 DDI_ENTRY(); 1343 1344 PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL; 1345 FxInterrupt* pFxInterrupt = NULL; 1346 1347 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1348 Interrupt, 1349 FX_TYPE_INTERRUPT, 1350 (PVOID*)&pFxInterrupt, 1351 &pFxDriverGlobals); 1352 1353 pFxInterrupt->ReportActive(); 1354 1355 return; 1356 } 1357 1358 __drv_maxIRQL(DISPATCH_LEVEL) 1359 VOID 1360 STDCALL 1361 WDFEXPORT(WdfInterruptReportInactive)( 1362 _In_ 1363 PWDF_DRIVER_GLOBALS DriverGlobals, 1364 _In_ 1365 WDFINTERRUPT Interrupt 1366 ) 1367 1368 /*++ 1369 1370 Routine Description: 1371 1372 This DDI informs the system that the the interrupt is no longer active 1373 and is not expecting interrupt requests on the associated lines. 1374 1375 Arguments: 1376 1377 Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. 1378 1379 Returns: 1380 1381 VOID 1382 1383 --*/ 1384 { 1385 DDI_ENTRY(); 1386 1387 PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL; 1388 FxInterrupt* pFxInterrupt = NULL; 1389 1390 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1391 Interrupt, 1392 FX_TYPE_INTERRUPT, 1393 (PVOID*)&pFxInterrupt, 1394 &pFxDriverGlobals); 1395 1396 pFxInterrupt->ReportInactive(); 1397 1398 return; 1399 } 1400 1401 } // extern "C" 1402