Source code of Windows XP (NT5)
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.

1869 lines
43 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. wake.c
  5. Abstract:
  6. Handles wake code for the entire ACPI subsystem
  7. Author:
  8. splante (splante)
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. 06-18-97: Initial Revision
  13. 11-24-97: Rewrite
  14. --*/
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #define INITGUID
  18. #include <initguid.h>
  19. #include <pciintrf.h>
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(PAGE,ACPIWakeEnableDisableSync)
  22. #endif
  23. //
  24. // This request is used by the synchronous mechanism when it calls the
  25. // asynchronous one
  26. //
  27. typedef struct _ACPI_WAKE_PSW_SYNC_CONTEXT {
  28. KEVENT Event;
  29. NTSTATUS Status;
  30. } ACPI_WAKE_PSW_SYNC_CONTEXT, *PACPI_WAKE_PSW_SYNC_CONTEXT;
  31. //
  32. // This is a lookaside list of contexts
  33. //
  34. NPAGED_LOOKASIDE_LIST PswContextLookAsideList;
  35. //
  36. // Pointer to the PCI PME interface, which we will need (maybe)
  37. //
  38. PPCI_PME_INTERFACE PciPmeInterface;
  39. //
  40. // Have we loaded the PCI PME Interface?
  41. //
  42. BOOLEAN PciPmeInterfaceInstantiated;
  43. //
  44. // We need to access this piece of data here
  45. //
  46. extern PACPIInformation AcpiInformation;
  47. VOID
  48. ACPIWakeCompleteRequestQueue(
  49. IN PLIST_ENTRY RequestList,
  50. IN NTSTATUS Status
  51. )
  52. /*++
  53. Routine Description:
  54. This routine takes a LIST_ENTRY of requests to be completed and completes
  55. all of them. This is to minimize code duplication.
  56. Arguments:
  57. RequestList - List Entry to process
  58. Status - Status to complete the requests with
  59. Return Value:
  60. None
  61. --*/
  62. {
  63. PLIST_ENTRY listEntry;
  64. PACPI_POWER_REQUEST powerRequest;
  65. //
  66. // walk the list
  67. //
  68. listEntry = RequestList->Flink;
  69. while (listEntry != RequestList) {
  70. //
  71. // Crack the request
  72. //
  73. powerRequest = CONTAINING_RECORD(
  74. listEntry,
  75. ACPI_POWER_REQUEST,
  76. ListEntry
  77. );
  78. listEntry = listEntry->Flink;
  79. //
  80. // Complete this power request
  81. //
  82. ACPIDevPrint( (
  83. ACPI_PRINT_WAKE,
  84. powerRequest->DeviceExtension,
  85. "ACPIWakeCompleteRequestQueue - Completing 0x%08lx - %08lx\n",
  86. powerRequest,
  87. Status
  88. ) );
  89. powerRequest->Status = Status;
  90. ACPIDeviceIrpWaitWakeRequestComplete( powerRequest );
  91. }
  92. }
  93. NTSTATUS
  94. ACPIWakeDisableAsync(
  95. IN PDEVICE_EXTENSION DeviceExtension,
  96. IN PLIST_ENTRY RequestList,
  97. IN PFNACB CallBack,
  98. IN PVOID Context
  99. )
  100. /*++
  101. Routine Description:
  102. This routine decrements the number of outstanding wake events on the
  103. supplied DeviceExtension by the number of items in the request list.
  104. If the reference goes to 0, then we run _PSW(Off) to disable wake support
  105. on the device
  106. Arguments:
  107. DeviceExtension - Device for which we to deference the wake count
  108. RequestList - The list of requests, for which the ref count will
  109. be decreased
  110. CallBack - Function to call when we are done
  111. Context - Argument to the function
  112. Return Value:
  113. NTSTATUS
  114. --*/
  115. {
  116. BOOLEAN runPsw = FALSE;
  117. KIRQL oldIrql;
  118. NTSTATUS status = STATUS_SUCCESS;
  119. OBJDATA pswData;
  120. PACPI_WAKE_PSW_CONTEXT pswContext;
  121. PLIST_ENTRY listEntry = RequestList->Flink;
  122. PNSOBJ pswObject = NULL;
  123. ULONG count = 0;
  124. //
  125. // Walk the list, counting the number of items within it
  126. //
  127. while (listEntry != RequestList) {
  128. count++;
  129. listEntry = listEntry->Flink;
  130. }
  131. //
  132. // Grab the spinlock
  133. //
  134. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  135. //
  136. // Let the world know what happened
  137. //
  138. ACPIDevPrint( (
  139. ACPI_PRINT_WAKE,
  140. DeviceExtension,
  141. "ACPIWakeDisableAsync - ReferenceCount: %lx - %lx = %lx\n",
  142. DeviceExtension->PowerInfo.WakeSupportCount,
  143. count,
  144. (DeviceExtension->PowerInfo.WakeSupportCount - count)
  145. ) );
  146. //
  147. // Update the number of references on the device
  148. //
  149. ASSERT( DeviceExtension->PowerInfo.WakeSupportCount <= count );
  150. DeviceExtension->PowerInfo.WakeSupportCount -= count;
  151. //
  152. // Grab the pswObject
  153. //
  154. pswObject = DeviceExtension->PowerInfo.PowerObject[PowerDeviceUnspecified];
  155. if (pswObject == NULL) {
  156. goto ACPIWakeDisableAsyncExit;
  157. }
  158. //
  159. // Are there no references left on the device?
  160. //
  161. if (DeviceExtension->PowerInfo.WakeSupportCount != 0) {
  162. //
  163. // If we own the PME pin for this device, then make sure that
  164. // we clear the status pin and keep the PME signal enabled
  165. //
  166. if (DeviceExtension->Flags & DEV_PROP_HAS_PME ) {
  167. ACPIWakeEnableDisablePciDevice(
  168. DeviceExtension,
  169. TRUE
  170. );
  171. }
  172. goto ACPIWakeDisableAsyncExit;
  173. }
  174. //
  175. // Allocate the _PSW context that we need to signify that there is
  176. // a pending _PSW on this device
  177. //
  178. pswContext = ExAllocateFromNPagedLookasideList(
  179. &PswContextLookAsideList
  180. );
  181. if (pswContext == NULL) {
  182. status = STATUS_INSUFFICIENT_RESOURCES;
  183. goto ACPIWakeDisableAsyncExit;
  184. }
  185. //
  186. // Initialize the context
  187. //
  188. pswContext->Enable = FALSE;
  189. pswContext->CallBack = CallBack;
  190. pswContext->Context = Context;
  191. pswContext->DeviceExtension = DeviceExtension;
  192. pswContext->Count = count;
  193. //
  194. // Check to see if we are simply going to queue the context up, or
  195. // call the interpreter
  196. //
  197. if (IsListEmpty( &(DeviceExtension->PowerInfo.WakeSupportList) ) ) {
  198. runPsw = TRUE;
  199. }
  200. //
  201. // List is non-empty, so we just queue up the context
  202. //
  203. InsertTailList(
  204. &(DeviceExtension->PowerInfo.WakeSupportList),
  205. &(pswContext->ListEntry)
  206. );
  207. //
  208. // Release the lock
  209. //
  210. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  211. //
  212. // Should we run the method?
  213. //
  214. if (runPsw) {
  215. //
  216. // If we own the PCI PME pin for this device, the make sure to clear the
  217. // status and disable it --- we enable the PME pin after we have
  218. // turned on the _PSW, and we disable the PME pin before we turn off
  219. // the _PSW
  220. //
  221. if ( (DeviceExtension->Flags & DEV_PROP_HAS_PME)) {
  222. ACPIWakeEnableDisablePciDevice(
  223. DeviceExtension,
  224. FALSE
  225. );
  226. }
  227. //
  228. // Initialize the arguments
  229. //
  230. RtlZeroMemory( &pswData, sizeof(OBJDATA) );
  231. pswData.dwDataType = OBJTYPE_INTDATA;
  232. pswData.uipDataValue = 0;
  233. //
  234. // Run the control method
  235. //
  236. status = AMLIAsyncEvalObject(
  237. pswObject,
  238. NULL,
  239. 1,
  240. &pswData,
  241. ACPIWakeEnableDisableAsyncCallBack,
  242. pswContext
  243. );
  244. //
  245. // What Happened
  246. //
  247. ACPIDevPrint( (
  248. ACPI_PRINT_WAKE,
  249. DeviceExtension,
  250. "ACPIWakeDisableAsync = 0x%08lx (P)\n",
  251. status
  252. ) );
  253. if (status != STATUS_PENDING) {
  254. ACPIWakeEnableDisableAsyncCallBack(
  255. pswObject,
  256. status,
  257. NULL,
  258. pswContext
  259. );
  260. }
  261. return STATUS_PENDING;
  262. } else {
  263. ACPIDevPrint( (
  264. ACPI_PRINT_WAKE,
  265. DeviceExtension,
  266. "ACPIWakeEnableDisableAsync = 0x%08lx (Q)\n",
  267. STATUS_PENDING
  268. ) );
  269. //
  270. // we queued the request up, so we must return pending
  271. //
  272. return STATUS_PENDING;
  273. }
  274. ACPIWakeDisableAsyncExit:
  275. //
  276. // Release the lock
  277. //
  278. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  279. //
  280. // What happened
  281. //
  282. ACPIDevPrint( (
  283. ACPI_PRINT_WAKE,
  284. DeviceExtension,
  285. "ACPIWakeDisableAsync = 0x%08lx\n",
  286. status
  287. ) );
  288. //
  289. // Call the specified callback ourselves
  290. //
  291. (*CallBack)(
  292. pswObject,
  293. status,
  294. NULL,
  295. Context
  296. );
  297. return STATUS_PENDING;
  298. }
  299. NTSTATUS
  300. ACPIWakeEmptyRequestQueue(
  301. IN PDEVICE_EXTENSION DeviceExtension
  302. )
  303. /*++
  304. Routine Description:
  305. This routine looks at the current list of Wake Request irps and
  306. completes the ones that are waiting on the specified device
  307. Note: this code assumes that if we clear the irps out but we don't
  308. run _PSW(O), that nothing bad will happen if that GPE fires
  309. Arguments:
  310. DeviceExtension - Device for which we want no wake requests
  311. Return Value:
  312. None
  313. --*/
  314. {
  315. KIRQL oldIrql;
  316. LIST_ENTRY powerList;
  317. //
  318. // We will store the list of matching requests onto this list, so we
  319. // must initialize it
  320. //
  321. InitializeListHead( &powerList );
  322. //
  323. // We need to hold both the Cancel and the Power lock while we remove
  324. // things from the PowerQueue list
  325. //
  326. IoAcquireCancelSpinLock( &oldIrql );
  327. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  328. ACPIWakeRemoveDevicesAndUpdate( DeviceExtension, &powerList );
  329. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  330. IoReleaseCancelSpinLock( oldIrql );
  331. //
  332. // Complete the requests
  333. //
  334. ACPIWakeCompleteRequestQueue( &powerList, STATUS_NO_SUCH_DEVICE );
  335. //
  336. // Done
  337. //
  338. return STATUS_SUCCESS;
  339. }
  340. NTSTATUS
  341. ACPIWakeEnableDisableAsync(
  342. IN PDEVICE_EXTENSION DeviceExtension,
  343. IN BOOLEAN Enable,
  344. IN PFNACB CallBack,
  345. IN PVOID Context
  346. )
  347. /*++
  348. Routine Description:
  349. Given a Device Extension, updates the count of outstanding PSW on the
  350. device. If there is a 0-1 transition, then we must run _PSW(1). If there
  351. is a 1-0 transition, then we must run _PSW(0)
  352. NB: The CallBack will always be invoked
  353. Arguments:
  354. DeviceExtension - Object to look at
  355. Enable - Increment or Decrement
  356. CallBack - Function to run after running _PSW()
  357. Context - Argument to pass to _PSW
  358. Return Value:
  359. Status
  360. --*/
  361. {
  362. BOOLEAN runPsw = FALSE;
  363. KIRQL oldIrql;
  364. OBJDATA pswData;
  365. NTSTATUS status = STATUS_SUCCESS;
  366. PACPI_WAKE_PSW_CONTEXT pswContext;
  367. PNSOBJ pswObject = NULL;
  368. //
  369. // Acquire the Spinlock
  370. //
  371. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  372. //
  373. // Update the number of references on the device
  374. //
  375. if (Enable) {
  376. DeviceExtension->PowerInfo.WakeSupportCount++;
  377. ACPIDevPrint( (
  378. ACPI_PRINT_WAKE,
  379. DeviceExtension,
  380. "ACPIWakeEnableDisableAsync - Count: %d (+)\n",
  381. DeviceExtension->PowerInfo.WakeSupportCount
  382. ) );
  383. //
  384. // Did we transition to one wake?
  385. //
  386. if (DeviceExtension->PowerInfo.WakeSupportCount != 1) {
  387. //
  388. // If we own the PME pin for this device, then make sure that
  389. // we clear the status pin and keep the PME signal enabled
  390. //
  391. if (DeviceExtension->Flags & DEV_PROP_HAS_PME ) {
  392. ACPIWakeEnableDisablePciDevice(
  393. DeviceExtension,
  394. TRUE
  395. );
  396. }
  397. goto ACPIWakeEnableDisableAsyncExit;
  398. }
  399. } else {
  400. ASSERT( DeviceExtension->PowerInfo.WakeSupportCount );
  401. DeviceExtension->PowerInfo.WakeSupportCount--;
  402. ACPIDevPrint( (
  403. ACPI_PRINT_WAKE,
  404. DeviceExtension,
  405. "ACPIWakeEnableDisableAsync - Count: %d (-)\n",
  406. DeviceExtension->PowerInfo.WakeSupportCount
  407. ) );
  408. //
  409. // Did we transition to zero wake?
  410. //
  411. if (DeviceExtension->PowerInfo.WakeSupportCount != 0) {
  412. //
  413. // If we own the PME pin for this device, then make sure that
  414. // we clear the status pin and keep the PME signal enabled
  415. //
  416. if (DeviceExtension->Flags & DEV_PROP_HAS_PME ) {
  417. ACPIWakeEnableDisablePciDevice(
  418. DeviceExtension,
  419. TRUE
  420. );
  421. }
  422. goto ACPIWakeEnableDisableAsyncExit;
  423. }
  424. }
  425. //
  426. // Grab the pswObject
  427. //
  428. pswObject = DeviceExtension->PowerInfo.PowerObject[PowerDeviceUnspecified];
  429. if (pswObject == NULL) {
  430. //
  431. // If we got here, that means that there isn't a _PSW to be run and
  432. // that we should make sure that if we own the PME pin, that we should
  433. // set it.
  434. //
  435. if (DeviceExtension->Flags & DEV_PROP_HAS_PME) {
  436. ACPIWakeEnableDisablePciDevice(
  437. DeviceExtension,
  438. TRUE
  439. );
  440. }
  441. goto ACPIWakeEnableDisableAsyncExit;
  442. }
  443. //
  444. // Allocate the _PSW context that we need to signify that there is
  445. // a pending _PSW on this device
  446. //
  447. pswContext = ExAllocateFromNPagedLookasideList(
  448. &PswContextLookAsideList
  449. );
  450. if (pswContext == NULL) {
  451. status = STATUS_INSUFFICIENT_RESOURCES;
  452. goto ACPIWakeEnableDisableAsyncExit;
  453. }
  454. //
  455. // Initialize the context
  456. //
  457. pswContext->Enable = Enable;
  458. pswContext->CallBack = CallBack;
  459. pswContext->Context = Context;
  460. pswContext->DeviceExtension = DeviceExtension;
  461. pswContext->Count = 1;
  462. //
  463. // Check to see if we are simply going to queue the context up, or
  464. // call the interpreter
  465. //
  466. if (IsListEmpty( &(DeviceExtension->PowerInfo.WakeSupportList) ) ) {
  467. runPsw = TRUE;
  468. }
  469. //
  470. // List is non-empty, so we just queue up the context
  471. //
  472. InsertTailList(
  473. &(DeviceExtension->PowerInfo.WakeSupportList),
  474. &(pswContext->ListEntry)
  475. );
  476. //
  477. // Release the lock
  478. //
  479. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  480. //
  481. // Should we run the method?
  482. //
  483. if (runPsw) {
  484. //
  485. // If we own the PCI PME pin for this device, the make sure to clear the
  486. // status and disable it --- we enable the PME pin after we have
  487. // turned on the _PSW, and we disable the PME pin before we turn off
  488. // the _PSW
  489. //
  490. if ( (DeviceExtension->Flags & DEV_PROP_HAS_PME) &&
  491. pswContext->Enable == FALSE) {
  492. ACPIWakeEnableDisablePciDevice(
  493. DeviceExtension,
  494. FALSE
  495. );
  496. }
  497. //
  498. // Initialize the arguments
  499. //
  500. RtlZeroMemory( &pswData, sizeof(OBJDATA) );
  501. pswData.dwDataType = OBJTYPE_INTDATA;
  502. pswData.uipDataValue = (Enable ? 1 : 0);
  503. //
  504. // Run the control method
  505. //
  506. status = AMLIAsyncEvalObject(
  507. pswObject,
  508. NULL,
  509. 1,
  510. &pswData,
  511. ACPIWakeEnableDisableAsyncCallBack,
  512. pswContext
  513. );
  514. //
  515. // What Happened
  516. //
  517. ACPIDevPrint( (
  518. ACPI_PRINT_WAKE,
  519. DeviceExtension,
  520. "ACPIWakeEnableDisableAsync = 0x%08lx (P)\n",
  521. status
  522. ) );
  523. if (status != STATUS_PENDING) {
  524. ACPIWakeEnableDisableAsyncCallBack(
  525. pswObject,
  526. status,
  527. NULL,
  528. pswContext
  529. );
  530. }
  531. return STATUS_PENDING;
  532. } else {
  533. ACPIDevPrint( (
  534. ACPI_PRINT_WAKE,
  535. DeviceExtension,
  536. "ACPIWakeEnableDisableAsync = 0x%08lx (Q)\n",
  537. STATUS_PENDING
  538. ) );
  539. //
  540. // we queued the request up, so we must return pending
  541. //
  542. return STATUS_PENDING;
  543. }
  544. ACPIWakeEnableDisableAsyncExit:
  545. //
  546. // Release the lock
  547. //
  548. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  549. //
  550. // What happened
  551. //
  552. ACPIDevPrint( (
  553. ACPI_PRINT_WAKE,
  554. DeviceExtension,
  555. "ACPIWakeEnableDisableAsync = 0x%08lx\n",
  556. status
  557. ) );
  558. //
  559. // Call the specified callback ourselves
  560. //
  561. (*CallBack)(
  562. pswObject,
  563. status,
  564. NULL,
  565. Context
  566. );
  567. return STATUS_PENDING;
  568. }
  569. VOID
  570. EXPORT
  571. ACPIWakeEnableDisableAsyncCallBack(
  572. IN PNSOBJ AcpiObject,
  573. IN NTSTATUS Status,
  574. IN POBJDATA ObjData,
  575. IN PVOID Context
  576. )
  577. /*++
  578. Routine Description:
  579. This routine is called after a _PSW method has been run on a device.
  580. This routine is responsible for seeing if there are any more delayed
  581. _PSW requests on the same device, and if so, run them.
  582. Arguments:
  583. AcpiObject - The method object that was run
  584. Status - The result of the eval
  585. ObjData - Not used
  586. Context - PACPI_WAKE_PSW_CONTEXT
  587. Return value:
  588. VOID
  589. --*/
  590. {
  591. BOOLEAN runPsw = FALSE;
  592. KIRQL oldIrql;
  593. PACPI_WAKE_PSW_CONTEXT pswContext = (PACPI_WAKE_PSW_CONTEXT) Context;
  594. PACPI_WAKE_PSW_CONTEXT nextContext;
  595. PDEVICE_EXTENSION deviceExtension = pswContext->DeviceExtension;
  596. ACPIDevPrint( (
  597. ACPI_PRINT_WAKE,
  598. deviceExtension,
  599. "ACPIWakeEnableDisableAsyncCallBack = %08lx (C)\n",
  600. Status
  601. ) );
  602. //
  603. // Acquire the spinlock
  604. //
  605. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  606. //
  607. // Remove the specified entry from the list
  608. //
  609. RemoveEntryList( &(pswContext->ListEntry) );
  610. //
  611. // If we failed the request, then we don't really know the status of the
  612. // _PSW on the device. Lets assume that it doesn't change and undo
  613. // whatever change we did to get here
  614. //
  615. if (!NT_SUCCESS(Status)) {
  616. ACPIDevPrint( (
  617. ACPI_PRINT_WAKE,
  618. deviceExtension,
  619. "ACPIWakeEnableDisableAsyncCallBack - RefCount: %lx %s %lx = %lx\n",
  620. deviceExtension->PowerInfo.WakeSupportCount,
  621. (pswContext->Enable ? "-" : "+"),
  622. pswContext->Count,
  623. (pswContext->Enable ? deviceExtension->PowerInfo.WakeSupportCount -
  624. pswContext->Count : deviceExtension->PowerInfo.WakeSupportCount +
  625. pswContext->Count)
  626. ) );
  627. if (pswContext->Enable) {
  628. deviceExtension->PowerInfo.WakeSupportCount -= pswContext->Count;
  629. } else {
  630. deviceExtension->PowerInfo.WakeSupportCount += pswContext->Count;
  631. }
  632. }
  633. //
  634. // If we own the PCI PME pin for this device, the make sure to clear the
  635. // status and either enable it --- we enable the PME pin after we have
  636. // turned on the _PSW, and we disable the PME pin before we turn off
  637. // the _PSW
  638. //
  639. if ( (deviceExtension->Flags & DEV_PROP_HAS_PME) &&
  640. pswContext->Enable == TRUE) {
  641. ACPIWakeEnableDisablePciDevice(
  642. deviceExtension,
  643. pswContext->Enable
  644. );
  645. }
  646. //
  647. // Are the any items on the list?
  648. //
  649. if (!IsListEmpty( &(deviceExtension->PowerInfo.WakeSupportList) ) ) {
  650. runPsw = TRUE;
  651. nextContext = CONTAINING_RECORD(
  652. deviceExtension->PowerInfo.WakeSupportList.Flink,
  653. ACPI_WAKE_PSW_CONTEXT,
  654. ListEntry
  655. );
  656. }
  657. //
  658. // We can release the lock now
  659. //
  660. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  661. //
  662. // Call the callback on the completed item
  663. //
  664. (*pswContext->CallBack)(
  665. AcpiObject,
  666. Status,
  667. ObjData,
  668. (pswContext->Context)
  669. );
  670. //
  671. // Free the completed context
  672. //
  673. ExFreeToNPagedLookasideList(
  674. &PswContextLookAsideList,
  675. pswContext
  676. );
  677. //
  678. // Do we have to run a method?
  679. //
  680. if (runPsw) {
  681. NTSTATUS status;
  682. OBJDATA pswData;
  683. RtlZeroMemory( &pswData, sizeof(OBJDATA) );
  684. pswData.dwDataType = OBJTYPE_INTDATA;
  685. pswData.uipDataValue = (nextContext->Enable ? 1 : 0);
  686. //
  687. // If we own the PCI PME pin for this device, the make sure to clear the
  688. // status and disable it --- we enable the PME pin after we have
  689. // turned on the _PSW, and we disable the PME pin before we turn off
  690. // the _PSW
  691. //
  692. if ( (deviceExtension->Flags & DEV_PROP_HAS_PME) &&
  693. nextContext->Enable == FALSE) {
  694. ACPIWakeEnableDisablePciDevice(
  695. deviceExtension,
  696. FALSE
  697. );
  698. }
  699. //
  700. // Call the interpreter
  701. //
  702. status = AMLIAsyncEvalObject(
  703. AcpiObject,
  704. NULL,
  705. 1,
  706. &pswData,
  707. ACPIWakeEnableDisableAsyncCallBack,
  708. nextContext
  709. );
  710. ACPIDevPrint( (
  711. ACPI_PRINT_WAKE,
  712. nextContext->DeviceExtension,
  713. "ACPIWakeEnableDisableAsyncCallBack = 0x%08lx (M)\n",
  714. status
  715. ) );
  716. if (status != STATUS_PENDING) {
  717. //
  718. // Ugh - Recursive
  719. //
  720. ACPIWakeEnableDisableAsyncCallBack(
  721. AcpiObject,
  722. status,
  723. NULL,
  724. nextContext
  725. );
  726. }
  727. }
  728. }
  729. VOID
  730. ACPIWakeEnableDisablePciDevice(
  731. IN PDEVICE_EXTENSION DeviceExtension,
  732. IN BOOLEAN Enable
  733. )
  734. /*++
  735. Routine Description:
  736. This routine is what is actually called to enable or disable the
  737. PCI PME pin for a device
  738. N.B. The AcpiPowerLock must be owned
  739. Arguments:
  740. DeviceExtension - The device extension that is a filter on top of the
  741. pdo from the PCI device
  742. Enable - True to enable PME, false otherwise
  743. Return Value:
  744. None
  745. --*/
  746. {
  747. KIRQL oldIrql;
  748. //
  749. // Is there an interface present?
  750. //
  751. if (!PciPmeInterfaceInstantiated) {
  752. return;
  753. }
  754. //
  755. // Prevent the device from going away while we make this call
  756. //
  757. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  758. //
  759. // Check to see if there is a device object...
  760. //
  761. if (!DeviceExtension->PhysicalDeviceObject) {
  762. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  763. return;
  764. }
  765. PciPmeInterface->UpdateEnable(
  766. DeviceExtension->PhysicalDeviceObject,
  767. Enable
  768. );
  769. //
  770. // Done with the lock
  771. //
  772. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  773. }
  774. NTSTATUS
  775. ACPIWakeEnableDisableSync(
  776. IN PDEVICE_EXTENSION DeviceExtension,
  777. IN BOOLEAN Enable
  778. )
  779. /*++
  780. Routine Description:
  781. Given a DeviceExtension, enables or disables the device wake support
  782. from the device
  783. NB: This routine can only be called at passive level
  784. Arguments:
  785. DeviceExtension - The device we care about
  786. Enable - True if we are to enable, false otherwise
  787. Return Value:
  788. NTSTATUS
  789. --*/
  790. {
  791. ACPI_WAKE_PSW_SYNC_CONTEXT syncContext;
  792. NTSTATUS status;
  793. PAGED_CODE();
  794. ASSERT( DeviceExtension != NULL &&
  795. DeviceExtension->Signature == ACPI_SIGNATURE );
  796. //
  797. // Initialize the event
  798. //
  799. KeInitializeEvent( &syncContext.Event, NotificationEvent, FALSE );
  800. //
  801. // Call the async procedure
  802. //
  803. status = ACPIWakeEnableDisableAsync(
  804. DeviceExtension,
  805. Enable,
  806. ACPIWakeEnableDisableSyncCallBack,
  807. &syncContext
  808. );
  809. if (status == STATUS_PENDING) {
  810. KeWaitForSingleObject(
  811. &syncContext.Event,
  812. Executive,
  813. KernelMode,
  814. FALSE,
  815. NULL
  816. );
  817. status = syncContext.Status;
  818. }
  819. //
  820. // Done
  821. //
  822. return status;
  823. }
  824. VOID
  825. EXPORT
  826. ACPIWakeEnableDisableSyncCallBack(
  827. IN PNSOBJ AcpiObject,
  828. IN NTSTATUS Status,
  829. IN POBJDATA ObjData,
  830. IN PVOID Context
  831. )
  832. /*++
  833. Routine Description:
  834. The Async part of the EnableDisable request has been completed
  835. Arguments:
  836. AcpiObject - The object that was executed
  837. Status - The result of the operation
  838. ObjData - Not used
  839. Context - ACPI_WAKE_PSW_SYNC_CONTEXT
  840. Return Value:
  841. VOID
  842. --*/
  843. {
  844. PACPI_WAKE_PSW_SYNC_CONTEXT pswContext = (PACPI_WAKE_PSW_SYNC_CONTEXT) Context;
  845. //
  846. // Set the real status
  847. //
  848. pswContext->Status = Status;
  849. //
  850. // Set the event
  851. //
  852. KeSetEvent( &(pswContext->Event), IO_NO_INCREMENT, FALSE );
  853. }
  854. VOID
  855. ACPIWakeEnableWakeEvents(
  856. VOID
  857. )
  858. /*++
  859. Routine Description:
  860. This routine is called just before the system is put to sleep.
  861. The purpose of this routine is re-allow all wake and run-time events
  862. in the GpeCurEnable to be correctly set. After the machine wakes up,
  863. the machine will check that register to see if any events triggered the
  864. wakeup
  865. NB: This routine is called with interrupts off.
  866. Arguments:
  867. None
  868. Return Value:
  869. None
  870. --*/
  871. {
  872. KIRQL oldIrql;
  873. ULONG gpeRegister = 0;
  874. //
  875. // This function is called when interrupts are disabled, so in theory,
  876. // all the following should be safe. However, better safe than sorry.
  877. //
  878. KeAcquireSpinLock( &GpeTableLock, &oldIrql );
  879. //
  880. // Remember that on the way back up, we will entering the S0 state
  881. //
  882. AcpiPowerLeavingS0 = FALSE;
  883. //
  884. // Update all the registers
  885. //
  886. for (gpeRegister = 0; gpeRegister < AcpiInformation->GpeSize; gpeRegister++) {
  887. //
  888. // In any case, make sure that our current enable mask includes all
  889. // the wake registers, but doesn't include any of the pending
  890. // events
  891. //
  892. GpeCurEnable[gpeRegister] |= (GpeWakeEnable[gpeRegister] &
  893. ~GpePending[gpeRegister]);
  894. }
  895. //
  896. // Set the wake events only
  897. //
  898. ACPIGpeEnableWakeEvents();
  899. //
  900. // Done with the table lock
  901. //
  902. KeReleaseSpinLock( &GpeTableLock, oldIrql );
  903. }
  904. NTSTATUS
  905. ACPIWakeInitializePciDevice(
  906. IN PDEVICE_OBJECT DeviceObject
  907. )
  908. /*++
  909. Routine Description:
  910. This routine is called when a filter is started to determine if the PCI
  911. device is capable of generating a PME
  912. Arguments:
  913. DeviceObject - The device object to initialize
  914. Return Value:
  915. NTSTATUS
  916. --*/
  917. {
  918. BOOLEAN pmeSupported;
  919. BOOLEAN pmeStatus;
  920. BOOLEAN pmeEnable;
  921. KIRQL oldIrql;
  922. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  923. //
  924. // We don't have to worry if the device doesn't support wake methods
  925. // directly
  926. //
  927. if (!(deviceExtension->Flags & DEV_CAP_WAKE) ) {
  928. return STATUS_SUCCESS;
  929. }
  930. //
  931. // Need to grab the power lock to do the following
  932. //
  933. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  934. //
  935. // Do we have an interface to call?
  936. //
  937. if (PciPmeInterfaceInstantiated == FALSE) {
  938. goto ACPIWakeInitializePciDeviceExit;
  939. }
  940. //
  941. // Get the status of PME for this device
  942. //
  943. PciPmeInterface->GetPmeInformation(
  944. deviceExtension->PhysicalDeviceObject,
  945. &pmeSupported,
  946. &pmeStatus,
  947. &pmeEnable
  948. );
  949. //
  950. // if the device supports pme, then we own it...
  951. //
  952. if (pmeSupported == TRUE) {
  953. //
  954. // We own the PME pin for this device
  955. //
  956. ACPIInternalUpdateFlags(
  957. &(deviceExtension->Flags),
  958. (DEV_PROP_HAS_PME),
  959. FALSE
  960. );
  961. //
  962. // Check to see if we should disable PME or disable the PME status
  963. //
  964. if (pmeEnable) {
  965. //
  966. // Calling this also clears the PME status pin
  967. //
  968. PciPmeInterface->UpdateEnable(
  969. deviceExtension->PhysicalDeviceObject,
  970. FALSE
  971. );
  972. } else if (pmeStatus) {
  973. //
  974. // Clear the PME status
  975. //
  976. PciPmeInterface->ClearPmeStatus(
  977. deviceExtension->PhysicalDeviceObject
  978. );
  979. }
  980. }
  981. ACPIWakeInitializePciDeviceExit:
  982. //
  983. // Done with lock
  984. //
  985. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  986. //
  987. // Done
  988. //
  989. return STATUS_SUCCESS;
  990. }
  991. NTSTATUS
  992. ACPIWakeInitializePmeRouting(
  993. IN PDEVICE_OBJECT DeviceObject
  994. )
  995. /*++
  996. Routine Description:
  997. This routine will ask the PCI driver for its PME interface
  998. Arguments:
  999. DeviceObject - The ACPI PDO for a PCI root bus
  1000. Return Value:
  1001. NTSTATUS
  1002. --*/
  1003. {
  1004. KIRQL oldIrql;
  1005. NTSTATUS status;
  1006. IO_STACK_LOCATION irpSp;
  1007. PPCI_PME_INTERFACE interface;
  1008. PULONG dummy;
  1009. //
  1010. // Allocate some memory for the interface
  1011. //
  1012. interface = ExAllocatePoolWithTag(
  1013. NonPagedPool,
  1014. sizeof(PCI_PME_INTERFACE),
  1015. ACPI_ARBITER_POOLTAG
  1016. );
  1017. if (interface == NULL) {
  1018. return STATUS_INSUFFICIENT_RESOURCES;
  1019. }
  1020. //
  1021. // Initialize the stack location
  1022. //
  1023. RtlZeroMemory( &irpSp, sizeof(IO_STACK_LOCATION) );
  1024. irpSp.MajorFunction = IRP_MJ_PNP;
  1025. irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
  1026. irpSp.Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCI_PME_INTERFACE;
  1027. irpSp.Parameters.QueryInterface.Version = PCI_PME_INTRF_STANDARD_VER;
  1028. irpSp.Parameters.QueryInterface.Size = sizeof (PCI_PME_INTERFACE);
  1029. irpSp.Parameters.QueryInterface.Interface = (PINTERFACE) interface;
  1030. irpSp.Parameters.QueryInterface.InterfaceSpecificData = NULL;
  1031. //
  1032. // Send the request along
  1033. //
  1034. status = ACPIInternalSendSynchronousIrp(
  1035. DeviceObject,
  1036. &irpSp,
  1037. &dummy
  1038. );
  1039. if (!NT_SUCCESS(status)) {
  1040. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension( DeviceObject );
  1041. ACPIDevPrint( (
  1042. ACPI_PRINT_CRITICAL,
  1043. deviceExtension,
  1044. " - ACPIWakeInitializePmeRouting = %08lx\n",
  1045. status
  1046. ) );
  1047. //
  1048. // Free the memory and return
  1049. //
  1050. ExFreePool( interface );
  1051. return status;
  1052. }
  1053. //
  1054. // Do this under spinlock protection
  1055. //
  1056. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  1057. if (PciPmeInterfaceInstantiated == FALSE) {
  1058. //
  1059. // Keep a global pointer to the interface
  1060. //
  1061. PciPmeInterfaceInstantiated = TRUE;
  1062. PciPmeInterface = interface;
  1063. } else {
  1064. //
  1065. // Someone else got here before us, so we need to make sure
  1066. // that we free the extra memory
  1067. //
  1068. ExFreePool (interface );
  1069. }
  1070. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  1071. //
  1072. // Done
  1073. //
  1074. return status;
  1075. }
  1076. VOID
  1077. ACPIWakeRemoveDevicesAndUpdate(
  1078. IN PDEVICE_EXTENSION TargetExtension,
  1079. OUT PLIST_ENTRY ListHead
  1080. )
  1081. /*++
  1082. Routine Description:
  1083. This routine finds the all of the WaitWake requests associated with
  1084. TargetDevice and return them on ListHead. This is done in a 'safe' way
  1085. NB: Caller must hold the AcpiPowerLock and Cancel Lock!
  1086. Arguments:
  1087. TargetExtension - The target extension that we are looking for
  1088. ListHead - Where to store the list of matched devices
  1089. Return Value:
  1090. NONE
  1091. --*/
  1092. {
  1093. PACPI_POWER_REQUEST powerRequest;
  1094. PDEVICE_EXTENSION deviceExtension;
  1095. PLIST_ENTRY listEntry;
  1096. SYSTEM_POWER_STATE sleepState;
  1097. ULONG gpeRegister;
  1098. ULONG gpeMask;
  1099. ULONG byteIndex;
  1100. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  1101. //
  1102. // We need to synchronize with the ProcessGPE code because we are going
  1103. // to touch one of the GPE Masks
  1104. //
  1105. KeAcquireSpinLockAtDpcLevel( &GpeTableLock );
  1106. //
  1107. // The first step is to disable all the wake vectors
  1108. //
  1109. for (gpeRegister = 0; gpeRegister < AcpiInformation->GpeSize; gpeRegister++) {
  1110. //
  1111. // Remove the wake vectors from the real-time vectors.
  1112. // Note that since we are going to be writting the GPE Enable vector
  1113. // later on in the process, it seems pointless to actually write them
  1114. // now as well
  1115. //
  1116. GpeCurEnable[gpeRegister] &= (GpeSpecialHandler[gpeRegister] |
  1117. ~(GpeWakeEnable[gpeRegister] | GpeWakeHandler[gpeRegister]));
  1118. }
  1119. //
  1120. // Next step is to reset the wake mask
  1121. //
  1122. RtlZeroMemory( GpeWakeEnable, AcpiInformation->GpeSize * sizeof(UCHAR) );
  1123. //
  1124. // Look at the first element in the wake list
  1125. //
  1126. listEntry = AcpiPowerWaitWakeList.Flink;
  1127. //
  1128. // Loop for all elements in the list
  1129. //
  1130. while (listEntry != &AcpiPowerWaitWakeList) {
  1131. //
  1132. // Grab the irp from the listEntry
  1133. //
  1134. powerRequest = CONTAINING_RECORD(
  1135. listEntry,
  1136. ACPI_POWER_REQUEST,
  1137. ListEntry
  1138. );
  1139. //
  1140. // Point to the next request
  1141. //
  1142. listEntry = listEntry->Flink;
  1143. //
  1144. // Obtain the device extension for the request
  1145. //
  1146. deviceExtension = powerRequest->DeviceExtension;
  1147. //
  1148. // If this device is to be removed, then remove it
  1149. //
  1150. if (deviceExtension == TargetExtension) {
  1151. //
  1152. // Remove the request from the list and move it to the next
  1153. // list. Mark the irp as no longer cancelable.
  1154. //
  1155. IoSetCancelRoutine( (PIRP) powerRequest->Context, NULL );
  1156. RemoveEntryList( &powerRequest->ListEntry );
  1157. InsertTailList( ListHead, &powerRequest->ListEntry );
  1158. } else {
  1159. //
  1160. // If the wake level of the bit indicates that it isn't supported
  1161. // in the current sleep state, then don't enable it... Note that
  1162. // this doesn't solve the problem where two devices share the
  1163. // same vector, one can wake the computer from S2, one from S3 and
  1164. // we are going to S3. In this case, we don't have the smarts to
  1165. // un-run the _PSW from the S2 device
  1166. //
  1167. sleepState = powerRequest->u.WaitWakeRequest.SystemPowerState;
  1168. if (sleepState < AcpiMostRecentSleepState) {
  1169. continue;
  1170. }
  1171. //
  1172. // Get the byteIndex for this GPE
  1173. //
  1174. byteIndex = ACPIGpeIndexToByteIndex(
  1175. deviceExtension->PowerInfo.WakeBit
  1176. );
  1177. //
  1178. // Drivers cannot register on wake vectors
  1179. //
  1180. if (GpeMap[byteIndex]) {
  1181. ACPIDevPrint( (
  1182. ACPI_PRINT_WAKE,
  1183. deviceExtension,
  1184. "ACPIWakeRemoveDeviceAndUpdate - %x cannot be used as a"
  1185. "wake pin.\n",
  1186. deviceExtension->PowerInfo.WakeBit
  1187. ) );
  1188. continue;
  1189. }
  1190. //
  1191. // Calculate the entry and offset. Assume that the Parameter is
  1192. // at most a UCHAR
  1193. //
  1194. gpeRegister = ACPIGpeIndexToGpeRegister(
  1195. deviceExtension->PowerInfo.WakeBit
  1196. );
  1197. gpeMask = 1 << ( (UCHAR) deviceExtension->PowerInfo.WakeBit % 8);
  1198. //
  1199. // This GPE is being used as a wake event
  1200. //
  1201. if (!(GpeWakeEnable[gpeRegister] & gpeMask)) {
  1202. //
  1203. // This is a wake pin
  1204. //
  1205. GpeWakeEnable[gpeRegister] |= gpeMask;
  1206. //
  1207. // Prevent machine stupity and try to clear the Status bit
  1208. //
  1209. ACPIWriteGpeStatusRegister( gpeRegister, (UCHAR) gpeMask );
  1210. //
  1211. // Do we have a control method associated with this GPE?
  1212. //
  1213. if (!(GpeEnable[gpeRegister] & gpeMask)) {
  1214. //
  1215. // Is this GPE already enabled?
  1216. //
  1217. if (GpeCurEnable[gpeRegister] & gpeMask) {
  1218. continue;
  1219. }
  1220. //
  1221. // Not enabled -- then there is no control method for this
  1222. // GPE, consider this to be a level vector.
  1223. //
  1224. GpeIsLevel[gpeRegister] |= gpeMask;
  1225. GpeCurEnable[gpeRegister] |= gpeMask;
  1226. } else if (!(GpeSpecialHandler[gpeRegister] & gpeMask) ) {
  1227. //
  1228. // In this case, the GPE *does* have a control method
  1229. // associated with it. Remember that.
  1230. //
  1231. GpeWakeHandler[gpeRegister] |= gpeMask;
  1232. }
  1233. }
  1234. }
  1235. }
  1236. //
  1237. // Update all the registers
  1238. //
  1239. for (gpeRegister = 0; gpeRegister < AcpiInformation->GpeSize; gpeRegister++) {
  1240. if (AcpiPowerLeavingS0) {
  1241. //
  1242. // If we are leaving S0, then make sure to remove *all* the
  1243. // wake events that we know about from the current enable mask.
  1244. // If any wake events are currently pending, that will cause us
  1245. // to continue processing them, but hopefully will not lead us
  1246. // to renable them
  1247. //
  1248. GpeCurEnable[gpeRegister] &= ~GpeWakeEnable[gpeRegister];
  1249. } else {
  1250. //
  1251. // If we are re-entering S0, then we need to renable all the wake
  1252. // events, except the ones that we are already processing
  1253. //
  1254. GpeCurEnable[gpeRegister] |= (GpeWakeEnable[gpeRegister] &
  1255. ~GpePending[gpeRegister]);
  1256. }
  1257. //
  1258. // Now that we have calculate what the proper register should be,
  1259. // write it back to the hardware
  1260. //
  1261. ACPIWriteGpeEnableRegister( gpeRegister, GpeCurEnable[gpeRegister] );
  1262. }
  1263. //
  1264. // Done with the spinlock
  1265. //
  1266. KeReleaseSpinLockFromDpcLevel( &GpeTableLock );
  1267. //
  1268. // Done
  1269. //
  1270. return;
  1271. }
  1272. NTSTATUS
  1273. ACPIWakeRestoreEnables(
  1274. IN PACPI_BUILD_CALLBACK CallBack,
  1275. IN PVOID CallBackContext
  1276. )
  1277. /*++
  1278. Routine Description:
  1279. This routine re-runs through the list of WAIT-WAKE irps and runs the _PSW
  1280. method for each of those irps again. The reason that this is done is to
  1281. restore the state of the hardware to what the OS thinks the state is.
  1282. Arguments:
  1283. CallBack - The function to call when done
  1284. CallBackContext - The context to pass to that function
  1285. Return Value:
  1286. NTSTATUS
  1287. --*/
  1288. {
  1289. NTSTATUS status;
  1290. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL);
  1291. //
  1292. // We need to hold the device tree lock
  1293. //
  1294. KeAcquireSpinLockAtDpcLevel( &AcpiDeviceTreeLock );
  1295. //
  1296. // Call the build routines that we have already tested and running to
  1297. // cause them to walk the device extension tree and run the appropriate
  1298. // control methods
  1299. //
  1300. status = ACPIBuildRunMethodRequest(
  1301. RootDeviceExtension,
  1302. CallBack,
  1303. CallBackContext,
  1304. PACKED_PSW,
  1305. (RUN_REQUEST_CHECK_STATUS | RUN_REQUEST_RECURSIVE |
  1306. RUN_REQUEST_CHECK_WAKE_COUNT),
  1307. TRUE
  1308. );
  1309. //
  1310. // Done with the device tree lock
  1311. //
  1312. KeReleaseSpinLockFromDpcLevel( &AcpiDeviceTreeLock );
  1313. //
  1314. // Done
  1315. //
  1316. return status;
  1317. }
  1318. VOID
  1319. ACPIWakeRestoreEnablesCompletion(
  1320. IN PDEVICE_EXTENSION DeviceExtension,
  1321. IN PVOID Context,
  1322. IN NTSTATUS Status
  1323. )
  1324. /*++
  1325. Routine Description:
  1326. This routine is called after we have finished running all the _PSWs in the
  1327. system
  1328. Arguments:
  1329. DeviceExtension - The device that just completed the enables
  1330. Context - PACPI_POWER_REQUEST
  1331. Status - What the status of the operation was
  1332. --*/
  1333. {
  1334. UNREFERENCED_PARAMETER( DeviceExtension);
  1335. //
  1336. // Restart the device power management engine
  1337. //
  1338. ACPIDeviceCompleteGenericPhase(
  1339. NULL,
  1340. Status,
  1341. NULL,
  1342. Context
  1343. );
  1344. }
  1345. NTSTATUS
  1346. ACPIWakeWaitIrp(
  1347. IN PDEVICE_OBJECT DeviceObject,
  1348. IN PIRP Irp
  1349. )
  1350. /*++
  1351. Routine Description:
  1352. This is the routine that is called when the system wants to be notified
  1353. of this device waking the system.
  1354. Arguments:
  1355. DeviceObject - The device object which is supposed to wake the system
  1356. Irp - The request
  1357. Return Value:
  1358. NTSTATUS
  1359. --*/
  1360. {
  1361. NTSTATUS status;
  1362. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  1363. PIO_STACK_LOCATION irpStack;
  1364. //
  1365. // The first step is to decide if this object can actually support
  1366. // a wake.
  1367. //
  1368. if ( !(deviceExtension->Flags & DEV_CAP_WAKE) ) {
  1369. //
  1370. // We do not support wake
  1371. //
  1372. return ACPIDispatchForwardOrFailPowerIrp( DeviceObject, Irp );
  1373. }
  1374. //
  1375. // Get the stack parameters
  1376. //
  1377. irpStack = IoGetCurrentIrpStackLocation( Irp );
  1378. //
  1379. // We must make sure that we are at the correct system level
  1380. // to support this functionality
  1381. //
  1382. if (deviceExtension->PowerInfo.SystemWakeLevel <
  1383. irpStack->Parameters.WaitWake.PowerState) {
  1384. //
  1385. // The system level is not the one we are currently at
  1386. //
  1387. ACPIDevPrint( (
  1388. ACPI_PRINT_WAKE,
  1389. deviceExtension,
  1390. "(0x%08lx): ACPIWakeWaitIrp ->S%d < Irp->S%d\n",
  1391. Irp,
  1392. deviceExtension->PowerInfo.SystemWakeLevel - 1,
  1393. irpStack->Parameters.WaitWake.PowerState - 1
  1394. ) );
  1395. //
  1396. // Fail the Irp
  1397. //
  1398. Irp->IoStatus.Status = status = STATUS_INVALID_DEVICE_STATE;
  1399. PoStartNextPowerIrp( Irp );
  1400. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1401. return status;
  1402. }
  1403. //
  1404. // We must make sure that the device is in the proper device level
  1405. // to support this functionality
  1406. //
  1407. if (deviceExtension->PowerInfo.DeviceWakeLevel <
  1408. deviceExtension->PowerInfo.PowerState) {
  1409. //
  1410. // We are too much powered off to wake the computer
  1411. //
  1412. ACPIDevPrint( (
  1413. ACPI_PRINT_WAKE,
  1414. deviceExtension,
  1415. "(0x%08lx): ACPIWakeWaitIrp Device->D%d Max->D%d\n",
  1416. Irp,
  1417. deviceExtension->PowerInfo.DeviceWakeLevel - 1,
  1418. deviceExtension->PowerInfo.PowerState - 1
  1419. ) );
  1420. //
  1421. // Fail the irp
  1422. //
  1423. Irp->IoStatus.Status = status = STATUS_INVALID_DEVICE_STATE;
  1424. PoStartNextPowerIrp( Irp );
  1425. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1426. return status;
  1427. }
  1428. //
  1429. // At this point, we are definately going to run the completion routine
  1430. // so, we mark the irp as pending and increment the reference count
  1431. //
  1432. IoMarkIrpPending( Irp );
  1433. InterlockedIncrement( &deviceExtension->OutstandingIrpCount );
  1434. //
  1435. // Feed the request to the device power management subsystem. Note that
  1436. // this function is supposed to invoke the completion request no matter
  1437. // what happens.
  1438. //
  1439. status = ACPIDeviceIrpWaitWakeRequest(
  1440. DeviceObject,
  1441. Irp,
  1442. ACPIDeviceIrpCompleteRequest
  1443. );
  1444. if (status == STATUS_MORE_PROCESSING_REQUIRED) {
  1445. status = STATUS_PENDING;
  1446. } else {
  1447. //
  1448. // Remove our reference
  1449. //
  1450. ACPIInternalDecrementIrpReferenceCount( deviceExtension );
  1451. }
  1452. return status;
  1453. }