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.

1871 lines
45 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. // Update the number of references on the device
  370. //
  371. if (Enable) {
  372. DeviceExtension->PowerInfo.WakeSupportCount++;
  373. ACPIDevPrint( (
  374. ACPI_PRINT_WAKE,
  375. DeviceExtension,
  376. "ACPIWakeEnableDisableAsync - Count: %d (+)\n",
  377. DeviceExtension->PowerInfo.WakeSupportCount
  378. ) );
  379. //
  380. // Did we transition to one wake?
  381. //
  382. if (DeviceExtension->PowerInfo.WakeSupportCount != 1) {
  383. //
  384. // If we own the PME pin for this device, then make sure that
  385. // we clear the status pin and keep the PME signal enabled
  386. //
  387. if (DeviceExtension->Flags & DEV_PROP_HAS_PME ) {
  388. ACPIWakeEnableDisablePciDevice(
  389. DeviceExtension,
  390. TRUE
  391. );
  392. }
  393. goto ACPIWakeEnableDisableAsyncExit;
  394. }
  395. } else {
  396. ASSERT( DeviceExtension->PowerInfo.WakeSupportCount );
  397. DeviceExtension->PowerInfo.WakeSupportCount--;
  398. ACPIDevPrint( (
  399. ACPI_PRINT_WAKE,
  400. DeviceExtension,
  401. "ACPIWakeEnableDisableAsync - Count: %d (-)\n",
  402. DeviceExtension->PowerInfo.WakeSupportCount
  403. ) );
  404. //
  405. // Did we transition to zero wake?
  406. //
  407. if (DeviceExtension->PowerInfo.WakeSupportCount != 0) {
  408. //
  409. // If we own the PME pin for this device, then make sure that
  410. // we clear the status pin and keep the PME signal enabled
  411. //
  412. if (DeviceExtension->Flags & DEV_PROP_HAS_PME ) {
  413. ACPIWakeEnableDisablePciDevice(
  414. DeviceExtension,
  415. TRUE
  416. );
  417. }
  418. goto ACPIWakeEnableDisableAsyncExit;
  419. }
  420. }
  421. //
  422. // Grab the pswObject
  423. //
  424. pswObject = DeviceExtension->PowerInfo.PowerObject[PowerDeviceUnspecified];
  425. if (pswObject == NULL) {
  426. //
  427. // If we got here, that means that there isn't a _PSW to be run and
  428. // that we should make sure that if we own the PME pin, that we should
  429. // set it.
  430. //
  431. if (DeviceExtension->Flags & DEV_PROP_HAS_PME) {
  432. ACPIWakeEnableDisablePciDevice(
  433. DeviceExtension,
  434. TRUE
  435. );
  436. }
  437. goto ACPIWakeEnableDisableAsyncExit;
  438. }
  439. //
  440. // Allocate the _PSW context that we need to signify that there is
  441. // a pending _PSW on this device
  442. //
  443. pswContext = ExAllocateFromNPagedLookasideList(
  444. &PswContextLookAsideList
  445. );
  446. if (pswContext == NULL) {
  447. status = STATUS_INSUFFICIENT_RESOURCES;
  448. goto ACPIWakeEnableDisableAsyncExit;
  449. }
  450. //
  451. // Initialize the context
  452. //
  453. pswContext->Enable = Enable;
  454. pswContext->CallBack = CallBack;
  455. pswContext->Context = Context;
  456. pswContext->DeviceExtension = DeviceExtension;
  457. pswContext->Count = 1;
  458. //
  459. // Acquire the Spinlock so we can safely look at
  460. // the WakeSupportList without worry of someone else
  461. // messing with it underneath us.
  462. //
  463. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  464. //
  465. // Check to see if we are simply going to queue the context up, or
  466. // call the interpreter
  467. //
  468. if (IsListEmpty( &(DeviceExtension->PowerInfo.WakeSupportList) ) ) {
  469. runPsw = TRUE;
  470. }
  471. //
  472. // List is non-empty, so we just queue up the context
  473. //
  474. InsertTailList(
  475. &(DeviceExtension->PowerInfo.WakeSupportList),
  476. &(pswContext->ListEntry)
  477. );
  478. //
  479. // Release the lock
  480. //
  481. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  482. //
  483. // Should we run the method?
  484. //
  485. if (runPsw) {
  486. //
  487. // If we own the PCI PME pin for this device, the make sure to clear the
  488. // status and disable it --- we enable the PME pin after we have
  489. // turned on the _PSW, and we disable the PME pin before we turn off
  490. // the _PSW
  491. //
  492. if ( (DeviceExtension->Flags & DEV_PROP_HAS_PME) &&
  493. pswContext->Enable == FALSE) {
  494. ACPIWakeEnableDisablePciDevice(
  495. DeviceExtension,
  496. FALSE
  497. );
  498. }
  499. //
  500. // Initialize the arguments
  501. //
  502. RtlZeroMemory( &pswData, sizeof(OBJDATA) );
  503. pswData.dwDataType = OBJTYPE_INTDATA;
  504. pswData.uipDataValue = (Enable ? 1 : 0);
  505. //
  506. // Run the control method
  507. //
  508. status = AMLIAsyncEvalObject(
  509. pswObject,
  510. NULL,
  511. 1,
  512. &pswData,
  513. ACPIWakeEnableDisableAsyncCallBack,
  514. pswContext
  515. );
  516. //
  517. // What Happened
  518. //
  519. ACPIDevPrint( (
  520. ACPI_PRINT_WAKE,
  521. DeviceExtension,
  522. "ACPIWakeEnableDisableAsync = 0x%08lx (P)\n",
  523. status
  524. ) );
  525. if (status != STATUS_PENDING) {
  526. ACPIWakeEnableDisableAsyncCallBack(
  527. pswObject,
  528. status,
  529. NULL,
  530. pswContext
  531. );
  532. }
  533. return STATUS_PENDING;
  534. } else {
  535. ACPIDevPrint( (
  536. ACPI_PRINT_WAKE,
  537. DeviceExtension,
  538. "ACPIWakeEnableDisableAsync = 0x%08lx (Q)\n",
  539. STATUS_PENDING
  540. ) );
  541. //
  542. // we queued the request up, so we must return pending
  543. //
  544. return STATUS_PENDING;
  545. }
  546. ACPIWakeEnableDisableAsyncExit:
  547. //
  548. // What happened
  549. //
  550. ACPIDevPrint( (
  551. ACPI_PRINT_WAKE,
  552. DeviceExtension,
  553. "ACPIWakeEnableDisableAsync = 0x%08lx\n",
  554. status
  555. ) );
  556. //
  557. // Call the specified callback ourselves
  558. //
  559. (*CallBack)(
  560. pswObject,
  561. status,
  562. NULL,
  563. Context
  564. );
  565. return STATUS_PENDING;
  566. }
  567. VOID
  568. EXPORT
  569. ACPIWakeEnableDisableAsyncCallBack(
  570. IN PNSOBJ AcpiObject,
  571. IN NTSTATUS Status,
  572. IN POBJDATA ObjData,
  573. IN PVOID Context
  574. )
  575. /*++
  576. Routine Description:
  577. This routine is called after a _PSW method has been run on a device.
  578. This routine is responsible for seeing if there are any more delayed
  579. _PSW requests on the same device, and if so, run them.
  580. Arguments:
  581. AcpiObject - The method object that was run
  582. Status - The result of the eval
  583. ObjData - Not used
  584. Context - PACPI_WAKE_PSW_CONTEXT
  585. Return value:
  586. VOID
  587. --*/
  588. {
  589. BOOLEAN runPsw = FALSE;
  590. KIRQL oldIrql;
  591. PACPI_WAKE_PSW_CONTEXT pswContext = (PACPI_WAKE_PSW_CONTEXT) Context;
  592. PACPI_WAKE_PSW_CONTEXT nextContext;
  593. PDEVICE_EXTENSION deviceExtension = pswContext->DeviceExtension;
  594. ACPIDevPrint( (
  595. ACPI_PRINT_WAKE,
  596. deviceExtension,
  597. "ACPIWakeEnableDisableAsyncCallBack = %08lx (C)\n",
  598. Status
  599. ) );
  600. //
  601. // Acquire the spinlock
  602. //
  603. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  604. //
  605. // Remove the specified entry from the list
  606. //
  607. RemoveEntryList( &(pswContext->ListEntry) );
  608. //
  609. // If we failed the request, then we don't really know the status of the
  610. // _PSW on the device. Lets assume that it doesn't change and undo
  611. // whatever change we did to get here
  612. //
  613. if (!NT_SUCCESS(Status)) {
  614. ACPIDevPrint( (
  615. ACPI_PRINT_WAKE,
  616. deviceExtension,
  617. "ACPIWakeEnableDisableAsyncCallBack - RefCount: %lx %s %lx = %lx\n",
  618. deviceExtension->PowerInfo.WakeSupportCount,
  619. (pswContext->Enable ? "-" : "+"),
  620. pswContext->Count,
  621. (pswContext->Enable ? deviceExtension->PowerInfo.WakeSupportCount -
  622. pswContext->Count : deviceExtension->PowerInfo.WakeSupportCount +
  623. pswContext->Count)
  624. ) );
  625. if (pswContext->Enable) {
  626. deviceExtension->PowerInfo.WakeSupportCount -= pswContext->Count;
  627. } else {
  628. deviceExtension->PowerInfo.WakeSupportCount += pswContext->Count;
  629. }
  630. }
  631. //
  632. // If we own the PCI PME pin for this device, the make sure to clear the
  633. // status and either enable it --- we enable the PME pin after we have
  634. // turned on the _PSW, and we disable the PME pin before we turn off
  635. // the _PSW
  636. //
  637. if ( (deviceExtension->Flags & DEV_PROP_HAS_PME) &&
  638. pswContext->Enable == TRUE) {
  639. ACPIWakeEnableDisablePciDevice(
  640. deviceExtension,
  641. pswContext->Enable
  642. );
  643. }
  644. //
  645. // Are the any items on the list?
  646. //
  647. if (!IsListEmpty( &(deviceExtension->PowerInfo.WakeSupportList) ) ) {
  648. runPsw = TRUE;
  649. nextContext = CONTAINING_RECORD(
  650. deviceExtension->PowerInfo.WakeSupportList.Flink,
  651. ACPI_WAKE_PSW_CONTEXT,
  652. ListEntry
  653. );
  654. }
  655. //
  656. // We can release the lock now
  657. //
  658. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  659. //
  660. // Call the callback on the completed item
  661. //
  662. (*pswContext->CallBack)(
  663. AcpiObject,
  664. Status,
  665. ObjData,
  666. (pswContext->Context)
  667. );
  668. //
  669. // Free the completed context
  670. //
  671. ExFreeToNPagedLookasideList(
  672. &PswContextLookAsideList,
  673. pswContext
  674. );
  675. //
  676. // Do we have to run a method?
  677. //
  678. if (runPsw) {
  679. NTSTATUS status;
  680. OBJDATA pswData;
  681. RtlZeroMemory( &pswData, sizeof(OBJDATA) );
  682. pswData.dwDataType = OBJTYPE_INTDATA;
  683. pswData.uipDataValue = (nextContext->Enable ? 1 : 0);
  684. //
  685. // If we own the PCI PME pin for this device, the make sure to clear the
  686. // status and disable it --- we enable the PME pin after we have
  687. // turned on the _PSW, and we disable the PME pin before we turn off
  688. // the _PSW
  689. //
  690. if ( (deviceExtension->Flags & DEV_PROP_HAS_PME) &&
  691. nextContext->Enable == FALSE) {
  692. ACPIWakeEnableDisablePciDevice(
  693. deviceExtension,
  694. FALSE
  695. );
  696. }
  697. //
  698. // Call the interpreter
  699. //
  700. status = AMLIAsyncEvalObject(
  701. AcpiObject,
  702. NULL,
  703. 1,
  704. &pswData,
  705. ACPIWakeEnableDisableAsyncCallBack,
  706. nextContext
  707. );
  708. ACPIDevPrint( (
  709. ACPI_PRINT_WAKE,
  710. nextContext->DeviceExtension,
  711. "ACPIWakeEnableDisableAsyncCallBack = 0x%08lx (M)\n",
  712. status
  713. ) );
  714. if (status != STATUS_PENDING) {
  715. //
  716. // Ugh - Recursive
  717. //
  718. ACPIWakeEnableDisableAsyncCallBack(
  719. AcpiObject,
  720. status,
  721. NULL,
  722. nextContext
  723. );
  724. }
  725. }
  726. }
  727. VOID
  728. ACPIWakeEnableDisablePciDevice(
  729. IN PDEVICE_EXTENSION DeviceExtension,
  730. IN BOOLEAN Enable
  731. )
  732. /*++
  733. Routine Description:
  734. This routine is what is actually called to enable or disable the
  735. PCI PME pin for a device
  736. N.B. The AcpiPowerLock must be owned
  737. Arguments:
  738. DeviceExtension - The device extension that is a filter on top of the
  739. pdo from the PCI device
  740. Enable - True to enable PME, false otherwise
  741. Return Value:
  742. None
  743. --*/
  744. {
  745. KIRQL oldIrql;
  746. //
  747. // Is there an interface present?
  748. //
  749. if (!PciPmeInterfaceInstantiated) {
  750. return;
  751. }
  752. //
  753. // Prevent the device from going away while we make this call
  754. //
  755. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  756. //
  757. // Check to see if there is a device object...
  758. //
  759. if (!DeviceExtension->PhysicalDeviceObject) {
  760. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  761. return;
  762. }
  763. PciPmeInterface->UpdateEnable(
  764. DeviceExtension->PhysicalDeviceObject,
  765. Enable
  766. );
  767. //
  768. // Done with the lock
  769. //
  770. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  771. }
  772. NTSTATUS
  773. ACPIWakeEnableDisableSync(
  774. IN PDEVICE_EXTENSION DeviceExtension,
  775. IN BOOLEAN Enable
  776. )
  777. /*++
  778. Routine Description:
  779. Given a DeviceExtension, enables or disables the device wake support
  780. from the device
  781. NB: This routine can only be called at passive level
  782. Arguments:
  783. DeviceExtension - The device we care about
  784. Enable - True if we are to enable, false otherwise
  785. Return Value:
  786. NTSTATUS
  787. --*/
  788. {
  789. ACPI_WAKE_PSW_SYNC_CONTEXT syncContext;
  790. NTSTATUS status;
  791. PAGED_CODE();
  792. ASSERT( DeviceExtension != NULL &&
  793. DeviceExtension->Signature == ACPI_SIGNATURE );
  794. //
  795. // Initialize the event
  796. //
  797. KeInitializeEvent( &syncContext.Event, NotificationEvent, FALSE );
  798. //
  799. // Call the async procedure
  800. //
  801. status = ACPIWakeEnableDisableAsync(
  802. DeviceExtension,
  803. Enable,
  804. ACPIWakeEnableDisableSyncCallBack,
  805. &syncContext
  806. );
  807. if (status == STATUS_PENDING) {
  808. KeWaitForSingleObject(
  809. &syncContext.Event,
  810. Executive,
  811. KernelMode,
  812. FALSE,
  813. NULL
  814. );
  815. status = syncContext.Status;
  816. }
  817. //
  818. // Done
  819. //
  820. return status;
  821. }
  822. VOID
  823. EXPORT
  824. ACPIWakeEnableDisableSyncCallBack(
  825. IN PNSOBJ AcpiObject,
  826. IN NTSTATUS Status,
  827. IN POBJDATA ObjData,
  828. IN PVOID Context
  829. )
  830. /*++
  831. Routine Description:
  832. The Async part of the EnableDisable request has been completed
  833. Arguments:
  834. AcpiObject - The object that was executed
  835. Status - The result of the operation
  836. ObjData - Not used
  837. Context - ACPI_WAKE_PSW_SYNC_CONTEXT
  838. Return Value:
  839. VOID
  840. --*/
  841. {
  842. PACPI_WAKE_PSW_SYNC_CONTEXT pswContext = (PACPI_WAKE_PSW_SYNC_CONTEXT) Context;
  843. UNREFERENCED_PARAMETER(AcpiObject);
  844. UNREFERENCED_PARAMETER(ObjData);
  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. }