Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

960 lines
24 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. interupt.c
  5. Abstract:
  6. This module contains the interupt handler for the ACPI driver
  7. Author:
  8. Stephane Plante (splante)
  9. Environment:
  10. NT Kernel Model Driver only
  11. --*/
  12. #include "pch.h"
  13. //
  14. // From shared\acpiinit.c
  15. // We need to know certain information about the system, such as how
  16. // many GPE bits are present
  17. //
  18. extern PACPIInformation AcpiInformation;
  19. //
  20. // Ignore the first interrupt because some machines are busted
  21. //
  22. BOOLEAN FirstInterrupt = TRUE;
  23. //
  24. // This is the variable that indicates wether or not the DPC is running
  25. //
  26. BOOLEAN AcpiGpeDpcRunning;
  27. //
  28. // This is the variable that indicates wether or not we have requested that
  29. // the DPC be running...
  30. //
  31. BOOLEAN AcpiGpeDpcScheduled;
  32. //
  33. // This is the variable that indicates wether or not the DPC has completed
  34. // real work
  35. //
  36. BOOLEAN AcpiGpeWorkDone;
  37. //
  38. // This is the timer that we use to schedule the DPC...
  39. //
  40. KTIMER AcpiGpeTimer;
  41. //
  42. // This is the DPC routine that we use to process the GPEs...
  43. //
  44. KDPC AcpiGpeDpc;
  45. VOID
  46. ACPIInterruptDispatchEvents(
  47. )
  48. /*++
  49. Routine Description:
  50. Function reads and dispatches GPE events.
  51. N.B. This function is not re-entrant. Caller disables & enables
  52. gpes with ACPIGpeEnableDisableEvents().
  53. Arguments:
  54. None
  55. Return Value:
  56. None
  57. --*/
  58. {
  59. NTSTATUS status;
  60. UCHAR edg;
  61. UCHAR sts;
  62. ULONG gpeRegister;
  63. ULONG gpeSize;
  64. //
  65. // Remember the size of the GPE registers and that we need a spinlock to
  66. // touch the tables
  67. //
  68. gpeSize = AcpiInformation->GpeSize;
  69. KeAcquireSpinLockAtDpcLevel (&GpeTableLock);
  70. //
  71. // Pre-handler processing. Read status bits and clear their enables.
  72. // Eoi any edge firing gpe before gpe handler is invoked
  73. //
  74. for (gpeRegister = 0; gpeRegister < gpeSize; gpeRegister++) {
  75. //
  76. // Read the list of currently trigged method from the hardware
  77. //
  78. sts = ACPIReadGpeStatusRegister(gpeRegister) & GpeCurEnable[gpeRegister];
  79. //
  80. // Remember which sts bits need processed
  81. //
  82. GpePending[gpeRegister] |= sts;
  83. GpeRunMethod[gpeRegister] |= sts;
  84. //
  85. // Clear gpe enables for the events we are handling
  86. //
  87. GpeCurEnable[gpeRegister] &= ~sts;
  88. //
  89. // We will need to clear the Edge triggered interrupts, so remember
  90. // which ones are those
  91. //
  92. edg = sts & ~GpeIsLevel[gpeRegister];
  93. //
  94. // Eoi edge gpe sts bits
  95. //
  96. if (edg) {
  97. ACPIWriteGpeStatusRegister(gpeRegister, edg);
  98. }
  99. }
  100. //
  101. // Tell the DPC that we have work to do
  102. //
  103. AcpiGpeWorkDone = TRUE;
  104. //
  105. // If the DPC isn't running, then schedule it
  106. //
  107. if (!AcpiGpeDpcRunning && !AcpiGpeDpcScheduled) {
  108. AcpiGpeDpcScheduled = TRUE;
  109. KeInsertQueueDpc( &AcpiGpeDpc, 0, 0);
  110. }
  111. //
  112. // Done with GPE spinlock
  113. //
  114. KeReleaseSpinLockFromDpcLevel(&GpeTableLock);
  115. }
  116. VOID
  117. ACPIInterruptDispatchEventDpc(
  118. IN PKDPC Dpc,
  119. IN PVOID DpcContext,
  120. IN PVOID SystemArgument1,
  121. IN PVOID SystemArgument2
  122. )
  123. /*++
  124. Routine Description:
  125. This is the DPC engine responsible for running all GPE based events. It
  126. looks at the outstanding events and executes methods as is appropriate
  127. Arguments:
  128. None used
  129. Return Value:
  130. Void
  131. --*/
  132. {
  133. static CHAR methodName[] = "\\_GPE._L00";
  134. ASYNC_GPE_CONTEXT asyncGpeEval;
  135. NTSTATUS status;
  136. PGPE_VECTOR_OBJECT gpeVectorObject;
  137. PNSOBJ pnsobj;
  138. UCHAR cmp;
  139. UCHAR gpeSTS[MAX_GPE_BUFFER_SIZE];
  140. UCHAR gpeLVL[MAX_GPE_BUFFER_SIZE];
  141. UCHAR gpeCMP[MAX_GPE_BUFFER_SIZE];
  142. UCHAR gpeWAK[MAX_GPE_BUFFER_SIZE];
  143. UCHAR lvl;
  144. UCHAR sts;
  145. ULONG bitmask;
  146. ULONG bitno;
  147. ULONG gpeIndex;
  148. ULONG gpeRegister;
  149. ULONG gpeSize;
  150. ULONG i;
  151. UNREFERENCED_PARAMETER( Dpc );
  152. UNREFERENCED_PARAMETER( DpcContext );
  153. UNREFERENCED_PARAMETER( SystemArgument1 );
  154. UNREFERENCED_PARAMETER( SystemArgument2 );
  155. //
  156. // Remember how many gpe bytes we have
  157. //
  158. gpeSize = AcpiInformation->GpeSize;
  159. //
  160. // First step is to acquire the DPC lock
  161. //
  162. KeAcquireSpinLockAtDpcLevel( &GpeTableLock );
  163. //
  164. // Remember that the DPC is no longer scheduled...
  165. //
  166. AcpiGpeDpcScheduled = FALSE;
  167. //
  168. // check to see if another DPC is already running
  169. if (AcpiGpeDpcRunning) {
  170. //
  171. // The DPC is already running, so we need to exit now
  172. //
  173. KeReleaseSpinLockFromDpcLevel( &GpeTableLock );
  174. return;
  175. }
  176. //
  177. // Remember that the DPC is now running
  178. //
  179. AcpiGpeDpcRunning = TRUE;
  180. //
  181. // Make sure that we know that we haven't completed anything
  182. //
  183. RtlZeroMemory( gpeCMP, MAX_GPE_BUFFER_SIZE );
  184. //
  185. // We must try to do *some* work
  186. //
  187. do {
  188. //
  189. // Assume that we haven't done any work
  190. //
  191. AcpiGpeWorkDone = FALSE;
  192. //
  193. // Pre-handler processing. Build up the list of GPEs that we are
  194. // going to run on this iteration of the loop
  195. //
  196. for (gpeRegister = 0; gpeRegister < gpeSize; gpeRegister++) {
  197. //
  198. // We have stored away the list of methods that need to be run
  199. //
  200. sts = GpeRunMethod[gpeRegister];
  201. //
  202. // Make sure that we don't run those methods again, unless
  203. // someone asks us too
  204. //
  205. GpeRunMethod[gpeRegister] = 0;
  206. //
  207. // Remember which of those methods are level trigged
  208. //
  209. lvl = GpeIsLevel[gpeRegister];
  210. //
  211. // Remember which sts bits need processed
  212. //
  213. gpeSTS[gpeRegister] = sts;
  214. gpeLVL[gpeRegister] = lvl;
  215. //
  216. // Update the list of bits that have been completed
  217. //
  218. gpeCMP[gpeRegister] |= GpeComplete[gpeRegister];
  219. GpeComplete[gpeRegister] = 0;
  220. }
  221. //
  222. // We want to remember which GPEs are currently armed for Wakeup
  223. // because we have a race condition if we check for GpeWakeEnable()
  224. // after we drop the lock
  225. //
  226. RtlCopyMemory( gpeWAK, GpeWakeEnable, gpeSize );
  227. //
  228. // At this point, we must release the lock
  229. //
  230. KeReleaseSpinLockFromDpcLevel( &GpeTableLock );
  231. //
  232. // Issue gpe handler for each set gpe
  233. //
  234. for (gpeRegister = 0; gpeRegister < gpeSize; gpeRegister++) {
  235. sts = gpeSTS[gpeRegister];
  236. lvl = gpeLVL[gpeRegister];
  237. cmp = 0;
  238. while (sts) {
  239. //
  240. // Determine which bits are set within the current index
  241. //
  242. bitno = FirstSetLeftBit[sts];
  243. bitmask = 1 << bitno;
  244. sts &= ~bitmask;
  245. gpeIndex = ACPIGpeRegisterToGpeIndex (gpeRegister, bitno);
  246. //
  247. // Do we have a method to run here?
  248. //
  249. if (GpeHandlerType[gpeRegister] & bitmask) {
  250. //
  251. // Run the control method for this gpe
  252. //
  253. methodName[7] = (lvl & bitmask) ? 'L' : 'E';
  254. methodName[8] = HexDigit[gpeIndex >> 4];
  255. methodName[9] = HexDigit[gpeIndex & 0x0f];
  256. status = AMLIGetNameSpaceObject(
  257. methodName,
  258. NULL,
  259. &pnsobj,
  260. 0
  261. );
  262. //
  263. // Setup the evaluation context. Note that we cheat
  264. // and instead of allocating a structure, we use the
  265. // pointer to hold the information (since the info is
  266. // so small)
  267. //
  268. asyncGpeEval.GpeRegister = (UCHAR) gpeRegister;
  269. asyncGpeEval.StsBit = (UCHAR) bitmask;
  270. asyncGpeEval.Lvl = lvl;
  271. //
  272. // Did we find a control method to execute?
  273. //
  274. if (!NT_SUCCESS(status)) {
  275. //
  276. // The GPE is not meaningful to us. Simply disable it -
  277. // which is a nop since it's already been removed
  278. // from the GpeCurEnables.
  279. //
  280. continue;
  281. }
  282. status = AMLIAsyncEvalObject (
  283. pnsobj,
  284. NULL,
  285. 0,
  286. NULL,
  287. (PFNACB) ACPIInterruptEventCompletion,
  288. (PVOID)ULongToPtr(asyncGpeEval.AsULONG)
  289. );
  290. //
  291. // If the evalution has completed re-enable the gpe; otherwise,
  292. // wait for the async completion routine to do it
  293. //
  294. if (NT_SUCCESS(status)) {
  295. if (status != STATUS_PENDING) {
  296. cmp |= bitmask;
  297. }
  298. } else {
  299. LONGLONG dueTime;
  300. //
  301. // We need to modify the table lock
  302. //
  303. KeAcquireSpinLockAtDpcLevel(&GpeTableLock);
  304. //
  305. // Remember that we have to run this method again
  306. //
  307. GpeRunMethod[gpeRegister] |= bitmask;
  308. //
  309. // Have we already scheduled the DPC?
  310. //
  311. if (!AcpiGpeDpcScheduled) {
  312. //
  313. // Remember that we have schedule the DPC...
  314. //
  315. AcpiGpeDpcScheduled = TRUE;
  316. //
  317. // We want approximately a 2 second delay in this case
  318. //
  319. dueTime = -2 * 1000* 1000 * 10;
  320. //
  321. // This is unconditional --- it will fire in 2 seconds
  322. //
  323. KeSetTimer(
  324. &AcpiGpeTimer,
  325. *(PLARGE_INTEGER) &dueTime,
  326. &AcpiGpeDpc
  327. );
  328. }
  329. //
  330. // Done with the lock
  331. //
  332. KeReleaseSpinLockFromDpcLevel(&GpeTableLock);
  333. }
  334. } else if (gpeWAK[gpeRegister] & bitmask) {
  335. //
  336. // Vector is used for exlucive wake signalling
  337. //
  338. OSNotifyDeviceWakeByGPEEvent(gpeIndex, gpeRegister, bitmask);
  339. //
  340. // Processing of this gpe complete
  341. //
  342. cmp |= bitmask;
  343. } else {
  344. //
  345. // Notify the target device driver
  346. //
  347. i = GpeMap[ACPIGpeIndexToByteIndex (gpeIndex)];
  348. if (i < GpeVectorTableSize) {
  349. gpeVectorObject = GpeVectorTable[i].GpeVectorObject;
  350. if (gpeVectorObject) {
  351. //
  352. // Call the target driver
  353. //
  354. gpeVectorObject->Handler(
  355. gpeVectorObject,
  356. gpeVectorObject->Context
  357. );
  358. } else {
  359. ACPIPrint( (
  360. ACPI_PRINT_CRITICAL,
  361. "ACPIInterruptDispatchEvents: No Handler for Gpe: 0x%x\n",
  362. gpeIndex
  363. ) );
  364. ACPIBreakPoint();
  365. }
  366. //
  367. // Processing of this gpe complete
  368. //
  369. cmp |= bitmask;
  370. }
  371. }
  372. }
  373. //
  374. // Remember what GPEs have been completed
  375. //
  376. gpeCMP[gpeRegister] |= cmp;
  377. }
  378. //
  379. // Synchronize accesses to the ACPI tables
  380. //
  381. KeAcquireSpinLockAtDpcLevel (&GpeTableLock);
  382. } while ( AcpiGpeWorkDone );
  383. //
  384. // Post-handler processing. EOI any completed lvl firing gpe and re-enable
  385. // any completed gpe event
  386. //
  387. for (gpeRegister = 0; gpeRegister < gpeSize; gpeRegister++) {
  388. cmp = gpeCMP[gpeRegister];
  389. lvl = gpeLVL[gpeRegister] & cmp;
  390. //
  391. // EOI any completed level gpes
  392. //
  393. if (lvl) {
  394. ACPIWriteGpeStatusRegister(gpeRegister, lvl);
  395. }
  396. //
  397. // Calculate which functions it is we have to re-enable
  398. //
  399. ACPIGpeUpdateCurrentEnable(
  400. gpeRegister,
  401. cmp
  402. );
  403. }
  404. //
  405. // Remember that we have exited the DPC...
  406. //
  407. AcpiGpeDpcRunning = FALSE;
  408. //
  409. // Before we exist, we should re-enable the GPEs...
  410. //
  411. ACPIGpeEnableDisableEvents( TRUE );
  412. //
  413. // Done with the table lock
  414. //
  415. KeReleaseSpinLockFromDpcLevel (&GpeTableLock);
  416. }
  417. VOID
  418. EXPORT
  419. ACPIInterruptEventCompletion (
  420. IN PNSOBJ AcpiObject,
  421. IN NTSTATUS Status,
  422. IN POBJDATA Result OPTIONAL,
  423. IN PVOID Context
  424. )
  425. /*++
  426. Routine Description:
  427. This function is called when the interpreter has finished executing a
  428. GPE. The routine updates some book-keeping and restarts the DPC engine
  429. to handle these things
  430. Arguments:
  431. AcpiObject - The method that was run
  432. Status - Whether or not the method succeeded
  433. Result - Not used
  434. Context - Specifies the information required to figure what GPE
  435. we executed
  436. Return Value:
  437. None
  438. --*/
  439. {
  440. ASYNC_GPE_CONTEXT gpeContext;
  441. KIRQL oldIrql;
  442. LONGLONG dueTime;
  443. ULONG gpeRegister;
  444. //
  445. // We store the context information as part of the pointer. Convert it
  446. // back to a ULONG so that it is useful to us
  447. //
  448. gpeContext.AsULONG = PtrToUlong(Context);
  449. gpeContext.Lvl &= gpeContext.StsBit;
  450. gpeRegister = gpeContext.GpeRegister;
  451. //
  452. // Need to synchronize access to these values
  453. //
  454. KeAcquireSpinLock (&GpeTableLock, &oldIrql);
  455. //
  456. // We have a different policy if the method failed then if it succeeded
  457. //
  458. if (!NT_SUCCESS(Status)) {
  459. //
  460. // In the failure case, we need to cause to method to run again
  461. //
  462. GpeRunMethod[gpeRegister] |= gpeContext.StsBit;
  463. //
  464. // Did we already schedule the DPC?
  465. //
  466. if (!AcpiGpeDpcScheduled) {
  467. //
  468. // Remember that we have schedule the DPC...
  469. //
  470. AcpiGpeDpcScheduled = TRUE;
  471. //
  472. // We want approximately a 2 second delay in this case
  473. //
  474. dueTime = -2 * 1000 * 1000 * 10;
  475. //
  476. // This is unconditional --- it will fire in 2 seconds
  477. //
  478. KeSetTimer(
  479. &AcpiGpeTimer,
  480. *(PLARGE_INTEGER) &dueTime,
  481. &AcpiGpeDpc
  482. );
  483. }
  484. } else {
  485. //
  486. // Remember that we did some work
  487. //
  488. AcpiGpeWorkDone = TRUE;
  489. //
  490. // Remember that this GPE is now complete
  491. //
  492. GpeComplete[gpeRegister] |= gpeContext.StsBit;
  493. //
  494. // If the DPC isn't already running, schedule it...
  495. //
  496. if (!AcpiGpeDpcRunning) {
  497. KeInsertQueueDpc( &AcpiGpeDpc, 0, 0);
  498. }
  499. }
  500. //
  501. // Done with the table lock
  502. //
  503. KeReleaseSpinLock (&GpeTableLock, oldIrql);
  504. }
  505. BOOLEAN
  506. ACPIInterruptServiceRoutine(
  507. IN PKINTERRUPT Interrupt,
  508. IN PVOID Context
  509. )
  510. /*++
  511. Routine Description:
  512. The interrupt handler for the ACPI driver
  513. Arguments:
  514. Interrupt - Interrupt Object
  515. Context - Pointer to the device object which interrupt is associated with
  516. Return Value:
  517. TRUE - It was our interrupt
  518. FALSE - Not our interrupt
  519. --*/
  520. {
  521. PDEVICE_EXTENSION deviceExtension;
  522. ULONG IntStatus;
  523. ULONG BitsHandled;
  524. ULONG PrevStatus;
  525. ULONG i;
  526. BOOLEAN Handled;
  527. //
  528. // No need to look at the interrupt object
  529. //
  530. UNREFERENCED_PARAMETER( Interrupt );
  531. //
  532. // Setup ---
  533. //
  534. deviceExtension = (PDEVICE_EXTENSION) Context;
  535. Handled = FALSE;
  536. //
  537. // Determine source of interrupt
  538. //
  539. IntStatus = ACPIIoReadPm1Status();
  540. //
  541. // Unfortently due to a piix4 errata we need to check the GPEs because
  542. // a piix4 sometimes forgets to raise an SCI on an asserted GPE
  543. //
  544. if (ACPIGpeIsEvent()) {
  545. IntStatus |= PM1_GPE_PENDING;
  546. }
  547. //
  548. // Nasty hack --- if we don't have any bits to handle at this point,
  549. // that probably means that someone changed the GPE Enable register
  550. // behind our back. The way that we can correct this problem is by
  551. // forcing a check of the GPEs...
  552. //
  553. if (!IntStatus) {
  554. IntStatus |= PM1_GPE_PENDING;
  555. }
  556. //
  557. // Are any status bits set for events which are handled at ISR time?
  558. //
  559. BitsHandled = IntStatus & (PM1_TMR_STS | PM1_BM_STS);
  560. if (BitsHandled) {
  561. //
  562. // Clear their status bits then handle them
  563. // (Note no special handling is required for PM1_BM_STS)
  564. //
  565. ACPIIoClearPm1Status ((USHORT) BitsHandled);
  566. //
  567. // If the overflow bit is set handle it
  568. //
  569. if (IntStatus & PM1_TMR_STS) {
  570. HalAcpiTimerInterrupt();
  571. }
  572. IntStatus &= ~BitsHandled;
  573. }
  574. //
  575. // If more service bits are pending, they are for the DPC function
  576. //
  577. if (IntStatus) {
  578. //
  579. // If no new status bits, then make sure we check for GPEs
  580. //
  581. if (!(IntStatus & (~deviceExtension->Fdo.Pm1Status))) {
  582. IntStatus |= PM1_GPE_PENDING;
  583. }
  584. //
  585. // If we're going to process outstanding GPEs, disable them
  586. // for DPC processing
  587. //
  588. if (IntStatus & PM1_GPE_PENDING) {
  589. ACPIGpeEnableDisableEvents( FALSE );
  590. }
  591. //
  592. // Clear the status bits we've handled
  593. //
  594. ACPIIoClearPm1Status ((USHORT) IntStatus);
  595. //
  596. // Set status bits for DPC routine to process
  597. //
  598. IntStatus |= PM1_DPC_IN_PROGRESS;
  599. PrevStatus = deviceExtension->Fdo.Pm1Status;
  600. do {
  601. i = PrevStatus;
  602. PrevStatus = InterlockedCompareExchange(
  603. &deviceExtension->Fdo.Pm1Status,
  604. (i | IntStatus),
  605. i
  606. );
  607. } while (i != PrevStatus);
  608. //
  609. // Compute which bits are new for the DPC to process
  610. //
  611. BitsHandled |= IntStatus & ~PrevStatus;
  612. //
  613. // If one of the new bits is "dpc in progress", we had better queue a dpc
  614. //
  615. if (BitsHandled & PM1_DPC_IN_PROGRESS) {
  616. KeInsertQueueDpc(&deviceExtension->Fdo.InterruptDpc, NULL, NULL);
  617. }
  618. }
  619. //
  620. // Done
  621. //
  622. return BitsHandled ? TRUE : FALSE;
  623. }
  624. VOID
  625. ACPIInterruptServiceRoutineDPC(
  626. IN PKDPC Dpc,
  627. IN PVOID Context,
  628. IN PVOID Arg1,
  629. IN PVOID Arg2
  630. )
  631. /*++
  632. Routine Description:
  633. This routine is called by the ISR. This is done so that our code is
  634. executing at DPC level, and not DIRQL
  635. Arguments:
  636. Dpc - Pointer to the DPC object
  637. Context - Pointer to the Device Object
  638. Arg1 - Not Used
  639. Arg2 - Not Used
  640. --*/
  641. {
  642. PDEVICE_EXTENSION deviceExtension;
  643. ULONG IntStatus;
  644. ULONG NewStatus;
  645. ULONG PrevStatus;
  646. ULONG BitsHandled;
  647. ULONG FixedButtonEvent;
  648. deviceExtension = (PDEVICE_EXTENSION) Context;
  649. UNREFERENCED_PARAMETER( Arg1 );
  650. UNREFERENCED_PARAMETER( Arg2 );
  651. //
  652. // Loop while there's work
  653. //
  654. BitsHandled = 0;
  655. IntStatus = 0;
  656. for (; ;) {
  657. //
  658. // Get the status bits form the ISR. If there are no more
  659. // status bits then exit
  660. //
  661. PrevStatus = deviceExtension->Fdo.Pm1Status;
  662. do {
  663. IntStatus = PrevStatus;
  664. //
  665. // If there's no work pending, try to complete DPC
  666. //
  667. NewStatus = PM1_DPC_IN_PROGRESS;
  668. if (!(IntStatus & ~PM1_DPC_IN_PROGRESS)) {
  669. //
  670. // Note: The original code, after this call, would go
  671. // out and check to see if we handeld any GPE Events.
  672. // If we, did, then we would call ACPIGpeEnableDisableEvents
  673. // in this context.
  674. //
  675. // The unfortunate problem with that approach is that it
  676. // is makes us more suspectible to gpe storms. The reason
  677. // is that there isn't a guarantee that GPE DPC has been
  678. // triggered. So, at the price of increasing the latency
  679. // in re-enabling events, we moved the re-enabling of
  680. // GPEs ad the end of the GPE DPC
  681. //
  682. // Before we complete, reenable events
  683. //
  684. ACPIEnablePMInterruptOnly();
  685. NewStatus = 0;
  686. BitsHandled = 0;
  687. }
  688. PrevStatus = InterlockedCompareExchange (
  689. &deviceExtension->Fdo.Pm1Status,
  690. NewStatus,
  691. IntStatus
  692. );
  693. } while (IntStatus != PrevStatus);
  694. //
  695. // If NewStatus cleared DPC_IN_PROGRESS, then we're done
  696. //
  697. if (!NewStatus) {
  698. break;
  699. }
  700. //
  701. // Track if GPE ever handled
  702. //
  703. BitsHandled |= IntStatus;
  704. //
  705. // Handle fixed power & sleep button events
  706. //
  707. FixedButtonEvent = 0;
  708. if (IntStatus & PM1_PWRBTN_STS) {
  709. FixedButtonEvent |= SYS_BUTTON_POWER;
  710. }
  711. if (IntStatus & PM1_SLEEPBTN_STS) {
  712. FixedButtonEvent |= SYS_BUTTON_SLEEP;
  713. }
  714. if (FixedButtonEvent) {
  715. if (IntStatus & PM1_WAK_STS) {
  716. FixedButtonEvent = SYS_BUTTON_WAKE;
  717. }
  718. ACPIButtonEvent (FixedButtonDeviceObject, FixedButtonEvent, NULL);
  719. }
  720. //
  721. // PM1_GBL_STS is set whenever the BIOS has released the global
  722. // lock (and we are waiting for it). Notify the global lock handler.
  723. //
  724. if (IntStatus & PM1_GBL_STS) {
  725. ACPIHardwareGlobalLockReleased();
  726. }
  727. //
  728. // Handle GP Registers
  729. //
  730. if (IntStatus & PM1_GPE_PENDING) {
  731. ACPIInterruptDispatchEvents();
  732. }
  733. }
  734. }