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.

6569 lines
162 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. dpower.c
  5. Abstract:
  6. This handles requests to have devices set themselves at specific power
  7. levels
  8. Author:
  9. Stephane Plante (splante)
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. 09-Oct-96 Initial Revision
  14. 20-Nov-96 Interrupt Vector support
  15. 31-Mar-97 Cleanup
  16. 17-Sep-97 Major Rewrite
  17. 06-Jan-98 Cleaned Up the SST code
  18. --*/
  19. #include "pch.h"
  20. //
  21. // This is the variable that indicates wether or not the DPC is running
  22. //
  23. BOOLEAN AcpiPowerDpcRunning;
  24. //
  25. // This is the variable that indicates wether or not the DPC has completed
  26. // real work
  27. //
  28. BOOLEAN AcpiPowerWorkDone;
  29. //
  30. // This is the lock that is used to protect certain power resources and
  31. // lists
  32. //
  33. KSPIN_LOCK AcpiPowerLock;
  34. //
  35. // This is the lock that is used *only* within this module to queue requests
  36. // onto the Phase0 list *and* to modify the state of some global variables
  37. //
  38. KSPIN_LOCK AcpiPowerQueueLock;
  39. //
  40. // This is the list that the build dpc queue power requests onto until it
  41. // has finished building all of the device extensions. Once the extensions
  42. // are built, the contents of the list are moved onto the AcpiPowerQueueList
  43. //
  44. LIST_ENTRY AcpiPowerDelayedQueueList;
  45. //
  46. // This is the only list that routines outside of the DPC can queue reqests
  47. // onto
  48. //
  49. LIST_ENTRY AcpiPowerQueueList;
  50. //
  51. // This is the list where we run the _STA to determine if the resources that
  52. // we care about are still present
  53. //
  54. LIST_ENTRY AcpiPowerPhase0List;
  55. //
  56. // This is the list for the phase where we run PS1-PS3 and figure out
  57. // which PowerResources need to be in the 'on' state
  58. //
  59. LIST_ENTRY AcpiPowerPhase1List;
  60. //
  61. // This is the list for when we process the System Requests. It turns out
  62. // that we have to let all of the DeviceRequests through Phase1 before
  63. // we can figure out which devices are on the hibernate path, and which
  64. // arent
  65. //
  66. LIST_ENTRY AcpiPowerPhase2List;
  67. //
  68. // This is the list for the phase where we run ON or OFF
  69. //
  70. LIST_ENTRY AcpiPowerPhase3List;
  71. //
  72. // This is the list for the phase where we check to see if ON/OFF ran okay
  73. //
  74. LIST_ENTRY AcpiPowerPhase4List;
  75. //
  76. // This is the list for the phase where we run PSW or PSW
  77. //
  78. LIST_ENTRY AcpiPowerPhase5List;
  79. //
  80. // This is the list for the phase where we have WaitWake Irps pending
  81. //
  82. LIST_ENTRY AcpiPowerWaitWakeList;
  83. //
  84. // This is the list for the synchronize power requests
  85. //
  86. LIST_ENTRY AcpiPowerSynchronizeList;
  87. //
  88. // This is the list of Power Device Nodes objects
  89. //
  90. LIST_ENTRY AcpiPowerNodeList;
  91. //
  92. // This is what we use to queue up the DPC
  93. //
  94. KDPC AcpiPowerDpc;
  95. //
  96. // This is where we remember if the system is in steady state or if it is going
  97. // into standby
  98. //
  99. BOOLEAN AcpiPowerLeavingS0;
  100. //
  101. // This is the list that we use to pre-allocate storage for requests
  102. //
  103. NPAGED_LOOKASIDE_LIST RequestLookAsideList;
  104. //
  105. // This is the list that we use to pre-allocate storage for object data
  106. //
  107. NPAGED_LOOKASIDE_LIST ObjectDataLookAsideList;
  108. //
  109. // This table is used to map DevicePowerStates from the ACPI format to some
  110. // thing the system can handle
  111. //
  112. DEVICE_POWER_STATE DevicePowerStateTranslation[DEVICE_POWER_MAXIMUM] = {
  113. PowerDeviceD0,
  114. PowerDeviceD1,
  115. PowerDeviceD2,
  116. PowerDeviceD3
  117. };
  118. //
  119. // This table is used to map SystemPowerStates from the ACPI format to some
  120. // thing the system can handle
  121. //
  122. SYSTEM_POWER_STATE SystemPowerStateTranslation[SYSTEM_POWER_MAXIMUM] = {
  123. PowerSystemWorking,
  124. PowerSystemSleeping1,
  125. PowerSystemSleeping2,
  126. PowerSystemSleeping3,
  127. PowerSystemHibernate,
  128. PowerSystemShutdown
  129. };
  130. //
  131. // This table is used to map SystemPowerStates from the NT format to the
  132. // ACPI format
  133. //
  134. ULONG AcpiSystemStateTranslation[PowerSystemMaximum] = {
  135. -1, // PowerSystemUnspecified
  136. 0, // PowerSystemWorking
  137. 1, // PowerSystemSleepingS1
  138. 2, // PowerSystemSleepingS2
  139. 3, // PowerSystemSleepingS3
  140. 4, // PowerSystemHibernate
  141. 5 // PowerSystemShutdown
  142. };
  143. //
  144. // This is the table used to map functions in the Phase0 case WORK_DONE_STEP_0
  145. //
  146. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase0Table1[AcpiPowerRequestMaximum+1] = {
  147. ACPIDevicePowerProcessPhase0DeviceSubPhase1,
  148. ACPIDevicePowerProcessPhase0SystemSubPhase1,
  149. ACPIDevicePowerProcessForward,
  150. ACPIDevicePowerProcessForward,
  151. ACPIDevicePowerProcessForward,
  152. ACPIDevicePowerProcessInvalid
  153. };
  154. //
  155. // This is the table used to map functions in the Phase0 case WORK_DONE_STEP_1
  156. //
  157. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase0Table2[AcpiPowerRequestMaximum+1] = {
  158. ACPIDevicePowerProcessPhase0DeviceSubPhase2,
  159. ACPIDevicePowerProcessInvalid,
  160. ACPIDevicePowerProcessInvalid,
  161. ACPIDevicePowerProcessInvalid,
  162. ACPIDevicePowerProcessInvalid,
  163. ACPIDevicePowerProcessInvalid
  164. };
  165. //
  166. // This is the dispatch table for Phase 0
  167. //
  168. PACPI_POWER_FUNCTION *AcpiDevicePowerProcessPhase0Dispatch[] = {
  169. NULL,
  170. NULL,
  171. NULL,
  172. AcpiDevicePowerProcessPhase0Table1,
  173. AcpiDevicePowerProcessPhase0Table2
  174. };
  175. //
  176. // This is the table used to map functions in the Phase1 case WORK_DONE_STEP_0
  177. //
  178. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase1Table1[AcpiPowerRequestMaximum+1] = {
  179. ACPIDevicePowerProcessPhase1DeviceSubPhase1,
  180. ACPIDevicePowerProcessForward,
  181. ACPIDevicePowerProcessForward,
  182. ACPIDevicePowerProcessForward,
  183. ACPIDevicePowerProcessForward,
  184. ACPIDevicePowerProcessInvalid
  185. };
  186. //
  187. // This is the table used to map functions in the Phase1 case WORK_DONE_STEP_1
  188. //
  189. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase1Table2[AcpiPowerRequestMaximum+1] = {
  190. ACPIDevicePowerProcessPhase1DeviceSubPhase2,
  191. ACPIDevicePowerProcessInvalid,
  192. ACPIDevicePowerProcessInvalid,
  193. ACPIDevicePowerProcessInvalid,
  194. ACPIDevicePowerProcessInvalid,
  195. ACPIDevicePowerProcessInvalid
  196. };
  197. //
  198. // This is the table used to map functions in the Phase1 case WORK_DONE_STEP_2
  199. //
  200. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase1Table3[AcpiPowerRequestMaximum+1] = {
  201. ACPIDevicePowerProcessPhase1DeviceSubPhase3,
  202. ACPIDevicePowerProcessInvalid,
  203. ACPIDevicePowerProcessInvalid,
  204. ACPIDevicePowerProcessInvalid,
  205. ACPIDevicePowerProcessInvalid,
  206. ACPIDevicePowerProcessInvalid
  207. };
  208. //
  209. // This is the table used to map functions in the Phase1 case WORK_DONE_STEP_3
  210. //
  211. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase1Table4[AcpiPowerRequestMaximum+1] = {
  212. ACPIDevicePowerProcessPhase1DeviceSubPhase4,
  213. ACPIDevicePowerProcessInvalid,
  214. ACPIDevicePowerProcessInvalid,
  215. ACPIDevicePowerProcessInvalid,
  216. ACPIDevicePowerProcessInvalid,
  217. ACPIDevicePowerProcessInvalid
  218. };
  219. //
  220. // This is the dispatch table for Phase 1
  221. //
  222. PACPI_POWER_FUNCTION *AcpiDevicePowerProcessPhase1Dispatch[] = {
  223. NULL,
  224. NULL,
  225. NULL,
  226. AcpiDevicePowerProcessPhase1Table1,
  227. AcpiDevicePowerProcessPhase1Table2,
  228. AcpiDevicePowerProcessPhase1Table3,
  229. AcpiDevicePowerProcessPhase1Table4
  230. };
  231. //
  232. // This is the table used to map functions in the Phase2 case WORK_DONE_STEP_0
  233. //
  234. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase2Table1[AcpiPowerRequestMaximum+1] = {
  235. ACPIDevicePowerProcessForward,
  236. ACPIDevicePowerProcessPhase2SystemSubPhase1,
  237. ACPIDevicePowerProcessForward,
  238. ACPIDevicePowerProcessForward,
  239. ACPIDevicePowerProcessForward,
  240. ACPIDevicePowerProcessInvalid
  241. };
  242. //
  243. // This is the table used to map functions in the Phase2 case WORK_DONE_STEP_1
  244. //
  245. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase2Table2[AcpiPowerRequestMaximum+1] = {
  246. ACPIDevicePowerProcessInvalid,
  247. ACPIDevicePowerProcessPhase2SystemSubPhase2,
  248. ACPIDevicePowerProcessInvalid,
  249. ACPIDevicePowerProcessInvalid,
  250. ACPIDevicePowerProcessInvalid,
  251. ACPIDevicePowerProcessInvalid
  252. };
  253. //
  254. // This is the table used to map functions in the Phase3 case WORK_DONE_STEP_2
  255. //
  256. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase2Table3[AcpiPowerRequestMaximum+1] = {
  257. ACPIDevicePowerProcessInvalid,
  258. ACPIDevicePowerProcessPhase2SystemSubPhase3,
  259. ACPIDevicePowerProcessInvalid,
  260. ACPIDevicePowerProcessInvalid,
  261. ACPIDevicePowerProcessInvalid,
  262. ACPIDevicePowerProcessInvalid
  263. };
  264. //
  265. // This is the dispatch table for Phase 2
  266. //
  267. PACPI_POWER_FUNCTION *AcpiDevicePowerProcessPhase2Dispatch[] = {
  268. NULL,
  269. NULL,
  270. NULL,
  271. AcpiDevicePowerProcessPhase2Table1,
  272. AcpiDevicePowerProcessPhase2Table2,
  273. AcpiDevicePowerProcessPhase2Table3
  274. };
  275. //
  276. // This is the table used to map functions in the Phase5 case WORK_DONE_STEP_0
  277. //
  278. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase5Table1[AcpiPowerRequestMaximum+1] = {
  279. ACPIDevicePowerProcessPhase5DeviceSubPhase1,
  280. ACPIDevicePowerProcessPhase5SystemSubPhase1,
  281. ACPIDevicePowerProcessForward,
  282. ACPIDevicePowerProcessPhase5WarmEjectSubPhase1,
  283. ACPIDevicePowerProcessForward,
  284. ACPIDevicePowerProcessInvalid
  285. };
  286. //
  287. // This is the table used to map functions in the Phase 5 case WORK_DONE_STEP_1
  288. //
  289. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase5Table2[AcpiPowerRequestMaximum+1] = {
  290. ACPIDevicePowerProcessPhase5DeviceSubPhase2,
  291. ACPIDevicePowerProcessPhase5SystemSubPhase2,
  292. ACPIDevicePowerProcessInvalid,
  293. ACPIDevicePowerProcessPhase5WarmEjectSubPhase2,
  294. ACPIDevicePowerProcessInvalid,
  295. ACPIDevicePowerProcessInvalid
  296. };
  297. //
  298. // This is the table used to map functions in the Phase 5 case WORK_DONE_STEP_2
  299. //
  300. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase5Table3[AcpiPowerRequestMaximum+1] = {
  301. ACPIDevicePowerProcessPhase5DeviceSubPhase3,
  302. ACPIDevicePowerProcessPhase5SystemSubPhase3,
  303. ACPIDevicePowerProcessInvalid,
  304. ACPIDevicePowerProcessInvalid,
  305. ACPIDevicePowerProcessInvalid,
  306. ACPIDevicePowerProcessInvalid
  307. };
  308. //
  309. // This is the table used to map functions in the Phase 5 case WORK_DONE_STEP_3
  310. //
  311. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase5Table4[AcpiPowerRequestMaximum+1] = {
  312. ACPIDevicePowerProcessPhase5DeviceSubPhase4,
  313. ACPIDevicePowerProcessPhase5SystemSubPhase4,
  314. ACPIDevicePowerProcessInvalid,
  315. ACPIDevicePowerProcessInvalid,
  316. ACPIDevicePowerProcessInvalid,
  317. ACPIDevicePowerProcessInvalid
  318. };
  319. //
  320. // This is the table used to map functions in the Phase 5 case WORK_DONE_STEP_4
  321. //
  322. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase5Table5[AcpiPowerRequestMaximum+1] = {
  323. ACPIDevicePowerProcessPhase5DeviceSubPhase5,
  324. ACPIDevicePowerProcessInvalid,
  325. ACPIDevicePowerProcessInvalid,
  326. ACPIDevicePowerProcessInvalid,
  327. ACPIDevicePowerProcessInvalid,
  328. ACPIDevicePowerProcessInvalid
  329. };
  330. //
  331. // This is the table used to map functions in the Phase 5 case WORK_DONE_STEP_5
  332. //
  333. PACPI_POWER_FUNCTION AcpiDevicePowerProcessPhase5Table6[AcpiPowerRequestMaximum+1] = {
  334. ACPIDevicePowerProcessPhase5DeviceSubPhase6,
  335. ACPIDevicePowerProcessInvalid,
  336. ACPIDevicePowerProcessInvalid,
  337. ACPIDevicePowerProcessInvalid,
  338. ACPIDevicePowerProcessInvalid,
  339. ACPIDevicePowerProcessInvalid
  340. };
  341. //
  342. // This is the dispatch table for Phase 5
  343. //
  344. PACPI_POWER_FUNCTION *AcpiDevicePowerProcessPhase5Dispatch[] = {
  345. NULL,
  346. NULL,
  347. NULL,
  348. AcpiDevicePowerProcessPhase5Table1,
  349. AcpiDevicePowerProcessPhase5Table2,
  350. AcpiDevicePowerProcessPhase5Table3,
  351. AcpiDevicePowerProcessPhase5Table4,
  352. AcpiDevicePowerProcessPhase5Table5,
  353. AcpiDevicePowerProcessPhase5Table6
  354. };
  355. #ifdef ALLOC_PRAGMA
  356. #pragma alloc_text(PAGE,ACPIDevicePowerDetermineSupportedDeviceStates)
  357. #endif
  358. VOID
  359. ACPIDeviceCancelWaitWakeIrp(
  360. IN PDEVICE_OBJECT DeviceObject,
  361. IN PIRP Irp
  362. )
  363. /*++
  364. Routine Description:
  365. This routine is called when the system wants to cancel any pending
  366. WaitWake Irps
  367. Note: This routine is called at DPC level
  368. Arguments:
  369. DeviceObject - The target device for which the irp was sent to
  370. Irp - The irp to be cancelled
  371. Return Value:
  372. None
  373. --*/
  374. {
  375. NTSTATUS status;
  376. PACPI_POWER_CALLBACK callBack;
  377. PACPI_POWER_REQUEST powerRequest;
  378. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  379. PLIST_ENTRY listEntry;
  380. PVOID context;
  381. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL);
  382. //
  383. // Let the world know that we are getting a cancel routine
  384. //
  385. ACPIDevPrint( (
  386. ACPI_PRINT_WARNING,
  387. deviceExtension,
  388. "(0x%08lx): ACPIDeviceCancelWaitWakeIrp - Start\n",
  389. Irp
  390. ) );
  391. //
  392. // We need to grab the lock so that we look for the irp in the lists
  393. // of pending WaitWake events. The cancel lock is already acquired
  394. //
  395. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  396. //
  397. // Walk the list, looking for the Irp in question
  398. //
  399. listEntry = AcpiPowerWaitWakeList.Flink;
  400. while (listEntry != &AcpiPowerWaitWakeList) {
  401. //
  402. // Crack the record, and get ready to look at the next item
  403. //
  404. powerRequest = CONTAINING_RECORD(
  405. listEntry,
  406. ACPI_POWER_REQUEST,
  407. ListEntry
  408. );
  409. //
  410. // Does the power request match the current target? We also know that
  411. // for WaitWake requests, the context poitns to the Irp, so we make
  412. // sure that those match as well.
  413. //
  414. if (powerRequest->DeviceExtension != deviceExtension ||
  415. (PIRP) powerRequest->Context != Irp ) {
  416. listEntry = listEntry->Flink;
  417. continue;
  418. }
  419. ACPIDevPrint( (
  420. ACPI_PRINT_POWER,
  421. deviceExtension,
  422. "(0x%08lx): ACPIDeviceCancelWaitWakeIrp - Match 0x%08lx\n",
  423. Irp,
  424. powerRequest
  425. ) );
  426. //
  427. // Remove the request from the WaitWakeList
  428. //
  429. RemoveEntryList( listEntry );
  430. //
  431. // Rebuild the GPE mask
  432. //
  433. ACPIWakeRemoveDevicesAndUpdate( NULL, NULL );
  434. //
  435. // Grab whatever information we feel we need from the request
  436. //
  437. powerRequest->Status = STATUS_CANCELLED;
  438. callBack = powerRequest->CallBack;
  439. context = powerRequest->Context;
  440. //
  441. // Release the power spinlock and the Cancel spinlock
  442. //
  443. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  444. IoReleaseCancelSpinLock( Irp->CancelIrql );
  445. //
  446. // Call the completion routine
  447. //
  448. (*callBack)(
  449. deviceExtension,
  450. Irp,
  451. STATUS_CANCELLED
  452. );
  453. //
  454. // Disable the device --- the CallBack *must* be invoked by this
  455. // routine, so we don't need to do it ourselves
  456. //
  457. status = ACPIWakeEnableDisableAsync(
  458. deviceExtension,
  459. FALSE,
  460. ACPIDeviceCancelWaitWakeIrpCallBack,
  461. powerRequest
  462. );
  463. //
  464. // We are done, so we can return now
  465. //
  466. return;
  467. } // while (listEntry != &AcpiPowerWaitWakeList)
  468. //
  469. // In this case, the irp isn't in our queue. Display and assert for
  470. // now
  471. //
  472. ACPIDevPrint( (
  473. ACPI_PRINT_WARNING,
  474. deviceExtension,
  475. "(0x%08lx): ACPIDeviceCancelWaitWakeIrp - Not Found!\n",
  476. Irp
  477. ) );
  478. //
  479. // We really shouldn't fall to this point,
  480. //
  481. ASSERT( FALSE );
  482. //
  483. // Release the spinlocks
  484. //
  485. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  486. IoReleaseCancelSpinLock( Irp->CancelIrql );
  487. }
  488. VOID EXPORT
  489. ACPIDeviceCancelWaitWakeIrpCallBack(
  490. IN PNSOBJ AcpiObject,
  491. IN NTSTATUS Status,
  492. IN POBJDATA ObjectData,
  493. IN PVOID Context
  494. )
  495. /*++
  496. Routine Description:
  497. This routine is called after _PSW(Off) has been run as part of the
  498. task of cancelling the irp. This routine is here so that we can free
  499. the request and to allow us to keep track of things
  500. Arguments:
  501. AcpiObject - Points to the control method that was run
  502. Status - Result of the method
  503. ObjectData - Information about the result
  504. Context - ACPI_POWER_REQUEST
  505. Return Value:
  506. NTSTATUS
  507. --*/
  508. {
  509. PACPI_POWER_REQUEST powerRequest = (PACPI_POWER_REQUEST) Context;
  510. PDEVICE_EXTENSION deviceExtension = powerRequest->DeviceExtension;
  511. ACPIDevPrint( (
  512. ACPI_PRINT_POWER,
  513. deviceExtension,
  514. "ACPIDeviceCancelWaitWakeIrpCallBack = 0x%08lx\n",
  515. Status
  516. ) );
  517. //
  518. // free the request
  519. //
  520. ExFreeToNPagedLookasideList(
  521. &RequestLookAsideList,
  522. powerRequest
  523. );
  524. }
  525. VOID
  526. ACPIDeviceCompleteCommon(
  527. IN PULONG OldWorkDone,
  528. IN ULONG NewWorkDone
  529. )
  530. /*++
  531. Routine Description:
  532. Since the completion routines all have to do some bit of common work
  533. to get the DPC firing again, this routine reduces the code duplication
  534. Arguments:
  535. OldWorkDone - Pointer to the old work done
  536. NewWorkDone - The new amount of work that has been completed
  537. NOTENOTE: There is an implicit assumption that the current value of
  538. WorkDone in the request is WORK_DONE_PENDING
  539. Return Value:
  540. None
  541. --*/
  542. {
  543. KIRQL oldIrql;
  544. //
  545. // Mark the request as being complete
  546. //
  547. InterlockedCompareExchange(
  548. OldWorkDone,
  549. NewWorkDone,
  550. WORK_DONE_PENDING
  551. );
  552. //
  553. // We need this lock to look at the following variables
  554. //
  555. KeAcquireSpinLock( &AcpiPowerQueueLock, &oldIrql );
  556. //
  557. // No matter what, work was done
  558. //
  559. AcpiPowerWorkDone = TRUE;
  560. //
  561. // Is the DPC already running?
  562. //
  563. if (!AcpiPowerDpcRunning) {
  564. //
  565. // Better make sure it does then
  566. //
  567. KeInsertQueueDpc( &AcpiPowerDpc, 0, 0 );
  568. }
  569. //
  570. // Done with the lock
  571. //
  572. KeReleaseSpinLock( &AcpiPowerQueueLock, oldIrql );
  573. }
  574. VOID EXPORT
  575. ACPIDeviceCompleteGenericPhase(
  576. IN PNSOBJ AcpiObject,
  577. IN NTSTATUS Status,
  578. IN POBJDATA ObjectData,
  579. IN PVOID Context
  580. )
  581. /*++
  582. Routine Description:
  583. This is the generic completion handler. If the interpreter has
  584. successfully executed the method, it completes the request to the
  585. next desired WORK_DONE, otherwise it fails the request.
  586. Arguments:
  587. AcpiObject - Points to the control method that was run
  588. Status - Result of the method
  589. ObjectData - Information about the result
  590. Context - ACPI_POWER_REQUEST
  591. Return Value:
  592. NTSTATUS
  593. --*/
  594. {
  595. DEVICE_POWER_STATE deviceState;
  596. PACPI_POWER_REQUEST powerRequest = (PACPI_POWER_REQUEST) Context;
  597. PDEVICE_EXTENSION deviceExtension = powerRequest->DeviceExtension;
  598. UNREFERENCED_PARAMETER( AcpiObject );
  599. UNREFERENCED_PARAMETER( ObjectData );
  600. ACPIDevPrint( (
  601. ACPI_PRINT_POWER,
  602. deviceExtension,
  603. "ACPIDeviceCompleteGenericPhase = 0x%08lx\n",
  604. Status
  605. ) );
  606. //
  607. // Decide what state we should transition to next
  608. //
  609. if (!NT_SUCCESS(Status)) {
  610. //
  611. // Then complete the request as failed
  612. //
  613. powerRequest->Status = Status;
  614. ACPIDeviceCompleteCommon( &(powerRequest->WorkDone), WORK_DONE_FAILURE);
  615. } else {
  616. //
  617. // Get ready to go the next stage
  618. //
  619. ACPIDeviceCompleteCommon(
  620. &(powerRequest->WorkDone),
  621. powerRequest->NextWorkDone
  622. );
  623. }
  624. }
  625. VOID EXPORT
  626. ACPIDeviceCompleteInterpreterRequest(
  627. IN PVOID Context
  628. )
  629. /*++
  630. Routine Description:
  631. This routine is called after the interpreter has flushed its queue and
  632. marked itself as no longer accepting requests.
  633. Arguments:
  634. Context - The context we told the interpreter to pass back to us
  635. Return Value:
  636. None
  637. --*/
  638. {
  639. //
  640. // This is just a wrapper for CompleteRequest (because the interpreter
  641. // used different callbacks in this case)
  642. //
  643. ACPIDeviceCompleteGenericPhase(
  644. NULL,
  645. STATUS_SUCCESS,
  646. NULL,
  647. Context
  648. );
  649. }
  650. VOID EXPORT
  651. ACPIDeviceCompletePhase3Off(
  652. IN PNSOBJ AcpiObject,
  653. IN NTSTATUS Status,
  654. IN POBJDATA ObjectData,
  655. IN PVOID Context
  656. )
  657. /*++
  658. Routine Description:
  659. This routine is called after _OFF has been run on a Power Resource
  660. Arguments:
  661. AcpiObject - Points to the control method that was run
  662. Status - Result of the method
  663. ObjectData - Information about the result
  664. Context - ACPI_POWER_DEVICE_NODE
  665. Return Value:
  666. NTSTATUS
  667. --*/
  668. {
  669. KIRQL oldIrql;
  670. PACPI_POWER_DEVICE_NODE powerNode = (PACPI_POWER_DEVICE_NODE) Context;
  671. UNREFERENCED_PARAMETER( AcpiObject );
  672. UNREFERENCED_PARAMETER( ObjectData );
  673. UNREFERENCED_PARAMETER( Status );
  674. ACPIPrint( (
  675. ACPI_PRINT_POWER,
  676. "ACPIDeviceCompletePhase3Off: PowerNode: 0x%08lx OFF = 0x%08lx\n",
  677. powerNode,
  678. Status
  679. ) );
  680. //
  681. // We need a spin lock for this
  682. //
  683. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  684. //
  685. // First step is to set the new flags for the node
  686. //
  687. if (NT_SUCCESS(Status)) {
  688. ACPIInternalUpdateFlags( &(powerNode->Flags), DEVICE_NODE_ON, TRUE );
  689. } else {
  690. ACPIInternalUpdateFlags( &(powerNode->Flags), DEVICE_NODE_FAIL, FALSE );
  691. }
  692. //
  693. // We can give up the lock now
  694. //
  695. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  696. //
  697. // Done
  698. //
  699. ACPIDeviceCompleteCommon( &(powerNode->WorkDone), WORK_DONE_COMPLETE );
  700. }
  701. VOID EXPORT
  702. ACPIDeviceCompletePhase3On(
  703. IN PNSOBJ AcpiObject,
  704. IN NTSTATUS Status,
  705. IN POBJDATA ObjectData,
  706. IN PVOID Context
  707. )
  708. /*++
  709. Routine Description:
  710. This routine is called after _ON has been run on a Power Resource
  711. Arguments:
  712. AcpiObject - Points to the control method that was run
  713. Status - Result of the method
  714. ObjectData - Information about the result
  715. Context - ACPI_POWER_DEVICE_NODE
  716. Return Value:
  717. NTSTATUS
  718. --*/
  719. {
  720. KIRQL oldIrql;
  721. PACPI_POWER_DEVICE_NODE powerNode = (PACPI_POWER_DEVICE_NODE) Context;
  722. UNREFERENCED_PARAMETER( AcpiObject );
  723. UNREFERENCED_PARAMETER( ObjectData );
  724. UNREFERENCED_PARAMETER( Status );
  725. ACPIPrint( (
  726. ACPI_PRINT_POWER,
  727. "ACPIDeviceCompletePhase3On: PowerNode: 0x%08lx ON = 0x%08lx\n",
  728. powerNode,
  729. Status
  730. ) );
  731. //
  732. // We need a spin lock for this
  733. //
  734. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  735. //
  736. // First step is to set the new flags for the node
  737. //
  738. if (NT_SUCCESS(Status)) {
  739. ACPIInternalUpdateFlags( &(powerNode->Flags), DEVICE_NODE_ON, FALSE );
  740. } else {
  741. ACPIInternalUpdateFlags( &(powerNode->Flags), DEVICE_NODE_FAIL, FALSE );
  742. }
  743. //
  744. // We can give up the lock now
  745. //
  746. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  747. //
  748. // Done
  749. //
  750. ACPIDeviceCompleteCommon( &(powerNode->WorkDone), WORK_DONE_COMPLETE );
  751. }
  752. VOID
  753. ACPIDeviceCompleteRequest(
  754. IN PACPI_POWER_REQUEST PowerRequest
  755. )
  756. /*++
  757. Routine Description:
  758. This routine invokes the callbacks on a given PowerRequest, dequeues the
  759. request from any list that it is on, and does any other post-processing
  760. that is required.
  761. Note: this is where *all* of the various special handling should be done.
  762. A prime example of something that should be done here is that we want
  763. to return STATUS_SUCCESS to any Dx irp that are more off
  764. Arguments:
  765. None used
  766. Return:
  767. Void
  768. --*/
  769. {
  770. KIRQL oldIrql;
  771. PACPI_POWER_CALLBACK callBack = PowerRequest->CallBack;
  772. PACPI_POWER_REQUEST nextRequest;
  773. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  774. ACPIDevPrint( (
  775. ACPI_PRINT_POWER,
  776. deviceExtension,
  777. "(0x%08lx): ACPIDeviceCompleteRequest = 0x%08lx\n",
  778. PowerRequest,
  779. PowerRequest->Status
  780. ) );
  781. if (PowerRequest->RequestType == AcpiPowerRequestDevice ) {
  782. if (deviceExtension->PowerInfo.PowerState != PowerDeviceUnspecified) {
  783. DEVICE_POWER_STATE deviceState;
  784. //
  785. // If this is the first time we have seen the request, and it
  786. // is a failure, then we should undo whatever it was we did
  787. //
  788. if (PowerRequest->FailedOnce == FALSE &&
  789. !NT_SUCCESS(PowerRequest->Status) ) {
  790. //
  791. // Grab the queue Lock
  792. //
  793. KeAcquireSpinLock( &AcpiPowerQueueLock, &oldIrql );
  794. //
  795. // Transition back to the previous state
  796. //
  797. PowerRequest->u.DevicePowerRequest.DevicePowerState =
  798. deviceExtension->PowerInfo.PowerState;
  799. PowerRequest->FailedOnce = TRUE;
  800. //
  801. // Remove the Request from the current list
  802. //
  803. RemoveEntryList( &(PowerRequest->ListEntry) );
  804. //
  805. // Insert the request back in the Phase0 list
  806. //
  807. InsertTailList(
  808. &(AcpiPowerQueueList),
  809. &(PowerRequest->ListEntry)
  810. );
  811. //
  812. // Work was done --- we reinserted the request into the queues
  813. //
  814. AcpiPowerWorkDone = TRUE;
  815. //
  816. // Make sure that the dpc is running, start it if neccessary.
  817. //
  818. if ( !AcpiPowerDpcRunning ) {
  819. KeInsertQueueDpc( &AcpiPowerDpc, NULL, NULL );
  820. }
  821. //
  822. // Done with the queue lock
  823. //
  824. KeReleaseSpinLock( &AcpiPowerQueueLock, oldIrql );
  825. //
  826. // we cannot continue
  827. //
  828. return;
  829. }
  830. //
  831. // Are we turning the device more off?
  832. //
  833. deviceState = PowerRequest->u.DevicePowerRequest.DevicePowerState;
  834. if (deviceExtension->PowerInfo.PowerState < deviceState ) {
  835. //
  836. // Yes, then no matter what, we succeeded
  837. //
  838. PowerRequest->Status = STATUS_SUCCESS;
  839. }
  840. }
  841. }
  842. //
  843. // Invoke the callback, if there is any
  844. //
  845. if (callBack != NULL) {
  846. (*callBack)(
  847. deviceExtension,
  848. PowerRequest->Context,
  849. PowerRequest->Status
  850. );
  851. }
  852. //
  853. // Grab the queue Lock
  854. //
  855. KeAcquireSpinLock( &AcpiPowerQueueLock, &oldIrql );
  856. //
  857. // Remove the Request from all lists
  858. //
  859. RemoveEntryList( &(PowerRequest->ListEntry) );
  860. RemoveEntryList( &(PowerRequest->SerialListEntry) );
  861. //
  862. // Should we queue up another request?
  863. //
  864. if (!IsListEmpty( &(deviceExtension->PowerInfo.PowerRequestListEntry) ) ) {
  865. //
  866. // No? Then make sure that the request gets processed
  867. //
  868. nextRequest = CONTAINING_RECORD(
  869. deviceExtension->PowerInfo.PowerRequestListEntry.Flink,
  870. ACPI_POWER_REQUEST,
  871. SerialListEntry
  872. );
  873. InsertTailList(
  874. &(AcpiPowerQueueList),
  875. &(nextRequest->ListEntry)
  876. );
  877. //
  878. // Remember this as the current request
  879. //
  880. deviceExtension->PowerInfo.CurrentPowerRequest = nextRequest;
  881. } else {
  882. deviceExtension->PowerInfo.CurrentPowerRequest = NULL;
  883. }
  884. //
  885. // Done with the queue lock
  886. //
  887. KeReleaseSpinLock( &AcpiPowerQueueLock, oldIrql );
  888. //
  889. // Free the allocate memory
  890. //
  891. ExFreeToNPagedLookasideList(
  892. &RequestLookAsideList,
  893. PowerRequest
  894. );
  895. }
  896. NTSTATUS
  897. ACPIDeviceInitializePowerRequest(
  898. IN PDEVICE_EXTENSION DeviceExtension,
  899. IN POWER_STATE Power,
  900. IN PACPI_POWER_CALLBACK CallBack,
  901. IN PVOID CallBackContext,
  902. IN POWER_ACTION PowerAction,
  903. IN ACPI_POWER_REQUEST_TYPE RequestType,
  904. IN ULONG Flags
  905. )
  906. /*++
  907. Routine Description:
  908. This is the actual worker function that fills in a PowerRequest
  909. Arguments:
  910. DeviceExtension - Target device
  911. PowerState - Target S or D state
  912. CallBack - routine to call when done
  913. CallBackContext - context to pass when done
  914. PowerAction - The reason we are doing this
  915. RequestType - What kind of request we are looking at
  916. Flags - Some flags that will let us control the behavior more
  917. Return Value:
  918. NTSTATUS
  919. --*/
  920. {
  921. KIRQL oldIrql;
  922. PACPI_POWER_REQUEST powerRequest;
  923. //
  924. // Allocate a powerRequest structure
  925. //
  926. powerRequest = ExAllocateFromNPagedLookasideList(
  927. &RequestLookAsideList
  928. );
  929. if (powerRequest == NULL) {
  930. //
  931. // Call the completion routine
  932. //
  933. if (*CallBack != NULL) {
  934. (*CallBack)(
  935. DeviceExtension,
  936. CallBackContext,
  937. STATUS_INSUFFICIENT_RESOURCES
  938. );
  939. }
  940. return STATUS_INSUFFICIENT_RESOURCES;
  941. }
  942. //
  943. // Fill in the common parts of the structure powerRequest structure
  944. //
  945. RtlZeroMemory( powerRequest, sizeof(ACPI_POWER_REQUEST) );
  946. powerRequest->Signature = ACPI_SIGNATURE;
  947. powerRequest->CallBack = CallBack;
  948. powerRequest->Context = CallBackContext;
  949. powerRequest->DeviceExtension = DeviceExtension;
  950. powerRequest->WorkDone = WORK_DONE_STEP_0;
  951. powerRequest->Status = STATUS_SUCCESS;
  952. powerRequest->RequestType = RequestType;
  953. InitializeListHead( &(powerRequest->ListEntry) );
  954. InitializeListHead( &(powerRequest->SerialListEntry) );
  955. //
  956. // At this point, we need the spinlock
  957. //
  958. KeAcquireSpinLock( &AcpiPowerQueueLock, &oldIrql );
  959. //
  960. // Fill in the request specific parts of the structure
  961. //
  962. switch (RequestType) {
  963. case AcpiPowerRequestDevice: {
  964. ULONG count;
  965. count = InterlockedCompareExchange( &(DeviceExtension->HibernatePathCount), 0, 0);
  966. if (count) {
  967. //
  968. // If we are on the hibernate path, then special rules apply
  969. // We need to basically lock down all the power resources on the
  970. // device.
  971. //
  972. if (PowerAction == PowerActionHibernate &&
  973. Power.DeviceState == PowerDeviceD3) {
  974. Flags |= DEVICE_REQUEST_LOCK_HIBER;
  975. } else if (PowerAction != PowerActionHibernate &&
  976. Power.DeviceState == PowerDeviceD0) {
  977. Flags |= DEVICE_REQUEST_UNLOCK_HIBER;
  978. }
  979. }
  980. powerRequest->u.DevicePowerRequest.DevicePowerState = Power.DeviceState;
  981. powerRequest->u.DevicePowerRequest.Flags = Flags;
  982. //
  983. // If the transition is *to* a lower Dx state, then we need to run
  984. // the function that lets the system that we are about to do this work
  985. //
  986. if (Power.DeviceState > DeviceExtension->PowerInfo.PowerState &&
  987. DeviceExtension->DeviceObject != NULL) {
  988. PoSetPowerState(
  989. DeviceExtension->DeviceObject,
  990. DevicePowerState,
  991. Power
  992. );
  993. }
  994. break;
  995. }
  996. case AcpiPowerRequestWaitWake: {
  997. NTSTATUS status;
  998. powerRequest->u.WaitWakeRequest.SystemPowerState = Power.SystemState;
  999. powerRequest->u.WaitWakeRequest.Flags = Flags;
  1000. //
  1001. // Release the spinlock --- no longer required, enable the wakeup for the
  1002. // device and return
  1003. //
  1004. KeReleaseSpinLock( &AcpiPowerQueueLock, oldIrql );
  1005. status = ACPIWakeEnableDisableAsync(
  1006. DeviceExtension,
  1007. TRUE,
  1008. ACPIDeviceIrpWaitWakeRequestPending,
  1009. powerRequest
  1010. );
  1011. if (status == STATUS_PENDING) {
  1012. status = STATUS_MORE_PROCESSING_REQUIRED;
  1013. }
  1014. return status;
  1015. }
  1016. case AcpiPowerRequestSystem:
  1017. powerRequest->u.SystemPowerRequest.SystemPowerState = Power.SystemState;
  1018. powerRequest->u.SystemPowerRequest.SystemPowerAction = PowerAction;
  1019. break;
  1020. case AcpiPowerRequestWarmEject:
  1021. powerRequest->u.EjectPowerRequest.EjectPowerState = Power.SystemState;
  1022. powerRequest->u.EjectPowerRequest.Flags = Flags;
  1023. break;
  1024. case AcpiPowerRequestSynchronize:
  1025. powerRequest->u.SynchronizePowerRequest.Flags = Flags;
  1026. break;
  1027. }
  1028. //
  1029. // Should we even queue the request?
  1030. //
  1031. if (Flags & DEVICE_REQUEST_NO_QUEUE) {
  1032. goto ACPIDeviceInitializePowerRequestExit;
  1033. }
  1034. //
  1035. // Add the request to the right place in the lists. Note that this function
  1036. // must be called with the PowerQueueLock being held.
  1037. //
  1038. ACPIDeviceInternalQueueRequest(
  1039. DeviceExtension,
  1040. powerRequest,
  1041. Flags
  1042. );
  1043. ACPIDeviceInitializePowerRequestExit:
  1044. //
  1045. // Done with the spinlock
  1046. //
  1047. KeReleaseSpinLock( &AcpiPowerQueueLock, oldIrql );
  1048. //
  1049. // The request will not be completed immediately. Note that we return
  1050. // MORE_PROCESSING requird just in case this routine was called within
  1051. // the context of a completion routine. It is the caller's responsibility
  1052. // to turn this into a STATUS_PENDING
  1053. //
  1054. return STATUS_MORE_PROCESSING_REQUIRED;
  1055. }
  1056. NTSTATUS
  1057. ACPIDeviceInternalDelayedDeviceRequest(
  1058. IN PDEVICE_EXTENSION DeviceExtension,
  1059. IN DEVICE_POWER_STATE DeviceState,
  1060. IN PACPI_POWER_CALLBACK CallBack,
  1061. IN PVOID CallBackContext
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This routine is called when a device extension wants to transition to
  1066. another Device State. This one differs from the
  1067. ACPIDeviceInternalDeviceRequest function in that the queue is only emptied
  1068. by the build device DPC when it has flushed the device list
  1069. Arguments:
  1070. DeviceExtension - The device which wants to transition
  1071. DeviceState - What the desired target state is
  1072. CallBack - The function to call when done
  1073. CallBackContext - The argument to pass to that function
  1074. Return Value:
  1075. NTSTATUS
  1076. --*/
  1077. {
  1078. NTSTATUS status;
  1079. POWER_STATE powerState;
  1080. //
  1081. // Let the user know what is going on
  1082. //
  1083. ACPIDevPrint( (
  1084. ACPI_PRINT_POWER,
  1085. DeviceExtension,
  1086. "(0x%08lx): ACPIDeviceInternalDelayedDeviceRequest - "
  1087. "Transition to D%d\n",
  1088. CallBackContext,
  1089. (DeviceState - PowerDeviceD0)
  1090. ) );
  1091. //
  1092. // Cast the desired state
  1093. //
  1094. powerState.DeviceState = DeviceState;
  1095. //
  1096. // Queue the request
  1097. //
  1098. status = ACPIDeviceInitializePowerRequest(
  1099. DeviceExtension,
  1100. powerState,
  1101. CallBack,
  1102. CallBackContext,
  1103. PowerActionNone,
  1104. AcpiPowerRequestDevice,
  1105. (DEVICE_REQUEST_DELAYED | DEVICE_REQUEST_UNLOCK_DEVICE)
  1106. );
  1107. if (status == STATUS_MORE_PROCESSING_REQUIRED) {
  1108. status = STATUS_PENDING;
  1109. }
  1110. return status;
  1111. }
  1112. NTSTATUS
  1113. ACPIDeviceInternalDeviceRequest(
  1114. IN PDEVICE_EXTENSION DeviceExtension,
  1115. IN DEVICE_POWER_STATE DeviceState,
  1116. IN PACPI_POWER_CALLBACK CallBack,
  1117. IN PVOID CallBackContext,
  1118. IN ULONG Flags
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. This routine is called when a device extension wants to transition to
  1123. another Device State
  1124. Arguments:
  1125. DeviceExtension - The device which wants to transition
  1126. DeviceState - What the desired target state is
  1127. CallBack - The function to call when done
  1128. CallBackContext - The argument to pass to that function
  1129. Flags - Flags (lock, unlock, etc)
  1130. Return Value:
  1131. NTSTATUS
  1132. --*/
  1133. {
  1134. NTSTATUS status;
  1135. POWER_STATE powerState;
  1136. //
  1137. // Let the user know what is going on
  1138. //
  1139. ACPIDevPrint( (
  1140. ACPI_PRINT_POWER,
  1141. DeviceExtension,
  1142. "(0x%08lx): ACPIDeviceInternalDeviceRequest - Transition to D%d\n",
  1143. CallBackContext,
  1144. (DeviceState - PowerDeviceD0)
  1145. ) );
  1146. //
  1147. // Cast the desired state
  1148. //
  1149. powerState.DeviceState = DeviceState;
  1150. //
  1151. // Queue the request
  1152. //
  1153. status = ACPIDeviceInitializePowerRequest(
  1154. DeviceExtension,
  1155. powerState,
  1156. CallBack,
  1157. CallBackContext,
  1158. PowerActionNone,
  1159. AcpiPowerRequestDevice,
  1160. Flags
  1161. );
  1162. if (status == STATUS_MORE_PROCESSING_REQUIRED) {
  1163. status = STATUS_PENDING;
  1164. }
  1165. return status;
  1166. }
  1167. VOID
  1168. ACPIDeviceInternalQueueRequest(
  1169. IN PDEVICE_EXTENSION DeviceExtension,
  1170. IN PACPI_POWER_REQUEST PowerRequest,
  1171. IN ULONG Flags
  1172. )
  1173. /*++
  1174. Routine Description:
  1175. This routine is called with the AcpiPowerQueueLock being held. The routine
  1176. correctly adds the PowerRequest into the right list entries such that it
  1177. will get processed in the correct order
  1178. Arguments:
  1179. DeviceExtension - The device in question
  1180. PowerRequest - The request to queue
  1181. Flags - Useful information about the request
  1182. Return Value:
  1183. None
  1184. --*/
  1185. {
  1186. if (Flags & DEVICE_REQUEST_TO_SYNC_QUEUE) {
  1187. //
  1188. // add the request to the synchronize list
  1189. //
  1190. InsertHeadList(
  1191. &AcpiPowerSynchronizeList,
  1192. &(PowerRequest->ListEntry)
  1193. );
  1194. } else if (IsListEmpty( &(DeviceExtension->PowerInfo.PowerRequestListEntry) ) ) {
  1195. //
  1196. // We are going to add the request to both the device's serial list and
  1197. // the main power queue.
  1198. //
  1199. InsertTailList(
  1200. &(DeviceExtension->PowerInfo.PowerRequestListEntry),
  1201. &(PowerRequest->SerialListEntry)
  1202. );
  1203. if (Flags & DEVICE_REQUEST_DELAYED) {
  1204. InsertTailList(
  1205. &(AcpiPowerDelayedQueueList),
  1206. &(PowerRequest->ListEntry)
  1207. );
  1208. } else {
  1209. InsertTailList(
  1210. &(AcpiPowerQueueList),
  1211. &(PowerRequest->ListEntry)
  1212. );
  1213. }
  1214. } else {
  1215. //
  1216. // Serialize the request
  1217. //
  1218. InsertTailList(
  1219. &(DeviceExtension->PowerInfo.PowerRequestListEntry),
  1220. &(PowerRequest->SerialListEntry)
  1221. );
  1222. }
  1223. //
  1224. // Remember that Work *was* done
  1225. //
  1226. AcpiPowerWorkDone = TRUE;
  1227. //
  1228. // Make sure that the dpc is running, if it has to
  1229. //
  1230. if (!(Flags & DEVICE_REQUEST_DELAYED) && !AcpiPowerDpcRunning ) {
  1231. KeInsertQueueDpc( &AcpiPowerDpc, NULL, NULL );
  1232. }
  1233. //
  1234. // Done
  1235. //
  1236. return;
  1237. }
  1238. NTSTATUS
  1239. ACPIDeviceInternalSynchronizeRequest(
  1240. IN PDEVICE_EXTENSION DeviceExtension,
  1241. IN PACPI_POWER_CALLBACK CallBack,
  1242. IN PVOID CallBackContext,
  1243. IN ULONG Flags
  1244. )
  1245. /*++
  1246. Routine Description:
  1247. This routine is called when a device wants to make sure that the power
  1248. dpc is empty
  1249. Arguments:
  1250. DeviceExtension - The device which wants to know
  1251. CallBack - The function to call when done
  1252. CallBackContext - The argument to pass to that function
  1253. Flags - Flags (lock, unlock, etc)
  1254. Return Value:
  1255. NTSTATUS
  1256. --*/
  1257. {
  1258. NTSTATUS status;
  1259. POWER_STATE powerState;
  1260. //
  1261. // Let the user know what is going on
  1262. //
  1263. ACPIDevPrint( (
  1264. ACPI_PRINT_POWER,
  1265. DeviceExtension,
  1266. "(0x%08lx): ACPIDeviceInternalSynchronizeRequest\n"
  1267. ) );
  1268. //
  1269. // We don't care about the state
  1270. //
  1271. powerState.DeviceState = PowerDeviceUnspecified;
  1272. //
  1273. // Queue the request
  1274. //
  1275. status = ACPIDeviceInitializePowerRequest(
  1276. DeviceExtension,
  1277. powerState,
  1278. CallBack,
  1279. CallBackContext,
  1280. PowerActionNone,
  1281. AcpiPowerRequestSynchronize,
  1282. (Flags | DEVICE_REQUEST_TO_SYNC_QUEUE)
  1283. );
  1284. if (status == STATUS_MORE_PROCESSING_REQUIRED) {
  1285. status = STATUS_PENDING;
  1286. }
  1287. return status;
  1288. }
  1289. VOID
  1290. ACPIDeviceIrpCompleteRequest(
  1291. IN PDEVICE_EXTENSION DeviceExtension,
  1292. IN PVOID Context,
  1293. IN NTSTATUS Status
  1294. )
  1295. /*++
  1296. Routine Description:
  1297. This is one of the completion routines for Irp-based device power
  1298. management requests
  1299. This routine will always complete the request with the given status.
  1300. Arguments:
  1301. DeviceExtension - Points to the DeviceExtension that was the target
  1302. Context - The Irp that was associated with the request
  1303. Status - The Result of the request
  1304. Return Value:
  1305. None
  1306. --*/
  1307. {
  1308. PIRP irp = (PIRP) Context;
  1309. LONG oldReferenceValue;
  1310. ACPIDevPrint( (
  1311. ACPI_PRINT_POWER,
  1312. DeviceExtension,
  1313. "(0x%08lx): ACPIDeviceIrpCompleteRequest = 0x%08lx\n",
  1314. irp,
  1315. Status
  1316. ) );
  1317. //
  1318. // Start the next power request
  1319. //
  1320. PoStartNextPowerIrp( irp );
  1321. //
  1322. // Mark it pending (again) because it was pending already
  1323. //
  1324. IoMarkIrpPending( irp );
  1325. //
  1326. // Complete this irp
  1327. //
  1328. irp->IoStatus.Status = Status;
  1329. IoCompleteRequest( irp, IO_NO_INCREMENT );
  1330. //
  1331. // Remove our reference
  1332. //
  1333. ACPIInternalDecrementIrpReferenceCount( DeviceExtension );
  1334. }
  1335. VOID
  1336. ACPIDeviceIrpDelayedDeviceOffRequest(
  1337. IN PDEVICE_EXTENSION DeviceExtension,
  1338. IN PVOID Context,
  1339. IN NTSTATUS Status
  1340. )
  1341. /*++
  1342. Routine Description:
  1343. This is one of the completion routines for Irp-based device power
  1344. management requests
  1345. This routine completes the irp (on failure), or forwards it to
  1346. the DeviceObject below this one (on success)
  1347. Arguments:
  1348. DeviceExtension - Points to the DeviceExtension that was the target
  1349. Context - The Irp that was associated with the request
  1350. Status - The Result of the request
  1351. Return Value:
  1352. None
  1353. --*/
  1354. {
  1355. PIRP irp = (PIRP) Context;
  1356. LONG oldReferenceValue;
  1357. ACPIDevPrint( (
  1358. ACPI_PRINT_POWER,
  1359. DeviceExtension,
  1360. "(0x%08lx): ACPIDeviceIrpDelayedDeviceOffRequest = 0x%08lx\n",
  1361. irp,
  1362. Status
  1363. ) );
  1364. if (!NT_SUCCESS(Status)) {
  1365. //
  1366. // Start the next power request
  1367. //
  1368. PoStartNextPowerIrp( irp );
  1369. //
  1370. // Complete this irp
  1371. //
  1372. irp->IoStatus.Status = Status;
  1373. IoCompleteRequest( irp, IO_NO_INCREMENT );
  1374. } else {
  1375. //
  1376. // We cannot call ForwardPowerIrp because that would blow away our
  1377. // completion routine
  1378. //
  1379. //
  1380. // Increment the OutstandingIrpCount since a completion routine
  1381. // counts for this purpose
  1382. //
  1383. InterlockedIncrement( (&DeviceExtension->OutstandingIrpCount) );
  1384. //
  1385. // Forward the power irp to target device
  1386. //
  1387. IoCopyCurrentIrpStackLocationToNext( irp );
  1388. //
  1389. // We want the completion routine to fire. We cannot call
  1390. // ACPIDispatchForwardPowerIrp here because we set this completion
  1391. // routine
  1392. //
  1393. IoSetCompletionRoutine(
  1394. irp,
  1395. ACPIDeviceIrpDeviceFilterRequest,
  1396. ACPIDeviceIrpCompleteRequest,
  1397. TRUE,
  1398. TRUE,
  1399. TRUE
  1400. );
  1401. //
  1402. // Start the next power irp
  1403. //
  1404. PoStartNextPowerIrp( irp );
  1405. //
  1406. // Let the person below us execute. Note: we can't block at
  1407. // any time within this code path.
  1408. //
  1409. ASSERT( DeviceExtension->TargetDeviceObject != NULL);
  1410. PoCallDriver( DeviceExtension->TargetDeviceObject, irp );
  1411. }
  1412. //
  1413. // Remove our reference
  1414. //
  1415. ACPIInternalDecrementIrpReferenceCount( DeviceExtension );
  1416. }
  1417. VOID
  1418. ACPIDeviceIrpDelayedDeviceOnRequest(
  1419. IN PDEVICE_EXTENSION DeviceExtension,
  1420. IN PVOID Context,
  1421. IN NTSTATUS Status
  1422. )
  1423. /*++
  1424. Routine Description:
  1425. This is one of the completion routines for Irp-based device power
  1426. management requests
  1427. This routine completes the irp (on failure), or forwards it to
  1428. the DeviceObject below this one (on success)
  1429. Arguments:
  1430. DeviceExtension - Points to the DeviceExtension that was the target
  1431. Context - The Irp that was associated with the request
  1432. Status - The Result of the request
  1433. Return Value:
  1434. None
  1435. --*/
  1436. {
  1437. PIRP irp = (PIRP) Context;
  1438. LONG oldReferenceValue;
  1439. ACPIDevPrint( (
  1440. ACPI_PRINT_POWER,
  1441. DeviceExtension,
  1442. "(0x%08lx): ACPIDeviceIrpDelayedDeviceOnRequest = 0x%08lx\n",
  1443. irp,
  1444. Status
  1445. ) );
  1446. if (!NT_SUCCESS(Status)) {
  1447. //
  1448. // Start the next power request
  1449. //
  1450. PoStartNextPowerIrp( irp );
  1451. //
  1452. // Complete this irp
  1453. //
  1454. irp->IoStatus.Status = Status;
  1455. IoCompleteRequest( irp, IO_NO_INCREMENT );
  1456. } else {
  1457. //
  1458. // We cannot call ForwardPowerIrp because that would blow away our
  1459. // completion routine
  1460. //
  1461. //
  1462. // Increment the OutstandingIrpCount since a completion routine
  1463. // counts for this purpose
  1464. //
  1465. InterlockedIncrement( (&DeviceExtension->OutstandingIrpCount) );
  1466. //
  1467. // Forward the power irp to target device
  1468. //
  1469. IoCopyCurrentIrpStackLocationToNext( irp );
  1470. //
  1471. // We want the completion routine to fire. We cannot call
  1472. // ACPIDispatchForwardPowerIrp here because we set this completion
  1473. // routine
  1474. //
  1475. IoSetCompletionRoutine(
  1476. irp,
  1477. ACPIBuildRegOnRequest,
  1478. ACPIDeviceIrpCompleteRequest,
  1479. TRUE,
  1480. TRUE,
  1481. TRUE
  1482. );
  1483. //
  1484. // Let the person below us execute. Note: we can't block at
  1485. // any time within this code path.
  1486. //
  1487. ASSERT( DeviceExtension->TargetDeviceObject != NULL);
  1488. PoCallDriver( DeviceExtension->TargetDeviceObject, irp );
  1489. }
  1490. //
  1491. // Remove our reference
  1492. //
  1493. ACPIInternalDecrementIrpReferenceCount( DeviceExtension );
  1494. }
  1495. NTSTATUS
  1496. ACPIDeviceIrpDeviceFilterRequest(
  1497. IN PDEVICE_OBJECT DeviceObject,
  1498. IN PIRP Irp,
  1499. IN PACPI_POWER_CALLBACK CallBack
  1500. )
  1501. /*++
  1502. Routine Description:
  1503. This routine is called when an Irp wishes to do D-level power management
  1504. Note: that we always pass the Irp back as the Context for the CallBack
  1505. Arguments:
  1506. DeviceObject - The target device object
  1507. Irp - The target irp
  1508. CallBack - The routine to call when done
  1509. Return Value:
  1510. NTSTATUS
  1511. --*/
  1512. {
  1513. BOOLEAN unlockDevice = FALSE;
  1514. DEVICE_POWER_STATE deviceState;
  1515. LONG oldReferenceValue;
  1516. NTSTATUS status;
  1517. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  1518. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
  1519. POWER_ACTION powerAction;
  1520. POWER_STATE powerState;
  1521. //
  1522. // Grab the requested device state
  1523. //
  1524. deviceState = irpStack->Parameters.Power.State.DeviceState;
  1525. powerAction = irpStack->Parameters.Power.ShutdownType;
  1526. //
  1527. // Let the user know what is going on
  1528. //
  1529. ACPIDevPrint( (
  1530. ACPI_PRINT_POWER,
  1531. deviceExtension,
  1532. "(0x%08lx): ACPIDeviceIrpDeviceFilterRequest - Transition to D%d\n",
  1533. Irp,
  1534. (deviceState - PowerDeviceD0)
  1535. ) );
  1536. //
  1537. // Do we need to mark the irp as pending?
  1538. //
  1539. if (Irp->PendingReturned) {
  1540. IoMarkIrpPending( Irp );
  1541. }
  1542. //
  1543. // Lets us look at the current status code for the request. On error,
  1544. // we cannot call a completion routine because we would complete the
  1545. // irp at that point. Double-completing an irp is bad.
  1546. //
  1547. status = Irp->IoStatus.Status;
  1548. if (!NT_SUCCESS(status)) {
  1549. //
  1550. // Remove our reference
  1551. //
  1552. ACPIInternalDecrementIrpReferenceCount( deviceExtension );
  1553. return status;
  1554. }
  1555. //
  1556. // Cast the desired state
  1557. //
  1558. powerState.DeviceState = deviceState;
  1559. #if defined(ACPI_INTERNAL_LOCKING)
  1560. //
  1561. // Determine if we should unlock the device
  1562. //
  1563. if (powerAction == PowerActionShutdown ||
  1564. powerAction == PowerActionShutdownReset ||
  1565. powerAction == PowerActionShutdownOff) {
  1566. unlockDevice = TRUE;
  1567. }
  1568. #endif
  1569. //
  1570. // Queue the request --- this function will always return
  1571. // MORE_PROCESSING_REQUIRED instead of PENDING, so we don't have
  1572. // to mess with it
  1573. //
  1574. status = ACPIDeviceInitializePowerRequest(
  1575. deviceExtension,
  1576. powerState,
  1577. CallBack,
  1578. Irp,
  1579. powerAction,
  1580. AcpiPowerRequestDevice,
  1581. (unlockDevice ? DEVICE_REQUEST_UNLOCK_DEVICE : 0)
  1582. );
  1583. return status;
  1584. }
  1585. NTSTATUS
  1586. ACPIDeviceIrpDeviceRequest(
  1587. IN PDEVICE_OBJECT DeviceObject,
  1588. IN PIRP Irp,
  1589. IN PACPI_POWER_CALLBACK CallBack
  1590. )
  1591. /*++
  1592. Routine Description:
  1593. This routine is called when an Irp wishes to do D-level power management
  1594. Note: that we always pass the Irp back as the Context for the CallBack
  1595. Arguments:
  1596. DeviceObject - The target device object
  1597. Irp - The target irp
  1598. CallBack - The routine to call when done
  1599. Return Value:
  1600. NTSTATUS
  1601. --*/
  1602. {
  1603. BOOLEAN unlockDevice = FALSE;
  1604. DEVICE_POWER_STATE deviceState;
  1605. NTSTATUS status;
  1606. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  1607. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
  1608. POWER_ACTION powerAction;
  1609. POWER_STATE powerState;
  1610. //
  1611. // Grab the requested device state and power action
  1612. //
  1613. deviceState = irpStack->Parameters.Power.State.DeviceState;
  1614. powerAction = irpStack->Parameters.Power.ShutdownType;
  1615. //
  1616. // Let the user know what is going on
  1617. //
  1618. ACPIDevPrint( (
  1619. ACPI_PRINT_POWER,
  1620. deviceExtension,
  1621. "(0x%08lx): ACPIDeviceIrpDeviceRequest - Transition to D%d\n",
  1622. Irp,
  1623. (deviceState - PowerDeviceD0)
  1624. ) );
  1625. //
  1626. // Do we need to mark the irp as pending?
  1627. //
  1628. if (Irp->PendingReturned) {
  1629. IoMarkIrpPending( Irp );
  1630. }
  1631. //
  1632. // Lets us look at the current status code for the request. On error,
  1633. // we will just call the completion right now, and it is responsible
  1634. // for doing the 'right' thing
  1635. //
  1636. status = Irp->IoStatus.Status;
  1637. if (!NT_SUCCESS(status)) {
  1638. //
  1639. // Call the completion routine and return
  1640. //
  1641. if (*CallBack != NULL ) {
  1642. (*CallBack)(
  1643. deviceExtension,
  1644. Irp,
  1645. status
  1646. );
  1647. return status;
  1648. }
  1649. }
  1650. //
  1651. // Cast the desired state
  1652. //
  1653. powerState.DeviceState = deviceState;
  1654. #if defined(ACPI_INTERNAL_LOCKING)
  1655. //
  1656. // Determine if we should unlock the device
  1657. //
  1658. if (powerAction == PowerActionShutdown ||
  1659. powerAction == PowerActionShutdownReset ||
  1660. powerAction == PowerActionShutdownOff) {
  1661. unlockDevice = TRUE;
  1662. }
  1663. #endif
  1664. //
  1665. // Queue the request --- this function will always return
  1666. // MORE_PROCESSING_REQUIRED instead of PENDING, so we don't have
  1667. // to mess with it
  1668. //
  1669. status = ACPIDeviceInitializePowerRequest(
  1670. deviceExtension,
  1671. powerState,
  1672. CallBack,
  1673. Irp,
  1674. powerAction,
  1675. AcpiPowerRequestDevice,
  1676. (unlockDevice ? DEVICE_REQUEST_UNLOCK_DEVICE : 0)
  1677. );
  1678. return status;
  1679. }
  1680. VOID
  1681. ACPIDeviceIrpForwardRequest(
  1682. IN PDEVICE_EXTENSION DeviceExtension,
  1683. IN PVOID Context,
  1684. IN NTSTATUS Status
  1685. )
  1686. /*++
  1687. Routine Description:
  1688. This is one of the completion routines for Irp-based device power
  1689. management requests
  1690. This routine completes the irp (on failure), or forwards it to
  1691. the DeviceObject below this one (on success)
  1692. Arguments:
  1693. DeviceExtension - Points to the DeviceExtension that was the target
  1694. Context - The Irp that was associated with the request
  1695. Status - The Result of the request
  1696. Return Value:
  1697. None
  1698. --*/
  1699. {
  1700. PIRP irp = (PIRP) Context;
  1701. LONG oldReferenceValue;
  1702. ACPIDevPrint( (
  1703. ACPI_PRINT_POWER,
  1704. DeviceExtension,
  1705. "(0x%08lx): ACPIDeviceIrpForwardRequest = 0x%08lx\n",
  1706. irp,
  1707. Status
  1708. ) );
  1709. if (!NT_SUCCESS(Status)) {
  1710. //
  1711. // Start the next power request
  1712. //
  1713. PoStartNextPowerIrp( irp );
  1714. //
  1715. // Complete this irp
  1716. //
  1717. irp->IoStatus.Status = Status;
  1718. IoCompleteRequest( irp, IO_NO_INCREMENT );
  1719. } else {
  1720. PDEVICE_OBJECT devObject;
  1721. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( irp );
  1722. devObject = irpSp->DeviceObject;
  1723. //
  1724. // Forward the request
  1725. //
  1726. ACPIDispatchForwardPowerIrp(
  1727. devObject,
  1728. irp
  1729. );
  1730. }
  1731. //
  1732. // Remove our reference
  1733. //
  1734. ACPIInternalDecrementIrpReferenceCount( DeviceExtension );
  1735. }
  1736. NTSTATUS
  1737. ACPIDeviceIrpSystemRequest(
  1738. IN PDEVICE_OBJECT DeviceObject,
  1739. IN PIRP Irp,
  1740. IN PACPI_POWER_CALLBACK CallBack
  1741. )
  1742. /*++
  1743. Routine Description:
  1744. This routine is called when an Irp wishes to do S-level power management
  1745. Note: that we always pass the Irp back as the Context for the CallBack
  1746. Arguments:
  1747. DeviceObject - The target device object
  1748. Irp - The target irp
  1749. CallBack - The routine to call when done
  1750. Return Value:
  1751. NTSTATUS
  1752. --*/
  1753. {
  1754. NTSTATUS status;
  1755. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  1756. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
  1757. POWER_ACTION powerAction;
  1758. POWER_STATE powerState;
  1759. SYSTEM_POWER_STATE systemState;
  1760. //
  1761. // Grab the requested system state and system action
  1762. //
  1763. systemState = irpStack->Parameters.Power.State.SystemState;
  1764. powerAction = irpStack->Parameters.Power.ShutdownType;
  1765. //
  1766. // Let the user know what is going on
  1767. //
  1768. ACPIDevPrint( (
  1769. ACPI_PRINT_POWER,
  1770. deviceExtension,
  1771. "(0x%08lx): ACPIDeviceIrpSystemRequest - Transition to S%d\n",
  1772. Irp,
  1773. ACPIDeviceMapACPIPowerState(systemState)
  1774. ) );
  1775. //
  1776. // Do we need to mark the irp as pending?
  1777. //
  1778. if (Irp->PendingReturned) {
  1779. IoMarkIrpPending( Irp );
  1780. }
  1781. //
  1782. // Lets us look at the current status code for the request. On error,
  1783. // we will just call the completion right now, and it is responsible
  1784. // for doing the 'right' thing
  1785. //
  1786. status = Irp->IoStatus.Status;
  1787. if (!NT_SUCCESS(status)) {
  1788. //
  1789. // Call the completion routine and return
  1790. //
  1791. (*CallBack)(
  1792. deviceExtension,
  1793. Irp,
  1794. status
  1795. );
  1796. return status;
  1797. }
  1798. //
  1799. // Cast the desired state
  1800. //
  1801. powerState.SystemState = systemState;
  1802. //
  1803. // Queue the request --- this function will always return
  1804. // MORE_PROCESSING_REQUIRED instead of PENDING, so we don't have
  1805. // to mess with it
  1806. //
  1807. status = ACPIDeviceInitializePowerRequest(
  1808. deviceExtension,
  1809. powerState,
  1810. CallBack,
  1811. Irp,
  1812. powerAction,
  1813. AcpiPowerRequestSystem,
  1814. 0
  1815. );
  1816. return status;
  1817. }
  1818. NTSTATUS
  1819. ACPIDeviceIrpWaitWakeRequest(
  1820. IN PDEVICE_OBJECT DeviceObject,
  1821. IN PIRP Irp,
  1822. IN PACPI_POWER_CALLBACK CallBack
  1823. )
  1824. /*++
  1825. Routine Description:
  1826. This routine is called when an Irp wishes to do wake support
  1827. Note: that we always pass the Irp back as the Context for the CallBack
  1828. Note: this function is coded differently then the other DeviceIrpXXXRequest
  1829. functions --- there are no provisions made that this routine can
  1830. be called as a IoCompletionRoutine, although the arguments could
  1831. support it.
  1832. Arguments:
  1833. DeviceObject - The target device object
  1834. Irp - The target irp
  1835. CallBack - The routine to call when done
  1836. Return Value:
  1837. NTSTATUS
  1838. --*/
  1839. {
  1840. NTSTATUS status = STATUS_SUCCESS;
  1841. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  1842. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
  1843. POWER_STATE powerState;
  1844. SYSTEM_POWER_STATE systemState;
  1845. //
  1846. // Grab the requested device state
  1847. //
  1848. systemState = irpStack->Parameters.WaitWake.PowerState;
  1849. //
  1850. // Let the user know what is going on
  1851. //
  1852. ACPIDevPrint( (
  1853. ACPI_PRINT_WAKE,
  1854. deviceExtension,
  1855. "(0x%08lx): ACPIDeviceIrpWaitWakeRequest - Wait Wake S%d\n",
  1856. Irp,
  1857. ACPIDeviceMapACPIPowerState(systemState)
  1858. ) );
  1859. //
  1860. // Cast the desired state
  1861. //
  1862. powerState.SystemState = systemState;
  1863. //
  1864. // Queue the request --- this function will always return
  1865. // MORE_PROCESSING_REQUIRED instead of PENDING, so we don't have
  1866. // to mess with it
  1867. //
  1868. status = ACPIDeviceInitializePowerRequest(
  1869. deviceExtension,
  1870. powerState,
  1871. CallBack,
  1872. Irp,
  1873. PowerActionNone,
  1874. AcpiPowerRequestWaitWake,
  1875. DEVICE_REQUEST_NO_QUEUE
  1876. );
  1877. return status;
  1878. }
  1879. VOID
  1880. ACPIDeviceIrpWaitWakeRequestComplete(
  1881. IN PACPI_POWER_REQUEST PowerRequest
  1882. )
  1883. /*++
  1884. Routine Description:
  1885. This routine is called when the WaitWake Irp is finally complete and we
  1886. need to pass it back to whomever called us with it
  1887. Arguments:
  1888. PowerRequest - The request that was completed
  1889. Return Value:
  1890. NTSTATUS
  1891. --*/
  1892. {
  1893. KIRQL oldIrql;
  1894. PDEVICE_EXTENSION deviceExtension;
  1895. //
  1896. // Make sure that we own the power lock for this
  1897. //
  1898. KeAcquireSpinLock( &AcpiPowerQueueLock, &oldIrql );
  1899. //
  1900. // Remember the device extension
  1901. //
  1902. deviceExtension = PowerRequest->DeviceExtension;
  1903. //
  1904. // Make sure that the request can no longer be cancelled
  1905. //
  1906. if (PowerRequest->u.WaitWakeRequest.Flags & DEVICE_REQUEST_HAS_CANCEL) {
  1907. KIRQL cancelIrql;
  1908. PIRP irp = (PIRP) PowerRequest->Context;
  1909. IoAcquireCancelSpinLock( &cancelIrql );
  1910. IoSetCancelRoutine( irp, NULL );
  1911. PowerRequest->u.WaitWakeRequest.Flags &= ~DEVICE_REQUEST_HAS_CANCEL;
  1912. IoReleaseCancelSpinLock( cancelIrql );
  1913. }
  1914. //
  1915. // Add the request to the right place in the lists. Note this function
  1916. // must be called with the PowerQueueLock being held
  1917. //
  1918. ACPIDeviceInternalQueueRequest(
  1919. deviceExtension,
  1920. PowerRequest,
  1921. PowerRequest->u.WaitWakeRequest.Flags
  1922. );
  1923. //
  1924. // Done with spinlock
  1925. //
  1926. KeReleaseSpinLock( &AcpiPowerQueueLock, oldIrql );
  1927. }
  1928. VOID EXPORT
  1929. ACPIDeviceIrpWaitWakeRequestPending(
  1930. IN PNSOBJ AcpiObject,
  1931. IN NTSTATUS Status,
  1932. IN POBJDATA ObjectData,
  1933. IN PVOID Context
  1934. )
  1935. /*++
  1936. Routine Description:
  1937. This routine is called after _PSW has been run and we want to enable
  1938. the GPE associated with the current object
  1939. Arguments:
  1940. AcpiObject - Points to the control method that was run
  1941. Status - Result of the method
  1942. ObjectData - Information about the result
  1943. Context - ACPI_POWER_REQUEST
  1944. Return Value:
  1945. NTSTATUS
  1946. --*/
  1947. {
  1948. KIRQL oldIrql;
  1949. PACPI_POWER_REQUEST powerRequest = (PACPI_POWER_REQUEST) Context;
  1950. PDEVICE_EXTENSION deviceExtension = powerRequest->DeviceExtension;
  1951. PIRP irp = (PIRP) powerRequest->Context;
  1952. ACPIDevPrint( (
  1953. ACPI_PRINT_WAKE,
  1954. deviceExtension,
  1955. "(0x%08lx): ACPIDeviceIrpWaitWakeRequestPending= 0x%08lx\n",
  1956. powerRequest,
  1957. Status
  1958. ) );
  1959. //
  1960. // Did we fail the request?
  1961. //
  1962. if (!NT_SUCCESS(Status)) {
  1963. powerRequest->Status = Status;
  1964. ACPIDeviceIrpWaitWakeRequestComplete( powerRequest );
  1965. return;
  1966. }
  1967. //
  1968. // At this point, we need the power spin lock and the cancel spinlock
  1969. //
  1970. IoAcquireCancelSpinLock( &oldIrql );
  1971. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  1972. //
  1973. // Remember that we have this request outstanding
  1974. //
  1975. InsertTailList(
  1976. &(AcpiPowerWaitWakeList),
  1977. &(powerRequest->ListEntry)
  1978. );
  1979. //
  1980. // Has the irp been cancelled?
  1981. //
  1982. if (irp->Cancel) {
  1983. //
  1984. // Yes, so lets release release the power lock and call the
  1985. // cancel routine
  1986. //
  1987. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  1988. ACPIDeviceCancelWaitWakeIrp(
  1989. deviceExtension->DeviceObject,
  1990. irp
  1991. );
  1992. //
  1993. // Return now --- the cancel routine should have taken care off
  1994. // everything else
  1995. //
  1996. return;
  1997. }
  1998. //
  1999. // Remember that this request has a cancel routine
  2000. //
  2001. powerRequest->u.WaitWakeRequest.Flags |= DEVICE_REQUEST_HAS_CANCEL;
  2002. //
  2003. // Update the Gpe Wake Bits
  2004. //
  2005. ACPIWakeRemoveDevicesAndUpdate( NULL, NULL );
  2006. //
  2007. // Mark the Irp as cancelable
  2008. //
  2009. IoSetCancelRoutine( irp, ACPIDeviceCancelWaitWakeIrp );
  2010. //
  2011. // Done with the spinlocks
  2012. //
  2013. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  2014. IoReleaseCancelSpinLock( oldIrql );
  2015. } // ACPIDeviceIrpWaitWakeRequestPending
  2016. NTSTATUS
  2017. ACPIDeviceIrpWarmEjectRequest(
  2018. IN PDEVICE_EXTENSION DeviceExtension,
  2019. IN PIRP Irp,
  2020. IN PACPI_POWER_CALLBACK CallBack,
  2021. IN BOOLEAN UpdateHardwareProfile
  2022. )
  2023. /*++
  2024. Routine Description:
  2025. This routine is called when an Irp wishes to do S-level power management
  2026. Note: that we always pass the Irp back as the Context for the CallBack
  2027. Arguments:
  2028. DeviceExtension - Extension of the device with the _EJx methods to run
  2029. Irp - The target irp
  2030. CallBack - The routine to call when done
  2031. Flags - Update profiles, etc
  2032. Return Value:
  2033. NTSTATUS
  2034. --*/
  2035. {
  2036. NTSTATUS status;
  2037. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
  2038. POWER_ACTION ejectAction;
  2039. POWER_STATE powerState;
  2040. SYSTEM_POWER_STATE ejectState;
  2041. //
  2042. // Grab the requested system state
  2043. //
  2044. ejectState = irpStack->Parameters.Power.State.SystemState;
  2045. //
  2046. // Let the user know what is going on
  2047. //
  2048. ACPIDevPrint( (
  2049. ACPI_PRINT_POWER,
  2050. DeviceExtension,
  2051. "(0x%08lx): ACPIDeviceIrpWarmEjectRequest - Transition to S%d\n",
  2052. Irp,
  2053. ACPIDeviceMapACPIPowerState(ejectState)
  2054. ) );
  2055. //
  2056. // Do we need to mark the irp as pending?
  2057. //
  2058. if (Irp->PendingReturned) {
  2059. IoMarkIrpPending( Irp );
  2060. }
  2061. //
  2062. // Lets us look at the current status code for the request. On error,
  2063. // we will just call the completion right now, and it is responsible
  2064. // for doing the 'right' thing
  2065. //
  2066. status = Irp->IoStatus.Status;
  2067. if (!NT_SUCCESS(status)) {
  2068. //
  2069. // Call the completion routine and return
  2070. //
  2071. (*CallBack)(
  2072. DeviceExtension,
  2073. Irp,
  2074. status
  2075. );
  2076. return status;
  2077. }
  2078. //
  2079. // Cast the desired state
  2080. //
  2081. powerState.SystemState = ejectState;
  2082. //
  2083. // Queue the request --- this function will always return
  2084. // MORE_PROCESSING_REQUIRED instead of PENDING, so we don't have
  2085. // to mess with it
  2086. //
  2087. status = ACPIDeviceInitializePowerRequest(
  2088. DeviceExtension,
  2089. powerState,
  2090. CallBack,
  2091. Irp,
  2092. PowerActionNone,
  2093. AcpiPowerRequestWarmEject,
  2094. UpdateHardwareProfile ? DEVICE_REQUEST_UPDATE_HW_PROFILE : 0
  2095. );
  2096. return status;
  2097. }
  2098. #if 0
  2099. ULONG
  2100. ACPIDeviceMapACPIPowerState(
  2101. SYSTEM_POWER_STATE Level
  2102. )
  2103. /*++
  2104. Routine Description:
  2105. This isn't a routine. Its a macro. It returns a ULONG that corresponds
  2106. to ACPI based System Power State based on the NT SystemPower State
  2107. Arguments:
  2108. Level - The NT Based S state
  2109. Return Value:
  2110. ULONG
  2111. --*/
  2112. {
  2113. }
  2114. #endif
  2115. #if 0
  2116. DEVICE_POWER_STATE
  2117. ACPIDeviceMapPowerState(
  2118. ULONG Level
  2119. )
  2120. /*++
  2121. Routine Description:
  2122. This isn't a routine. Its a macro. It returns a DEVICE_POWER_STATE
  2123. that corresponds to the mapping provided in the ACPI spec
  2124. Arguments:
  2125. Level - The 0-based D level (0 == D0, 1 == D1, ..., 3 == D3)
  2126. Return Value:
  2127. DEVICE_POWER_STATE
  2128. --*/
  2129. {
  2130. }
  2131. #endif
  2132. #if 0
  2133. SYSTEM_POWER_STATE
  2134. ACPIDeviceMapSystemState(
  2135. ULONG Level
  2136. )
  2137. /*++
  2138. Routine Description:
  2139. This isn't a routine. Its a macro. It returns a SYSTEM_POWER_STATE that
  2140. corresponds to the mapping provided in the ACPI spec
  2141. Arguments:
  2142. Level - The 0-based S level (0 = Working, ..., 5 = Shutdown)
  2143. Return Value:
  2144. SYSTEM_POWER_STATE
  2145. --*/
  2146. {
  2147. }
  2148. #endif
  2149. NTSTATUS
  2150. ACPIDevicePowerDetermineSupportedDeviceStates(
  2151. IN PDEVICE_EXTENSION DeviceExtension,
  2152. IN PULONG SupportedPrStates,
  2153. IN PULONG SupportedPsStates
  2154. )
  2155. /*++
  2156. Routine Description:
  2157. This routine calculates the bit masks that reflect which D states are
  2158. supported via PRx methods and which D states are supported via PSx
  2159. methods
  2160. Arguments:
  2161. DeviceExtension - Device Extension to determine D-States
  2162. SupportedPrStates - Bit Mask of supported D-States via _PRx
  2163. SupportedPsStates - Bit Mask of supported D-States via _PSx
  2164. Return Value:
  2165. NTSTATUS
  2166. --*/
  2167. {
  2168. DEVICE_POWER_STATE index;
  2169. PNSOBJ object;
  2170. ULONG i;
  2171. ULONG prBitIndex = 0;
  2172. ULONG prNames[] = { PACKED_PR0, PACKED_PR1, PACKED_PR2 };
  2173. ULONG psBitIndex = 0;
  2174. ULONG psNames[] = { PACKED_PS0, PACKED_PS1, PACKED_PS2, PACKED_PS3 };
  2175. ULONG supportedIndex = 0;
  2176. PAGED_CODE();
  2177. ASSERT( DeviceExtension != NULL );
  2178. ASSERT( SupportedPrStates != NULL );
  2179. ASSERT( SupportedPsStates != NULL );
  2180. //
  2181. // Assume we support nothing
  2182. //
  2183. *SupportedPrStates = 0;
  2184. *SupportedPsStates = 0;
  2185. //
  2186. // This is another place that we want to be able to call this code even
  2187. // though there is no NameSpace Object associated with this extension.
  2188. // This special case code lets us avoid adding a check to GetNamedChild
  2189. //
  2190. if (DeviceExtension->Flags & DEV_PROP_NO_OBJECT) {
  2191. //
  2192. // Assume that we support 'PS' states 0 and 3
  2193. //
  2194. psBitIndex = ( 1 << PowerDeviceD0 ) + ( 1 << PowerDeviceD3 );
  2195. goto ACPIDevicePowerDetermineSupportedDeviceStatesExit;
  2196. }
  2197. //
  2198. // Look for all of the _PS methods
  2199. //
  2200. for (i = 0, index = PowerDeviceD0; index <= PowerDeviceD3; i++, index++) {
  2201. //
  2202. // Does the object exist?
  2203. //
  2204. object = ACPIAmliGetNamedChild(
  2205. DeviceExtension->AcpiObject,
  2206. psNames[i]
  2207. );
  2208. if (object != NULL) {
  2209. psBitIndex |= (1 << index);
  2210. }
  2211. }
  2212. //
  2213. // Look for all of the _PR methods
  2214. //
  2215. for (i = 0, index = PowerDeviceD0; index <= PowerDeviceD2; i++, index++) {
  2216. //
  2217. // Does the object exist?
  2218. //
  2219. object = ACPIAmliGetNamedChild(
  2220. DeviceExtension->AcpiObject,
  2221. prNames[i]
  2222. );
  2223. if (object != NULL) {
  2224. prBitIndex |= (1 << index);
  2225. //
  2226. // We always support D3 'passively'
  2227. //
  2228. prBitIndex |= (1 << PowerDeviceD3);
  2229. }
  2230. }
  2231. //
  2232. // The supported index is the union of which _PR and which _PS are
  2233. // present
  2234. supportedIndex = (prBitIndex | psBitIndex);
  2235. //
  2236. // If we didn't find anything, then there is nothing for us to do
  2237. //
  2238. if (!supportedIndex) {
  2239. //
  2240. // Done
  2241. //
  2242. return STATUS_SUCCESS;
  2243. }
  2244. //
  2245. // One of the rules that we have setup is that we must support D3 and
  2246. // D0 if we support any power states at all. Make sure that this is
  2247. // true.
  2248. //
  2249. if ( !(supportedIndex & (1 << PowerDeviceD0) ) ) {
  2250. ACPIDevPrint( (
  2251. ACPI_PRINT_CRITICAL,
  2252. DeviceExtension,
  2253. "does not support D0 power state!\n"
  2254. ) );
  2255. KeBugCheckEx(
  2256. ACPI_BIOS_ERROR,
  2257. ACPI_REQUIRED_METHOD_NOT_PRESENT,
  2258. (ULONG_PTR) DeviceExtension,
  2259. (prBitIndex != 0 ? PACKED_PR0 : PACKED_PS0),
  2260. 0
  2261. );
  2262. }
  2263. if ( !(supportedIndex & (1 << PowerDeviceD3) ) ) {
  2264. ACPIDevPrint( (
  2265. ACPI_PRINT_CRITICAL,
  2266. DeviceExtension,
  2267. "does not support D3 power state!\n"
  2268. ) );
  2269. KeBugCheckEx(
  2270. ACPI_BIOS_ERROR,
  2271. ACPI_REQUIRED_METHOD_NOT_PRESENT,
  2272. (ULONG_PTR) DeviceExtension,
  2273. PACKED_PS3,
  2274. 0
  2275. );
  2276. ACPIInternalError( ACPI_INTERNAL );
  2277. }
  2278. if ( prBitIndex != 0 && psBitIndex != 0 && prBitIndex != psBitIndex) {
  2279. ACPIDevPrint( (
  2280. ACPI_PRINT_CRITICAL,
  2281. DeviceExtension,
  2282. "has mismatch between power plane and power source information!\n"
  2283. ) );
  2284. prBitIndex &= psBitIndex;
  2285. psBitIndex &= prBitIndex;
  2286. }
  2287. ACPIDevicePowerDetermineSupportedDeviceStatesExit:
  2288. //
  2289. // Give the answer of what we support
  2290. //
  2291. *SupportedPrStates = prBitIndex;
  2292. *SupportedPsStates = psBitIndex;
  2293. //
  2294. // Done
  2295. //
  2296. return STATUS_SUCCESS;
  2297. }
  2298. VOID
  2299. ACPIDevicePowerDpc(
  2300. IN PKDPC Dpc,
  2301. IN PVOID DpcContext,
  2302. IN PVOID SystemArgument1,
  2303. IN PVOID SystemArgument2
  2304. )
  2305. /*++
  2306. Routine Description:
  2307. This routine is where all of the Power-related work is done. It looks
  2308. at queued requests and processes them as appropriate.
  2309. Arguments:
  2310. None used
  2311. Return Value:
  2312. Void
  2313. --*/
  2314. {
  2315. LIST_ENTRY tempList;
  2316. NTSTATUS status;
  2317. UNREFERENCED_PARAMETER( Dpc );
  2318. UNREFERENCED_PARAMETER( DpcContext );
  2319. UNREFERENCED_PARAMETER( SystemArgument1 );
  2320. UNREFERENCED_PARAMETER( SystemArgument2 );
  2321. //
  2322. // First step is to acquire the DPC Lock, and check to see if another
  2323. // DPC is already running
  2324. //
  2325. KeAcquireSpinLockAtDpcLevel( &AcpiPowerQueueLock );
  2326. if (AcpiPowerDpcRunning) {
  2327. //
  2328. // The DPC is already running, so we need to exit now
  2329. //
  2330. KeReleaseSpinLockFromDpcLevel( &AcpiPowerQueueLock );
  2331. return;
  2332. }
  2333. //
  2334. // Remember that the DPC is now running
  2335. //
  2336. AcpiPowerDpcRunning = TRUE;
  2337. //
  2338. // Initialize the list that will hold the synchronize items
  2339. //
  2340. InitializeListHead( &tempList );
  2341. //
  2342. // We must try to do *some* work
  2343. //
  2344. do {
  2345. //
  2346. // Assume that we won't do any work
  2347. //
  2348. AcpiPowerWorkDone = FALSE;
  2349. //
  2350. // If there are items in the Queue list, move them to the Phase0 list
  2351. //
  2352. if (!IsListEmpty( &AcpiPowerQueueList ) ) {
  2353. ACPIInternalMovePowerList(
  2354. &AcpiPowerQueueList,
  2355. &AcpiPowerPhase0List
  2356. );
  2357. }
  2358. //
  2359. // We can release the spin lock now
  2360. //
  2361. KeReleaseSpinLockFromDpcLevel( &AcpiPowerQueueLock );
  2362. //
  2363. // If there are items in the Phase0 list, process the list
  2364. //
  2365. if (!IsListEmpty( &AcpiPowerPhase0List ) ) {
  2366. status = ACPIDevicePowerProcessGenericPhase(
  2367. &AcpiPowerPhase0List,
  2368. AcpiDevicePowerProcessPhase0Dispatch,
  2369. FALSE
  2370. );
  2371. if (NT_SUCCESS(status) && status != STATUS_PENDING) {
  2372. //
  2373. // This indicates that we have completed all the work
  2374. // on the Phase0 list, so we are ready to move all the
  2375. // items to the next list
  2376. //
  2377. ACPIInternalMovePowerList(
  2378. &AcpiPowerPhase0List,
  2379. &AcpiPowerPhase1List
  2380. );
  2381. }
  2382. }
  2383. //
  2384. // If there are items in Phase1 list, process the list
  2385. //
  2386. if (!IsListEmpty( &AcpiPowerPhase1List ) &&
  2387. IsListEmpty( &AcpiPowerPhase0List) ) {
  2388. status = ACPIDevicePowerProcessGenericPhase(
  2389. &AcpiPowerPhase1List,
  2390. AcpiDevicePowerProcessPhase1Dispatch,
  2391. FALSE
  2392. );
  2393. if (NT_SUCCESS(status) && status != STATUS_PENDING) {
  2394. //
  2395. // This indicates that we have completed all the work
  2396. // on the Phase1 list, so we are ready to move all the
  2397. // items to the next list
  2398. //
  2399. ACPIInternalMovePowerList(
  2400. &AcpiPowerPhase1List,
  2401. &AcpiPowerPhase2List
  2402. );
  2403. }
  2404. }
  2405. //
  2406. // If there are items in the Phase2 list, then process those
  2407. //
  2408. if (IsListEmpty( &AcpiPowerPhase0List) &&
  2409. IsListEmpty( &AcpiPowerPhase1List) &&
  2410. !IsListEmpty( &AcpiPowerPhase2List) ) {
  2411. status = ACPIDevicePowerProcessGenericPhase(
  2412. &AcpiPowerPhase2List,
  2413. AcpiDevicePowerProcessPhase2Dispatch,
  2414. FALSE
  2415. );
  2416. if (NT_SUCCESS(status) && status != STATUS_PENDING) {
  2417. //
  2418. // This indicates that we have completed all the work
  2419. // on the Phase1 list, so we are ready to move all the
  2420. // items to the next list
  2421. //
  2422. ACPIInternalMovePowerList(
  2423. &AcpiPowerPhase2List,
  2424. &AcpiPowerPhase3List
  2425. );
  2426. }
  2427. }
  2428. //
  2429. // We cannot do this step if the Phase1List or Phase2List are non-empty
  2430. //
  2431. if (IsListEmpty( &AcpiPowerPhase0List) &&
  2432. IsListEmpty( &AcpiPowerPhase1List) &&
  2433. IsListEmpty( &AcpiPowerPhase2List) &&
  2434. !IsListEmpty( &AcpiPowerPhase3List) ) {
  2435. status = ACPIDevicePowerProcessPhase3( );
  2436. if (NT_SUCCESS(status) && status != STATUS_PENDING) {
  2437. //
  2438. // This indicates that we have completed all the work
  2439. // on the Phase2 list, so we are ready to move all the
  2440. // itmes to the Phase3 list
  2441. //
  2442. ACPIInternalMovePowerList(
  2443. &AcpiPowerPhase3List,
  2444. &AcpiPowerPhase4List
  2445. );
  2446. }
  2447. }
  2448. //
  2449. // We can always empty the Phase4 list
  2450. //
  2451. if (!IsListEmpty( &AcpiPowerPhase4List ) ) {
  2452. status = ACPIDevicePowerProcessPhase4( );
  2453. if (NT_SUCCESS(status) && status != STATUS_PENDING) {
  2454. //
  2455. // This indicates that we have completed all the work
  2456. // on the Phase1 list, so we are ready to move all the
  2457. // items to the Phase2 list
  2458. //
  2459. ACPIInternalMovePowerList(
  2460. &AcpiPowerPhase4List,
  2461. &AcpiPowerPhase5List
  2462. );
  2463. }
  2464. }
  2465. //
  2466. // We can always empty the Phase5 list
  2467. //
  2468. if (!IsListEmpty( &AcpiPowerPhase5List) ) {
  2469. status = ACPIDevicePowerProcessGenericPhase(
  2470. &AcpiPowerPhase5List,
  2471. AcpiDevicePowerProcessPhase5Dispatch,
  2472. TRUE
  2473. );
  2474. }
  2475. //
  2476. // We need the lock again, since we are about to check to see if
  2477. // we have completed some work
  2478. //
  2479. KeAcquireSpinLockAtDpcLevel( &AcpiPowerQueueLock );
  2480. } while ( AcpiPowerWorkDone );
  2481. //
  2482. // The DPC is no longer running
  2483. //
  2484. AcpiPowerDpcRunning = FALSE;
  2485. //
  2486. // Have we flushed all of our queues?
  2487. //
  2488. if (IsListEmpty( &AcpiPowerPhase0List ) &&
  2489. IsListEmpty( &AcpiPowerPhase1List ) &&
  2490. IsListEmpty( &AcpiPowerPhase2List ) &&
  2491. IsListEmpty( &AcpiPowerPhase3List ) &&
  2492. IsListEmpty( &AcpiPowerPhase4List ) &&
  2493. IsListEmpty( &AcpiPowerPhase5List ) ) {
  2494. //
  2495. // Let the world know
  2496. //
  2497. ACPIPrint( (
  2498. ACPI_PRINT_POWER,
  2499. "ACPIDevicePowerDPC: Queues Empty. Terminating.\n"
  2500. ) );
  2501. //
  2502. // Do we have a synchronization request?
  2503. //
  2504. if (!IsListEmpty( &AcpiPowerSynchronizeList ) ) {
  2505. //
  2506. // Move all the item from the Sync list to the temp list
  2507. //
  2508. ACPIInternalMovePowerList(
  2509. &AcpiPowerSynchronizeList,
  2510. &tempList
  2511. );
  2512. }
  2513. }
  2514. //
  2515. // We no longer need the lock
  2516. //
  2517. KeReleaseSpinLockFromDpcLevel( &AcpiPowerQueueLock );
  2518. //
  2519. // Do we have any work in the synchronize list?
  2520. //
  2521. if (!IsListEmpty( &tempList) ) {
  2522. ACPIDevicePowerProcessSynchronizeList( &tempList );
  2523. }
  2524. }
  2525. NTSTATUS
  2526. ACPIDevicePowerFlushQueue(
  2527. PDEVICE_EXTENSION DeviceExtension
  2528. )
  2529. /*++
  2530. Routine Description:
  2531. This routine will block until the Power queues have been flushed
  2532. Arguments:
  2533. DeviceExtension - The device extension which wants to flush
  2534. Return Value:
  2535. NTSTATUS
  2536. --*/
  2537. {
  2538. KEVENT event;
  2539. NTSTATUS status;
  2540. //
  2541. // Initialize the event that we will wait on
  2542. //
  2543. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  2544. //
  2545. // Now, push a request onto the stack such that when the power lists
  2546. // have been emptied, we unblock this thread
  2547. //
  2548. status = ACPIDeviceInternalSynchronizeRequest(
  2549. DeviceExtension,
  2550. ACPIDevicePowerNotifyEvent,
  2551. &event,
  2552. 0
  2553. );
  2554. //
  2555. // Block until its done
  2556. //
  2557. if (status == STATUS_PENDING) {
  2558. KeWaitForSingleObject(
  2559. &event,
  2560. Executive,
  2561. KernelMode,
  2562. FALSE,
  2563. NULL
  2564. );
  2565. status = STATUS_SUCCESS;
  2566. }
  2567. //
  2568. // Let the world know
  2569. //
  2570. return status;
  2571. }
  2572. VOID
  2573. ACPIDevicePowerNotifyEvent(
  2574. IN PDEVICE_EXTENSION DeviceExtension,
  2575. IN PVOID Context,
  2576. IN NTSTATUS Status
  2577. )
  2578. /*++
  2579. Routine Description:
  2580. This routine is called when all the power queues are empty
  2581. Arguments:
  2582. DeviceExtension - The device that asked to be notified
  2583. Context - KEVENT
  2584. Status - The result of the operation
  2585. --*/
  2586. {
  2587. PKEVENT event = (PKEVENT) Context;
  2588. UNREFERENCED_PARAMETER( DeviceExtension );
  2589. UNREFERENCED_PARAMETER( Status );
  2590. //
  2591. // Set the event
  2592. //
  2593. KeSetEvent( event, IO_NO_INCREMENT, FALSE );
  2594. }
  2595. NTSTATUS
  2596. ACPIDevicePowerProcessForward(
  2597. IN PACPI_POWER_REQUEST PowerRequest
  2598. )
  2599. /*++
  2600. Routine Description:
  2601. This routine is called in liew of another PowerProcessPhaseXXX routine.
  2602. It is called because there is no real work to do in the current phase
  2603. on the selected request
  2604. Arguments:
  2605. PowerRequest - The request that we must process
  2606. Return Value:
  2607. NTSTATUS
  2608. --*/
  2609. {
  2610. InterlockedCompareExchange(
  2611. &(PowerRequest->WorkDone),
  2612. WORK_DONE_COMPLETE,
  2613. WORK_DONE_PENDING
  2614. );
  2615. //
  2616. // Remember that we have completed some work
  2617. //
  2618. KeAcquireSpinLockAtDpcLevel( &AcpiPowerQueueLock );
  2619. AcpiPowerWorkDone = TRUE;
  2620. KeReleaseSpinLockFromDpcLevel( &AcpiPowerQueueLock );
  2621. //
  2622. // We always succeed
  2623. //
  2624. return STATUS_SUCCESS;
  2625. }
  2626. NTSTATUS
  2627. ACPIDevicePowerProcessGenericPhase(
  2628. IN PLIST_ENTRY ListEntry,
  2629. IN PACPI_POWER_FUNCTION **DispatchTable,
  2630. IN BOOLEAN Complete
  2631. )
  2632. /*++
  2633. Routine Description:
  2634. This routine dispatches an item on the queue to the proper handler,
  2635. based on what type of request is present
  2636. Arguments:
  2637. ListEntry - The list we are currently walking
  2638. DispatchTable - Where to find which functions to call
  2639. Complete - Do we need complete the request when done?
  2640. Return Value:
  2641. NTSTATUS
  2642. - If any request is not marked as being complete, then STATUS_PENDING
  2643. is returned, otherwise, STATUS_SUCCESS is returned
  2644. --*/
  2645. {
  2646. BOOLEAN allWorkComplete = TRUE;
  2647. NTSTATUS status = STATUS_SUCCESS;
  2648. PACPI_POWER_FUNCTION *powerTable;
  2649. PACPI_POWER_REQUEST powerRequest;
  2650. PLIST_ENTRY currentEntry = ListEntry->Flink;
  2651. PLIST_ENTRY tempEntry;
  2652. ULONG workDone;
  2653. //
  2654. // Look at all the items in the list
  2655. //
  2656. while (currentEntry != ListEntry) {
  2657. //
  2658. // Turn this into a device request
  2659. //
  2660. powerRequest = CONTAINING_RECORD(
  2661. currentEntry,
  2662. ACPI_POWER_REQUEST,
  2663. ListEntry
  2664. );
  2665. //
  2666. // Set the temporary pointer to the next element
  2667. //
  2668. tempEntry = currentEntry->Flink;
  2669. //
  2670. // Check to see if we have any work to do on the request
  2671. //
  2672. workDone = InterlockedCompareExchange(
  2673. &(powerRequest->WorkDone),
  2674. WORK_DONE_PENDING,
  2675. WORK_DONE_PENDING
  2676. );
  2677. //
  2678. // Do we have a table associated with this level of workdone?
  2679. //
  2680. powerTable = DispatchTable[ workDone ];
  2681. if (powerTable != NULL) {
  2682. //
  2683. // Mark the request as pending
  2684. //
  2685. workDone = InterlockedCompareExchange(
  2686. &(powerRequest->WorkDone),
  2687. WORK_DONE_PENDING,
  2688. workDone
  2689. );
  2690. //
  2691. // Call the function
  2692. //
  2693. status = (powerTable[powerRequest->RequestType])( powerRequest );
  2694. //
  2695. // Did we succeed?
  2696. //
  2697. if (NT_SUCCESS(status)) {
  2698. //
  2699. // Go to the next request
  2700. //
  2701. continue;
  2702. }
  2703. //
  2704. // If we got an error before, then we must assume that we
  2705. // have completed the work request
  2706. //
  2707. workDone = WORK_DONE_COMPLETE;
  2708. }
  2709. //
  2710. // Grab the next entry
  2711. //
  2712. currentEntry = tempEntry;
  2713. //
  2714. // Check the status of the request
  2715. //
  2716. if (workDone != WORK_DONE_COMPLETE) {
  2717. allWorkComplete = FALSE;
  2718. }
  2719. //
  2720. // Do we need to complete the request or not?
  2721. //
  2722. if (workDone == WORK_DONE_FAILURE ||
  2723. (Complete == TRUE && workDone == WORK_DONE_COMPLETE)) {
  2724. //
  2725. // We are done with the request
  2726. //
  2727. ACPIDeviceCompleteRequest(
  2728. powerRequest
  2729. );
  2730. }
  2731. }
  2732. //
  2733. // Have we completed all of our work?
  2734. //
  2735. return (allWorkComplete ? STATUS_SUCCESS : STATUS_PENDING);
  2736. } // ACPIPowerProcessGenericPhase
  2737. NTSTATUS
  2738. ACPIDevicePowerProcessInvalid(
  2739. IN PACPI_POWER_REQUEST PowerRequest
  2740. )
  2741. /*++
  2742. Routine Description:
  2743. This routine is called in liew of another PowerProcessPhaseXXX routine.
  2744. It is called because the request is invalid
  2745. Arguments:
  2746. PowerRequest - The request that we must process
  2747. Return Value:
  2748. NTSTATUS
  2749. --*/
  2750. {
  2751. //
  2752. // Note the status of the request as having failed
  2753. //
  2754. PowerRequest->Status = STATUS_INVALID_PARAMETER_1;
  2755. //
  2756. // Complete the request
  2757. //
  2758. ACPIDeviceCompleteRequest( PowerRequest );
  2759. //
  2760. // Remember that we have completed some work
  2761. //
  2762. KeAcquireSpinLockAtDpcLevel( &AcpiPowerQueueLock );
  2763. AcpiPowerWorkDone = TRUE;
  2764. KeReleaseSpinLockFromDpcLevel( &AcpiPowerQueueLock );
  2765. //
  2766. // We always fail
  2767. //
  2768. return STATUS_INVALID_PARAMETER_1;
  2769. } // ACPIPowerProcessInvalid
  2770. NTSTATUS
  2771. ACPIDevicePowerProcessPhase0DeviceSubPhase1(
  2772. IN PACPI_POWER_REQUEST PowerRequest
  2773. )
  2774. /*++
  2775. Routine Description:
  2776. This routine looks for the _STA object and evalutes it. We will base
  2777. many things on wether or not the device is present
  2778. Arguments:
  2779. PowerRequest - The request that we are asked to process
  2780. Return Value:
  2781. NTSTATUS
  2782. --*/
  2783. {
  2784. NTSTATUS status = STATUS_SUCCESS;
  2785. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  2786. POBJDATA resultData = &(PowerRequest->ResultData);
  2787. //
  2788. // The next step is STEP_1
  2789. //
  2790. PowerRequest->NextWorkDone = WORK_DONE_STEP_1;
  2791. //
  2792. // Initialize the result data
  2793. //
  2794. RtlZeroMemory( resultData, sizeof(OBJDATA) );
  2795. //
  2796. // Get the device presence
  2797. //
  2798. status = ACPIGetDeviceHardwarePresenceAsync(
  2799. deviceExtension,
  2800. ACPIDeviceCompleteGenericPhase,
  2801. PowerRequest,
  2802. &(resultData->uipDataValue),
  2803. &(resultData->dwDataLen)
  2804. );
  2805. ACPIDevPrint( (
  2806. ACPI_PRINT_POWER,
  2807. deviceExtension,
  2808. "(0x%08lx): ACPIDevicePowerProcessPhase0DeviceSubPhase1 = 0x%08lx\n",
  2809. PowerRequest,
  2810. status
  2811. ) );
  2812. if (status == STATUS_PENDING) {
  2813. return status;
  2814. }
  2815. //
  2816. // Call the completion routine by brute force. Note that at this
  2817. // point, we count everything as being SUCCESS
  2818. //
  2819. ACPIDeviceCompleteGenericPhase(
  2820. NULL,
  2821. status,
  2822. resultData,
  2823. PowerRequest
  2824. );
  2825. return STATUS_SUCCESS;
  2826. } // ACPIDevicePowerProcessPhase0DeviceSubPhase1
  2827. NTSTATUS
  2828. ACPIDevicePowerProcessPhase0DeviceSubPhase2(
  2829. IN PACPI_POWER_REQUEST PowerRequest
  2830. )
  2831. /*++
  2832. Routine Description:
  2833. This routine is called after the _STA method on a device has been run.
  2834. If the method was successfull, or not present, then we can continue to
  2835. process the request
  2836. Arguments:
  2837. PowerRequest - The request that we are asked to process
  2838. Return Value:
  2839. NTSTATUS
  2840. --*/
  2841. {
  2842. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  2843. POBJDATA resultData = &(PowerRequest->ResultData);
  2844. ACPIDevPrint( (
  2845. ACPI_PRINT_POWER,
  2846. deviceExtension,
  2847. "(0x%08lx): ACPIDevicePowerProcessPhase0DeviceSubPhase2\n",
  2848. PowerRequest
  2849. ) );
  2850. //
  2851. // If the bit isn't set as being present, then we must abort this
  2852. // request
  2853. //
  2854. if (!(resultData->uipDataValue & STA_STATUS_PRESENT) ) {
  2855. //
  2856. // The next work done phase is WORK_DONE_FAILURE. This allows the
  2857. // request to be completed right away. We will mark the status as
  2858. // success however, so that processing can continue
  2859. //
  2860. PowerRequest->NextWorkDone = WORK_DONE_FAILURE;
  2861. PowerRequest->Status = STATUS_SUCCESS;
  2862. } else {
  2863. //
  2864. // We are done with this work
  2865. //
  2866. PowerRequest->NextWorkDone = WORK_DONE_COMPLETE;
  2867. }
  2868. //
  2869. // Call the completion routine by brute force. Note that at this
  2870. // point, we count everything as being SUCCESS
  2871. //
  2872. ACPIDeviceCompleteGenericPhase(
  2873. NULL,
  2874. STATUS_SUCCESS,
  2875. NULL,
  2876. PowerRequest
  2877. );
  2878. return STATUS_SUCCESS;
  2879. } // ACPIDevicePowerProcessPhase0DeviceSubPhase2
  2880. NTSTATUS
  2881. ACPIDevicePowerProcessPhase0SystemSubPhase1(
  2882. IN PACPI_POWER_REQUEST PowerRequest
  2883. )
  2884. /*++
  2885. Routine Description:
  2886. This routine unpauses the interpreter (if so required)
  2887. Arguments:
  2888. PowerRequest - The request we are currently processing
  2889. Return Value:
  2890. NTSTATUS
  2891. --*/
  2892. {
  2893. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  2894. SYSTEM_POWER_STATE systemState;
  2895. ACPIDevPrint( (
  2896. ACPI_PRINT_POWER,
  2897. deviceExtension,
  2898. "(0x%08lx): ACPIDevicePowerProcessPhase0SystemSubPhase1\n",
  2899. PowerRequest
  2900. ) );
  2901. //
  2902. // We are done the first phase
  2903. //
  2904. PowerRequest->NextWorkDone = WORK_DONE_COMPLETE;
  2905. //
  2906. // Fetch the target system state
  2907. //
  2908. systemState = PowerRequest->u.SystemPowerRequest.SystemPowerState;
  2909. //
  2910. // If we are going to S0, then tell the interperter to resume
  2911. //
  2912. if (systemState == PowerSystemWorking) {
  2913. AMLIResumeInterpreter();
  2914. }
  2915. //
  2916. // Call the completion routine
  2917. //
  2918. ACPIDeviceCompleteInterpreterRequest(
  2919. PowerRequest
  2920. );
  2921. //
  2922. // We are successfull
  2923. //
  2924. return STATUS_SUCCESS;
  2925. } // ACPIDevicePowerProcessPhase0SystemSubPhase1
  2926. NTSTATUS
  2927. ACPIDevicePowerProcessPhase1DeviceSubPhase1(
  2928. IN PACPI_POWER_REQUEST PowerRequest
  2929. )
  2930. /*++
  2931. Routine Description:
  2932. Any device that is going to transition to the D3 state should have
  2933. have it resources disabled. This function detects if this is the
  2934. case and runs the _DIS object, if appropriate
  2935. Arguments:
  2936. PowerRequest - The current request structure that we must process
  2937. Return Value:
  2938. NTSTATUS
  2939. If we ignore errors, then this function can only return:
  2940. STATUS_SUCCESS
  2941. STATUS_PENDING
  2942. Otherwise, it can return any STATUS_XXX code it wants
  2943. --*/
  2944. {
  2945. DEVICE_POWER_STATE deviceState;
  2946. NTSTATUS status = STATUS_SUCCESS;
  2947. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  2948. PNSOBJ disObject = NULL;
  2949. ULONG flags;
  2950. //
  2951. // Get some data from the request
  2952. //
  2953. deviceState = PowerRequest->u.DevicePowerRequest.DevicePowerState;
  2954. flags = PowerRequest->u.DevicePowerRequest.Flags;
  2955. //
  2956. // We are going to need to fake the value from an _STA, so lets do
  2957. // that now
  2958. //
  2959. RtlZeroMemory( &(PowerRequest->ResultData), sizeof(OBJDATA) );
  2960. PowerRequest->ResultData.dwDataType = OBJTYPE_INTDATA;
  2961. PowerRequest->ResultData.uipDataValue = 0;
  2962. //
  2963. // Decide what the next subphase will be. The rule here is that if we
  2964. // are going to D0, then we can skip to Step 3, otherwise, we must go
  2965. // to Step 1. We also skip to step3 if we are on the hibernate path
  2966. //
  2967. if (deviceState == PowerDeviceD0 ||
  2968. (flags & DEVICE_REQUEST_LOCK_HIBER) ) {
  2969. PowerRequest->NextWorkDone = WORK_DONE_STEP_3;
  2970. goto ACPIDevicePowerProcessPhase1DeviceSubPhase1Exit;
  2971. } else if (deviceExtension->Flags & DEV_PROP_NO_OBJECT) {
  2972. PowerRequest->NextWorkDone = WORK_DONE_STEP_2;
  2973. goto ACPIDevicePowerProcessPhase1DeviceSubPhase1Exit;
  2974. } else {
  2975. PowerRequest->NextWorkDone = WORK_DONE_STEP_1;
  2976. if (deviceState != PowerDeviceD3) {
  2977. goto ACPIDevicePowerProcessPhase1DeviceSubPhase1Exit;
  2978. }
  2979. }
  2980. //
  2981. // See if the _DIS object exists
  2982. //
  2983. disObject = ACPIAmliGetNamedChild(
  2984. deviceExtension->AcpiObject,
  2985. PACKED_DIS
  2986. );
  2987. if (disObject != NULL) {
  2988. //
  2989. // Lets run that method
  2990. //
  2991. status = AMLIAsyncEvalObject(
  2992. disObject,
  2993. NULL,
  2994. 0,
  2995. NULL,
  2996. ACPIDeviceCompleteGenericPhase,
  2997. PowerRequest
  2998. );
  2999. //
  3000. // If we got a pending back, then we should return now
  3001. //
  3002. if (status == STATUS_PENDING) {
  3003. return status;
  3004. }
  3005. }
  3006. ACPIDevicePowerProcessPhase1DeviceSubPhase1Exit:
  3007. //
  3008. // Call the completion routine by brute force. Note that at this
  3009. // point, we count everything as being SUCCESS
  3010. //
  3011. ACPIDeviceCompleteGenericPhase(
  3012. disObject,
  3013. status,
  3014. NULL,
  3015. PowerRequest
  3016. );
  3017. return STATUS_SUCCESS;
  3018. } // ACPIDevicePowerProcessPhase1DeviceSubPhase1
  3019. NTSTATUS
  3020. ACPIDevicePowerProcessPhase1DeviceSubPhase2(
  3021. IN PACPI_POWER_REQUEST PowerRequest
  3022. )
  3023. /*++
  3024. Routine Description:
  3025. This routine runs the _PS1, _PS2, or _PS3 control methods
  3026. Arguments:
  3027. PowerRequest - The current request structure that we must process
  3028. Return Value:
  3029. NTSTATUS
  3030. If we ignore errors, then this function can only return:
  3031. STATUS_SUCCESS
  3032. STATUS_PENDING
  3033. Otherwise, it can return any STATUS_XXX code it wants
  3034. --*/
  3035. {
  3036. DEVICE_POWER_STATE deviceState;
  3037. NTSTATUS status = STATUS_SUCCESS;
  3038. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  3039. PNSOBJ powerObject = NULL;
  3040. //
  3041. // The next phase that we will go to is Step_2
  3042. //
  3043. PowerRequest->NextWorkDone = WORK_DONE_STEP_2;
  3044. //
  3045. // Since we cannot get to this subphase when transitioning to D0, its
  3046. // safe to just look for the object to run
  3047. //
  3048. deviceState = PowerRequest->u.DevicePowerRequest.DevicePowerState;
  3049. powerObject = deviceExtension->PowerInfo.PowerObject[ deviceState ];
  3050. //
  3051. // If there is an object, then run the control method
  3052. //
  3053. if (powerObject != NULL) {
  3054. status = AMLIAsyncEvalObject(
  3055. powerObject,
  3056. NULL,
  3057. 0,
  3058. NULL,
  3059. ACPIDeviceCompleteGenericPhase,
  3060. PowerRequest
  3061. );
  3062. ACPIDevPrint( (
  3063. ACPI_PRINT_POWER,
  3064. deviceExtension,
  3065. "(0x%08lx): ACPIDevicePowerProcessPhase1DeviceSubPhase2 "
  3066. "= 0x%08lx\n",
  3067. PowerRequest,
  3068. status
  3069. ) );
  3070. //
  3071. // If we cannot complete the work ourselves, we must stop now
  3072. //
  3073. if (status == STATUS_PENDING) {
  3074. return status;
  3075. }
  3076. }
  3077. //
  3078. // Call the completion routine by brute force.
  3079. //
  3080. ACPIDeviceCompleteGenericPhase(
  3081. powerObject,
  3082. status,
  3083. NULL,
  3084. PowerRequest
  3085. );
  3086. return STATUS_SUCCESS;
  3087. } // ACPIPowerProcessPhase1DeviceSubPhase2
  3088. NTSTATUS
  3089. ACPIDevicePowerProcessPhase1DeviceSubPhase3(
  3090. IN PACPI_POWER_REQUEST PowerRequest
  3091. )
  3092. /*++
  3093. Routine Description:
  3094. This routine runs the _STA of the device to make sure that it has in
  3095. fact been turned off
  3096. Arguments:
  3097. PowerRequest - The current request structure that we must process
  3098. Return Value:
  3099. NTSTATUS
  3100. If we ignore errors, then this function can only return:
  3101. STATUS_SUCCESS
  3102. STATUS_PENDING
  3103. Otherwise, it can return any STATUS_XXX code it wants
  3104. --*/
  3105. {
  3106. NTSTATUS status = STATUS_SUCCESS;
  3107. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  3108. POBJDATA resultData = &(PowerRequest->ResultData);
  3109. PNSOBJ staObject = NULL;
  3110. PNSOBJ acpiObject = NULL;
  3111. //
  3112. // The next stage is STEP_3
  3113. //
  3114. PowerRequest->NextWorkDone = WORK_DONE_STEP_3;
  3115. //
  3116. // We already have space allocate for the result of the _STA. Make
  3117. // that there is no garbage present
  3118. //
  3119. RtlZeroMemory( resultData, sizeof(OBJDATA) );
  3120. //
  3121. // Is there an _STA object present on this device?
  3122. //
  3123. if (deviceExtension->Flags & DEV_PROP_DOCK) {
  3124. ASSERT( deviceExtension->Dock.CorrospondingAcpiDevice );
  3125. acpiObject = deviceExtension->Dock.CorrospondingAcpiDevice->AcpiObject;
  3126. } else {
  3127. acpiObject = deviceExtension->AcpiObject;
  3128. }
  3129. staObject = ACPIAmliGetNamedChild(
  3130. acpiObject,
  3131. PACKED_STA
  3132. );
  3133. if (staObject != NULL) {
  3134. status = AMLIAsyncEvalObject(
  3135. staObject,
  3136. resultData,
  3137. 0,
  3138. NULL,
  3139. ACPIDeviceCompleteGenericPhase,
  3140. PowerRequest
  3141. );
  3142. ACPIDevPrint( (
  3143. ACPI_PRINT_POWER,
  3144. deviceExtension,
  3145. "(0x%08lx): ACPIDevicePowerProcessPhase1DeviceSubPhase3 "
  3146. "= 0x%08lx\n",
  3147. PowerRequest,
  3148. status
  3149. ) );
  3150. } else {
  3151. //
  3152. // Lets fake the data. Note that in this case we will pretend that
  3153. // the value is 0x0, even though the spec says that the default
  3154. // is (ULONG) - 1. The reason we are doing this is that in this
  3155. // case we want to approximate the behaviour of the real _STA...
  3156. //
  3157. resultData->dwDataType = OBJTYPE_INTDATA;
  3158. resultData->uipDataValue = STA_STATUS_PRESENT;
  3159. status = STATUS_SUCCESS;
  3160. }
  3161. //
  3162. // Do we have to call the completion routine ourselves?
  3163. //
  3164. if (status != STATUS_PENDING) {
  3165. ACPIDeviceCompleteGenericPhase(
  3166. staObject,
  3167. status,
  3168. NULL,
  3169. PowerRequest
  3170. );
  3171. }
  3172. //
  3173. // Always return success
  3174. //
  3175. return STATUS_SUCCESS;
  3176. } // ACPIDevicePowerProcessPhase1DeviceSubPhase3
  3177. NTSTATUS
  3178. ACPIDevicePowerProcessPhase1DeviceSubPhase4(
  3179. IN PACPI_POWER_REQUEST PowerRequest
  3180. )
  3181. /*++
  3182. Routine Description:
  3183. This function determines which device nodes need to be looked at. The
  3184. generic rule is that we need to remember which nodes belong to a device
  3185. that is either starting or stopping to use that node. Generally, these
  3186. are the nodes in the current power state and the nodes in the desired
  3187. power state
  3188. Arguments:
  3189. PowerRequest - The current request structure that we must process
  3190. Return Value:
  3191. NTSTATUS
  3192. If we ignore errors, then this function can only return:
  3193. STATUS_SUCCESS
  3194. STATUS_PENDING
  3195. Otherwise, it can return any STATUS_XXX code it wants
  3196. --*/
  3197. {
  3198. DEVICE_POWER_STATE deviceState;
  3199. KIRQL oldIrql;
  3200. PACPI_DEVICE_POWER_NODE deviceNode = NULL;
  3201. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  3202. POBJDATA resultData = &(PowerRequest->ResultData);
  3203. ULONG flags;
  3204. //
  3205. // Clear the result
  3206. //
  3207. AMLIFreeDataBuffs( resultData, 1 );
  3208. RtlZeroMemory( resultData, sizeof(OBJDATA) );
  3209. //
  3210. // We cannot walk any data structures without holding a lock
  3211. //
  3212. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  3213. //
  3214. // First step is to find the list of nodes which are in use by this
  3215. // device
  3216. //
  3217. deviceState = deviceExtension->PowerInfo.PowerState;
  3218. if (deviceState >= PowerDeviceD0 && deviceState <= PowerDeviceD2) {
  3219. //
  3220. // In this case, we have to look at the current and the desired
  3221. // device states only
  3222. //
  3223. deviceNode = deviceExtension->PowerInfo.PowerNode[ deviceState ];
  3224. //
  3225. // Next step is to look at all the nodes and mark the power objects
  3226. // as requiring an update
  3227. //
  3228. while (deviceNode != NULL) {
  3229. InterlockedExchange(
  3230. &(deviceNode->PowerNode->WorkDone),
  3231. WORK_DONE_STEP_0
  3232. );
  3233. deviceNode = deviceNode->Next;
  3234. }
  3235. //
  3236. // Now, we need to find the list of nodes which are going to be used
  3237. //
  3238. deviceState = PowerRequest->u.DevicePowerRequest.DevicePowerState;
  3239. if (deviceState >= PowerDeviceD0 && deviceState <= PowerDeviceD2) {
  3240. deviceNode = deviceExtension->PowerInfo.PowerNode[ deviceState ];
  3241. }
  3242. //
  3243. // Next step is to look at all the nodes and mark the power objects
  3244. // as requiring an update
  3245. //
  3246. while (deviceNode != NULL) {
  3247. InterlockedExchange(
  3248. &(deviceNode->PowerNode->WorkDone),
  3249. WORK_DONE_STEP_0
  3250. );
  3251. deviceNode = deviceNode->Next;
  3252. }
  3253. } else {
  3254. //
  3255. // In this case, we have to look at all possible Device states
  3256. //
  3257. for (deviceState = PowerDeviceD0;
  3258. deviceState < PowerDeviceD3;
  3259. deviceState++) {
  3260. deviceNode = deviceExtension->PowerInfo.PowerNode[ deviceState ];
  3261. //
  3262. // Next step is to look at all the nodes and mark the power objects
  3263. // as requiring an update
  3264. //
  3265. while (deviceNode != NULL) {
  3266. InterlockedExchange(
  3267. &(deviceNode->PowerNode->WorkDone),
  3268. WORK_DONE_STEP_0
  3269. );
  3270. deviceNode = deviceNode->Next;
  3271. }
  3272. }
  3273. //
  3274. // This is the device state that we will go to
  3275. //
  3276. deviceState = PowerRequest->u.DevicePowerRequest.DevicePowerState;
  3277. }
  3278. //
  3279. // If this is a request on the hibernate path, the mark all the nodes
  3280. // for the D0 as being required Hibernate nodes
  3281. //
  3282. flags = PowerRequest->u.DevicePowerRequest.Flags;
  3283. if (flags & DEVICE_REQUEST_LOCK_HIBER) {
  3284. deviceNode = deviceExtension->PowerInfo.PowerNode[ PowerDeviceD0 ];
  3285. //
  3286. // Next step is to look at all the nodes and mark the power objects
  3287. // as requiring an update
  3288. //
  3289. while (deviceNode != NULL) {
  3290. ACPIInternalUpdateFlags(
  3291. &(deviceNode->PowerNode->Flags),
  3292. (DEVICE_NODE_HIBERNATE_PATH | DEVICE_NODE_OVERRIDE_ON),
  3293. FALSE
  3294. );
  3295. ACPIInternalUpdateFlags(
  3296. &(deviceNode->PowerNode->Flags),
  3297. DEVICE_NODE_OVERRIDE_OFF,
  3298. TRUE
  3299. );
  3300. InterlockedExchange(
  3301. &(deviceNode->PowerNode->WorkDone),
  3302. WORK_DONE_STEP_0
  3303. );
  3304. deviceNode = deviceNode->Next;
  3305. }
  3306. } else if (flags & DEVICE_REQUEST_UNLOCK_HIBER) {
  3307. deviceNode = deviceExtension->PowerInfo.PowerNode[ PowerDeviceD0 ];
  3308. //
  3309. // Next step is to look at all the nodes and mark the power objects
  3310. // as requiring an update
  3311. //
  3312. while (deviceNode != NULL) {
  3313. ACPIInternalUpdateFlags(
  3314. &(deviceNode->PowerNode->Flags),
  3315. (DEVICE_NODE_HIBERNATE_PATH | DEVICE_NODE_OVERRIDE_ON),
  3316. TRUE
  3317. );
  3318. InterlockedExchange(
  3319. &(deviceNode->PowerNode->WorkDone),
  3320. WORK_DONE_STEP_0
  3321. );
  3322. deviceNode = deviceNode->Next;
  3323. }
  3324. }
  3325. //
  3326. // Remember the desired state
  3327. //
  3328. deviceExtension->PowerInfo.DesiredPowerState = deviceState;
  3329. //
  3330. // Also, consider that the device is now in an unknown state ---
  3331. // if we fail something, the is the power state that we will be left
  3332. // at
  3333. //
  3334. deviceExtension->PowerInfo.PowerState = PowerDeviceUnspecified;
  3335. //
  3336. // We no longer need the PowerLock
  3337. //
  3338. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  3339. //
  3340. // Done
  3341. //
  3342. ACPIDeviceCompleteCommon( &(PowerRequest->WorkDone), WORK_DONE_COMPLETE );
  3343. return STATUS_SUCCESS;
  3344. }
  3345. NTSTATUS
  3346. ACPIDevicePowerProcessPhase2SystemSubPhase1(
  3347. IN PACPI_POWER_REQUEST PowerRequest
  3348. )
  3349. /*++
  3350. Routine Description:
  3351. This routine updates the PowerObject references so that we can run
  3352. _ON or _OFF methods as needed
  3353. This also cause _WAK() to be run on the system
  3354. Arguments:
  3355. PowerRequest - The current request structure that we must process
  3356. Return Value:
  3357. NTSTATUS
  3358. If we ignore errors, then this function can only return:
  3359. STATUS_SUCCESS
  3360. STATUS_PENDING
  3361. Otherwise, it can return any STATUS_XXX code it wants
  3362. --*/
  3363. {
  3364. BOOLEAN restart = FALSE;
  3365. NTSTATUS status = STATUS_SUCCESS;
  3366. OBJDATA objData;
  3367. PACPI_DEVICE_POWER_NODE deviceNode = NULL;
  3368. PACPI_POWER_DEVICE_NODE powerNode = NULL;
  3369. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  3370. PLIST_ENTRY deviceList;
  3371. PLIST_ENTRY powerList;
  3372. PNSOBJ sleepObject = NULL;
  3373. POWER_ACTION systemAction;
  3374. SYSTEM_POWER_STATE systemState;
  3375. SYSTEM_POWER_STATE wakeFromState;
  3376. ULONG hibernateCount = 0;
  3377. //
  3378. // The next stage after this one is STEP_1
  3379. //
  3380. PowerRequest->NextWorkDone = WORK_DONE_STEP_1;
  3381. //
  3382. // Get the desired system state
  3383. //
  3384. systemState = PowerRequest->u.SystemPowerRequest.SystemPowerState;
  3385. systemAction = PowerRequest->u.SystemPowerRequest.SystemPowerAction;
  3386. //
  3387. // Is the system restarting?
  3388. //
  3389. restart = ( (systemState == PowerSystemShutdown) &&
  3390. (systemAction == PowerActionShutdownReset) );
  3391. //
  3392. // We need to hold this lock before we can walk this list
  3393. //
  3394. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  3395. //
  3396. // Get the first power node
  3397. //
  3398. powerList = AcpiPowerNodeList.Flink;
  3399. //
  3400. // Walk the list and see which devices need to be turned on or
  3401. // turned off
  3402. //
  3403. while (powerList != &AcpiPowerNodeList) {
  3404. //
  3405. // Obtain the power node from the listEntry
  3406. //
  3407. powerNode = CONTAINING_RECORD(
  3408. powerList,
  3409. ACPI_POWER_DEVICE_NODE,
  3410. ListEntry
  3411. );
  3412. //
  3413. // Next node
  3414. //
  3415. powerList = powerList->Flink;
  3416. //
  3417. // We need to walk the list of device nodes to see if any of
  3418. // the devices are in the hibernate path.
  3419. //
  3420. deviceList = powerNode->DevicePowerListHead.Flink;
  3421. while (deviceList != &(powerNode->DevicePowerListHead) ) {
  3422. //
  3423. // Obtain the devicenode from the list pointer
  3424. //
  3425. deviceNode = CONTAINING_RECORD(
  3426. deviceList,
  3427. ACPI_DEVICE_POWER_NODE,
  3428. DevicePowerListEntry
  3429. );
  3430. //
  3431. // Point to the next node
  3432. //
  3433. deviceList = deviceList->Flink;
  3434. //
  3435. // Grab the associated device extension
  3436. //
  3437. deviceExtension = deviceNode->DeviceExtension;
  3438. //
  3439. // Does the node belong on the hibernate path
  3440. //
  3441. hibernateCount = InterlockedCompareExchange(
  3442. &(deviceExtension->HibernatePathCount),
  3443. 0,
  3444. 0
  3445. );
  3446. if (hibernateCount) {
  3447. break;
  3448. }
  3449. }
  3450. //
  3451. // Mark the node as being in the hibernate path, or not, as the
  3452. // case might be
  3453. //
  3454. ACPIInternalUpdateFlags(
  3455. &(powerNode->Flags),
  3456. DEVICE_NODE_HIBERNATE_PATH,
  3457. (BOOLEAN) !hibernateCount
  3458. );
  3459. //
  3460. // First check is to see if the node is on the hibernate path and
  3461. // this is a hibernate request, or if the system is restarting
  3462. //
  3463. if ( (hibernateCount && systemState == PowerSystemHibernate) ||
  3464. (restart == TRUE) ) {
  3465. if (powerNode->Flags & DEVICE_NODE_OVERRIDE_OFF) {
  3466. //
  3467. // make sure that the Override Off flag is disabled
  3468. //
  3469. ACPIInternalUpdateFlags(
  3470. &(powerNode->Flags),
  3471. DEVICE_NODE_OVERRIDE_OFF,
  3472. TRUE
  3473. );
  3474. //
  3475. // Mark the node as requiring an update
  3476. //
  3477. InterlockedExchange(
  3478. &(powerNode->WorkDone),
  3479. WORK_DONE_STEP_0
  3480. );
  3481. }
  3482. } else {
  3483. //
  3484. // Does the node support the indicates system state?
  3485. //
  3486. if (powerNode->SystemLevel < systemState) {
  3487. //
  3488. // No --- we must disable it, but if we cannot always be on.
  3489. //
  3490. if ( !(powerNode->Flags & DEVICE_NODE_ALWAYS_ON) ) {
  3491. ACPIInternalUpdateFlags(
  3492. &(powerNode->Flags),
  3493. DEVICE_NODE_OVERRIDE_OFF,
  3494. FALSE
  3495. );
  3496. }
  3497. //
  3498. // Mark the node as requiring an update
  3499. //
  3500. InterlockedExchange(
  3501. &(powerNode->WorkDone),
  3502. WORK_DONE_STEP_0
  3503. );
  3504. } else if (powerNode->Flags & DEVICE_NODE_OVERRIDE_OFF) {
  3505. //
  3506. // Disable this flag
  3507. //
  3508. ACPIInternalUpdateFlags(
  3509. &(powerNode->Flags),
  3510. DEVICE_NODE_OVERRIDE_OFF,
  3511. TRUE
  3512. );
  3513. //
  3514. // Mark the node as requiring an update
  3515. //
  3516. InterlockedExchange(
  3517. &(powerNode->WorkDone),
  3518. WORK_DONE_STEP_0
  3519. );
  3520. }
  3521. }
  3522. }
  3523. //
  3524. // Set the WakeFromState while we still hold the power lock.
  3525. //
  3526. wakeFromState = AcpiMostRecentSleepState;
  3527. //
  3528. // We don't need to hold lock anymore
  3529. //
  3530. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  3531. //
  3532. // We can only do the following if we are transitioning to the S0 state
  3533. //
  3534. if (systemState == PowerSystemWorking) {
  3535. //
  3536. // Always run the _WAK method (this clears the PTS(S5) if that is
  3537. // the last thing we did, otherwise it is the proper action to take
  3538. //
  3539. sleepObject = ACPIAmliGetNamedChild(
  3540. PowerRequest->DeviceExtension->AcpiObject->pnsParent,
  3541. PACKED_WAK
  3542. );
  3543. //
  3544. // We only try to evaluate a method if we found an object
  3545. //
  3546. if (sleepObject != NULL) {
  3547. //
  3548. // Remember that AMLI doesn't use our definitions, so we will
  3549. // have to normalize the S value
  3550. //
  3551. RtlZeroMemory( &objData, sizeof(OBJDATA) );
  3552. objData.dwDataType = OBJTYPE_INTDATA;
  3553. objData.uipDataValue = ACPIDeviceMapACPIPowerState(
  3554. wakeFromState
  3555. );
  3556. //
  3557. // Safely run the control method
  3558. //
  3559. status = AMLIAsyncEvalObject(
  3560. sleepObject,
  3561. NULL,
  3562. 1,
  3563. &objData,
  3564. ACPIDeviceCompleteGenericPhase,
  3565. PowerRequest
  3566. );
  3567. //
  3568. // If we got STATUS_PENDING, then we cannot do any more work here.
  3569. //
  3570. if (status == STATUS_PENDING) {
  3571. return status;
  3572. }
  3573. }
  3574. }
  3575. //
  3576. // Always call the completion routine
  3577. //
  3578. ACPIDeviceCompleteGenericPhase(
  3579. sleepObject,
  3580. status,
  3581. NULL,
  3582. PowerRequest
  3583. );
  3584. //
  3585. // Never return anything other then STATUS_SUCCESS
  3586. //
  3587. return STATUS_SUCCESS;
  3588. } // ACPIPowerProcessPhase2SystemSubPhase1
  3589. NTSTATUS
  3590. ACPIDevicePowerProcessPhase2SystemSubPhase2(
  3591. IN PACPI_POWER_REQUEST PowerRequest
  3592. )
  3593. /*++
  3594. Routine Description:
  3595. This phase is called after the _WAK method has been run
  3596. Arguments:
  3597. PowerRequest - The current request structure that we must process
  3598. Return Value:
  3599. NTSTATUS
  3600. If we ignore errors, then this function can only return:
  3601. STATUS_SUCCESS
  3602. STATUS_PENDING
  3603. Otherwise, it can return any STATUS_XXX code it wants
  3604. --*/
  3605. {
  3606. NTSTATUS status = STATUS_SUCCESS;
  3607. SYSTEM_POWER_STATE systemState;
  3608. //
  3609. // The next stage is STEP_2
  3610. //
  3611. PowerRequest->NextWorkDone = WORK_DONE_STEP_2;
  3612. //
  3613. // We need to make sure that the IRQ arbiter has been restored
  3614. // if we are making an S0 transition
  3615. //
  3616. systemState = PowerRequest->u.SystemPowerRequest.SystemPowerState;
  3617. if (systemState == PowerSystemWorking) {
  3618. //
  3619. // Restore the IRQ arbiter
  3620. //
  3621. status = IrqArbRestoreIrqRouting(
  3622. ACPIDeviceCompleteGenericPhase,
  3623. (PVOID) PowerRequest
  3624. );
  3625. if (status == STATUS_PENDING) {
  3626. //
  3627. // Do not do any more work here
  3628. //
  3629. return status;
  3630. }
  3631. }
  3632. //
  3633. // Call the next completion routine
  3634. //
  3635. ACPIDeviceCompleteGenericPhase(
  3636. NULL,
  3637. status,
  3638. NULL,
  3639. PowerRequest
  3640. );
  3641. //
  3642. // Always return success
  3643. //
  3644. return STATUS_SUCCESS;
  3645. } // ACPIDevicePowerProcessPhase2SystemSubPhase2
  3646. NTSTATUS
  3647. ACPIDevicePowerProcessPhase2SystemSubPhase3(
  3648. IN PACPI_POWER_REQUEST PowerRequest
  3649. )
  3650. /*++
  3651. Routine Description:
  3652. This phase is used to see if we need to re-run the _PSW for all the
  3653. devices. We need to do this when we restore from the hibernate state
  3654. Arguments:
  3655. PowerRequest - The current request structure that we must process
  3656. Return Value:
  3657. NTSTATUS
  3658. If we ignore errors, then this function can only return:
  3659. STATUS_SUCCESS
  3660. STATUS_PENDING
  3661. Otherwise, it can return any STATUS_XXX code it wants
  3662. --*/
  3663. {
  3664. NTSTATUS status = STATUS_SUCCESS;
  3665. SYSTEM_POWER_STATE systemState;
  3666. SYSTEM_POWER_STATE wakeFromState;
  3667. //
  3668. // The next stage is COMPLETE
  3669. //
  3670. PowerRequest->NextWorkDone = WORK_DONE_COMPLETE;
  3671. //
  3672. // If we just transitioned from Hibernate, then we must re-enable all
  3673. // the wake devices
  3674. //
  3675. systemState = PowerRequest->u.SystemPowerRequest.SystemPowerState;
  3676. //
  3677. // Grab the current most recent sleep state and make sure to hold the
  3678. // locks while doing so
  3679. //
  3680. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  3681. wakeFromState = AcpiMostRecentSleepState;
  3682. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  3683. if (systemState == PowerSystemWorking &&
  3684. wakeFromState == PowerSystemHibernate) {
  3685. //
  3686. // Restore the IRQ arbiter
  3687. //
  3688. status = ACPIWakeRestoreEnables(
  3689. ACPIWakeRestoreEnablesCompletion,
  3690. PowerRequest
  3691. );
  3692. if (status == STATUS_PENDING) {
  3693. //
  3694. // Do not do any more work here
  3695. //
  3696. return status;
  3697. }
  3698. }
  3699. //
  3700. // Call the next completion routine
  3701. //
  3702. ACPIDeviceCompleteGenericPhase(
  3703. NULL,
  3704. status,
  3705. NULL,
  3706. PowerRequest
  3707. );
  3708. //
  3709. // Always return success
  3710. //
  3711. return STATUS_SUCCESS;
  3712. } // ACPIDevicePowerProcessPhase2SystemSubPhase3
  3713. NTSTATUS
  3714. ACPIDevicePowerProcessPhase3(
  3715. VOID
  3716. )
  3717. /*++
  3718. Routine Description:
  3719. This routine ensures that the Power Resources are in sync
  3720. Arguments:
  3721. NONE
  3722. Return Value:
  3723. NTSTATUS
  3724. - If any request is not marked as being complete, then STATUS_PENDING
  3725. is returned, otherwise, STATUS_SUCCESS is returned
  3726. --*/
  3727. {
  3728. BOOLEAN returnPending = FALSE;
  3729. NTSTATUS status = STATUS_SUCCESS;
  3730. PACPI_DEVICE_POWER_NODE deviceNode;
  3731. PACPI_POWER_DEVICE_NODE powerNode;
  3732. PDEVICE_EXTENSION deviceExtension;
  3733. PLIST_ENTRY deviceList;
  3734. PLIST_ENTRY powerList;
  3735. ULONG useCounts;
  3736. ULONG wakeCount;
  3737. ULONG workDone;
  3738. //
  3739. // Grab the PowerLock that we need for this
  3740. //
  3741. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  3742. //
  3743. // Grab the first node in the PowerNode list
  3744. //
  3745. powerList = AcpiPowerNodeList.Flink;
  3746. //
  3747. // Walk the list forward to device what to turn on
  3748. //
  3749. while (powerList != &AcpiPowerNodeList) {
  3750. //
  3751. // Look at the current power node
  3752. //
  3753. powerNode = CONTAINING_RECORD(
  3754. powerList,
  3755. ACPI_POWER_DEVICE_NODE,
  3756. ListEntry
  3757. );
  3758. //
  3759. // Next item in the list
  3760. //
  3761. powerList = powerList->Flink;
  3762. //
  3763. // Have we marked the node has having some potential work that
  3764. // needs to be done?
  3765. //
  3766. workDone = InterlockedCompareExchange(
  3767. &(powerNode->WorkDone),
  3768. WORK_DONE_STEP_1,
  3769. WORK_DONE_STEP_0
  3770. );
  3771. //
  3772. // If we don't have any work to do, then loop back to the start
  3773. //
  3774. if (workDone != WORK_DONE_STEP_0) {
  3775. continue;
  3776. }
  3777. //
  3778. // We need to walk the list of device nodes to see if
  3779. // any of the devices are in need of this power resource
  3780. //
  3781. useCounts = 0;
  3782. deviceList = powerNode->DevicePowerListHead.Flink;
  3783. while (deviceList != &(powerNode->DevicePowerListHead) ) {
  3784. //
  3785. // Obtain the deviceNode from the list pointer
  3786. //
  3787. deviceNode = CONTAINING_RECORD(
  3788. deviceList,
  3789. ACPI_DEVICE_POWER_NODE,
  3790. DevicePowerListEntry
  3791. );
  3792. //
  3793. // Point to the next node
  3794. //
  3795. deviceList = deviceList->Flink;
  3796. //
  3797. // Grab the associated device extension
  3798. //
  3799. deviceExtension = deviceNode->DeviceExtension;
  3800. //
  3801. // Grab the number of wake counts on the node
  3802. //
  3803. wakeCount = InterlockedCompareExchange(
  3804. &(deviceExtension->PowerInfo.WakeSupportCount),
  3805. 0,
  3806. 0
  3807. );
  3808. //
  3809. // Does the device node belong to the desired state? The
  3810. // other valid state is if the node is required to wake the
  3811. // device and we have functionality enabled.
  3812. //
  3813. if (deviceExtension->PowerInfo.DesiredPowerState ==
  3814. deviceNode->AssociatedDeviceState ||
  3815. (wakeCount && deviceNode->WakePowerResource) ) {
  3816. useCounts++;
  3817. }
  3818. }
  3819. //
  3820. // Set the number of use counts in the PowerResource
  3821. //
  3822. InterlockedExchange(
  3823. &(powerNode->UseCounts),
  3824. useCounts
  3825. );
  3826. //
  3827. // See if the override bits are set properly
  3828. //
  3829. if ( (powerNode->Flags & DEVICE_NODE_TURN_OFF) ) {
  3830. //
  3831. // Do not run anything
  3832. //
  3833. continue;
  3834. }
  3835. if ( !(powerNode->Flags & DEVICE_NODE_TURN_ON) &&
  3836. useCounts == 0 ) {
  3837. //
  3838. // Do not run anything
  3839. //
  3840. continue;
  3841. }
  3842. //
  3843. // We are going to do some work on this node, so mark it as
  3844. // such, so that we don't accidently run the _OFF method for
  3845. // this device
  3846. //
  3847. workDone = InterlockedCompareExchange(
  3848. &(powerNode->WorkDone),
  3849. WORK_DONE_PENDING,
  3850. WORK_DONE_STEP_1
  3851. );
  3852. //
  3853. // We cannot hold the spin lock while we eval the method
  3854. //
  3855. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  3856. //
  3857. // Evaluate the method to turn this node on
  3858. //
  3859. status = AMLIAsyncEvalObject(
  3860. powerNode->PowerOnObject,
  3861. NULL,
  3862. 0,
  3863. NULL,
  3864. ACPIDeviceCompletePhase3On,
  3865. powerNode
  3866. );
  3867. //
  3868. // Let the world know
  3869. //
  3870. ACPIPrint( (
  3871. ACPI_PRINT_POWER,
  3872. "ACPIDevicePowerProcessPhase3: PowerNode: 0x%08lx ON = 0x%08lx\n",
  3873. powerNode,
  3874. status
  3875. ) );
  3876. if (status != STATUS_PENDING) {
  3877. //
  3878. // Fake a call to the callback
  3879. //
  3880. ACPIDeviceCompletePhase3On(
  3881. powerNode->PowerOnObject,
  3882. status,
  3883. NULL,
  3884. powerNode
  3885. );
  3886. } else {
  3887. //
  3888. // Remember that a function returned Pending
  3889. //
  3890. returnPending = TRUE;
  3891. }
  3892. //
  3893. // Reacquire the spinlock so that we can loop again
  3894. //
  3895. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  3896. } // while
  3897. //
  3898. // Grab the blink so that we can start walking the list backward
  3899. //
  3900. powerList = AcpiPowerNodeList.Blink;
  3901. //
  3902. // Walk the list backward
  3903. //
  3904. while (powerList != &AcpiPowerNodeList) {
  3905. //
  3906. // Look at the current power node
  3907. //
  3908. powerNode = CONTAINING_RECORD(
  3909. powerList,
  3910. ACPI_POWER_DEVICE_NODE,
  3911. ListEntry
  3912. );
  3913. //
  3914. // Next item in the list
  3915. //
  3916. powerList = powerList->Blink;
  3917. //
  3918. // Have we marked the node has having some potential work that
  3919. // needs to be done?
  3920. //
  3921. workDone = InterlockedCompareExchange(
  3922. &(powerNode->WorkDone),
  3923. WORK_DONE_PENDING,
  3924. WORK_DONE_STEP_1
  3925. );
  3926. //
  3927. // To do work on this node, we need to see WORK_DONE_STEP_1
  3928. //
  3929. if (workDone != WORK_DONE_STEP_1) {
  3930. //
  3931. // While we are here, we can check to see if the request is
  3932. // complete --- if it isn't then we must return STATUS_PENDING
  3933. //
  3934. if (workDone != WORK_DONE_COMPLETE) {
  3935. returnPending = TRUE;
  3936. }
  3937. continue;
  3938. }
  3939. //
  3940. // Release the spinlock since we cannot own it while we call
  3941. // the interpreter
  3942. //
  3943. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  3944. //
  3945. // If we are here, we *must* run the _OFF method
  3946. //
  3947. status = AMLIAsyncEvalObject(
  3948. powerNode->PowerOffObject,
  3949. NULL,
  3950. 0,
  3951. NULL,
  3952. ACPIDeviceCompletePhase3Off,
  3953. powerNode
  3954. );
  3955. //
  3956. // Let the world know
  3957. //
  3958. ACPIPrint( (
  3959. ACPI_PRINT_POWER,
  3960. "ACPIDevicePowerProcessPhase3: PowerNode: 0x%08lx OFF = 0x%08lx\n",
  3961. powerNode,
  3962. status
  3963. ) );
  3964. if (status != STATUS_PENDING) {
  3965. //
  3966. // Fake a call to the callback
  3967. //
  3968. ACPIDeviceCompletePhase3Off(
  3969. powerNode->PowerOffObject,
  3970. status,
  3971. NULL,
  3972. powerNode
  3973. );
  3974. } else {
  3975. //
  3976. // Remember that a function returned Pending
  3977. //
  3978. returnPending = TRUE;
  3979. }
  3980. //
  3981. // Reacquire the spinlock so that we can loop again
  3982. //
  3983. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  3984. }
  3985. //
  3986. // We no longer need the spin lock
  3987. //
  3988. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  3989. //
  3990. // Do we need to return status pending?
  3991. //
  3992. return (returnPending ? STATUS_PENDING : STATUS_SUCCESS);
  3993. } // ACPIPowerProcessPhase3
  3994. NTSTATUS
  3995. ACPIDevicePowerProcessPhase4(
  3996. VOID
  3997. )
  3998. /*++
  3999. Routine Description:
  4000. This routine looks at the all the PowerNodes again and determines wether
  4001. or not to fail a given request by wether or not a powernode failed to
  4002. go to the desired state
  4003. Arguments:
  4004. None
  4005. Return Value:
  4006. NTSTATUS
  4007. --*/
  4008. {
  4009. PACPI_DEVICE_POWER_NODE deviceNode;
  4010. PACPI_POWER_DEVICE_NODE powerNode;
  4011. PACPI_POWER_REQUEST powerRequest;
  4012. PDEVICE_EXTENSION deviceExtension;
  4013. PLIST_ENTRY listEntry = AcpiPowerPhase4List.Flink;
  4014. PLIST_ENTRY nodeList;
  4015. PLIST_ENTRY requestList;
  4016. //
  4017. // Now, we have to look at all the power nodes, and clear the fail flags
  4018. // This has to be done under spinlock protection
  4019. //
  4020. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  4021. listEntry = AcpiPowerNodeList.Flink;
  4022. while (listEntry != &AcpiPowerNodeList) {
  4023. powerNode = CONTAINING_RECORD(
  4024. listEntry,
  4025. ACPI_POWER_DEVICE_NODE,
  4026. ListEntry
  4027. );
  4028. listEntry = listEntry->Flink;
  4029. if (powerNode->Flags & DEVICE_NODE_FAIL) {
  4030. //
  4031. // Clear the failure flag
  4032. //
  4033. ACPIInternalUpdateFlags(
  4034. &(powerNode->Flags),
  4035. DEVICE_NODE_FAIL,
  4036. TRUE
  4037. );
  4038. //
  4039. // Loop for all the device extensions
  4040. //
  4041. nodeList = powerNode->DevicePowerListHead.Flink;
  4042. while (nodeList != &(powerNode->DevicePowerListHead)) {
  4043. deviceNode = CONTAINING_RECORD(
  4044. nodeList,
  4045. ACPI_DEVICE_POWER_NODE,
  4046. DevicePowerListEntry
  4047. );
  4048. nodeList = nodeList->Flink;
  4049. //
  4050. // We must do the next part not under spinlock
  4051. //
  4052. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  4053. //
  4054. // Grab the device extension associated with this node
  4055. //
  4056. deviceExtension = deviceNode->DeviceExtension;
  4057. //
  4058. // Loop on all the requests
  4059. //
  4060. requestList = AcpiPowerPhase4List.Flink;
  4061. while (requestList != &AcpiPowerPhase4List) {
  4062. powerRequest = CONTAINING_RECORD(
  4063. requestList,
  4064. ACPI_POWER_REQUEST,
  4065. ListEntry
  4066. );
  4067. requestList = requestList->Flink;
  4068. //
  4069. // Do we have a match?
  4070. //
  4071. if (powerRequest->DeviceExtension != deviceExtension) {
  4072. //
  4073. // No? Then continue
  4074. //
  4075. continue;
  4076. }
  4077. //
  4078. // Yes? Then fail the request
  4079. //
  4080. powerRequest->Status = STATUS_ACPI_POWER_REQUEST_FAILED;
  4081. ACPIDeviceCompleteRequest( powerRequest );
  4082. }
  4083. //
  4084. // Reacquire the lock
  4085. //
  4086. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  4087. }
  4088. }
  4089. }
  4090. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  4091. //
  4092. // Always return success
  4093. //
  4094. return STATUS_SUCCESS;
  4095. }
  4096. NTSTATUS
  4097. ACPIDevicePowerProcessPhase5DeviceSubPhase1(
  4098. IN PACPI_POWER_REQUEST PowerRequest
  4099. )
  4100. /*++
  4101. Routine Description:
  4102. This routine runs the _PS0 control method
  4103. Arguments:
  4104. PowerRequest - The current request structure that we must process
  4105. Return Value:
  4106. NTSTATUS
  4107. If we ignore errors, then this function can only return:
  4108. STATUS_SUCCESS
  4109. STATUS_PENDING
  4110. Otherwise, it can return any STATUS_XXX code it wants
  4111. --*/
  4112. {
  4113. BOOLEAN nodeOkay = TRUE;
  4114. DEVICE_POWER_STATE deviceState;
  4115. KIRQL oldIrql;
  4116. NTSTATUS status = STATUS_SUCCESS;
  4117. PACPI_DEVICE_POWER_NODE deviceNode = NULL;
  4118. PACPI_POWER_DEVICE_NODE powerNode = NULL;
  4119. PACPI_POWER_INFO powerInfo;
  4120. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4121. PNSOBJ powerObject = NULL;
  4122. //
  4123. // What is our desired device state?
  4124. //
  4125. deviceState = PowerRequest->u.DevicePowerRequest.DevicePowerState;
  4126. //
  4127. // Grab the power Information structure
  4128. //
  4129. powerInfo = &(deviceExtension->PowerInfo);
  4130. //
  4131. // Decide what the next subphase will be. The rule here is that if we
  4132. // are not going to D0, then we can skip to STEP_2, otherwise, we must go
  4133. // to STEP_1
  4134. //
  4135. if (deviceState != PowerDeviceD0) {
  4136. PowerRequest->NextWorkDone = WORK_DONE_STEP_2;
  4137. } else {
  4138. PowerRequest->NextWorkDone = WORK_DONE_STEP_1;
  4139. //
  4140. // We cannot walk any data structures without holding a lock
  4141. //
  4142. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  4143. //
  4144. // Look at the device nodes for D0
  4145. //
  4146. deviceNode = powerInfo->PowerNode[PowerDeviceD0];
  4147. //
  4148. // Next step is to look at all the nodes and mark the power objects
  4149. // as requiring an update
  4150. //
  4151. while (deviceNode != NULL) {
  4152. //
  4153. // Grab the associated power node
  4154. //
  4155. powerNode = deviceNode->PowerNode;
  4156. //
  4157. // Make sure that the power node is in the ON state
  4158. //
  4159. if ( !(powerNode->Flags & DEVICE_NODE_ON) ) {
  4160. nodeOkay = FALSE;
  4161. break;
  4162. }
  4163. //
  4164. // Look at the next node
  4165. //
  4166. deviceNode = deviceNode->Next;
  4167. }
  4168. //
  4169. // We are done with the lock
  4170. //
  4171. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  4172. //
  4173. // Are all the nodes in the correct state?
  4174. //
  4175. if (!nodeOkay) {
  4176. status = STATUS_UNSUCCESSFUL;
  4177. } else {
  4178. //
  4179. // Otherwise, see if there is a _PS0 method to run
  4180. //
  4181. powerObject = powerInfo->PowerObject[ deviceState ];
  4182. //
  4183. // If there is an object, then run the control method
  4184. //
  4185. if (powerObject != NULL) {
  4186. status = AMLIAsyncEvalObject(
  4187. powerObject,
  4188. NULL,
  4189. 0,
  4190. NULL,
  4191. ACPIDeviceCompleteGenericPhase,
  4192. PowerRequest
  4193. );
  4194. }
  4195. ACPIDevPrint( (
  4196. ACPI_PRINT_POWER,
  4197. deviceExtension,
  4198. "(0x%08lx): ACPIDevicePowerProcessPhase5DeviceSubPhase1 "
  4199. "= 0x%08lx\n",
  4200. PowerRequest,
  4201. status
  4202. ) );
  4203. //
  4204. // If we cannot complete the work ourselves, we must stop now
  4205. //
  4206. if (status == STATUS_PENDING) {
  4207. return status;
  4208. } else {
  4209. status = STATUS_SUCCESS;
  4210. }
  4211. }
  4212. }
  4213. //
  4214. // Call the completion routine by brute force. Note that at this
  4215. // point, we count everything as being SUCCESS
  4216. //
  4217. ACPIDeviceCompleteGenericPhase(
  4218. powerObject,
  4219. status,
  4220. NULL,
  4221. PowerRequest
  4222. );
  4223. return STATUS_SUCCESS;
  4224. } // ACPIPowerProcessPhase5DeviceSubPhase1
  4225. NTSTATUS
  4226. ACPIDevicePowerProcessPhase5DeviceSubPhase2(
  4227. IN PACPI_POWER_REQUEST PowerRequest
  4228. )
  4229. /*++
  4230. Routine Description:
  4231. This routine runs the _SRS control method
  4232. Note: that we only come down this path if we are transitioning to D0
  4233. Arguments:
  4234. PowerRequest - The current request structure that we must process
  4235. Return Value:
  4236. NTSTATUS
  4237. If we ignore errors, then this function can only return:
  4238. STATUS_SUCCESS
  4239. STATUS_PENDING
  4240. Otherwise, it can return any STATUS_XXX code it wants
  4241. --*/
  4242. {
  4243. DEVICE_POWER_STATE deviceState =
  4244. PowerRequest->u.DevicePowerRequest.DevicePowerState;
  4245. KIRQL oldIrql;
  4246. NTSTATUS status = STATUS_SUCCESS;
  4247. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4248. PNSOBJ srsObject = NULL;
  4249. //
  4250. // The next phase is STEP_2
  4251. //
  4252. PowerRequest->NextWorkDone = WORK_DONE_STEP_2;
  4253. if (!(deviceExtension->Flags & DEV_PROP_NO_OBJECT)) {
  4254. //
  4255. // Is there an _SRS object present on this device?
  4256. //
  4257. srsObject = ACPIAmliGetNamedChild(
  4258. deviceExtension->AcpiObject,
  4259. PACKED_SRS
  4260. );
  4261. }
  4262. if (srsObject != NULL) {
  4263. //
  4264. // We must hold this lock while we run the Control Method.
  4265. //
  4266. // Note: Because the interpreter will make a copy of the data
  4267. // arguments passed to it, we only need to hold the lock as long
  4268. // as it takes for the interpreter to return
  4269. //
  4270. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  4271. if (deviceExtension->PnpResourceList != NULL) {
  4272. //
  4273. // Evalute the method
  4274. //
  4275. status = AMLIAsyncEvalObject(
  4276. srsObject,
  4277. NULL,
  4278. 1,
  4279. deviceExtension->PnpResourceList,
  4280. ACPIDeviceCompleteGenericPhase,
  4281. PowerRequest
  4282. );
  4283. ACPIDevPrint( (
  4284. ACPI_PRINT_POWER,
  4285. deviceExtension,
  4286. "(0x%08lx): ACPIDevicePowerProcessPhase5DeviceSubPhase2 "
  4287. "= 0x%08lx\n",
  4288. PowerRequest,
  4289. status
  4290. ) );
  4291. }
  4292. //
  4293. // Mo longer need the lock
  4294. //
  4295. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  4296. if (status == STATUS_PENDING) {
  4297. return status;
  4298. }
  4299. } else {
  4300. //
  4301. // Consider the request successfull
  4302. //
  4303. status = STATUS_SUCCESS;
  4304. }
  4305. //
  4306. // Call the completion routine brute force
  4307. //
  4308. ACPIDeviceCompleteGenericPhase(
  4309. srsObject,
  4310. status,
  4311. NULL,
  4312. PowerRequest
  4313. );
  4314. //
  4315. // Always return success
  4316. //
  4317. return STATUS_SUCCESS;
  4318. } // ACPIDevicePowerProcessPhase5DeviceSubPhase2
  4319. NTSTATUS
  4320. ACPIDevicePowerProcessPhase5DeviceSubPhase3(
  4321. IN PACPI_POWER_REQUEST PowerRequest
  4322. )
  4323. /*++
  4324. Routine Description:
  4325. This routine enables or disables the lock on the device
  4326. Arguments:
  4327. PowerRequest - The current request structure that we must process
  4328. Return Value:
  4329. NTSTATUS
  4330. If we ignore errors, then this function can only return:
  4331. STATUS_SUCCESS
  4332. STATUS_PENDING
  4333. Otherwise, it can return any STATUS_XXX code it wants
  4334. --*/
  4335. {
  4336. DEVICE_POWER_STATE deviceState;
  4337. NTSTATUS status = STATUS_SUCCESS;
  4338. OBJDATA objData;
  4339. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4340. PNSOBJ lckObject = NULL;
  4341. ULONG flags;
  4342. ACPIDevPrint( (
  4343. ACPI_PRINT_POWER,
  4344. deviceExtension,
  4345. "(%#08lx): ACPIDevicePowerProcessPhase5DeviceSubPhase4\n",
  4346. PowerRequest
  4347. ) );
  4348. //
  4349. // What is our desired device state and action?
  4350. //
  4351. deviceState = PowerRequest->u.DevicePowerRequest.DevicePowerState;
  4352. flags = PowerRequest->u.DevicePowerRequest.Flags;
  4353. //
  4354. // If we aren't going to D0, then skip to the end
  4355. //
  4356. if (deviceState != PowerDeviceD0) {
  4357. //
  4358. // The next stage is STEP_5
  4359. //
  4360. PowerRequest->NextWorkDone = WORK_DONE_STEP_5;
  4361. } else {
  4362. //
  4363. // The next stage is STEP_3
  4364. //
  4365. PowerRequest->NextWorkDone = WORK_DONE_STEP_3;
  4366. }
  4367. if (deviceExtension->Flags & DEV_PROP_NO_OBJECT) {
  4368. goto ACPIDevicePowerProcessPhase5DeviceSubPhase3Exit;
  4369. }
  4370. //
  4371. // Is there an _LCK object present on this device?
  4372. //
  4373. lckObject = ACPIAmliGetNamedChild(
  4374. deviceExtension->AcpiObject,
  4375. PACKED_LCK
  4376. );
  4377. if (lckObject == NULL) {
  4378. goto ACPIDevicePowerProcessPhase5DeviceSubPhase3Exit;
  4379. }
  4380. //
  4381. // Initialize the argument that we will pass to the function
  4382. //
  4383. RtlZeroMemory( &objData, sizeof(OBJDATA) );
  4384. objData.dwDataType = OBJTYPE_INTDATA;
  4385. //
  4386. // Look at the flags and see if we should lock or unlock the device
  4387. //
  4388. if (flags & DEVICE_REQUEST_LOCK_DEVICE) {
  4389. objData.uipDataValue = 1; // Lock the device
  4390. } else if (flags & DEVICE_REQUEST_UNLOCK_DEVICE) {
  4391. objData.uipDataValue = 0; // Unlock the device
  4392. } else {
  4393. goto ACPIDevicePowerProcessPhase5DeviceSubPhase3Exit;
  4394. }
  4395. //
  4396. // Run the control method now
  4397. //
  4398. status = AMLIAsyncEvalObject(
  4399. lckObject,
  4400. NULL,
  4401. 1,
  4402. &objData,
  4403. ACPIDeviceCompleteGenericPhase,
  4404. PowerRequest
  4405. );
  4406. ACPIDevPrint( (
  4407. ACPI_PRINT_POWER,
  4408. deviceExtension,
  4409. "(0x%08lx): ACPIDevicePowerProcessPhase5DeviceSubPhase3 "
  4410. "= 0x%08lx\n",
  4411. PowerRequest,
  4412. status
  4413. ) );
  4414. ACPIDevicePowerProcessPhase5DeviceSubPhase3Exit:
  4415. //
  4416. // Do we have to call the completion routine ourselves?
  4417. //
  4418. if (status != STATUS_PENDING) {
  4419. ACPIDeviceCompleteGenericPhase(
  4420. lckObject,
  4421. status,
  4422. NULL,
  4423. PowerRequest
  4424. );
  4425. }
  4426. //
  4427. // Always return success
  4428. //
  4429. return STATUS_SUCCESS;
  4430. } // ACPIDevicePowerProcessPhase5DeviceSubPhase3
  4431. NTSTATUS
  4432. ACPIDevicePowerProcessPhase5DeviceSubPhase4(
  4433. IN PACPI_POWER_REQUEST PowerRequest
  4434. )
  4435. /*++
  4436. Routine Description:
  4437. This routine runs the _STA control method
  4438. Note: that we only come down this path if we are transitioning to D0
  4439. Arguments:
  4440. PowerRequest - The current request structure that we must process
  4441. Return Value:
  4442. NTSTATUS
  4443. If we ignore errors, then this function can only return:
  4444. STATUS_SUCCESS
  4445. STATUS_PENDING
  4446. Otherwise, it can return any STATUS_XXX code it wants
  4447. --*/
  4448. {
  4449. NTSTATUS status = STATUS_SUCCESS;
  4450. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4451. POBJDATA resultData = &(PowerRequest->ResultData);
  4452. //
  4453. // The next phase is STEP_4
  4454. //
  4455. PowerRequest->NextWorkDone = WORK_DONE_STEP_4;
  4456. //
  4457. // Make sure to initialize the structure. Since we are using the
  4458. // objdata structure in request, we need to make sure that it will
  4459. // look like something that the interpreter will understand
  4460. //
  4461. RtlZeroMemory( resultData, sizeof(OBJDATA) );
  4462. //
  4463. // Get the status of the device
  4464. //
  4465. status = ACPIGetDeviceHardwarePresenceAsync(
  4466. deviceExtension,
  4467. ACPIDeviceCompleteGenericPhase,
  4468. PowerRequest,
  4469. &(resultData->uipDataValue),
  4470. &(resultData->dwDataLen)
  4471. );
  4472. ACPIDevPrint( (
  4473. ACPI_PRINT_POWER,
  4474. deviceExtension,
  4475. "(0x%08lx): ACPIDevicePowerProcessPhase5DeviceSubPhase4 "
  4476. "= 0x%08lx\n",
  4477. PowerRequest,
  4478. status
  4479. ) );
  4480. if (status == STATUS_PENDING) {
  4481. return status;
  4482. }
  4483. //
  4484. // Call the completion routine ourselves
  4485. //
  4486. ACPIDeviceCompleteGenericPhase(
  4487. NULL,
  4488. status,
  4489. NULL,
  4490. PowerRequest
  4491. );
  4492. //
  4493. // Always return success
  4494. //
  4495. return STATUS_SUCCESS;
  4496. } // ACPIDevicePowerProcessPhase5DeviceSubPhase4
  4497. NTSTATUS
  4498. ACPIDevicePowerProcessPhase5DeviceSubPhase5(
  4499. IN PACPI_POWER_REQUEST PowerRequest
  4500. )
  4501. /*++
  4502. Routine Description:
  4503. This is the where we look at the device state.
  4504. Arguments:
  4505. PowerRequest - The request we are currently handling
  4506. Return Value:
  4507. NTSTATUS
  4508. --*/
  4509. {
  4510. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4511. POBJDATA resultData = &(PowerRequest->ResultData);
  4512. ACPIDevPrint( (
  4513. ACPI_PRINT_POWER,
  4514. deviceExtension,
  4515. "(0x%08lx): ACPIDevicePowerProcessPhase5DeviceSubPhase5\n",
  4516. PowerRequest
  4517. ) );
  4518. //
  4519. // The next phase is STEP_5
  4520. //
  4521. PowerRequest->NextWorkDone = WORK_DONE_STEP_5;
  4522. //
  4523. // First things first --- we just ran _STA (or faked it), so we
  4524. // must check the return data
  4525. //
  4526. if (!(resultData->uipDataValue & STA_STATUS_PRESENT) ||
  4527. !(resultData->uipDataValue & STA_STATUS_WORKING_OK) ||
  4528. ( !(resultData->uipDataValue & STA_STATUS_ENABLED) &&
  4529. !(deviceExtension->Flags & DEV_TYPE_FILTER) ) ) {
  4530. //
  4531. // This device is not working
  4532. //
  4533. PowerRequest->Status = STATUS_INVALID_DEVICE_STATE;
  4534. ACPIDeviceCompleteCommon(
  4535. &(PowerRequest->WorkDone),
  4536. WORK_DONE_FAILURE
  4537. );
  4538. return STATUS_SUCCESS;
  4539. }
  4540. //
  4541. // We don't clear the result or do anything on the resultData structure
  4542. // because we only used some of its storage --- the entire structure
  4543. // is not valid. However, just to be safe, we will zero everything out
  4544. //
  4545. RtlZeroMemory( resultData, sizeof(OBJDATA) );
  4546. //
  4547. // Call the completion routine by brute force. Note that at this
  4548. // point, we count everything as being SUCCESS
  4549. //
  4550. ACPIDeviceCompleteGenericPhase(
  4551. NULL,
  4552. STATUS_SUCCESS,
  4553. NULL,
  4554. PowerRequest
  4555. );
  4556. //
  4557. // Always return success
  4558. //
  4559. return STATUS_SUCCESS;
  4560. } // ACPIDevicePowerProcessPhase5DeviceSubPhase5
  4561. NTSTATUS
  4562. ACPIDevicePowerProcessPhase5DeviceSubPhase6(
  4563. IN PACPI_POWER_REQUEST PowerRequest
  4564. )
  4565. /*++
  4566. Routine Description:
  4567. This is the final routine in the device path. This routines
  4568. determines if everything is okay and updates the system book-keeping.
  4569. Arguments:
  4570. PowerRequest - The request we are currently handling
  4571. Return Value:
  4572. NTSTATUS
  4573. --*/
  4574. {
  4575. PDEVICE_OBJECT deviceObject;
  4576. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4577. POBJDATA resultData = &(PowerRequest->ResultData);
  4578. POWER_STATE state;
  4579. ACPIDevPrint( (
  4580. ACPI_PRINT_POWER,
  4581. deviceExtension,
  4582. "(0x%08lx): ACPIDevicePowerProcessPhase5DeviceSubPhase6\n",
  4583. PowerRequest
  4584. ) );
  4585. //
  4586. // We need a spinlock to touch these values
  4587. //
  4588. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  4589. //
  4590. // Update the current PowerState with the requested PowerState
  4591. //
  4592. deviceExtension->PowerInfo.PowerState =
  4593. deviceExtension->PowerInfo.DesiredPowerState;
  4594. //
  4595. // We also need to store the new device state so that we can notify
  4596. // the system
  4597. //
  4598. state.DeviceState = deviceExtension->PowerInfo.PowerState;
  4599. //
  4600. // Remember the device object
  4601. //
  4602. deviceObject = deviceExtension->DeviceObject;
  4603. //
  4604. // Just release the spin lock
  4605. //
  4606. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  4607. //
  4608. // If this deviceExtension has an associated deviceObject, then
  4609. // we had better tell the system about which state we are in
  4610. //
  4611. if (deviceObject != NULL) {
  4612. //
  4613. // Notify the system
  4614. //
  4615. PoSetPowerState(
  4616. deviceObject,
  4617. DevicePowerState,
  4618. state
  4619. );
  4620. }
  4621. //
  4622. // Make sure that we set the current status in the PowerRequest
  4623. // to indicate what happened
  4624. //
  4625. PowerRequest->Status = STATUS_SUCCESS;
  4626. //
  4627. // We are done
  4628. //
  4629. ACPIDeviceCompleteCommon( &(PowerRequest->WorkDone), WORK_DONE_COMPLETE );
  4630. //
  4631. // Always return success
  4632. //
  4633. return STATUS_SUCCESS;
  4634. } // ACPIDevicePowerProcessPhase5DeviceSubPhase6
  4635. NTSTATUS
  4636. ACPIDevicePowerProcessPhase5SystemSubPhase1(
  4637. IN PACPI_POWER_REQUEST PowerRequest
  4638. )
  4639. /*++
  4640. Routine Description:
  4641. This routine runs the _PTS, or _WAK method
  4642. Arguments:
  4643. PowerRequest - The current request structure that we must process
  4644. Return Value:
  4645. NTSTATUS
  4646. If we ignore errors, then this function can only return:
  4647. STATUS_SUCCESS
  4648. STATUS_PENDING
  4649. Otherwise, it can return any STATUS_XXX code it wants
  4650. --*/
  4651. {
  4652. NTSTATUS status = STATUS_SUCCESS;
  4653. OBJDATA objData;
  4654. PACPI_POWER_INFO powerInfo;
  4655. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4656. PNSOBJ sleepObject = NULL;
  4657. SYSTEM_POWER_STATE systemState =
  4658. PowerRequest->u.SystemPowerRequest.SystemPowerState;
  4659. //
  4660. // The next phase is STEP_1
  4661. //
  4662. PowerRequest->NextWorkDone = WORK_DONE_STEP_1;
  4663. //
  4664. // If we are going back to the working state, then don't run any _PTS
  4665. // code
  4666. //
  4667. if (systemState != PowerSystemWorking) {
  4668. //
  4669. // First step it to initialize the objData so that we can remember
  4670. // what arguments we want to pass to the AML Interpreter
  4671. //
  4672. RtlZeroMemory( &objData, sizeof(OBJDATA) );
  4673. objData.dwDataType = OBJTYPE_INTDATA;
  4674. //
  4675. // Obtain the correct NameSpace object to run
  4676. //
  4677. sleepObject = ACPIAmliGetNamedChild(
  4678. deviceExtension->AcpiObject->pnsParent,
  4679. PACKED_PTS
  4680. );
  4681. //
  4682. // We only try to evaluate a method if we found an object
  4683. //
  4684. if (sleepObject != NULL) {
  4685. //
  4686. // Remember that AMLI doesn't use our definitions, so we will
  4687. // have to normalize the S value
  4688. //
  4689. objData.uipDataValue = ACPIDeviceMapACPIPowerState( systemState );
  4690. //
  4691. // Safely run the control method
  4692. //
  4693. status = AMLIAsyncEvalObject(
  4694. sleepObject,
  4695. NULL,
  4696. 1,
  4697. &objData,
  4698. ACPIDeviceCompleteGenericPhase,
  4699. PowerRequest
  4700. );
  4701. //
  4702. // If we got STATUS_PENDING, then we cannot do any more work here.
  4703. //
  4704. if (status == STATUS_PENDING) {
  4705. return status;
  4706. }
  4707. }
  4708. }
  4709. //
  4710. // Call the completion routine
  4711. //
  4712. ACPIDeviceCompleteGenericPhase(
  4713. sleepObject,
  4714. status,
  4715. NULL,
  4716. PowerRequest
  4717. );
  4718. //
  4719. // We are successfull
  4720. //
  4721. return STATUS_SUCCESS;
  4722. } // ACPIPowerProcessPhase5SystemSubPhase1
  4723. NTSTATUS
  4724. ACPIDevicePowerProcessPhase5SystemSubPhase2(
  4725. IN PACPI_POWER_REQUEST PowerRequest
  4726. )
  4727. /*++
  4728. Routine Description:
  4729. This routine runs the _SST method
  4730. Arguments:
  4731. PowerRequest - The current request structure that we must process
  4732. Return Value:
  4733. NTSTATUS
  4734. If we ignore errors, then this function can only return:
  4735. STATUS_SUCCESS
  4736. STATUS_PENDING
  4737. Otherwise, it can return any STATUS_XXX code it wants
  4738. --*/
  4739. {
  4740. NTSTATUS status = STATUS_SUCCESS;
  4741. OBJDATA objData;
  4742. PACPI_POWER_INFO powerInfo;
  4743. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4744. PNSOBJ sstObject = NULL;
  4745. SYSTEM_POWER_STATE systemState =
  4746. PowerRequest->u.SystemPowerRequest.SystemPowerState;
  4747. //
  4748. // The next phase is STEP_2
  4749. //
  4750. PowerRequest->NextWorkDone = WORK_DONE_STEP_2;
  4751. //
  4752. // First step it to initialize the objData so that we can remember
  4753. // what arguments we want to pass to the AML Interpreter
  4754. //
  4755. RtlZeroMemory( &objData, sizeof(OBJDATA) );
  4756. objData.dwDataType = OBJTYPE_INTDATA;
  4757. //
  4758. // Obtain the correct NameSpace object to run
  4759. //
  4760. sstObject = ACPIAmliGetNamedChild(
  4761. deviceExtension->AcpiObject->pnsParent,
  4762. PACKED_SI
  4763. );
  4764. if (sstObject != NULL) {
  4765. sstObject = ACPIAmliGetNamedChild(
  4766. sstObject,
  4767. PACKED_SST
  4768. );
  4769. }
  4770. //
  4771. // We only try to evaluate a method if we found an object
  4772. //
  4773. if (sstObject != NULL) {
  4774. switch (systemState) {
  4775. case PowerSystemWorking:
  4776. objData.uipDataValue = 1;
  4777. break;
  4778. case PowerSystemHibernate:
  4779. objData.uipDataValue = 4;
  4780. break;
  4781. case PowerSystemSleeping1:
  4782. case PowerSystemSleeping2:
  4783. case PowerSystemSleeping3:
  4784. objData.uipDataValue = 3;
  4785. break;
  4786. default:
  4787. objData.uipDataValue = 0;
  4788. }
  4789. //
  4790. // Safely run the control method
  4791. //
  4792. status = AMLIAsyncEvalObject(
  4793. sstObject,
  4794. NULL,
  4795. 1,
  4796. &objData,
  4797. ACPIDeviceCompleteGenericPhase,
  4798. PowerRequest
  4799. );
  4800. //
  4801. // If we got STATUS_PENDING, then we cannot do any more work here.
  4802. //
  4803. if (status == STATUS_PENDING) {
  4804. return status;
  4805. }
  4806. } else {
  4807. //
  4808. // Consider the request successfull
  4809. //
  4810. status = STATUS_SUCCESS;
  4811. }
  4812. //
  4813. // Call the completion routine
  4814. //
  4815. ACPIDeviceCompleteGenericPhase(
  4816. sstObject,
  4817. status,
  4818. NULL,
  4819. PowerRequest
  4820. );
  4821. //
  4822. // We are successfull
  4823. //
  4824. return STATUS_SUCCESS;
  4825. } // ACPIPowerProcessPhase5SystemSubPhase2
  4826. NTSTATUS
  4827. ACPIDevicePowerProcessPhase5SystemSubPhase3(
  4828. IN PACPI_POWER_REQUEST PowerRequest
  4829. )
  4830. /*++
  4831. Routine Description:
  4832. This routine will pause the interpreter if requird
  4833. Arguments:
  4834. PowerRequest - The request we are currently processing
  4835. Return Value:
  4836. NTSTATUS
  4837. --*/
  4838. {
  4839. NTSTATUS status;
  4840. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4841. SYSTEM_POWER_STATE systemState;
  4842. ACPIDevPrint( (
  4843. ACPI_PRINT_POWER,
  4844. deviceExtension,
  4845. "(0x%08lx): ACPIDevicePowerProcessPhase5SystemSubPhase3\n",
  4846. PowerRequest
  4847. ) );
  4848. //
  4849. // The next phase is STEP_3
  4850. //
  4851. PowerRequest->NextWorkDone = WORK_DONE_STEP_3;
  4852. //
  4853. // Fetch the target system state
  4854. //
  4855. systemState = PowerRequest->u.SystemPowerRequest.SystemPowerState;
  4856. //
  4857. // If we are going to a system state other than S0, then we need to pause
  4858. // the interpreter. After this call completes, no one can execute a control
  4859. // method
  4860. //
  4861. if (systemState != PowerSystemWorking) {
  4862. status = AMLIPauseInterpreter(
  4863. ACPIDeviceCompleteInterpreterRequest,
  4864. PowerRequest
  4865. );
  4866. if (status == STATUS_PENDING) {
  4867. return status;
  4868. }
  4869. }
  4870. //
  4871. // Call the completion routine
  4872. //
  4873. ACPIDeviceCompleteInterpreterRequest(
  4874. PowerRequest
  4875. );
  4876. //
  4877. // We are successfull
  4878. //
  4879. return STATUS_SUCCESS;
  4880. } // ACPIDevicePowerProcessPhase5SystemSubPhase3
  4881. NTSTATUS
  4882. ACPIDevicePowerProcessPhase5SystemSubPhase4(
  4883. IN PACPI_POWER_REQUEST PowerRequest
  4884. )
  4885. /*++
  4886. Routine Description:
  4887. This is the final routine in the system path. It updates the bookkeeping
  4888. Arguments:
  4889. PowerRequest - The request we are currently processing
  4890. Return Value:
  4891. NTSTATUS
  4892. --*/
  4893. {
  4894. KIRQL oldIrql;
  4895. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4896. PDEVICE_OBJECT deviceObject;
  4897. POWER_STATE state;
  4898. SYSTEM_POWER_STATE systemState;
  4899. ACPIDevPrint( (
  4900. ACPI_PRINT_POWER,
  4901. deviceExtension,
  4902. "(0x%08lx): ACPIDevicePowerProcessPhase5SystemSubPhase4\n",
  4903. PowerRequest
  4904. ) );
  4905. //
  4906. // Fetch the target system state
  4907. //
  4908. systemState = PowerRequest->u.SystemPowerRequest.SystemPowerState;
  4909. //
  4910. // Grab the spinlock
  4911. //
  4912. IoAcquireCancelSpinLock( &oldIrql );
  4913. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  4914. //
  4915. // Remember this as being our most recent sleeping state
  4916. //
  4917. AcpiMostRecentSleepState = systemState;
  4918. //
  4919. // Update the Gpe Wake Bits
  4920. //
  4921. ACPIWakeRemoveDevicesAndUpdate( NULL, NULL );
  4922. //
  4923. // Fetch the associated device object
  4924. //
  4925. deviceObject = deviceExtension->DeviceObject;
  4926. //
  4927. // We are done with the lock
  4928. //
  4929. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  4930. IoReleaseCancelSpinLock( oldIrql );
  4931. //
  4932. // Is there an ACPI device object?
  4933. //
  4934. if (deviceObject != NULL) {
  4935. //
  4936. // Notify the system of the new S state
  4937. //
  4938. state.SystemState = systemState;
  4939. PoSetPowerState(
  4940. deviceObject,
  4941. SystemPowerState,
  4942. state
  4943. );
  4944. }
  4945. //
  4946. // Make sure that we set the current status in the PowerRequest
  4947. // to indicate what happened.
  4948. //
  4949. PowerRequest->Status = STATUS_SUCCESS;
  4950. //
  4951. // Finally, we mark the power request has having had all of its works
  4952. // done
  4953. //
  4954. ACPIDeviceCompleteCommon( &(PowerRequest->WorkDone), WORK_DONE_COMPLETE );
  4955. return STATUS_SUCCESS;
  4956. } // ACPIDevicePowerProcessPhase5SystemSubPhase4
  4957. NTSTATUS
  4958. ACPIDevicePowerProcessPhase5WarmEjectSubPhase1(
  4959. IN PACPI_POWER_REQUEST PowerRequest
  4960. )
  4961. /*++
  4962. Routine Description:
  4963. This is the method that runs the _EJx method appropriate for this
  4964. device
  4965. Arguments:
  4966. PowerRequest - The request we are currently processing
  4967. Return Value:
  4968. NTSTATUS
  4969. --*/
  4970. {
  4971. NTSTATUS status = STATUS_SUCCESS;
  4972. OBJDATA objData;
  4973. PACPI_POWER_INFO powerInfo;
  4974. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  4975. PNSOBJ ejectObject = NULL;
  4976. SYSTEM_POWER_STATE ejectState =
  4977. PowerRequest->u.EjectPowerRequest.EjectPowerState;
  4978. ULONG ejectNames[] = { 0, 0, PACKED_EJ1, PACKED_EJ2,
  4979. PACKED_EJ3, PACKED_EJ4, 0 };
  4980. ULONG flags;
  4981. //
  4982. // The next phase is STEP_1 if we have profile work to do, otherwise we're
  4983. // done.
  4984. //
  4985. flags = PowerRequest->u.EjectPowerRequest.Flags;
  4986. PowerRequest->NextWorkDone = (flags & DEVICE_REQUEST_UPDATE_HW_PROFILE) ?
  4987. WORK_DONE_STEP_1 :
  4988. WORK_DONE_COMPLETE;
  4989. //
  4990. // Obtain the correct NameSpace object to run
  4991. //
  4992. ejectObject = ACPIAmliGetNamedChild(
  4993. deviceExtension->AcpiObject,
  4994. ejectNames[ejectState]
  4995. );
  4996. //
  4997. // If we didn't find the object, then something terrible happened
  4998. // and we cannot continue
  4999. //
  5000. if (ejectObject == NULL) {
  5001. ACPIInternalError( ACPI_DEVPOWER );
  5002. }
  5003. //
  5004. // Kiss the device goodbye
  5005. //
  5006. status = ACPIGetNothingEvalIntegerAsync(
  5007. deviceExtension,
  5008. ejectNames[ejectState],
  5009. 1,
  5010. ACPIDeviceCompleteGenericPhase,
  5011. PowerRequest
  5012. );
  5013. ACPIDevPrint( (
  5014. ACPI_PRINT_POWER,
  5015. deviceExtension,
  5016. "(%0x%08lx) : ACPIDevicePowerProcessPhase5WarmEjectSubPhase1 = %08lx\n",
  5017. PowerRequest,
  5018. status
  5019. ) );
  5020. if (status == STATUS_PENDING) {
  5021. return status;
  5022. }
  5023. //
  5024. // Call the completion routine by brute force. Note that at this
  5025. // point, we count everything as being SUCCESS
  5026. //
  5027. ACPIDeviceCompleteGenericPhase(
  5028. ejectObject,
  5029. status,
  5030. NULL,
  5031. PowerRequest
  5032. );
  5033. return STATUS_SUCCESS;
  5034. }
  5035. NTSTATUS
  5036. ACPIDevicePowerProcessPhase5WarmEjectSubPhase2(
  5037. IN PACPI_POWER_REQUEST PowerRequest
  5038. )
  5039. /*++
  5040. Routine Description:
  5041. This is the method that runs the _DCK method appropriate for this
  5042. device
  5043. Arguments:
  5044. PowerRequest - The request we are currently processing
  5045. Return Value:
  5046. NTSTATUS
  5047. --*/
  5048. {
  5049. NTSTATUS status = STATUS_SUCCESS;
  5050. OBJDATA objData;
  5051. PACPI_POWER_INFO powerInfo;
  5052. PDEVICE_EXTENSION deviceExtension = PowerRequest->DeviceExtension;
  5053. PDEVICE_EXTENSION dockExtension;
  5054. PNSOBJ dckObject = NULL;
  5055. //
  5056. // The next phase is WORK_DONE_COMPLETE
  5057. //
  5058. PowerRequest->NextWorkDone = WORK_DONE_COMPLETE;
  5059. //
  5060. // Obtain the correct NameSpace object to run
  5061. //
  5062. dckObject = ACPIAmliGetNamedChild(
  5063. deviceExtension->AcpiObject,
  5064. PACKED_DCK
  5065. );
  5066. //
  5067. // We might not find the _DCK method if this isn't a dock.
  5068. //
  5069. if (dckObject != NULL) {
  5070. dockExtension = ACPIDockFindCorrespondingDock( deviceExtension );
  5071. if (dockExtension &&
  5072. (dockExtension->Dock.IsolationState == IS_ISOLATION_DROPPED)) {
  5073. //
  5074. // Kiss the dock connect goodbye. Note that we don't even care
  5075. // about the return value because of the spec says that if it
  5076. // is called with 0, it should be ignored
  5077. //
  5078. dockExtension->Dock.IsolationState = IS_ISOLATED;
  5079. KdDisableDebugger();
  5080. status = ACPIGetNothingEvalIntegerAsync(
  5081. deviceExtension,
  5082. PACKED_DCK,
  5083. 0,
  5084. ACPIDeviceCompleteGenericPhase,
  5085. PowerRequest
  5086. );
  5087. KdEnableDebugger();
  5088. ACPIDevPrint( (
  5089. ACPI_PRINT_POWER,
  5090. deviceExtension,
  5091. "(%0x%08lx) : ACPIDevicePowerProcessPhase5WarmEjectSubPhase2 = %08lx\n",
  5092. PowerRequest,
  5093. status
  5094. ) );
  5095. if (status == STATUS_PENDING) {
  5096. return status;
  5097. }
  5098. }
  5099. }
  5100. //
  5101. // Call the completion routine by brute force. Note that at this
  5102. // point, we count everything as being SUCCESS
  5103. //
  5104. ACPIDeviceCompleteGenericPhase(
  5105. dckObject,
  5106. status,
  5107. NULL,
  5108. PowerRequest
  5109. );
  5110. return STATUS_SUCCESS;
  5111. }
  5112. NTSTATUS
  5113. ACPIDevicePowerProcessSynchronizeList(
  5114. IN PLIST_ENTRY ListEntry
  5115. )
  5116. /*++
  5117. Routine Description:
  5118. This routine completes all of the synchronize requests...
  5119. Arguments:
  5120. ListEntry - The list we are currently walking
  5121. Return Value:
  5122. NTSTATUS
  5123. - If any request is not marked as being complete, then STATUS_PENDING
  5124. is returned, otherwise, STATUS_SUCCESS is returned
  5125. --*/
  5126. {
  5127. NTSTATUS status = STATUS_SUCCESS;
  5128. PACPI_POWER_REQUEST powerRequest;
  5129. PLIST_ENTRY currentEntry = ListEntry->Flink;
  5130. PLIST_ENTRY tempEntry;
  5131. //
  5132. // Look at all the items in the list
  5133. //
  5134. while (currentEntry != ListEntry) {
  5135. //
  5136. // Turn this into a device request
  5137. //
  5138. powerRequest = CONTAINING_RECORD(
  5139. currentEntry,
  5140. ACPI_POWER_REQUEST,
  5141. ListEntry
  5142. );
  5143. //
  5144. // Set the temporary pointer to the next element
  5145. //
  5146. tempEntry = currentEntry->Flink;
  5147. //
  5148. // We are done with the request
  5149. //
  5150. ACPIDeviceCompleteRequest(
  5151. powerRequest
  5152. );
  5153. //
  5154. // Grab the next entry
  5155. //
  5156. currentEntry = tempEntry;
  5157. }
  5158. //
  5159. // Have we completed all of our work?
  5160. //
  5161. return (STATUS_SUCCESS);
  5162. } // ACPIDevicePowerProcessSynchronizeList