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.

7417 lines
184 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. buildsrc.c
  5. Abstract:
  6. This module is used to 'build' associations and new device objects.
  7. It contains functionality that was within detect.c but split to make
  8. the files more readable
  9. Someone asked me to describe how the building of a device extension
  10. works
  11. PhaseAdrOrHid
  12. |
  13. ------------------------------------------------
  14. | |
  15. PhaseAdr PhaseUid
  16. | |--------------------------|
  17. |-------------------| PhaseHid
  18. |--------------------------|
  19. | PhaseCid
  20. |--------------------------|
  21. |
  22. PhaseSta
  23. |
  24. PhaseEjd
  25. |
  26. ---------------------------|
  27. | PhaseCrs
  28. ---------------------------|
  29. PhasePrw
  30. |
  31. PhasePr0
  32. |
  33. PhasePr1
  34. |
  35. PhasePr2
  36. |
  37. ----------------------
  38. | |
  39. | PhasePsc
  40. |--------------------|
  41. |
  42. PhasePsc+1
  43. Author:
  44. Stephane Plante (splante)
  45. Environment:
  46. NT Kernel Model Driver only
  47. Revision History:
  48. July 7, 1997 - Complete Rewrite
  49. --*/
  50. #include "pch.h"
  51. #ifdef ALLOC_PRAGMA
  52. #pragma alloc_text(PAGE,ACPIBuildFlushQueue)
  53. #endif
  54. //
  55. // This is the variable that indicates wether or not the BUILD DPC is running
  56. //
  57. BOOLEAN AcpiBuildDpcRunning;
  58. //
  59. // This is set to true if we have done the fixed button enumeration
  60. //
  61. BOOLEAN AcpiBuildFixedButtonEnumerated;
  62. //
  63. // This is the variable that indicates wether or not the BUILD DPC has
  64. // completed real work
  65. //
  66. BOOLEAN AcpiBuildWorkDone;
  67. //
  68. // This is the lock used to the entry queue
  69. //
  70. KSPIN_LOCK AcpiBuildQueueLock;
  71. //
  72. // This is the list that requests are queued onto. You must be holding the
  73. // QueueLock to access this list
  74. //
  75. LIST_ENTRY AcpiBuildQueueList;
  76. //
  77. // This is the list for Devices
  78. //
  79. LIST_ENTRY AcpiBuildDeviceList;
  80. //
  81. // This is the list for Operation Regions
  82. //
  83. LIST_ENTRY AcpiBuildOperationRegionList;
  84. //
  85. // This is the list for Power Resources
  86. //
  87. LIST_ENTRY AcpiBuildPowerResourceList;
  88. //
  89. // This is the list entry for the running Control Methods
  90. //
  91. LIST_ENTRY AcpiBuildRunMethodList;
  92. //
  93. //
  94. // This is the list for Synchronization with external (to the DPC anyways)
  95. // threads. Items in this list are blocked on an event.
  96. //
  97. LIST_ENTRY AcpiBuildSynchronizationList;
  98. //
  99. // This is the list for Thermal Zones
  100. //
  101. LIST_ENTRY AcpiBuildThermalZoneList;
  102. //
  103. // This is what we use to queue up the DPC
  104. //
  105. KDPC AcpiBuildDpc;
  106. //
  107. // This is the list that we use to pre-allocate storage for requests
  108. //
  109. NPAGED_LOOKASIDE_LIST BuildRequestLookAsideList;
  110. //
  111. // This is the table used to map functions for the Device case. The indices
  112. // are based on the WORK_DONE_xxx fields
  113. //
  114. PACPI_BUILD_FUNCTION AcpiBuildDeviceDispatch[] = {
  115. ACPIBuildProcessGenericComplete, // WORK_DONE_COMPLETE
  116. NULL, // WORK_DONE_PENDING
  117. ACPIBuildProcessDeviceFailure, // WORK_DONE_FAILURE
  118. ACPIBuildProcessDevicePhaseAdrOrHid, // WORK_DONE_STEP_ADR_OR_UID
  119. ACPIBuildProcessDevicePhaseAdr, // WORK_DONE_STEP_ADR
  120. ACPIBuildProcessDevicePhaseHid, // WORK_DONE_STEP_HID
  121. ACPIBuildProcessDevicePhaseUid, // WORK_DONE_STEP_UID
  122. ACPIBuildProcessDevicePhaseCid, // WORK_DONE_STEP_CID
  123. ACPIBuildProcessDevicePhaseSta, // WORK_DONE_STEP_STA
  124. ACPIBuildProcessDeviceGenericEvalStrict, // WORK_DONE_STEP_EJD
  125. ACPIBuildProcessDevicePhaseEjd, // WORK_DONE_STEP_EJD + 1
  126. ACPIBuildProcessDeviceGenericEvalStrict, // WORK_DONE_STEP_PRW
  127. ACPIBuildProcessDevicePhasePrw, // WORK_DONE_STEP_PRW + 1
  128. ACPIBuildProcessDeviceGenericEvalStrict, // WORK_DONE_STEP_PR0
  129. ACPIBuildProcessDevicePhasePr0, // WORK_DONE_STEP_PR0 + 1
  130. ACPIBuildProcessDeviceGenericEvalStrict, // WORK_DONE_STEP_PR1
  131. ACPIBuildProcessDevicePhasePr1, // WORK_DONE_STEP_PR1 + 1
  132. ACPIBuildProcessDeviceGenericEvalStrict, // WORK_DONE_STEP_PR2
  133. ACPIBuildProcessDevicePhasePr2, // WORK_DONE_STEP_PR2 + 1
  134. ACPIBuildProcessDeviceGenericEvalStrict, // WORK_DONE_STEP_CRS
  135. ACPIBuildProcessDevicePhaseCrs, // WORK_DONE_STEP_CRS + 1
  136. ACPIBuildProcessDeviceGenericEval, // WORK_DONE_STEP_PSC
  137. ACPIBuildProcessDevicePhasePsc, // WORK_DONE_STEP_PSC + 1
  138. };
  139. //
  140. // This is the table that is used to map the level of WorkDone with the
  141. // object that we are currently looking for
  142. //
  143. ULONG AcpiBuildDevicePowerNameLookup[] = {
  144. 0, // WORK_DONE_COMPLETE
  145. 0, // WORK_DONE_PENDING
  146. 0, // WORK_DONE_FAILURE
  147. 0, // WORK_DONE_ADR_OR_HID
  148. 0, // WORK_DONE_ADR
  149. 0, // WORK_DONE_HID
  150. 0, // WORK_DONE_UID
  151. 0, // WORK_DONE_CID
  152. 0, // WORK_DONE_STA
  153. PACKED_EJD, // WORK_DONE_EJD
  154. 0, // WORK_DONE_EJD + 1
  155. PACKED_PRW, // WORK_DONE_PRW
  156. 0, // WORK_DONE_PRW + 1
  157. PACKED_PR0, // WORK_DONE_PR0
  158. 0, // WORK_DONE_PR0 + 1
  159. PACKED_PR1, // WORK_DONE_PR1
  160. 0, // WORK_DONE_PR1 + 1
  161. PACKED_PR2, // WORK_DONE_PR2
  162. 0, // WORK_DONE_PR2 + 1
  163. PACKED_CRS, // WORK_DONE_CRS
  164. 0, // WORK_DONE_CRS + 1
  165. PACKED_PSC, // WORK_DONE_PSC
  166. 0, // WORK_DONE_PSC + 1
  167. };
  168. //
  169. // We aren't using the Operation Region dispatch point yet
  170. //
  171. PACPI_BUILD_FUNCTION AcpiBuildOperationRegionDispatch[] = {
  172. ACPIBuildProcessGenericComplete, // WORK_DONE_COMPLETE
  173. NULL, // WORK_DONE_PENDING
  174. NULL, // WORK_DONE_FAILURE
  175. NULL // WORK_DONE_STEP_0
  176. };
  177. //
  178. // This is the table used to map functions for the PowerResource case.
  179. // The indices are based on the WORK_DONE_xxx fields
  180. //
  181. PACPI_BUILD_FUNCTION AcpiBuildPowerResourceDispatch[] = {
  182. ACPIBuildProcessGenericComplete, // WORK_DONE_COMPLETE
  183. NULL, // WORK_DONE_PENDING
  184. ACPIBuildProcessPowerResourceFailure, // WORK_DONE_FAILURE
  185. ACPIBuildProcessPowerResourcePhase0, // WORK_DONE_STEP_0
  186. ACPIBuildProcessPowerResourcePhase1 // WORK_DONE_STEP_1
  187. };
  188. //
  189. // This is the table used to map functions for the RunMethod case.
  190. // The indices are based on the WORK_DONE_xxx fields
  191. //
  192. PACPI_BUILD_FUNCTION AcpiBuildRunMethodDispatch[] = {
  193. ACPIBuildProcessGenericComplete, // WORK_DONE_COMPLETE,
  194. NULL, // WORK_DONE_PENDING
  195. NULL, // WORK_DONE_FAILURE
  196. ACPIBuildProcessRunMethodPhaseCheckSta, // WORK_DONE_STEP_0
  197. ACPIBuildProcessRunMethodPhaseCheckBridge, // WORK_DONE_STEP_1
  198. ACPIBuildProcessRunMethodPhaseRunMethod, // WORK_DONE_STEP_2
  199. ACPIBuildProcessRunMethodPhaseRecurse // WORK_DONE_STEP_3
  200. };
  201. //
  202. // This is the table used to map functions for the ThermalZone case.
  203. // The indices are based on the WORK_DONE_xxx fields
  204. //
  205. PACPI_BUILD_FUNCTION AcpiBuildThermalZoneDispatch[] = {
  206. ACPIBuildProcessGenericComplete, // WORK_DONE_COMPLETE
  207. NULL, // WORK_DONE_PENDING
  208. NULL, // WORK_DONE_FAILURE
  209. ACPIBuildProcessThermalZonePhase0 // WORK_DONE_STEP_0
  210. };
  211. VOID
  212. ACPIBuildCompleteCommon(
  213. IN PULONG OldWorkDone,
  214. IN ULONG NewWorkDone
  215. )
  216. /*++
  217. Routine Description:
  218. Since the completion routines all have to do some bit of common work to
  219. get the DPC firing again, this routine reduces the code duplication
  220. Arguments:
  221. OldWorkDone - Pointer to the old amount of work done
  222. NewWorkDone - The new amount of work that has been completed
  223. NOTENOTE: There is an implicit assumption that the current value of
  224. WorkDone in the request is WORK_DONE_PENDING. If that is
  225. not the case, we will fail to transition to the next stage,
  226. which means that we will loop forever.
  227. Return Value:
  228. None
  229. --*/
  230. {
  231. KIRQL oldIrql;
  232. //
  233. // Update the state of the request
  234. //
  235. InterlockedCompareExchange( OldWorkDone, NewWorkDone,WORK_DONE_PENDING);
  236. //
  237. // We need this lock to look at the following variables
  238. //
  239. KeAcquireSpinLock( &AcpiBuildQueueLock, &oldIrql );
  240. //
  241. // No matter what, work was done
  242. //
  243. AcpiBuildWorkDone = TRUE;
  244. //
  245. // Is the DPC already running?
  246. //
  247. if (!AcpiBuildDpcRunning) {
  248. //
  249. // Better make sure that it does then
  250. //
  251. KeInsertQueueDpc( &AcpiBuildDpc, 0, 0 );
  252. }
  253. //
  254. // Done with the lock
  255. //
  256. KeReleaseSpinLock( &AcpiBuildQueueLock, oldIrql );
  257. }
  258. VOID EXPORT
  259. ACPIBuildCompleteGeneric(
  260. IN PNSOBJ AcpiObject,
  261. IN NTSTATUS Status,
  262. IN POBJDATA ObjectData,
  263. IN PVOID Context
  264. )
  265. /*++
  266. Routine Description:
  267. This is a generic completion handler. If the interperter has successfully
  268. execute the method, it completes the request to the next desired WORK_DONE,
  269. otherwise, it fails the request
  270. Arguments:
  271. AcpiObject - Points to the control that was run
  272. Status - Result of the method
  273. ObjectData - Information about the result
  274. Context - PACPI_BUILD_REQUEST
  275. Return Value:
  276. VOID
  277. --*/
  278. {
  279. PACPI_BUILD_REQUEST buildRequest = (PACPI_BUILD_REQUEST) Context;
  280. ULONG nextWorkDone = buildRequest->NextWorkDone;
  281. //
  282. // Device what state we should transition to next
  283. //
  284. if (!NT_SUCCESS(Status)) {
  285. //
  286. // Remember why we failed, but do not mark the request as being failed
  287. //
  288. buildRequest->Status = Status;
  289. }
  290. //
  291. // Note: we don't have a race condition here because only one
  292. // routine can be processing a request at any given time. Thus it
  293. // is safe for us to specify a new next phase
  294. //
  295. buildRequest->NextWorkDone = WORK_DONE_FAILURE;
  296. //
  297. // Transition to the next stage
  298. //
  299. ACPIBuildCompleteCommon(
  300. &(buildRequest->WorkDone),
  301. nextWorkDone
  302. );
  303. }
  304. VOID EXPORT
  305. ACPIBuildCompleteMustSucceed(
  306. IN PNSOBJ AcpiObject,
  307. IN NTSTATUS Status,
  308. IN POBJDATA ObjectData,
  309. IN PVOID Context
  310. )
  311. /*++
  312. Routine Description:
  313. This is a generic completion handler. If the interperter has successfully
  314. execute the method, it completes the request to the next desired WORK_DONE,
  315. otherwise, it fails the request
  316. Arguments:
  317. AcpiObject - Points to the control that was run
  318. Status - Result of the method
  319. ObjectData - Information about the result
  320. Context - PACPI_BUILD_REQUEST
  321. Return Value:
  322. VOID
  323. --*/
  324. {
  325. PACPI_BUILD_REQUEST buildRequest = (PACPI_BUILD_REQUEST) Context;
  326. ULONG nextWorkDone = buildRequest->NextWorkDone;
  327. //
  328. // Device what state we should transition to next
  329. //
  330. if (!NT_SUCCESS(Status)) {
  331. //
  332. // Remember why we failed, and mark the request as being failed
  333. //
  334. buildRequest->Status = Status;
  335. //
  336. // Death
  337. //
  338. KeBugCheckEx(
  339. ACPI_BIOS_ERROR,
  340. ACPI_FAILED_MUST_SUCCEED_METHOD,
  341. (ULONG_PTR) AcpiObject,
  342. Status,
  343. (AcpiObject ? AcpiObject->dwNameSeg : 0)
  344. );
  345. } else {
  346. //
  347. // Note: we don't have a race condition here because only one
  348. // routine can be processing a request at any given time. Thus it
  349. // is safe for us to specify a new next phase
  350. //
  351. buildRequest->NextWorkDone = WORK_DONE_FAILURE;
  352. //
  353. // Transition to the next stage
  354. //
  355. ACPIBuildCompleteCommon(
  356. &(buildRequest->WorkDone),
  357. nextWorkDone
  358. );
  359. }
  360. }
  361. VOID
  362. ACPIBuildDeviceDpc(
  363. IN PKDPC Dpc,
  364. IN PVOID DpcContext,
  365. IN PVOID SystemArgument1,
  366. IN PVOID SystemArgument2
  367. )
  368. /*++
  369. Routine Description:
  370. This routine is where all of the device extension related work is done.
  371. It looks at queued requests and processes them as appropriate.
  372. READ THIS:
  373. The design of this DPC is such that it goes out and tries to find
  374. work to do. Only if it finds no work does it stop. For this reason,
  375. one *cannot* use a 'break' statement within the main 'do - while()'
  376. loop. A continue must be use. Additionally, the code cannot make
  377. assumptions that at a certain point, that any of the lists are assumed
  378. to be empty. The code *must* use the IsListEmpty() macro to ensure
  379. that lists that should be empty are in fact empty.
  380. Arguments:
  381. None used
  382. Return Value:
  383. VOID
  384. --*/
  385. {
  386. NTSTATUS status;
  387. UNREFERENCED_PARAMETER( Dpc );
  388. UNREFERENCED_PARAMETER( DpcContext );
  389. UNREFERENCED_PARAMETER( SystemArgument1 );
  390. UNREFERENCED_PARAMETER( SystemArgument2 );
  391. //
  392. // First step is to acquire the DPC Lock, and check to see if another
  393. // DPC is already running
  394. //
  395. KeAcquireSpinLockAtDpcLevel( &AcpiBuildQueueLock );
  396. if (AcpiBuildDpcRunning) {
  397. //
  398. // The DPC is already running, so we need to exit now
  399. //
  400. KeReleaseSpinLockFromDpcLevel( &AcpiBuildQueueLock );
  401. return;
  402. }
  403. //
  404. // Remember that the DPC is now running
  405. //
  406. AcpiBuildDpcRunning = TRUE;
  407. //
  408. // We must try to do *some* work
  409. //
  410. do {
  411. //
  412. // Assume that we won't do any work
  413. //
  414. AcpiBuildWorkDone = FALSE;
  415. //
  416. // If there are items in the Request Queue, then move them to the
  417. // proper list
  418. //
  419. if (!IsListEmpty( &AcpiBuildQueueList ) ) {
  420. //
  421. // Sort the list
  422. //
  423. ACPIBuildProcessQueueList();
  424. }
  425. //
  426. // We can release the spin lock now
  427. //
  428. KeReleaseSpinLockFromDpcLevel( &AcpiBuildQueueLock );
  429. //
  430. // If there are items in the Run Method list, then process the
  431. // list
  432. //
  433. if (!IsListEmpty( &AcpiBuildRunMethodList ) ) {
  434. //
  435. // We actually care what this call returns. The reason we do
  436. // is that we want all of the control methods to be run before
  437. // we do any of the following steps
  438. //
  439. status = ACPIBuildProcessGenericList(
  440. &AcpiBuildRunMethodList,
  441. AcpiBuildRunMethodDispatch
  442. );
  443. //
  444. // We must own the spin lock before we do the following...
  445. //
  446. KeAcquireSpinLockAtDpcLevel( &AcpiBuildQueueLock );
  447. //
  448. // If we got back STATUS_PENDING, that means that there's
  449. // a method queued in the interpreter somewhere. This will
  450. // cause the DPC to (eventually) become scheduled again.
  451. // That means that we don't have to do anything special to
  452. // handle it.
  453. //
  454. if (status == STATUS_PENDING) {
  455. continue;
  456. }
  457. //
  458. // The case that is special is where we are do get STATUS_SUCCESS
  459. // back. This indicates that we've drained the list. The little
  460. // fly in the ointment is that we might have scheduled other
  461. // run requests, but those are stuck in the BuildQueue list. So
  462. // what we need to do here is check to see if the BuildQueue list
  463. // is non-empty and if it is, set the AcpiBuildWorkDone to TRUE
  464. // so that we iterage again (and move the elements to the proper
  465. // list).
  466. //
  467. if (!IsListEmpty( &AcpiBuildQueueList) ) {
  468. AcpiBuildWorkDone = TRUE;
  469. continue;
  470. }
  471. //
  472. // If we've reached this point, then the Run list must be complete
  473. // and there must be no items in the BuildQueue list. This means
  474. // that's its safe to drop the lock and continue
  475. //
  476. KeReleaseSpinLockFromDpcLevel( &AcpiBuildQueueLock );
  477. }
  478. //
  479. // If there are items in the Operation Region list, then process
  480. // the list
  481. //
  482. if (!IsListEmpty( &AcpiBuildOperationRegionList ) ) {
  483. //
  484. // Since we don't block on this list --- ie: we can create
  485. // operation regions at any time that we want, we don't care what
  486. // this function returns.
  487. //
  488. status = ACPIBuildProcessGenericList(
  489. &AcpiBuildOperationRegionList,
  490. AcpiBuildOperationRegionDispatch
  491. );
  492. }
  493. //
  494. // If there are items in the Power Resource list, then process
  495. // the list
  496. //
  497. if (!IsListEmpty( &AcpiBuildPowerResourceList ) ) {
  498. //
  499. // We actually care what this call returns. The reason we do
  500. // is that we want all of the power resources to be built before
  501. // we do any of the following steps
  502. //
  503. status = ACPIBuildProcessGenericList(
  504. &AcpiBuildPowerResourceList,
  505. AcpiBuildPowerResourceDispatch
  506. );
  507. if (status == STATUS_PENDING) {
  508. //
  509. // We must own the spinlock before we continue
  510. //
  511. KeAcquireSpinLockAtDpcLevel( &AcpiBuildQueueLock );
  512. continue;
  513. }
  514. }
  515. //
  516. // If there are items in Device list, then process the list
  517. //
  518. if (!IsListEmpty( &AcpiBuildDeviceList ) ) {
  519. //
  520. // Since we don't block on this list --- ie we can create
  521. // devices at any time that we want, we don't care what this
  522. // function returns.
  523. //
  524. status = ACPIBuildProcessGenericList(
  525. &AcpiBuildDeviceList,
  526. AcpiBuildDeviceDispatch
  527. );
  528. }
  529. //
  530. // If there are items in the Thermal list, then process the list
  531. //
  532. if (!IsListEmpty( &AcpiBuildThermalZoneList ) ) {
  533. //
  534. // Since we don't block on this list --- ie we can create
  535. // thermal zones at any time that we want, we don't care what this
  536. // function returns.
  537. //
  538. status = ACPIBuildProcessGenericList(
  539. &AcpiBuildThermalZoneList,
  540. AcpiBuildThermalZoneDispatch
  541. );
  542. }
  543. //
  544. // If we have emptied out all the lists, then we can issue the
  545. // synchronization requests
  546. //
  547. if (IsListEmpty( &AcpiBuildDeviceList ) &&
  548. IsListEmpty( &AcpiBuildOperationRegionList) &&
  549. IsListEmpty( &AcpiBuildPowerResourceList) &&
  550. IsListEmpty( &AcpiBuildRunMethodList) &&
  551. IsListEmpty( &AcpiBuildThermalZoneList ) ) {
  552. //
  553. // Check to see if we have any devices in the Delayed queue for
  554. // the Power DPC. Note that we have to own the power lock for
  555. // this, so claim it now
  556. //
  557. KeAcquireSpinLockAtDpcLevel( &AcpiPowerQueueLock );
  558. if (!IsListEmpty( &AcpiPowerDelayedQueueList) ) {
  559. //
  560. // Move the contents of the list over
  561. //
  562. ACPIInternalMoveList(
  563. &AcpiPowerDelayedQueueList,
  564. &AcpiPowerQueueList
  565. );
  566. //
  567. // Schedule the DPC, if necessary
  568. //
  569. if (!AcpiPowerDpcRunning) {
  570. KeInsertQueueDpc( &AcpiPowerDpc, 0, 0 );
  571. }
  572. }
  573. KeReleaseSpinLockFromDpcLevel( &AcpiPowerQueueLock );
  574. }
  575. //
  576. // This is our chance to look at the synchronization list and
  577. // see if some of the events have occured
  578. //
  579. if (!IsListEmpty( &AcpiBuildSynchronizationList) ) {
  580. //
  581. // Since we don't block on this list --- ie we can notify the
  582. // system that the lists are empty at any time that we want,
  583. // we don't care about what this function returns
  584. //
  585. status = ACPIBuildProcessSynchronizationList(
  586. &AcpiBuildSynchronizationList
  587. );
  588. }
  589. //
  590. // We need the lock again, since we are about to check to see if
  591. // we have completed some work
  592. //
  593. KeAcquireSpinLockAtDpcLevel( &AcpiBuildQueueLock );
  594. } while ( AcpiBuildWorkDone );
  595. //
  596. // The DPC is no longer running
  597. //
  598. AcpiBuildDpcRunning = FALSE;
  599. //
  600. // We no longer need the lock
  601. //
  602. KeReleaseSpinLockFromDpcLevel( &AcpiBuildQueueLock );
  603. //
  604. // Done
  605. //
  606. return;
  607. }
  608. NTSTATUS
  609. ACPIBuildDeviceExtension(
  610. IN PNSOBJ CurrentObject OPTIONAL,
  611. IN PDEVICE_EXTENSION ParentDeviceExtension OPTIONAL,
  612. OUT PDEVICE_EXTENSION *ReturnExtension
  613. )
  614. /*++
  615. Routine Description:
  616. This routine just creates the bare frameworks for an ACPI device extension.
  617. No control methods can be run at this point in time.
  618. N.B: This routine is called with AcpiDeviceTreeLock being held by the
  619. caller. So this routine executes at DISPATCH_LEVEL
  620. Arguments:
  621. CurrentObject - The object that we will link into the tree
  622. ParentDeviceExtension - Where to link the deviceExtension into
  623. ReturnExtension - Where we store a pointer to what we just created
  624. Return Value:
  625. NTSTATUS
  626. --*/
  627. {
  628. NTSTATUS status;
  629. PACPI_POWER_INFO powerInfo;
  630. PDEVICE_EXTENSION deviceExtension;
  631. //
  632. // Sanity checks
  633. //
  634. if (ParentDeviceExtension) {
  635. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL);
  636. //
  637. // We must be under the tree lock.
  638. //
  639. //ASSERT_SPINLOCK_HELD(&AcpiDeviceTreeLock) ;
  640. }
  641. //
  642. // Make sure that the current device doesn't already have a device extension
  643. // This shouldn't really happen --- if it did, the interpreter called us
  644. // twice, which is a bug on its part.
  645. //
  646. if ( CurrentObject != NULL &&
  647. (PDEVICE_EXTENSION) CurrentObject->Context != NULL) {
  648. //
  649. // We have a value --- in theory, it should point to a DeviceExtension
  650. //
  651. deviceExtension = (PDEVICE_EXTENSION) CurrentObject->Context;
  652. //
  653. // It might not be safe to deref this
  654. //
  655. ASSERT( deviceExtension->ParentExtension == ParentDeviceExtension);
  656. if (deviceExtension->ParentExtension == ParentDeviceExtension) {
  657. //
  658. // This again requires some thought: processing the same node
  659. // again insn't a failure
  660. //
  661. return STATUS_SUCCESS;
  662. }
  663. //
  664. // This is probably a bad place to be since we deref'ed something
  665. // that may or may not exist
  666. //
  667. return STATUS_NO_SUCH_DEVICE;
  668. }
  669. //
  670. // Create a new extension for the object
  671. //
  672. deviceExtension = ExAllocateFromNPagedLookasideList(
  673. &DeviceExtensionLookAsideList
  674. );
  675. if (deviceExtension == NULL) {
  676. ACPIPrint( (
  677. ACPI_PRINT_CRITICAL,
  678. "ACPIBuildDeviceExtension: NS %08lx - No Memory for "
  679. "extension\n",
  680. CurrentObject
  681. ) );
  682. return STATUS_INSUFFICIENT_RESOURCES;
  683. }
  684. //
  685. // Lets begin with a clean slate
  686. //
  687. RtlZeroMemory( deviceExtension, sizeof(DEVICE_EXTENSION) );
  688. //
  689. // Initialize the reference count mechanism. We only have a NS object
  690. // so the value should be 1
  691. //
  692. deviceExtension->ReferenceCount++ ;
  693. //
  694. // The initial outstanding IRP count will be set to one. Only during a
  695. // remove IRP will this drop to zero, and then it will immediately pop
  696. // back up to one.
  697. //
  698. deviceExtension->OutstandingIrpCount++;
  699. //
  700. // Initialize the link fields
  701. //
  702. deviceExtension->AcpiObject = CurrentObject;
  703. //
  704. // Initialize the data fields
  705. //
  706. deviceExtension->Signature = ACPI_SIGNATURE;
  707. deviceExtension->Flags = DEV_TYPE_NOT_FOUND | DEV_TYPE_NOT_PRESENT;
  708. deviceExtension->DispatchTable = NULL;
  709. deviceExtension->DeviceState = Stopped;
  710. *ReturnExtension = deviceExtension;
  711. //
  712. // Setup some of the power information values
  713. //
  714. powerInfo = &(deviceExtension->PowerInfo);
  715. powerInfo->DevicePowerMatrix[PowerSystemUnspecified] =
  716. PowerDeviceUnspecified;
  717. powerInfo->DevicePowerMatrix[PowerSystemWorking] = PowerDeviceD0;
  718. powerInfo->DevicePowerMatrix[PowerSystemSleeping1] = PowerDeviceD0;
  719. powerInfo->DevicePowerMatrix[PowerSystemSleeping2] = PowerDeviceD0;
  720. powerInfo->DevicePowerMatrix[PowerSystemSleeping3] = PowerDeviceD0;
  721. powerInfo->DevicePowerMatrix[PowerSystemHibernate] = PowerDeviceD3;
  722. powerInfo->DevicePowerMatrix[PowerSystemShutdown] = PowerDeviceD3;
  723. powerInfo->SystemWakeLevel = PowerSystemUnspecified;
  724. powerInfo->DeviceWakeLevel = PowerDeviceUnspecified;
  725. //
  726. // Initialize the list entries
  727. //
  728. InitializeListHead( &(deviceExtension->ChildDeviceList) );
  729. InitializeListHead( &(deviceExtension->EjectDeviceHead) );
  730. InitializeListHead( &(deviceExtension->EjectDeviceList) );
  731. InitializeListHead( &(powerInfo->WakeSupportList) );
  732. InitializeListHead( &(powerInfo->PowerRequestListEntry) );
  733. //
  734. // Make sure that the deviceExtension has pointers to its parent
  735. // extension. Note, that this should cause the ref count on the
  736. // parent to increase
  737. //
  738. deviceExtension->ParentExtension = ParentDeviceExtension;
  739. if (ParentDeviceExtension) {
  740. InterlockedIncrement( &(ParentDeviceExtension->ReferenceCount) );
  741. //
  742. // Add the deviceExtension into the deviceExtension tree
  743. //
  744. InsertTailList(
  745. &(ParentDeviceExtension->ChildDeviceList),
  746. &(deviceExtension->SiblingDeviceList)
  747. );
  748. }
  749. //
  750. // And make sure that the Name Space Object points to the extension
  751. //
  752. if (CurrentObject != NULL ) {
  753. CurrentObject->Context = deviceExtension;
  754. }
  755. //
  756. // Done
  757. //
  758. return STATUS_SUCCESS;
  759. }
  760. NTSTATUS
  761. ACPIBuildDevicePowerNodes(
  762. IN PDEVICE_EXTENSION DeviceExtension,
  763. IN PNSOBJ ResultObject,
  764. IN POBJDATA ResultData,
  765. IN DEVICE_POWER_STATE DeviceState
  766. )
  767. /*++
  768. Routine Description:
  769. This routine builds the Device Power Nodes for a Device, using the
  770. given result data as a template
  771. N.B. This routine is always called at DPC_LEVEL
  772. Arguments:
  773. DeviceExtension - Device to build power nodes for
  774. ResultObject - The object that was used to get the data
  775. ResultData - Information about the power nodes
  776. DeviceState - The power state the information is for. Note that we
  777. use PowerDeviceUnspecified for the Wake capabilities
  778. Return Value:
  779. NTSTATUS
  780. --*/
  781. {
  782. NTSTATUS status;
  783. PACPI_DEVICE_POWER_NODE deviceNode;
  784. PACPI_DEVICE_POWER_NODE deviceNodePool;
  785. PNSOBJ packageObject = NULL;
  786. POBJDATA currentData;
  787. ULONG count;
  788. ULONG index = 0;
  789. ULONG i;
  790. //
  791. // The number of nodes to build is based on what is in the package
  792. //
  793. count = ((PACKAGEOBJ *) ResultData->pbDataBuff)->dwcElements;
  794. if (DeviceState == PowerDeviceUnspecified) {
  795. //
  796. // If this node doesn't have the bear minimum of entries then
  797. // we should just crash
  798. //
  799. if (count < 2) {
  800. KeBugCheckEx(
  801. ACPI_BIOS_ERROR,
  802. ACPI_PRW_PACKAGE_TOO_SMALL,
  803. (ULONG_PTR) DeviceExtension,
  804. (ULONG_PTR) ResultObject,
  805. count
  806. );
  807. goto ACPIBuildDevicePowerNodesExit;
  808. }
  809. //
  810. // The first two elements in the _PRW are taken up by other things
  811. //
  812. count -= 2;
  813. //
  814. // Remember to bias the count by 2
  815. //
  816. index = 2;
  817. }
  818. //
  819. // Never allocate zero bytes of memory
  820. //
  821. if (count == 0) {
  822. goto ACPIBuildDevicePowerNodesExit;
  823. }
  824. //
  825. // Allocate a block of memory to hold the device nodes
  826. //
  827. deviceNode = deviceNodePool = ExAllocatePoolWithTag(
  828. NonPagedPool,
  829. count * sizeof(ACPI_DEVICE_POWER_NODE),
  830. ACPI_POWER_POOLTAG
  831. );
  832. if (deviceNode == NULL) {
  833. return STATUS_INSUFFICIENT_RESOURCES;
  834. }
  835. //
  836. // We need a spinlock for the following
  837. //
  838. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  839. //
  840. // Remember the device power nodes for this Dx state
  841. //
  842. DeviceExtension->PowerInfo.PowerNode[DeviceState] = deviceNode;
  843. //
  844. // Process all the nodes listed
  845. //
  846. for (i = 0; i < count; i++, index++) {
  847. //
  848. // Initialize the current device node
  849. //
  850. RtlZeroMemory( deviceNode, sizeof(ACPI_DEVICE_POWER_NODE) );
  851. //
  852. // Grab the current object data
  853. //
  854. currentData =
  855. &( ( (PACKAGEOBJ *) ResultData->pbDataBuff)->adata[index]);
  856. //
  857. // Remember that we don't have the package object yet
  858. //
  859. packageObject = NULL;
  860. //
  861. // Turn this into a name space object
  862. //
  863. status = AMLIGetNameSpaceObject(
  864. currentData->pbDataBuff,
  865. ResultObject,
  866. &packageObject,
  867. 0
  868. );
  869. if (!NT_SUCCESS(status)) {
  870. ACPIDevPrint( (
  871. ACPI_PRINT_FAILURE,
  872. DeviceExtension,
  873. "ACPIBuildDevicePowerNodes: %s Status = %08lx\n",
  874. currentData->pbDataBuff,
  875. status
  876. ) );
  877. KeBugCheckEx(
  878. ACPI_BIOS_ERROR,
  879. ACPI_PRX_CANNOT_FIND_OBJECT,
  880. (ULONG_PTR) DeviceExtension,
  881. (ULONG_PTR) ResultObject,
  882. (ULONG_PTR) currentData->pbDataBuff
  883. );
  884. }
  885. //
  886. // Make sure that the associated power object is not null
  887. //
  888. if (packageObject == NULL ||
  889. NSGETOBJTYPE(packageObject) != OBJTYPE_POWERRES) {
  890. ACPIDevPrint( (
  891. ACPI_PRINT_FAILURE,
  892. DeviceExtension,
  893. "ACPIBuildDevicePowerNodes: %s references bad power object.\n",
  894. currentData->pbDataBuff
  895. ) );
  896. KeBugCheckEx(
  897. ACPI_BIOS_ERROR,
  898. ACPI_EXPECTED_POWERRES,
  899. (ULONG_PTR) DeviceExtension,
  900. (ULONG_PTR) ResultObject,
  901. (ULONG_PTR) currentData->pbDataBuff
  902. );
  903. }
  904. //
  905. // Find the associated power object.
  906. //
  907. deviceNode->PowerNode = (PACPI_POWER_DEVICE_NODE)
  908. packageObject->Context;
  909. //
  910. // Determine the support system level, and other static values
  911. //
  912. deviceNode->SystemState = deviceNode->PowerNode->SystemLevel;
  913. deviceNode->DeviceExtension = DeviceExtension;
  914. deviceNode->AssociatedDeviceState = DeviceState;
  915. if (DeviceState == PowerDeviceUnspecified) {
  916. deviceNode->WakePowerResource = TRUE;
  917. }
  918. if (DeviceState == PowerDeviceD0 &&
  919. DeviceExtension->Flags & DEV_CAP_NO_OVERRIDE) {
  920. ACPIInternalUpdateFlags(
  921. &(deviceNode->PowerNode->Flags),
  922. (DEVICE_NODE_ALWAYS_ON | DEVICE_NODE_OVERRIDE_ON),
  923. FALSE
  924. );
  925. }
  926. //
  927. // Add the device to the list that the power node maintains
  928. //
  929. InsertTailList(
  930. &(deviceNode->PowerNode->DevicePowerListHead),
  931. &(deviceNode->DevicePowerListEntry)
  932. );
  933. //
  934. // If this is not the last node, then make sure to keep a pointer
  935. // to the next node
  936. //
  937. if (i < count - 1) {
  938. deviceNode->Next = (deviceNode + 1);
  939. } else {
  940. deviceNode->Next = NULL;
  941. }
  942. //
  943. // Point to the next node in the array of device nodes
  944. //
  945. deviceNode++;
  946. }
  947. //
  948. // Done with lock
  949. //
  950. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  951. ACPIBuildDevicePowerNodesExit:
  952. //
  953. // Done
  954. //
  955. return STATUS_SUCCESS;
  956. }
  957. NTSTATUS
  958. ACPIBuildDeviceRequest(
  959. IN PDEVICE_EXTENSION DeviceExtension,
  960. IN PACPI_BUILD_CALLBACK CallBack,
  961. IN PVOID CallBackContext,
  962. IN BOOLEAN RunDPC
  963. )
  964. /*++
  965. Routine Description:
  966. This routine is called when a device extension is ready to be filled in.
  967. This routine creates a request which is enqueued. When the DPC is fired,
  968. the request will be processed
  969. Note: AcpiDeviceTreeLock must be held to call this function
  970. Arguments:
  971. DeviceExtension - The device which wants to be filled in
  972. CallBack - The function to call when done
  973. CallBackContext - The argument to pass to that function
  974. RunDPC - Should we enqueue the DPC immediately (if it is not
  975. running?)
  976. Return Value:
  977. NTSTATUS
  978. --*/
  979. {
  980. PACPI_BUILD_REQUEST buildRequest;
  981. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  982. //
  983. // Allocate a buildRequest structure
  984. //
  985. buildRequest = ExAllocateFromNPagedLookasideList(
  986. &BuildRequestLookAsideList
  987. );
  988. if (buildRequest == NULL) {
  989. return STATUS_INSUFFICIENT_RESOURCES;
  990. }
  991. //
  992. // If the current reference is 0, that means that someone else beat
  993. // use to the device extension that that we *CANNOT* touch it
  994. //
  995. if (DeviceExtension->ReferenceCount == 0) {
  996. ExFreeToNPagedLookasideList(
  997. &BuildRequestLookAsideList,
  998. buildRequest
  999. );
  1000. return STATUS_DEVICE_REMOVED;
  1001. } else {
  1002. InterlockedIncrement( &(DeviceExtension->ReferenceCount) );
  1003. }
  1004. //
  1005. // Fill in the structure
  1006. //
  1007. RtlZeroMemory( buildRequest, sizeof(ACPI_BUILD_REQUEST) );
  1008. buildRequest->Signature = ACPI_SIGNATURE;
  1009. buildRequest->TargetListEntry = &AcpiBuildDeviceList;
  1010. buildRequest->WorkDone = WORK_DONE_STEP_0;
  1011. buildRequest->Status = STATUS_SUCCESS;
  1012. buildRequest->CallBack = CallBack;
  1013. buildRequest->CallBackContext = CallBackContext;
  1014. buildRequest->BuildContext = DeviceExtension;
  1015. buildRequest->Flags = BUILD_REQUEST_VALID_TARGET |
  1016. BUILD_REQUEST_DEVICE;
  1017. //
  1018. // At this point, we need the spinlock
  1019. //
  1020. KeAcquireSpinLockAtDpcLevel( &AcpiBuildQueueLock );
  1021. //
  1022. // Add this to the list
  1023. //
  1024. InsertTailList(
  1025. &AcpiBuildQueueList,
  1026. &(buildRequest->ListEntry)
  1027. );
  1028. //
  1029. // Do we need to queue up the DPC?
  1030. //
  1031. if (RunDPC && !AcpiBuildDpcRunning) {
  1032. KeInsertQueueDpc( &AcpiBuildDpc, 0, 0 );
  1033. }
  1034. //
  1035. // Done with the lock
  1036. //
  1037. KeReleaseSpinLockFromDpcLevel( &AcpiBuildQueueLock );
  1038. //
  1039. // Done
  1040. //
  1041. return STATUS_PENDING;
  1042. }
  1043. NTSTATUS
  1044. ACPIBuildFilter(
  1045. IN PDRIVER_OBJECT DriverObject,
  1046. IN PDEVICE_EXTENSION DeviceExtension,
  1047. IN PDEVICE_OBJECT PdoObject
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. This routine builds a device object for the given device extension and
  1052. attaches to the specified PDO
  1053. Arguments:
  1054. DriverObject - This is used for IoCreateDevice
  1055. DeviceExtension - The extension to create a PDO for
  1056. PdoObject - The stack to attach the PDO to
  1057. Return Value:
  1058. NTSTATUS
  1059. --*/
  1060. {
  1061. KIRQL oldIrql;
  1062. NTSTATUS status;
  1063. PDEVICE_OBJECT newDeviceObject = NULL;
  1064. PDEVICE_OBJECT targetDeviceObject = NULL;
  1065. //
  1066. // First step is to create a device object
  1067. //
  1068. status = IoCreateDevice(
  1069. DriverObject,
  1070. 0,
  1071. NULL,
  1072. FILE_DEVICE_ACPI,
  1073. FILE_AUTOGENERATED_DEVICE_NAME,
  1074. FALSE,
  1075. &newDeviceObject
  1076. );
  1077. if ( !NT_SUCCESS(status) ) {
  1078. return status;
  1079. }
  1080. //
  1081. // Attach the device to the PDO
  1082. //
  1083. targetDeviceObject = IoAttachDeviceToDeviceStack(
  1084. newDeviceObject,
  1085. PdoObject
  1086. );
  1087. if (targetDeviceObject == NULL) {
  1088. //
  1089. // Bad. We could not attach to a PDO. So we must fail this
  1090. //
  1091. IoDeleteDevice( newDeviceObject );
  1092. //
  1093. // This is as good as it gets
  1094. //
  1095. return STATUS_INVALID_PARAMETER_3;
  1096. }
  1097. //
  1098. // At this point, we have succeeded in creating everything we need
  1099. // so lets update the device extension.
  1100. //
  1101. // First, we need the lock
  1102. //
  1103. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1104. //
  1105. // Now, update the links
  1106. //
  1107. newDeviceObject->DeviceExtension = DeviceExtension;
  1108. DeviceExtension->DeviceObject = newDeviceObject;
  1109. DeviceExtension->PhysicalDeviceObject = PdoObject;
  1110. DeviceExtension->TargetDeviceObject = targetDeviceObject;
  1111. //
  1112. // Setup initial reference counts.
  1113. //
  1114. InterlockedIncrement( &(DeviceExtension->ReferenceCount) );
  1115. //
  1116. // Update the flags for the extension
  1117. //
  1118. ACPIInternalUpdateFlags( &(DeviceExtension->Flags), DEV_MASK_TYPE, TRUE );
  1119. ACPIInternalUpdateFlags( &(DeviceExtension->Flags), DEV_TYPE_FILTER, FALSE );
  1120. DeviceExtension->PreviousState = DeviceExtension->DeviceState;
  1121. DeviceExtension->DeviceState = Stopped;
  1122. DeviceExtension->DispatchTable = &AcpiFilterIrpDispatch;
  1123. //
  1124. // Propagate the Pdo's requirements
  1125. //
  1126. newDeviceObject->StackSize = targetDeviceObject->StackSize + 1;
  1127. newDeviceObject->AlignmentRequirement =
  1128. targetDeviceObject->AlignmentRequirement;
  1129. if (targetDeviceObject->Flags & DO_POWER_PAGABLE) {
  1130. newDeviceObject->Flags |= DO_POWER_PAGABLE;
  1131. }
  1132. if (targetDeviceObject->Flags & DO_DIRECT_IO) {
  1133. newDeviceObject->Flags |= DO_DIRECT_IO;
  1134. }
  1135. //
  1136. // Done with the device lock
  1137. //
  1138. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1139. //
  1140. // We are done initializing the device object
  1141. //
  1142. newDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  1143. //
  1144. // Done
  1145. //
  1146. return STATUS_SUCCESS;
  1147. }
  1148. NTSTATUS
  1149. ACPIBuildFixedButtonExtension(
  1150. IN PDEVICE_EXTENSION ParentExtension,
  1151. OUT PDEVICE_EXTENSION *ResultExtension
  1152. )
  1153. /*++
  1154. Routine Description:
  1155. This routine builds a device extension for the fixed button if one is
  1156. detected
  1157. N.B. This function is called with ACPIDeviceTreeLock being owned
  1158. Arguments:
  1159. ParentExtension - Which child are we?
  1160. ResultExtension - Where to store the created extension
  1161. Return Value:
  1162. NTSTATUS
  1163. --*/
  1164. {
  1165. NTSTATUS status;
  1166. PDEVICE_EXTENSION deviceExtension;
  1167. ULONG buttonCaps;
  1168. ULONG fixedEnables;
  1169. //
  1170. // Have we already done this?
  1171. //
  1172. if (AcpiBuildFixedButtonEnumerated) {
  1173. //
  1174. // Make sure not to return anything
  1175. //
  1176. *ResultExtension = NULL;
  1177. return STATUS_SUCCESS;
  1178. }
  1179. AcpiBuildFixedButtonEnumerated = TRUE;
  1180. //
  1181. // Lets look at the Fixed enables
  1182. //
  1183. fixedEnables = ACPIEnableQueryFixedEnables();
  1184. buttonCaps = 0;
  1185. if (fixedEnables & PM1_PWRBTN_EN) {
  1186. buttonCaps |= SYS_BUTTON_POWER;
  1187. }
  1188. if (fixedEnables & PM1_SLEEPBTN_EN) {
  1189. buttonCaps |= SYS_BUTTON_SLEEP;
  1190. }
  1191. //
  1192. // If we have no caps, then do nothing
  1193. //
  1194. if (!buttonCaps) {
  1195. *ResultExtension = NULL;
  1196. return STATUS_SUCCESS;
  1197. }
  1198. //
  1199. // By default, the button can wake the computer
  1200. //
  1201. buttonCaps |= SYS_BUTTON_WAKE;
  1202. //
  1203. // Build the device extension
  1204. //
  1205. status = ACPIBuildDeviceExtension(
  1206. NULL,
  1207. ParentExtension,
  1208. ResultExtension
  1209. );
  1210. if (!NT_SUCCESS(status)) {
  1211. //
  1212. // Make sure not to return anything
  1213. //
  1214. *ResultExtension = NULL;
  1215. return status;
  1216. }
  1217. deviceExtension = *ResultExtension;
  1218. //
  1219. // Set the flags for the device
  1220. //
  1221. ACPIInternalUpdateFlags(
  1222. &(deviceExtension->Flags),
  1223. (DEV_PROP_NO_OBJECT | DEV_CAP_RAW |
  1224. DEV_MASK_INTERNAL_DEVICE | DEV_CAP_BUTTON),
  1225. FALSE
  1226. );
  1227. //
  1228. // Initialize the button specific extension
  1229. //
  1230. KeInitializeSpinLock( &deviceExtension->Button.SpinLock);
  1231. deviceExtension->Button.Capabilities = buttonCaps;
  1232. //
  1233. // Create the HID for the device
  1234. //
  1235. deviceExtension->DeviceID = ExAllocatePoolWithTag(
  1236. NonPagedPool,
  1237. strlen(ACPIFixedButtonId) + 1,
  1238. ACPI_STRING_POOLTAG
  1239. );
  1240. if (deviceExtension->DeviceID == NULL) {
  1241. //
  1242. // Mark the device as having failed init
  1243. //
  1244. ACPIInternalUpdateFlags(
  1245. &(deviceExtension->Flags),
  1246. DEV_PROP_FAILED_INIT,
  1247. FALSE
  1248. );
  1249. //
  1250. // Done
  1251. //
  1252. *ResultExtension = NULL;
  1253. return STATUS_INSUFFICIENT_RESOURCES;
  1254. }
  1255. RtlCopyMemory(
  1256. deviceExtension->DeviceID,
  1257. ACPIFixedButtonId,
  1258. strlen(ACPIFixedButtonId) + 1
  1259. );
  1260. //
  1261. // Remember that we now have an _HID
  1262. //
  1263. ACPIInternalUpdateFlags(
  1264. &(deviceExtension->Flags),
  1265. (DEV_PROP_HID | DEV_PROP_FIXED_HID),
  1266. FALSE
  1267. );
  1268. //
  1269. // Done
  1270. //
  1271. return STATUS_SUCCESS;
  1272. }
  1273. NTSTATUS
  1274. ACPIBuildFlushQueue(
  1275. PDEVICE_EXTENSION DeviceExtension
  1276. )
  1277. /*++
  1278. Routine Description:
  1279. This routine will block until the Build Queues have been flushed
  1280. Arguments:
  1281. DeviceExtension - The device which wants to flush the queue
  1282. Return Value:
  1283. NSTATUS
  1284. --*/
  1285. {
  1286. KEVENT event;
  1287. NTSTATUS status;
  1288. //
  1289. // Initialize the event that we will wait on
  1290. //
  1291. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  1292. //
  1293. // Now, push a request onto the stack such that when the build
  1294. // list has been flushed, we unblock this thread
  1295. //
  1296. status = ACPIBuildSynchronizationRequest(
  1297. DeviceExtension,
  1298. ACPIBuildNotifyEvent,
  1299. &event,
  1300. &AcpiBuildDeviceList,
  1301. TRUE
  1302. );
  1303. //
  1304. // Block until its done
  1305. //
  1306. if (status == STATUS_PENDING) {
  1307. KeWaitForSingleObject(
  1308. &event,
  1309. Executive,
  1310. KernelMode,
  1311. FALSE,
  1312. NULL
  1313. );
  1314. status = STATUS_SUCCESS;
  1315. }
  1316. //
  1317. // Let the world know
  1318. //
  1319. return status;
  1320. }
  1321. NTSTATUS
  1322. ACPIBuildMissingChildren(
  1323. PDEVICE_EXTENSION DeviceExtension
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. Walk the ACPI namespace children of this device extension and create
  1328. device extension for any of the missing devices.
  1329. N.B. This function is called with the device tree locked...
  1330. Arguments:
  1331. DeviceExtension - Extension to walk
  1332. Return Value:
  1333. NTSTATUS
  1334. --*/
  1335. {
  1336. NTSTATUS status;
  1337. PNSOBJ nsObject;
  1338. ULONG objType;
  1339. //
  1340. // Sanity check
  1341. //
  1342. if (DeviceExtension->Flags & DEV_PROP_NO_OBJECT) {
  1343. return STATUS_SUCCESS;
  1344. }
  1345. //
  1346. // Walk all of children of this object
  1347. //
  1348. for (nsObject = NSGETFIRSTCHILD(DeviceExtension->AcpiObject);
  1349. nsObject != NULL;
  1350. nsObject = NSGETNEXTSIBLING(nsObject)) {
  1351. //
  1352. // Does the namespace object already have a context object? If so,
  1353. // then the object likely already has an extension...
  1354. //
  1355. if (nsObject->Context != NULL) {
  1356. continue;
  1357. }
  1358. //
  1359. // At this point, we possible don't have a device extension
  1360. // (depending on the object type) so we need to simulate an Object
  1361. // Creation call, similar to what OSNotifyCreate() does
  1362. //
  1363. objType = nsObject->ObjData.dwDataType;
  1364. switch (objType) {
  1365. case OBJTYPE_DEVICE:
  1366. status = OSNotifyCreateDevice(
  1367. nsObject,
  1368. DEV_PROP_REBUILD_CHILDREN
  1369. );
  1370. break;
  1371. case OBJTYPE_OPREGION:
  1372. status = OSNotifyCreateOperationRegion(
  1373. nsObject
  1374. );
  1375. break;
  1376. case OBJTYPE_PROCESSOR:
  1377. status = OSNotifyCreateProcessor(
  1378. nsObject,
  1379. DEV_PROP_REBUILD_CHILDREN
  1380. );
  1381. break;
  1382. case OBJTYPE_THERMALZONE:
  1383. status = OSNotifyCreateThermalZone(
  1384. nsObject,
  1385. DEV_PROP_REBUILD_CHILDREN
  1386. );
  1387. break;
  1388. default:
  1389. status = STATUS_SUCCESS;
  1390. break;
  1391. }
  1392. if (!NT_SUCCESS(status)) {
  1393. ACPIPrint( (
  1394. ACPI_PRINT_CRITICAL,
  1395. "ACPIBuildMissingChildren: Error %x when building %x\n",
  1396. status,
  1397. nsObject
  1398. ) );
  1399. }
  1400. }
  1401. //
  1402. // Done
  1403. //
  1404. return STATUS_SUCCESS;
  1405. }
  1406. NTSTATUS
  1407. ACPIBuildMissingEjectionRelations(
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. This routine takes the elements from the AcpiUnresolvedEjectList and tries
  1412. to resolve them
  1413. N.B. This function can only be called IRQL < DISPATCH_LEVEL
  1414. Argument
  1415. None
  1416. Return Value:
  1417. NTSTATUS
  1418. --*/
  1419. {
  1420. KIRQL oldIrql;
  1421. LIST_ENTRY tempList;
  1422. LONG oldReferenceCount;
  1423. NTSTATUS status;
  1424. OBJDATA objData;
  1425. PDEVICE_EXTENSION deviceExtension;
  1426. PDEVICE_EXTENSION ejectorExtension;
  1427. PNSOBJ ejdObject;
  1428. PNSOBJ ejdTarget;
  1429. ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
  1430. //
  1431. // Initialize the list
  1432. //
  1433. InitializeListHead( &tempList);
  1434. //
  1435. // We need the device tree lock to manipulate the UnresolvedEject list
  1436. //
  1437. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1438. //
  1439. // Check to see if there is work to do...
  1440. //
  1441. if (IsListEmpty( &AcpiUnresolvedEjectList ) ) {
  1442. //
  1443. // No work todo
  1444. //
  1445. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1446. return STATUS_SUCCESS;
  1447. }
  1448. //
  1449. // Move the list so that we can release the lock...
  1450. //
  1451. ACPIInternalMoveList( &AcpiUnresolvedEjectList, &tempList );
  1452. //
  1453. // As long as we haven't drained the list, look at each element...
  1454. //
  1455. while (!IsListEmpty( &tempList ) ) {
  1456. //
  1457. // Get the corresponding device extension and remove the entry
  1458. // from the list
  1459. //
  1460. deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
  1461. tempList.Flink,
  1462. DEVICE_EXTENSION,
  1463. EjectDeviceList
  1464. );
  1465. RemoveEntryList( tempList.Flink );
  1466. //
  1467. // See if the _EJD object exists --- it really should otherwise we
  1468. // wouldn't be here..
  1469. //
  1470. ejdObject = ACPIAmliGetNamedChild(
  1471. deviceExtension->AcpiObject,
  1472. PACKED_EJD
  1473. );
  1474. if (!ejdObject) {
  1475. continue;
  1476. }
  1477. //
  1478. // Grab a reference to the object since we will be dropping the
  1479. // DeviceTreeLock.
  1480. //
  1481. InterlockedIncrement( &(deviceExtension->ReferenceCount) );
  1482. //
  1483. // Done with the lock for now...
  1484. //
  1485. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1486. //
  1487. // Evaluate it... Note that we are not holding the lock at this point,
  1488. // so its safe to call the blocking semantic version of the API
  1489. //
  1490. status = AMLIEvalNameSpaceObject(
  1491. ejdObject,
  1492. &objData,
  1493. 0,
  1494. NULL
  1495. );
  1496. //
  1497. // Hold the device tree lock while we look for a match
  1498. //
  1499. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1500. //
  1501. // Decrement the reference count...
  1502. //
  1503. oldReferenceCount = InterlockedDecrement( &(deviceExtension->ReferenceCount) );
  1504. if (oldReferenceCount == 0) {
  1505. //
  1506. // Free the extension...
  1507. //
  1508. ACPIInitDeleteDeviceExtension( deviceExtension );
  1509. continue;
  1510. }
  1511. //
  1512. // Now we can check to see if the call succeeded
  1513. //
  1514. if (!NT_SUCCESS(status)) {
  1515. //
  1516. // Be more forgiving and add the entry back to the unresolved list
  1517. //
  1518. InsertTailList(
  1519. &AcpiUnresolvedEjectList,
  1520. &(deviceExtension->EjectDeviceList)
  1521. );
  1522. continue;
  1523. }
  1524. //
  1525. // However, we must get back a string from the BIOS...
  1526. //
  1527. if (objData.dwDataType != OBJTYPE_STRDATA) {
  1528. KeBugCheckEx(
  1529. ACPI_BIOS_ERROR,
  1530. ACPI_EXPECTED_STRING,
  1531. (ULONG_PTR) deviceExtension,
  1532. (ULONG_PTR) ejdObject,
  1533. objData.dwDataType
  1534. );
  1535. }
  1536. //
  1537. // See what this object points to
  1538. //
  1539. ejdTarget = NULL;
  1540. status = AMLIGetNameSpaceObject(
  1541. objData.pbDataBuff,
  1542. NULL,
  1543. &ejdTarget,
  1544. 0
  1545. );
  1546. //
  1547. // Free the objData now
  1548. //
  1549. if (NT_SUCCESS(status)) {
  1550. AMLIFreeDataBuffs( &objData, 1 );
  1551. }
  1552. if (!NT_SUCCESS(status) || ejdTarget == NULL || ejdTarget->Context == NULL) {
  1553. //
  1554. // No, match. Be forgiving and add this entry back to the
  1555. // unresolved extension...
  1556. //
  1557. InsertTailList(
  1558. &AcpiUnresolvedEjectList,
  1559. &(deviceExtension->EjectDeviceList)
  1560. );
  1561. } else {
  1562. ejectorExtension = (PDEVICE_EXTENSION) ejdTarget->Context;
  1563. InsertTailList(
  1564. &(ejectorExtension->EjectDeviceHead),
  1565. &(deviceExtension->EjectDeviceList)
  1566. );
  1567. if (!(ejectorExtension->Flags & DEV_TYPE_NOT_FOUND)) {
  1568. IoInvalidateDeviceRelations(
  1569. ejectorExtension->PhysicalDeviceObject,
  1570. EjectionRelations
  1571. );
  1572. }
  1573. }
  1574. }
  1575. //
  1576. // Done with the spinlock
  1577. //
  1578. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1579. //
  1580. // Done
  1581. //
  1582. return STATUS_SUCCESS;
  1583. }
  1584. VOID
  1585. ACPIBuildNotifyEvent(
  1586. IN PVOID BuildContext,
  1587. IN PVOID Context,
  1588. IN NTSTATUS Status
  1589. )
  1590. /*++
  1591. Routine Description:
  1592. This routine is called when one of the queues that we are attempting
  1593. to synchronize on has gotten empty. The point of this routine is to
  1594. set an event so that we can resume processing in the proper thread.
  1595. Arguments:
  1596. BuildContext - Aka the Device Extension
  1597. Context - Aka the Event to set
  1598. Status - The result of the operation
  1599. Return Value:
  1600. None
  1601. --*/
  1602. {
  1603. PKEVENT event = (PKEVENT) Context;
  1604. UNREFERENCED_PARAMETER( BuildContext );
  1605. UNREFERENCED_PARAMETER( Status );
  1606. //
  1607. // Set the event
  1608. //
  1609. KeSetEvent( event, IO_NO_INCREMENT, FALSE );
  1610. }
  1611. NTSTATUS
  1612. ACPIBuildPdo(
  1613. IN PDRIVER_OBJECT DriverObject,
  1614. IN PDEVICE_EXTENSION DeviceExtension,
  1615. IN PDEVICE_OBJECT ParentPdoObject,
  1616. IN BOOLEAN CreateAsFilter
  1617. )
  1618. /*++
  1619. Routine Description:
  1620. This routine builds a device object for the given device extension.
  1621. Arguments:
  1622. DriverObject - This is used for IoCreateDevice
  1623. DeviceExtension - The extension to create a PDO for
  1624. ParentPdoObject - Used to get reference required for filter
  1625. CreateAsFilter - If we should create as a PDO-Filter
  1626. Return Status:
  1627. NTSTATUS
  1628. --*/
  1629. {
  1630. KIRQL oldIrql;
  1631. NTSTATUS status;
  1632. PDEVICE_OBJECT filterDeviceObject = NULL;
  1633. PDEVICE_OBJECT newDeviceObject = NULL;
  1634. //
  1635. // First step is to create a device object
  1636. //
  1637. status = IoCreateDevice(
  1638. DriverObject,
  1639. 0,
  1640. NULL,
  1641. FILE_DEVICE_ACPI,
  1642. FILE_AUTOGENERATED_DEVICE_NAME,
  1643. FALSE,
  1644. &newDeviceObject
  1645. );
  1646. if ( !NT_SUCCESS(status) ) {
  1647. return status;
  1648. }
  1649. //
  1650. // Next step is device if we should create the extension as a filter
  1651. // or not
  1652. //
  1653. if (CreateAsFilter) {
  1654. if (!(DeviceExtension->Flags & DEV_CAP_NO_FILTER) ) {
  1655. filterDeviceObject = IoGetAttachedDeviceReference(
  1656. ParentPdoObject
  1657. );
  1658. //
  1659. // Did we fail to attach?
  1660. //
  1661. if (filterDeviceObject == NULL) {
  1662. //
  1663. // We failed --- we must clean up this device object
  1664. //
  1665. IoDeleteDevice( newDeviceObject );
  1666. return STATUS_NO_SUCH_DEVICE;
  1667. }
  1668. } else {
  1669. CreateAsFilter = FALSE;
  1670. }
  1671. }
  1672. //
  1673. // At this point, we have succeeded in creating everything we need
  1674. // so lets update the device extension.
  1675. //
  1676. // First, we need the lock
  1677. //
  1678. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1679. //
  1680. // Now, update the links and the reference counts
  1681. //
  1682. newDeviceObject->DeviceExtension = DeviceExtension;
  1683. DeviceExtension->DeviceObject = newDeviceObject;
  1684. DeviceExtension->PhysicalDeviceObject = newDeviceObject;
  1685. InterlockedIncrement( &(DeviceExtension->ReferenceCount) );
  1686. //
  1687. // Update the flags for the extension
  1688. //
  1689. ACPIInternalUpdateFlags( &(DeviceExtension->Flags), DEV_MASK_TYPE, TRUE );
  1690. ACPIInternalUpdateFlags( &(DeviceExtension->Flags), DEV_TYPE_PDO, FALSE );
  1691. DeviceExtension->PreviousState = DeviceExtension->DeviceState;
  1692. DeviceExtension->DeviceState = Stopped;
  1693. //
  1694. // Set the Irp Dispatch point
  1695. //
  1696. DeviceExtension->DispatchTable = &AcpiPdoIrpDispatch;
  1697. //
  1698. // Did we have to create as a PDO-Filter
  1699. //
  1700. if (CreateAsFilter) {
  1701. //
  1702. // Update the target field
  1703. //
  1704. DeviceExtension->TargetDeviceObject = filterDeviceObject;
  1705. //
  1706. // Update the flags to indicate that this a filter
  1707. //
  1708. ACPIInternalUpdateFlags(
  1709. &(DeviceExtension->Flags),
  1710. DEV_TYPE_FILTER,
  1711. FALSE
  1712. );
  1713. //
  1714. // Update the Irp Dispatch point
  1715. //
  1716. DeviceExtension->DispatchTable = &AcpiBusFilterIrpDispatch;
  1717. //
  1718. // Update the deviceObject information...
  1719. //
  1720. newDeviceObject->StackSize = filterDeviceObject->StackSize + 1;
  1721. newDeviceObject->AlignmentRequirement =
  1722. filterDeviceObject->AlignmentRequirement;
  1723. if (filterDeviceObject->Flags & DO_POWER_PAGABLE) {
  1724. newDeviceObject->Flags |= DO_POWER_PAGABLE;
  1725. }
  1726. }
  1727. //
  1728. // A further refinition of the PDO is to see if it one of the 'special'
  1729. // internal devices
  1730. //
  1731. if (DeviceExtension->Flags & DEV_CAP_PROCESSOR) {
  1732. DeviceExtension->DispatchTable = &AcpiProcessorIrpDispatch;
  1733. } else if (DeviceExtension->Flags & DEV_PROP_HID) {
  1734. ULONG i;
  1735. PUCHAR ptr;
  1736. ASSERT( DeviceExtension->DeviceID );
  1737. for (i = 0; AcpiInternalDeviceTable[i].PnPId; i++) {
  1738. ptr = strstr(
  1739. DeviceExtension->DeviceID,
  1740. AcpiInternalDeviceTable[i].PnPId
  1741. );
  1742. if (ptr) {
  1743. DeviceExtension->DispatchTable =
  1744. AcpiInternalDeviceTable[i].DispatchTable;
  1745. break;
  1746. }
  1747. }
  1748. }
  1749. //
  1750. // Do some more specialized handling here
  1751. //
  1752. if (DeviceExtension->Flags & DEV_CAP_BUTTON &&
  1753. DeviceExtension->Flags & DEV_PROP_NO_OBJECT) {
  1754. //
  1755. // This means that this is the fixed button
  1756. //
  1757. FixedButtonDeviceObject = newDeviceObject;
  1758. }
  1759. //
  1760. // Done with the device lock
  1761. //
  1762. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1763. //
  1764. // We are done initializing the device object
  1765. //
  1766. newDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  1767. if (DeviceExtension->Flags & DEV_PROP_EXCLUSIVE) {
  1768. newDeviceObject->Flags |= DO_EXCLUSIVE;
  1769. }
  1770. //
  1771. // Done
  1772. //
  1773. return STATUS_SUCCESS;
  1774. }
  1775. NTSTATUS
  1776. ACPIBuildPowerResourceExtension(
  1777. IN PNSOBJ PowerResource,
  1778. OUT PACPI_POWER_DEVICE_NODE *ReturnNode
  1779. )
  1780. /*++
  1781. Routine Description:
  1782. This routine is called when a new power resource appears. This routine
  1783. builds the basic framework for the power resource. More data is filled
  1784. in latter
  1785. Note: this function is called with the AcpiDeviceTreeLock being held by
  1786. the caller
  1787. Arguments:
  1788. PowerResource - ACPI NameSpace Object that was added
  1789. ReturnNode - Where to store what we create
  1790. Return Value:
  1791. NTSTATUS
  1792. --*/
  1793. {
  1794. PACPI_POWER_DEVICE_NODE powerNode;
  1795. PACPI_POWER_DEVICE_NODE tempNode;
  1796. PLIST_ENTRY listEntry;
  1797. PPOWERRESOBJ powerResourceObject;
  1798. //
  1799. // Allocate some memory for the power node
  1800. //
  1801. powerNode = ExAllocatePoolWithTag(
  1802. NonPagedPool,
  1803. sizeof(ACPI_POWER_DEVICE_NODE),
  1804. ACPI_DEVICE_POOLTAG
  1805. );
  1806. if (powerNode == NULL) {
  1807. ACPIPrint( (
  1808. ACPI_PRINT_CRITICAL,
  1809. "ACPIBuildPowerResourceExtension: Could not allocate %08lx\n",
  1810. sizeof(ACPI_POWER_DEVICE_NODE)
  1811. ) );
  1812. return STATUS_INSUFFICIENT_RESOURCES;
  1813. }
  1814. //
  1815. // This will give us some useful data about the power resource
  1816. //
  1817. powerResourceObject = (PPOWERRESOBJ) (PowerResource->ObjData.pbDataBuff);
  1818. //
  1819. // Fill in the node. Note that the RtlZero explicitly clears all the flags.
  1820. // This is the desired behaviour
  1821. //
  1822. RtlZeroMemory( powerNode, sizeof(ACPI_POWER_DEVICE_NODE) );
  1823. powerNode->Flags = DEVICE_NODE_STA_UNKNOWN;
  1824. powerNode->PowerObject = PowerResource;
  1825. powerNode->ResourceOrder = powerResourceObject->bResOrder;
  1826. powerNode->WorkDone = WORK_DONE_STEP_0;
  1827. powerNode->SystemLevel = ACPIDeviceMapSystemState(
  1828. powerResourceObject->bSystemLevel
  1829. );
  1830. InitializeListHead( &powerNode->DevicePowerListHead );
  1831. *ReturnNode = powerNode;
  1832. //
  1833. // Make sure that the nsobj points to this entry.
  1834. //
  1835. PowerResource->Context = powerNode;
  1836. //
  1837. // We need to be holding the lock so that we add the node to the list
  1838. //
  1839. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  1840. //
  1841. // Grab the first element in the list and walk it
  1842. //
  1843. for (listEntry = AcpiPowerNodeList.Flink;
  1844. listEntry != &AcpiPowerNodeList;
  1845. listEntry = listEntry->Flink) {
  1846. //
  1847. // Look at the current node
  1848. //
  1849. tempNode = CONTAINING_RECORD(
  1850. listEntry,
  1851. ACPI_POWER_DEVICE_NODE,
  1852. ListEntry
  1853. );
  1854. //
  1855. // Should this node go *before* the current one?
  1856. //
  1857. if (tempNode->ResourceOrder >= powerNode->ResourceOrder) {
  1858. InsertTailList(
  1859. listEntry,
  1860. &(powerNode->ListEntry)
  1861. );
  1862. break;
  1863. }
  1864. }
  1865. //
  1866. // Did we loop all the way around?
  1867. //
  1868. if (listEntry == &AcpiPowerNodeList) {
  1869. //
  1870. // Yes? Oh well, we have to add the entry to the tail now
  1871. //
  1872. InsertTailList(
  1873. listEntry,
  1874. &(powerNode->ListEntry)
  1875. );
  1876. }
  1877. //
  1878. // Done with the lock
  1879. //
  1880. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  1881. //
  1882. // Done
  1883. //
  1884. return STATUS_PENDING;
  1885. }
  1886. NTSTATUS
  1887. ACPIBuildPowerResourceRequest(
  1888. IN PACPI_POWER_DEVICE_NODE PowerNode,
  1889. IN PACPI_BUILD_CALLBACK CallBack,
  1890. IN PVOID CallBackContext,
  1891. IN BOOLEAN RunDPC
  1892. )
  1893. /*++
  1894. Routine Description:
  1895. This routine is called when a power node is ready to be filled in.
  1896. This routine creates a request which is enqueued. When the DPC is fired,
  1897. the request will be processed
  1898. Note: AcpiDeviceTreeLock must be held to call this function
  1899. Arguments:
  1900. PowerNode - The PowerNode that wants to be filled in
  1901. CallBack - The function to call when done
  1902. CallBackContext - The argument to pass to that function
  1903. RunDPC - Should we enqueue the DPC immediately (if it is not
  1904. running?)
  1905. Return Value:
  1906. NTSTATUS
  1907. --*/
  1908. {
  1909. PACPI_BUILD_REQUEST buildRequest;
  1910. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  1911. //
  1912. // Allocate a buildRequest structure
  1913. //
  1914. buildRequest = ExAllocateFromNPagedLookasideList(
  1915. &BuildRequestLookAsideList
  1916. );
  1917. if (buildRequest == NULL) {
  1918. //
  1919. // If there is a completion routine, call it
  1920. //
  1921. if (CallBack != NULL) {
  1922. (*CallBack)(
  1923. PowerNode,
  1924. CallBackContext,
  1925. STATUS_INSUFFICIENT_RESOURCES
  1926. );
  1927. }
  1928. return STATUS_INSUFFICIENT_RESOURCES;
  1929. }
  1930. //
  1931. // Fill in the structure
  1932. //
  1933. RtlZeroMemory( buildRequest, sizeof(ACPI_BUILD_REQUEST) );
  1934. buildRequest->Signature = ACPI_SIGNATURE;
  1935. buildRequest->TargetListEntry = &AcpiBuildPowerResourceList;
  1936. buildRequest->WorkDone = WORK_DONE_STEP_0;
  1937. buildRequest->Status = STATUS_SUCCESS;
  1938. buildRequest->CallBack = CallBack;
  1939. buildRequest->CallBackContext = CallBackContext;
  1940. buildRequest->BuildContext = PowerNode;
  1941. buildRequest->Flags = BUILD_REQUEST_VALID_TARGET;
  1942. //
  1943. // At this point, we need the spinlock
  1944. //
  1945. KeAcquireSpinLockAtDpcLevel( &AcpiBuildQueueLock );
  1946. //
  1947. // Add this to the list
  1948. //
  1949. InsertTailList(
  1950. &AcpiBuildQueueList,
  1951. &(buildRequest->ListEntry)
  1952. );
  1953. //
  1954. // Do we need to queue up the DPC?
  1955. //
  1956. if (RunDPC && !AcpiBuildDpcRunning) {
  1957. KeInsertQueueDpc( &AcpiBuildDpc, 0, 0 );
  1958. }
  1959. //
  1960. // Done with the lock
  1961. //
  1962. KeReleaseSpinLockFromDpcLevel( &AcpiBuildQueueLock );
  1963. //
  1964. // Done
  1965. //
  1966. return STATUS_PENDING;
  1967. }
  1968. NTSTATUS
  1969. ACPIBuildProcessDeviceFailure(
  1970. IN PACPI_BUILD_REQUEST BuildRequest
  1971. )
  1972. /*++
  1973. Routine Description:
  1974. This routine handle the case where we failed to initialize the device
  1975. extension due to some error
  1976. Arguments:
  1977. BuildRequest - The request that failed
  1978. Return Value:
  1979. NTSTATUS
  1980. --*/
  1981. {
  1982. NTSTATUS status = BuildRequest->Status;
  1983. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  1984. ACPIDevPrint( (
  1985. ACPI_PRINT_FAILURE,
  1986. deviceExtension,
  1987. "ACPIBuildProcessDeviceFailure: NextWorkDone = %lx Status = %08lx\n",
  1988. BuildRequest->NextWorkDone,
  1989. status
  1990. ) );
  1991. //
  1992. // Mark the node as having failed
  1993. //
  1994. ACPIInternalUpdateFlags(
  1995. &(deviceExtension->Flags),
  1996. DEV_PROP_FAILED_INIT,
  1997. FALSE
  1998. );
  1999. //
  2000. // Complete the request using the generic completion routine
  2001. //
  2002. status = ACPIBuildProcessGenericComplete( BuildRequest );
  2003. //
  2004. // Done
  2005. //
  2006. return status;
  2007. }
  2008. NTSTATUS
  2009. ACPIBuildProcessDeviceGenericEval(
  2010. IN PACPI_BUILD_REQUEST BuildRequest
  2011. )
  2012. /*++
  2013. Routine Description:
  2014. This routine is very generic. Since the remainder of the work involve
  2015. us executing a request then doing some specialized work on the result,
  2016. it is easy to share the common first part.
  2017. Path: PhaseX ---> PhaseX+1
  2018. Arguments:
  2019. BuildRequest - The request that we will try to fill
  2020. Return Value:
  2021. NTSTATUS
  2022. --*/
  2023. {
  2024. NTSTATUS status = STATUS_SUCCESS;
  2025. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  2026. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  2027. ULONG objectName;
  2028. //
  2029. // Make sure that we clear the result
  2030. //
  2031. RtlZeroMemory( result, sizeof(OBJDATA) );
  2032. //
  2033. // Base everything on the current amount of workDone
  2034. //
  2035. objectName = AcpiBuildDevicePowerNameLookup[BuildRequest->CurrentWorkDone];
  2036. //
  2037. // Remember that the next work done is the CurrentWorkDone + 1
  2038. //
  2039. BuildRequest->NextWorkDone = BuildRequest->CurrentWorkDone + 1;
  2040. //
  2041. // Does this object exists?
  2042. //
  2043. BuildRequest->CurrentObject = ACPIAmliGetNamedChild(
  2044. deviceExtension->AcpiObject,
  2045. objectName
  2046. );
  2047. if (BuildRequest->CurrentObject != NULL) {
  2048. //
  2049. // Yes, then call that function
  2050. //
  2051. status = AMLIAsyncEvalObject(
  2052. BuildRequest->CurrentObject,
  2053. result,
  2054. 0,
  2055. NULL,
  2056. ACPIBuildCompleteGeneric,
  2057. BuildRequest
  2058. );
  2059. }
  2060. //
  2061. // If we didn't get pending back, then call the method ourselves
  2062. //
  2063. if (status != STATUS_PENDING) {
  2064. ACPIBuildCompleteGeneric(
  2065. BuildRequest->CurrentObject,
  2066. status,
  2067. result,
  2068. BuildRequest
  2069. );
  2070. }
  2071. ACPIDevPrint( (
  2072. ACPI_PRINT_LOADING,
  2073. deviceExtension,
  2074. "ACPIBuildProcessDeviceGenericEval: Phase%lx Status = %08lx\n",
  2075. BuildRequest->CurrentWorkDone - WORK_DONE_STEP_0,
  2076. status
  2077. ) );
  2078. //
  2079. // Done
  2080. //
  2081. return STATUS_SUCCESS;
  2082. }
  2083. NTSTATUS
  2084. ACPIBuildProcessDeviceGenericEvalStrict(
  2085. IN PACPI_BUILD_REQUEST BuildRequest
  2086. )
  2087. /*++
  2088. Routine Description:
  2089. This routine is very generic. Since the remainder of the work involve
  2090. us executing a request then doing some specialized work on the result,
  2091. it is easy to share the common first part.
  2092. Path: PhaseX ---> PhaseX+1
  2093. Arguments:
  2094. BuildRequest - The request that we will try to fill
  2095. Return Value:
  2096. NTSTATUS
  2097. --*/
  2098. {
  2099. NTSTATUS status = STATUS_SUCCESS;
  2100. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  2101. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  2102. ULONG objectName;
  2103. //
  2104. // Make sure that we clear the result
  2105. //
  2106. RtlZeroMemory( result, sizeof(OBJDATA) );
  2107. //
  2108. // Base everything on the current amount of workDone
  2109. //
  2110. objectName = AcpiBuildDevicePowerNameLookup[BuildRequest->CurrentWorkDone];
  2111. //
  2112. // Remember that the next work done is the CurrentWorkDone + 1
  2113. //
  2114. BuildRequest->NextWorkDone = BuildRequest->CurrentWorkDone + 1;
  2115. //
  2116. // Does this object exists?
  2117. //
  2118. BuildRequest->CurrentObject = ACPIAmliGetNamedChild(
  2119. deviceExtension->AcpiObject,
  2120. objectName
  2121. );
  2122. if (BuildRequest->CurrentObject != NULL) {
  2123. //
  2124. // Yes, then call that function
  2125. //
  2126. status = AMLIAsyncEvalObject(
  2127. BuildRequest->CurrentObject,
  2128. result,
  2129. 0,
  2130. NULL,
  2131. ACPIBuildCompleteMustSucceed,
  2132. BuildRequest
  2133. );
  2134. }
  2135. //
  2136. // What happened
  2137. //
  2138. ACPIDevPrint( (
  2139. ACPI_PRINT_LOADING,
  2140. deviceExtension,
  2141. "ACPIBuildProcessDeviceGenericEval: Phase%lx Status = %08lx\n",
  2142. BuildRequest->CurrentWorkDone - WORK_DONE_STEP_0,
  2143. status
  2144. ) );
  2145. //
  2146. // If we didn't get pending back, then call the method ourselves
  2147. //
  2148. if (status != STATUS_PENDING) {
  2149. ACPIBuildCompleteMustSucceed(
  2150. BuildRequest->CurrentObject,
  2151. status,
  2152. result,
  2153. BuildRequest
  2154. );
  2155. }
  2156. //
  2157. // Done
  2158. //
  2159. return STATUS_SUCCESS;
  2160. }
  2161. NTSTATUS
  2162. ACPIBuildProcessDevicePhaseAdr(
  2163. IN PACPI_BUILD_REQUEST BuildRequest
  2164. )
  2165. /*++
  2166. Routine Description:
  2167. This routine is called by the interpreter once it has evaluate the _ADR
  2168. method.
  2169. Path: PhaseAdr -> PhaseSta
  2170. Arguments:
  2171. BuildRequest - The request that we will try to fill
  2172. Return Value:
  2173. NTSTATUS
  2174. --*/
  2175. {
  2176. NTSTATUS status = STATUS_SUCCESS;
  2177. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  2178. //
  2179. // If we got to this point, that means that the control method was
  2180. // successfull and so lets remember that we have an address
  2181. //
  2182. ACPIInternalUpdateFlags(
  2183. &(deviceExtension->Flags),
  2184. DEV_PROP_ADDRESS,
  2185. FALSE
  2186. );
  2187. //
  2188. // The next phase is to run the _STA
  2189. //
  2190. BuildRequest->NextWorkDone = WORK_DONE_STA;
  2191. //
  2192. // Get the device status
  2193. //
  2194. status = ACPIGetDevicePresenceAsync(
  2195. deviceExtension,
  2196. ACPIBuildCompleteMustSucceed,
  2197. BuildRequest,
  2198. (PVOID *) &(BuildRequest->Integer),
  2199. NULL
  2200. );
  2201. //
  2202. // What happened?
  2203. //
  2204. ACPIDevPrint( (
  2205. ACPI_PRINT_LOADING,
  2206. deviceExtension,
  2207. "ACPIBuildProcessDevicePhaseAdr: Status = %08lx\n",
  2208. status
  2209. ) );
  2210. //
  2211. // Common code to handle the result of the 'Get' routine
  2212. //
  2213. if (status != STATUS_PENDING) {
  2214. ACPIBuildCompleteMustSucceed(
  2215. NULL,
  2216. status,
  2217. NULL,
  2218. BuildRequest
  2219. );
  2220. } else {
  2221. status = STATUS_SUCCESS;
  2222. }
  2223. //
  2224. // Done
  2225. //
  2226. return status;
  2227. } // ACPIBuildProcessDevicePhaseAdr
  2228. NTSTATUS
  2229. ACPIBuildProcessDevicePhaseAdrOrHid(
  2230. IN PACPI_BUILD_REQUEST BuildRequest
  2231. )
  2232. /*++
  2233. Routine Description:
  2234. This routine is called after all the children of the current device
  2235. have been created with the name space tree. This function is responsible
  2236. then for evaluating the 'safe' control methods to determine the name
  2237. of the extension, etc, etc
  2238. Path: PhaseAdrOrHid -> PhaseAdr
  2239. |-> PhaseUid
  2240. |-> PhaseHid
  2241. Arguments:
  2242. BuildRequest - The request that we will try to fill
  2243. Return Value:
  2244. NTSTATUS
  2245. --*/
  2246. {
  2247. NTSTATUS status;
  2248. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  2249. PNSOBJ nsObject = NULL;
  2250. POBJDATA resultData = &(BuildRequest->DeviceRequest.ResultData);
  2251. //
  2252. // We need to name this node, so lets determine if there is an _HID
  2253. // or an _ADR is present
  2254. //
  2255. nsObject = ACPIAmliGetNamedChild(
  2256. deviceExtension->AcpiObject,
  2257. PACKED_HID
  2258. );
  2259. if (nsObject == NULL) {
  2260. //
  2261. // Otherwise, there had better be an _ADR present
  2262. //
  2263. nsObject = ACPIAmliGetNamedChild(
  2264. deviceExtension->AcpiObject,
  2265. PACKED_ADR
  2266. );
  2267. if (nsObject == NULL) {
  2268. //
  2269. // At this point, we have an invalid name space object ---
  2270. // this should not happen
  2271. //
  2272. KeBugCheckEx(
  2273. ACPI_BIOS_ERROR,
  2274. ACPI_REQUIRED_METHOD_NOT_PRESENT,
  2275. (ULONG_PTR) deviceExtension,
  2276. PACKED_ADR,
  2277. 0
  2278. );
  2279. //
  2280. // Never get here
  2281. //
  2282. return STATUS_NO_SUCH_DEVICE;
  2283. } else {
  2284. //
  2285. // If we think there is an ADR, then the correct next stage is
  2286. // to post process the ADR
  2287. //
  2288. BuildRequest->NextWorkDone = WORK_DONE_ADR;
  2289. //
  2290. // Remember which name space object we are evaluating
  2291. //
  2292. BuildRequest->CurrentObject = nsObject;
  2293. //
  2294. // Get the Address
  2295. //
  2296. status = ACPIGetAddressAsync(
  2297. deviceExtension,
  2298. ACPIBuildCompleteMustSucceed,
  2299. BuildRequest,
  2300. (PVOID *) &(deviceExtension->Address),
  2301. NULL
  2302. );
  2303. }
  2304. } else {
  2305. //
  2306. // Remember which name space object we are evaluating
  2307. //
  2308. BuildRequest->CurrentObject = nsObject;
  2309. //
  2310. // When we go down this path, we actually want to build the UID before
  2311. // the HID because that makes deciding wether to run the CID much easier
  2312. //
  2313. nsObject = ACPIAmliGetNamedChild(
  2314. deviceExtension->AcpiObject,
  2315. PACKED_UID
  2316. );
  2317. if (nsObject != NULL) {
  2318. //
  2319. // If we think there is an UID, then the correct next stage is
  2320. // to postprocess the UID. The reason that
  2321. //
  2322. BuildRequest->NextWorkDone = WORK_DONE_UID;
  2323. //
  2324. // Remember which name space object we are evaluating
  2325. //
  2326. BuildRequest->CurrentObject = nsObject;
  2327. //
  2328. // Get the Instance ID
  2329. //
  2330. status = ACPIGetInstanceIDAsync(
  2331. deviceExtension,
  2332. ACPIBuildCompleteMustSucceed,
  2333. BuildRequest,
  2334. &(deviceExtension->InstanceID),
  2335. NULL
  2336. );
  2337. } else {
  2338. //
  2339. // We don't have UID, so lets process the HID
  2340. //
  2341. BuildRequest->NextWorkDone = WORK_DONE_HID;
  2342. //
  2343. // Get the Device ID
  2344. //
  2345. status = ACPIGetDeviceIDAsync(
  2346. deviceExtension,
  2347. ACPIBuildCompleteMustSucceed,
  2348. BuildRequest,
  2349. &(deviceExtension->DeviceID),
  2350. NULL
  2351. );
  2352. }
  2353. }
  2354. //
  2355. // Common code to handle the result of the 'Get' routine
  2356. //
  2357. if (status != STATUS_PENDING) {
  2358. ACPIBuildCompleteMustSucceed(
  2359. nsObject,
  2360. status,
  2361. NULL,
  2362. BuildRequest
  2363. );
  2364. } else {
  2365. status = STATUS_SUCCESS;
  2366. }
  2367. //
  2368. // Done
  2369. //
  2370. return status;
  2371. } // ACPIBuildProcessDevicePhaseAdrOrUid
  2372. NTSTATUS
  2373. ACPIBuildProcessDevicePhaseCid(
  2374. IN PACPI_BUILD_REQUEST BuildRequest
  2375. )
  2376. /*++
  2377. This routine is called by the interpreter once it has evaluate the _CID
  2378. method. This routine then sets any flag that are appropriate
  2379. device
  2380. Path: PhaseCid -> PhaseSta
  2381. Arguments:
  2382. BuildRequest - The request that we will try to fill
  2383. Return Value:
  2384. NTSTATUS
  2385. --*/
  2386. {
  2387. NTSTATUS status = STATUS_SUCCESS;
  2388. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  2389. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  2390. PUCHAR tempPtr = BuildRequest->String;
  2391. ULONG i;
  2392. //
  2393. // Walk the CID, trying to find the double NULL
  2394. //
  2395. for ( ;tempPtr != NULL && *tempPtr != '\0'; ) {
  2396. tempPtr += strlen(tempPtr);
  2397. if (*(tempPtr+1) == '\0') {
  2398. //
  2399. // Found the double null, so we can break
  2400. //
  2401. break;
  2402. }
  2403. //
  2404. // Set the character to be a 'space'
  2405. //
  2406. *tempPtr = ' ';
  2407. }
  2408. tempPtr = BuildRequest->String;
  2409. //
  2410. // Set any special flags associated with this device id
  2411. //
  2412. for (i = 0; AcpiInternalDeviceFlagTable[i].PnPId != NULL; i++) {
  2413. if (strstr( tempPtr, AcpiInternalDeviceFlagTable[i].PnPId ) ) {
  2414. ACPIInternalUpdateFlags(
  2415. &(deviceExtension->Flags),
  2416. AcpiInternalDeviceFlagTable[i].Flags,
  2417. FALSE
  2418. );
  2419. break;
  2420. }
  2421. }
  2422. //
  2423. // Done with the string
  2424. //
  2425. if (tempPtr != NULL) {
  2426. ExFreePool( tempPtr );
  2427. }
  2428. //
  2429. // The next stage is to run the _STA
  2430. //
  2431. BuildRequest->NextWorkDone = WORK_DONE_STA;
  2432. //
  2433. // Get the device status
  2434. //
  2435. status = ACPIGetDevicePresenceAsync(
  2436. deviceExtension,
  2437. ACPIBuildCompleteMustSucceed,
  2438. BuildRequest,
  2439. (PVOID *) &(BuildRequest->Integer),
  2440. NULL
  2441. );
  2442. //
  2443. // What happened?
  2444. //
  2445. ACPIDevPrint( (
  2446. ACPI_PRINT_LOADING,
  2447. deviceExtension,
  2448. "ACPIBuildProcessDevicePhaseCid: Status = %08lx\n",
  2449. status
  2450. ) );
  2451. //
  2452. // Common code to handle the result of the 'Get' routine
  2453. //
  2454. if (status != STATUS_PENDING) {
  2455. ACPIBuildCompleteMustSucceed(
  2456. NULL,
  2457. status,
  2458. NULL,
  2459. BuildRequest
  2460. );
  2461. } else {
  2462. status = STATUS_SUCCESS;
  2463. }
  2464. //
  2465. // Done
  2466. //
  2467. return status;
  2468. }
  2469. NTSTATUS
  2470. ACPIBuildProcessDevicePhaseCrs(
  2471. IN PACPI_BUILD_REQUEST BuildRequest
  2472. )
  2473. /*++
  2474. Routine Description:
  2475. This routine is called by the interpreter once it has evaluate the _CRS
  2476. method. This routine then determines if this is the kernel debugger
  2477. Path: PhaseCrs ---> PhasePrw
  2478. Arguments:
  2479. BuildRequest - The request that we will try to fill
  2480. Return Value:
  2481. NTSTATUS
  2482. --*/
  2483. {
  2484. NTSTATUS status = STATUS_SUCCESS;
  2485. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  2486. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  2487. //
  2488. // The next step is to run the _PRW
  2489. //
  2490. BuildRequest->NextWorkDone = WORK_DONE_PRW;
  2491. //
  2492. // Did we have an object to run?
  2493. //
  2494. if (BuildRequest->CurrentObject == NULL) {
  2495. //
  2496. // No? Then there is no work for us to do here
  2497. //
  2498. goto ACPIBuildProcessDevicePhaseCrsExit;
  2499. }
  2500. //
  2501. // We are expecting a package
  2502. //
  2503. if (result->dwDataType != OBJTYPE_BUFFDATA) {
  2504. //
  2505. // A bios must return a package to a PRW method
  2506. //
  2507. KeBugCheckEx(
  2508. ACPI_BIOS_ERROR,
  2509. ACPI_EXPECTED_BUFFER,
  2510. (ULONG_PTR) deviceExtension,
  2511. (ULONG_PTR) BuildRequest->CurrentObject,
  2512. result->dwDataType
  2513. );
  2514. goto ACPIBuildProcessDevicePhaseCrsExit;
  2515. }
  2516. //
  2517. // Update the bits to see if the serial port matches either the kernel debugger
  2518. // port or the kernel headless port.
  2519. //
  2520. ACPIMatchKernelPorts(
  2521. deviceExtension,
  2522. result
  2523. );
  2524. //
  2525. // Do not leave object lying around without having freed them first
  2526. //
  2527. AMLIFreeDataBuffs( result, 1 );
  2528. ACPIBuildProcessDevicePhaseCrsExit:
  2529. ACPIDevPrint( (
  2530. ACPI_PRINT_LOADING,
  2531. deviceExtension,
  2532. "ACPIBuildProcessDevicePhaseCrs: Status = %08lx\n",
  2533. status
  2534. ) );
  2535. //
  2536. // We won't actually need to call the interpreter, but we will call
  2537. // the generic callback so that we don't have to duplicate code
  2538. //
  2539. ACPIBuildCompleteMustSucceed(
  2540. NULL,
  2541. status,
  2542. NULL,
  2543. BuildRequest
  2544. );
  2545. //
  2546. // Done
  2547. //
  2548. return status;
  2549. }
  2550. NTSTATUS
  2551. ACPIBuildProcessDevicePhaseEjd(
  2552. IN PACPI_BUILD_REQUEST BuildRequest
  2553. )
  2554. /*++
  2555. Routine Description:
  2556. This routine is called when we have run _EJD
  2557. Arguments:
  2558. BuildRequest - The request that has just been completed
  2559. Return Value:
  2560. NTSTATUS
  2561. --*/
  2562. {
  2563. NTSTATUS status = STATUS_SUCCESS;
  2564. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  2565. PDEVICE_EXTENSION ejectorExtension = NULL;
  2566. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  2567. PNSOBJ ejectObject = NULL;
  2568. //
  2569. // From here, decide if we have a serial port or not
  2570. //
  2571. if (!(deviceExtension->Flags & DEV_TYPE_NOT_PRESENT) &&
  2572. (deviceExtension->Flags & DEV_CAP_SERIAL) ) {
  2573. //
  2574. // The next step is to run the _CRS
  2575. //
  2576. BuildRequest->NextWorkDone = WORK_DONE_CRS;
  2577. } else {
  2578. //
  2579. // The next step is to run the _PRW
  2580. //
  2581. BuildRequest->NextWorkDone = WORK_DONE_PRW;
  2582. }
  2583. //
  2584. // Did we have an object to run?
  2585. //
  2586. if (BuildRequest->CurrentObject == NULL) {
  2587. //
  2588. // No? Then there is no work for us to do here
  2589. //
  2590. goto ACPIBuildProcessDevicePhaseEjdExit;
  2591. }
  2592. //
  2593. // No longer need the result
  2594. //
  2595. AMLIFreeDataBuffs( result, 1 );
  2596. //
  2597. // Add the device extension into the unresolved eject tree
  2598. //
  2599. ExInterlockedInsertTailList(
  2600. &AcpiUnresolvedEjectList,
  2601. &(deviceExtension->EjectDeviceList),
  2602. &AcpiDeviceTreeLock
  2603. );
  2604. #if DBG
  2605. if (deviceExtension->DebugFlags & DEVDBG_EJECTOR_FOUND) {
  2606. ACPIDevPrint( (
  2607. ACPI_PRINT_WARNING,
  2608. deviceExtension,
  2609. "ACPIBuildProcessDevicePhaseEjd: Ejector already found\n"
  2610. ) );
  2611. } else {
  2612. deviceExtension->DebugFlags |= DEVDBG_EJECTOR_FOUND;
  2613. }
  2614. #endif
  2615. ACPIBuildProcessDevicePhaseEjdExit:
  2616. //
  2617. // Check to see if we have a dock device
  2618. //
  2619. if (!ACPIDockIsDockDevice( deviceExtension->AcpiObject) ) {
  2620. //
  2621. // If it's not a dock, then don't bother...
  2622. //
  2623. status = STATUS_SUCCESS;
  2624. goto ACPIBuildProcessDevicePhaseEjdExit2;
  2625. }
  2626. if (!AcpiInformation->Dockable) {
  2627. ACPIDevPrint( (
  2628. ACPI_PRINT_WARNING,
  2629. deviceExtension,
  2630. "ACPIBuildProcessDevicePhaseEjd: BIOS BUG - DOCK bit not set\n"
  2631. ) );
  2632. KeBugCheckEx(
  2633. ACPI_BIOS_ERROR,
  2634. ACPI_CLAIMS_BOGUS_DOCK_SUPPORT,
  2635. (ULONG_PTR) deviceExtension,
  2636. (ULONG_PTR) BuildRequest->CurrentObject,
  2637. 0
  2638. );
  2639. }
  2640. #if DBG
  2641. //
  2642. // Have we already handled this? --- This guy will grab the lock. So don't
  2643. // hold the DeviceTree Lock at this point
  2644. //
  2645. if (ACPIDockFindCorrespondingDock( deviceExtension ) ) {
  2646. KeBugCheckEx(
  2647. ACPI_BIOS_ERROR,
  2648. ACPI_CLAIMS_BOGUS_DOCK_SUPPORT,
  2649. (ULONG_PTR) deviceExtension,
  2650. (ULONG_PTR) BuildRequest->CurrentObject,
  2651. 1
  2652. );
  2653. }
  2654. #endif
  2655. //
  2656. // We need the spinlock to touch the device tree
  2657. //
  2658. KeAcquireSpinLockAtDpcLevel( &AcpiDeviceTreeLock );
  2659. //
  2660. // Build the device extension
  2661. //
  2662. status = ACPIBuildDockExtension(
  2663. deviceExtension->AcpiObject,
  2664. RootDeviceExtension
  2665. );
  2666. //
  2667. // Done with the lock
  2668. //
  2669. KeReleaseSpinLockFromDpcLevel( &AcpiDeviceTreeLock );
  2670. ACPIBuildProcessDevicePhaseEjdExit2:
  2671. ACPIDevPrint( (
  2672. ACPI_PRINT_LOADING,
  2673. deviceExtension,
  2674. "ACPIBuildProcessDevicePhaseEjd: Status = %08lx\n",
  2675. status
  2676. ) );
  2677. //
  2678. // We won't actually need to call the interpreter, but we will call
  2679. // the generic callback so that we don't have to duplicate code
  2680. //
  2681. ACPIBuildCompleteGeneric(
  2682. NULL,
  2683. status,
  2684. NULL,
  2685. BuildRequest
  2686. );
  2687. //
  2688. // Done
  2689. //
  2690. return status;
  2691. }
  2692. NTSTATUS
  2693. ACPIBuildProcessDevicePhaseHid(
  2694. IN PACPI_BUILD_REQUEST BuildRequest
  2695. )
  2696. /*++
  2697. Routine Description:
  2698. This routine is called by the interpreter once it has evaluate the _HID
  2699. method.
  2700. Path: PhaseHid -> PhaseCid
  2701. |-> PhaseSta
  2702. Arguments:
  2703. BuildRequest - The request that we will try to fill
  2704. Return Value:
  2705. NTSTATUS
  2706. --*/
  2707. {
  2708. BOOLEAN matchFound = FALSE;
  2709. NTSTATUS status = STATUS_SUCCESS;
  2710. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  2711. PNSOBJ nsObject = NULL;
  2712. PUCHAR tempPtr = deviceExtension->DeviceID;
  2713. ULONG i;
  2714. //
  2715. // Set any special flags associated with this device id
  2716. //
  2717. for (i = 0; AcpiInternalDeviceFlagTable[i].PnPId != NULL; i++) {
  2718. if (strstr( tempPtr, AcpiInternalDeviceFlagTable[i].PnPId ) ) {
  2719. ACPIInternalUpdateFlags(
  2720. &(deviceExtension->Flags),
  2721. AcpiInternalDeviceFlagTable[i].Flags,
  2722. FALSE
  2723. );
  2724. matchFound = TRUE;
  2725. break;
  2726. }
  2727. }
  2728. //
  2729. // Remember that we have an HID
  2730. //
  2731. ACPIInternalUpdateFlags(
  2732. &(deviceExtension->Flags),
  2733. DEV_PROP_HID,
  2734. FALSE
  2735. );
  2736. //
  2737. // Lets see if there is a _CID to run. Only run the _CID if there
  2738. // was no match found above
  2739. //
  2740. nsObject = ACPIAmliGetNamedChild(
  2741. deviceExtension->AcpiObject,
  2742. PACKED_CID
  2743. );
  2744. if (nsObject != NULL && matchFound == FALSE) {
  2745. //
  2746. // The next phase is to post process the _CID
  2747. //
  2748. BuildRequest->NextWorkDone = WORK_DONE_CID;
  2749. //
  2750. // Get the compatible ID
  2751. //
  2752. status = ACPIGetCompatibleIDAsync(
  2753. deviceExtension,
  2754. ACPIBuildCompleteMustSucceed,
  2755. BuildRequest,
  2756. &(BuildRequest->String),
  2757. NULL
  2758. );
  2759. } else {
  2760. //
  2761. // The next step is to run the _STA
  2762. //
  2763. BuildRequest->NextWorkDone = WORK_DONE_STA;
  2764. //
  2765. // Get the device status
  2766. //
  2767. status = ACPIGetDevicePresenceAsync(
  2768. deviceExtension,
  2769. ACPIBuildCompleteMustSucceed,
  2770. BuildRequest,
  2771. (PVOID *) &(BuildRequest->Integer),
  2772. NULL
  2773. );
  2774. }
  2775. //
  2776. // What happened?
  2777. //
  2778. ACPIDevPrint( (
  2779. ACPI_PRINT_LOADING,
  2780. deviceExtension,
  2781. "ACPIBuildProcessDevicePhaseHid: Status = %08lx\n",
  2782. status
  2783. ) );
  2784. //
  2785. // Common code to handle the result of the 'Get' routine
  2786. //
  2787. if (status != STATUS_PENDING) {
  2788. ACPIBuildCompleteMustSucceed(
  2789. nsObject,
  2790. status,
  2791. NULL,
  2792. BuildRequest
  2793. );
  2794. } else {
  2795. status = STATUS_SUCCESS;
  2796. }
  2797. //
  2798. // Done
  2799. //
  2800. return status;
  2801. } // ACPIBuildProcessDevicePhaseHid
  2802. NTSTATUS
  2803. ACPIBuildProcessDevicePhasePr0(
  2804. IN PACPI_BUILD_REQUEST BuildRequest
  2805. )
  2806. /*++
  2807. This routine is called by the interpreter once it has evaluate the _PR0
  2808. method. This routine then determines the current power state of the
  2809. device
  2810. Path: PhasePr0 ---> PhasePr1
  2811. Arguments:
  2812. BuildRequest - The request that we will try to fill
  2813. Return Value:
  2814. NTSTATUS
  2815. --*/
  2816. {
  2817. NTSTATUS status = STATUS_SUCCESS;
  2818. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  2819. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  2820. //
  2821. // The next stage is PR1
  2822. //
  2823. BuildRequest->NextWorkDone = WORK_DONE_PR1;
  2824. //
  2825. // Get the appropriate _PSx object to go with this object
  2826. //
  2827. deviceExtension->PowerInfo.PowerObject[PowerDeviceD0] =
  2828. ACPIAmliGetNamedChild(
  2829. deviceExtension->AcpiObject,
  2830. PACKED_PS0
  2831. );
  2832. //
  2833. // Did we have an object to run?
  2834. //
  2835. if (BuildRequest->CurrentObject == NULL) {
  2836. //
  2837. // No? Then there is no work for us to do here
  2838. //
  2839. goto ACPIBuildProcessDevicePhasePr0Exit;
  2840. }
  2841. //
  2842. // We are expecting a package
  2843. //
  2844. if (result->dwDataType != OBJTYPE_PKGDATA) {
  2845. //
  2846. // A bios must return a package to a PRW method
  2847. //
  2848. KeBugCheckEx(
  2849. ACPI_BIOS_ERROR,
  2850. ACPI_EXPECTED_PACKAGE,
  2851. (ULONG_PTR) deviceExtension,
  2852. (ULONG_PTR) BuildRequest->CurrentObject,
  2853. result->dwDataType
  2854. );
  2855. goto ACPIBuildProcessDevicePhasePr0Exit;
  2856. }
  2857. //
  2858. // Process the package
  2859. //
  2860. status = ACPIBuildDevicePowerNodes(
  2861. deviceExtension,
  2862. BuildRequest->CurrentObject,
  2863. result,
  2864. PowerDeviceD0
  2865. );
  2866. //
  2867. // Do not leave object lying around without having freed them first
  2868. //
  2869. AMLIFreeDataBuffs( result, 1 );
  2870. ACPIBuildProcessDevicePhasePr0Exit:
  2871. ACPIDevPrint( (
  2872. ACPI_PRINT_LOADING,
  2873. deviceExtension,
  2874. "ACPIBuildProcessDevicePhasePr0: Status = %08lx\n",
  2875. status
  2876. ) );
  2877. //
  2878. // We won't actually need to call the interpreter, but we will call
  2879. // the generic callback so that we don't have to duplicate code
  2880. //
  2881. ACPIBuildCompleteMustSucceed(
  2882. NULL,
  2883. status,
  2884. NULL,
  2885. BuildRequest
  2886. );
  2887. //
  2888. // Done
  2889. //
  2890. return status;
  2891. }
  2892. NTSTATUS
  2893. ACPIBuildProcessDevicePhasePr1(
  2894. IN PACPI_BUILD_REQUEST BuildRequest
  2895. )
  2896. /*++
  2897. This routine is called by the interpreter once it has evaluate the _PR1
  2898. method. This routine then determines the current power state of the
  2899. device
  2900. Path: PhasePr1 ---> PhasePr2
  2901. Arguments:
  2902. BuildRequest - The request that we will try to fill
  2903. Return Value:
  2904. NTSTATUS
  2905. --*/
  2906. {
  2907. NTSTATUS status = STATUS_SUCCESS;
  2908. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  2909. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  2910. //
  2911. // The next stage is Phase16
  2912. //
  2913. BuildRequest->NextWorkDone = WORK_DONE_PR2;
  2914. //
  2915. // Get the appropriate _PSx object to go with this object
  2916. //
  2917. deviceExtension->PowerInfo.PowerObject[PowerDeviceD1] =
  2918. ACPIAmliGetNamedChild(
  2919. deviceExtension->AcpiObject,
  2920. PACKED_PS1
  2921. );
  2922. if (deviceExtension->PowerInfo.PowerObject[PowerDeviceD1] == NULL) {
  2923. deviceExtension->PowerInfo.PowerObject[PowerDeviceD1] =
  2924. deviceExtension->PowerInfo.PowerObject[PowerDeviceD0];
  2925. }
  2926. //
  2927. // Did we have an object to run?
  2928. //
  2929. if (BuildRequest->CurrentObject == NULL) {
  2930. //
  2931. // No? Then there is no work for us to do here
  2932. //
  2933. goto ACPIBuildProcessDevicePhasePr1Exit;
  2934. }
  2935. //
  2936. // We are expecting a package
  2937. //
  2938. if (result->dwDataType != OBJTYPE_PKGDATA) {
  2939. //
  2940. // A bios must return a package to a PRW method
  2941. //
  2942. KeBugCheckEx(
  2943. ACPI_BIOS_ERROR,
  2944. ACPI_EXPECTED_PACKAGE,
  2945. (ULONG_PTR) deviceExtension,
  2946. (ULONG_PTR) BuildRequest->CurrentObject,
  2947. result->dwDataType
  2948. );
  2949. goto ACPIBuildProcessDevicePhasePr1Exit;
  2950. }
  2951. //
  2952. // Process the package
  2953. //
  2954. status = ACPIBuildDevicePowerNodes(
  2955. deviceExtension,
  2956. BuildRequest->CurrentObject,
  2957. result,
  2958. PowerDeviceD1
  2959. );
  2960. //
  2961. // Do not leave object lying around without having freed them first
  2962. //
  2963. AMLIFreeDataBuffs( result, 1 );
  2964. ACPIBuildProcessDevicePhasePr1Exit:
  2965. ACPIDevPrint( (
  2966. ACPI_PRINT_LOADING,
  2967. deviceExtension,
  2968. "ACPIBuildProcessDevicePhasePr1: Status = %08lx\n",
  2969. status
  2970. ) );
  2971. //
  2972. // We won't actually need to call the interpreter, but we will call
  2973. // the generic callback so that we don't have to duplicate code
  2974. //
  2975. ACPIBuildCompleteMustSucceed(
  2976. NULL,
  2977. status,
  2978. NULL,
  2979. BuildRequest
  2980. );
  2981. //
  2982. // Done
  2983. //
  2984. return status;
  2985. }
  2986. NTSTATUS
  2987. ACPIBuildProcessDevicePhasePr2(
  2988. IN PACPI_BUILD_REQUEST BuildRequest
  2989. )
  2990. /*++
  2991. This routine is called by the interpreter once it has evaluate the _PR2
  2992. method. This routine then determines the current power state of the
  2993. device
  2994. Path: PhasePr2 ---> PhasePsc
  2995. |-> PhasePsc+1
  2996. Arguments:
  2997. BuildRequest - The request that we will try to fill
  2998. Return Value:
  2999. NTSTATUS
  3000. --*/
  3001. {
  3002. NTSTATUS status = STATUS_SUCCESS;
  3003. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  3004. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  3005. //
  3006. // Get the appropriate _PSx object to go with this object
  3007. //
  3008. deviceExtension->PowerInfo.PowerObject[PowerDeviceD2] =
  3009. ACPIAmliGetNamedChild(
  3010. deviceExtension->AcpiObject,
  3011. PACKED_PS2
  3012. );
  3013. if (deviceExtension->PowerInfo.PowerObject[PowerDeviceD2] == NULL) {
  3014. deviceExtension->PowerInfo.PowerObject[PowerDeviceD2] =
  3015. deviceExtension->PowerInfo.PowerObject[PowerDeviceD1];
  3016. }
  3017. //
  3018. // Did we have an object to run?
  3019. //
  3020. if (BuildRequest->CurrentObject == NULL) {
  3021. //
  3022. // No? Then there is no work for us to do here
  3023. //
  3024. goto ACPIBuildProcessDevicePhasePr2Exit;
  3025. }
  3026. //
  3027. // We are expecting a package
  3028. //
  3029. if (result->dwDataType != OBJTYPE_PKGDATA) {
  3030. //
  3031. // A bios must return a package to a PRW method
  3032. //
  3033. KeBugCheckEx(
  3034. ACPI_BIOS_ERROR,
  3035. ACPI_EXPECTED_PACKAGE,
  3036. (ULONG_PTR) deviceExtension,
  3037. (ULONG_PTR) BuildRequest->CurrentObject,
  3038. result->dwDataType
  3039. );
  3040. goto ACPIBuildProcessDevicePhasePr2Exit;
  3041. }
  3042. //
  3043. // Process the package
  3044. //
  3045. status = ACPIBuildDevicePowerNodes(
  3046. deviceExtension,
  3047. BuildRequest->CurrentObject,
  3048. result,
  3049. PowerDeviceD2
  3050. );
  3051. //
  3052. // Do not leave object lying around without having freed them first
  3053. //
  3054. AMLIFreeDataBuffs( result, 1 );
  3055. ACPIBuildProcessDevicePhasePr2Exit:
  3056. //
  3057. // If the device is not physically present, then we cannot run the _CRS and
  3058. // _PSC. If the device is not present, the we cannot run those two methods,
  3059. // but we can fake it..
  3060. //
  3061. if (deviceExtension->Flags & DEV_TYPE_NOT_PRESENT) {
  3062. BuildRequest->CurrentObject = NULL;
  3063. BuildRequest->NextWorkDone = (WORK_DONE_PSC + 1);
  3064. } else {
  3065. //
  3066. // The next step is to run the _PSC
  3067. //
  3068. BuildRequest->NextWorkDone = WORK_DONE_PSC;
  3069. }
  3070. ACPIDevPrint( (
  3071. ACPI_PRINT_LOADING,
  3072. deviceExtension,
  3073. "ACPIBuildProcessDevicePhasePr2: Status = %08lx\n",
  3074. status
  3075. ) );
  3076. //
  3077. // We won't actually need to call the interpreter, but we will call
  3078. // the generic callback so that we don't have to duplicate code
  3079. //
  3080. ACPIBuildCompleteMustSucceed(
  3081. NULL,
  3082. status,
  3083. NULL,
  3084. BuildRequest
  3085. );
  3086. //
  3087. // Done
  3088. //
  3089. return status;
  3090. }
  3091. NTSTATUS
  3092. ACPIBuildProcessDevicePhasePrw(
  3093. IN PACPI_BUILD_REQUEST BuildRequest
  3094. )
  3095. /*++
  3096. This routine is called by the interpreter once it has evaluate the _PRW
  3097. method. This routine then determines the current power state of the
  3098. device
  3099. Path: PhasePRW ---> PhasePR0
  3100. Arguments:
  3101. BuildRequest - The request that we will try to fill
  3102. Return Value:
  3103. NTSTATUS
  3104. --*/
  3105. {
  3106. BOOLEAN ignorePrw = FALSE;
  3107. NTSTATUS status = STATUS_SUCCESS;
  3108. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  3109. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  3110. POBJDATA stateObject = NULL;
  3111. POBJDATA pinObject = NULL;
  3112. ULONG gpeRegister;
  3113. ULONG gpeMask;
  3114. //
  3115. // The next stage is Phase12
  3116. //
  3117. BuildRequest->NextWorkDone = WORK_DONE_PR0;
  3118. //
  3119. // Get the appropriate _PSx object to go with this object
  3120. //
  3121. deviceExtension->PowerInfo.PowerObject[PowerDeviceUnspecified] =
  3122. ACPIAmliGetNamedChild(
  3123. deviceExtension->AcpiObject,
  3124. PACKED_PSW
  3125. );
  3126. //
  3127. // Did we have an object to run?
  3128. //
  3129. if (BuildRequest->CurrentObject == NULL) {
  3130. //
  3131. // No? Then there is no work for us to do here
  3132. //
  3133. goto ACPIBuildProcessDevicePhasePrwExit;
  3134. }
  3135. //
  3136. // Should we ignore the _PRW for this device?
  3137. //
  3138. if ( (AcpiOverrideAttributes & ACPI_OVERRIDE_OPTIONAL_WAKE) &&
  3139. !(deviceExtension->Flags & DEV_CAP_NO_DISABLE_WAKE) ) {
  3140. ignorePrw = TRUE;
  3141. }
  3142. //
  3143. // We are expecting a package
  3144. //
  3145. if (result->dwDataType != OBJTYPE_PKGDATA) {
  3146. //
  3147. // A bios must return a package to a PRW method
  3148. //
  3149. KeBugCheckEx(
  3150. ACPI_BIOS_ERROR,
  3151. ACPI_EXPECTED_PACKAGE,
  3152. (ULONG_PTR) deviceExtension,
  3153. (ULONG_PTR) BuildRequest->CurrentObject,
  3154. result->dwDataType
  3155. );
  3156. }
  3157. //
  3158. // Process the package
  3159. //
  3160. status = ACPIBuildDevicePowerNodes(
  3161. deviceExtension,
  3162. BuildRequest->CurrentObject,
  3163. result,
  3164. PowerDeviceUnspecified
  3165. );
  3166. //
  3167. // Hold the power lock for the following
  3168. //
  3169. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  3170. //
  3171. // Since this was a _PRW object, then we want to store a bit more information
  3172. // about the wake capabilities
  3173. //
  3174. //
  3175. // Set the GPE pin which will be used to wake the system
  3176. //
  3177. pinObject = &( ( (PACKAGEOBJ *) result->pbDataBuff)->adata[0]);
  3178. if (pinObject->dwDataType != OBJTYPE_INTDATA) {
  3179. KeBugCheckEx(
  3180. ACPI_BIOS_ERROR,
  3181. ACPI_PRW_PACKAGE_EXPECTED_INTEGER,
  3182. (ULONG_PTR) deviceExtension,
  3183. (ULONG_PTR) BuildRequest->CurrentObject,
  3184. pinObject->dwDataType
  3185. );
  3186. }
  3187. //
  3188. // Set the system wake level for the device
  3189. //
  3190. stateObject = &( ( (PACKAGEOBJ *) result->pbDataBuff)->adata[1]);
  3191. if (stateObject->dwDataType != OBJTYPE_INTDATA) {
  3192. KeBugCheckEx(
  3193. ACPI_BIOS_ERROR,
  3194. ACPI_PRW_PACKAGE_EXPECTED_INTEGER,
  3195. (ULONG_PTR) deviceExtension,
  3196. (ULONG_PTR) BuildRequest->CurrentObject,
  3197. stateObject->dwDataType
  3198. );
  3199. }
  3200. //
  3201. // Set these bits only if we support sleep
  3202. //
  3203. if (!ignorePrw) {
  3204. //
  3205. // First, store the pin that we use as the wakeup signal
  3206. //
  3207. deviceExtension->PowerInfo.WakeBit = (ULONG)pinObject->uipDataValue;
  3208. //
  3209. // Next, store the system state that we can wake up from
  3210. //
  3211. deviceExtension->PowerInfo.SystemWakeLevel = ACPIDeviceMapSystemState(
  3212. stateObject->uipDataValue
  3213. );
  3214. //
  3215. // Finally, lets set the Wake capabilities flag
  3216. //
  3217. ACPIInternalUpdateFlags( &(deviceExtension->Flags), DEV_CAP_WAKE, FALSE );
  3218. }
  3219. //
  3220. // Done with the lock
  3221. //
  3222. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  3223. //
  3224. // Calculate the correct register and mask
  3225. //
  3226. gpeRegister = ( (UCHAR) (pinObject->uipDataValue) / 8);
  3227. gpeMask = 1 << ( (UCHAR) (pinObject->uipDataValue) % 8);
  3228. //
  3229. // We need access to the table lock for this
  3230. //
  3231. KeAcquireSpinLockAtDpcLevel( &GpeTableLock );
  3232. //
  3233. // Does this vector have a GPE?
  3234. //
  3235. if ( (GpeEnable[gpeRegister] & gpeMask) ) {
  3236. //
  3237. // If we got here, and we aren't marked as DEV_CAP_NO_DISABLE, then we
  3238. // should turn off the GPE. The easiest way to do this is to make sure
  3239. // that the GpeWakeHandler[] vector is masked with the appropriate
  3240. // bit
  3241. //
  3242. if (!(deviceExtension->Flags & DEV_CAP_NO_DISABLE_WAKE) ) {
  3243. //
  3244. // It has a gpe mask, so remember that there is a wake handler
  3245. // for it. This should prevent us from arming the GPE without
  3246. // a request for it
  3247. //
  3248. if (!(GpeSpecialHandler[gpeRegister] & gpeMask) ) {
  3249. GpeWakeHandler[gpeRegister] |= gpeMask;
  3250. }
  3251. } else {
  3252. //
  3253. // If we got here, then we should remember that we can never
  3254. // consider this pin as *just* a wake handler
  3255. //
  3256. GpeSpecialHandler[gpeRegister] |= gpeMask;
  3257. //
  3258. // Make sure that the pin isn't set as a wake handler
  3259. //
  3260. if (GpeWakeHandler[gpeRegister] & gpeMask) {
  3261. //
  3262. // Clear the pin from the wake handler mask
  3263. //
  3264. GpeWakeHandler[gpeRegister] &= ~gpeMask;
  3265. }
  3266. }
  3267. }
  3268. //
  3269. // Done with the table lock
  3270. //
  3271. KeReleaseSpinLockFromDpcLevel( &GpeTableLock );
  3272. //
  3273. // Do not leave object lying around without having freed them first
  3274. //
  3275. AMLIFreeDataBuffs( result, 1 );
  3276. //
  3277. // Finally, if there is a _PSW object, make sure that we run it to disable
  3278. // that capability --- this way we resume from a known state
  3279. //
  3280. if (deviceExtension->PowerInfo.PowerObject[PowerDeviceUnspecified]) {
  3281. OBJDATA argData;
  3282. //
  3283. // Setup the parameters
  3284. //
  3285. RtlZeroMemory( &argData, sizeof(OBJDATA) );
  3286. argData.dwDataType = OBJTYPE_INTDATA;
  3287. argData.uipDataValue = 0;
  3288. //
  3289. // Run the method. Note that we don't specify a callback because we
  3290. // don't actually care when it completes
  3291. //
  3292. AMLIAsyncEvalObject(
  3293. deviceExtension->PowerInfo.PowerObject[PowerDeviceUnspecified],
  3294. NULL,
  3295. 1,
  3296. &argData,
  3297. NULL,
  3298. NULL
  3299. );
  3300. }
  3301. ACPIBuildProcessDevicePhasePrwExit:
  3302. ACPIDevPrint( (
  3303. ACPI_PRINT_LOADING,
  3304. deviceExtension,
  3305. "ACPIBuildProcessDevicePhasePrw: Status = %08lx\n",
  3306. status
  3307. ) );
  3308. //
  3309. // We won't actually need to call the interpreter, but we will call
  3310. // the generic callback so that we don't have to duplicate code
  3311. //
  3312. ACPIBuildCompleteMustSucceed(
  3313. NULL,
  3314. status,
  3315. NULL,
  3316. BuildRequest
  3317. );
  3318. //
  3319. // Done
  3320. //
  3321. return status;
  3322. }
  3323. NTSTATUS
  3324. ACPIBuildProcessDevicePhasePsc(
  3325. IN PACPI_BUILD_REQUEST BuildRequest
  3326. )
  3327. /*++
  3328. Routine Description:
  3329. This routine is called by the interpreter once it has evaluate the _PSC
  3330. method. This routine then determines the current power state of the
  3331. device
  3332. Path: PhasePsc ---> COMPLETE
  3333. Arguments:
  3334. BuildRequest - The request that we will try to fill
  3335. Return Value:
  3336. NTSTATUS
  3337. --*/
  3338. {
  3339. DEVICE_POWER_STATE i;
  3340. NTSTATUS status = STATUS_SUCCESS;
  3341. PACPI_DEVICE_POWER_NODE deviceNode;
  3342. PACPI_POWER_INFO powerInfo;
  3343. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  3344. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  3345. SYSTEM_POWER_STATE matrixIndex = PowerSystemSleeping1;
  3346. //
  3347. // The next stage is Complete
  3348. //
  3349. BuildRequest->NextWorkDone = WORK_DONE_COMPLETE;
  3350. //
  3351. // We will use the power information structure a lot
  3352. //
  3353. powerInfo = &(deviceExtension->PowerInfo);
  3354. //
  3355. // Since we didn't get a change to look for the _PS3 object earlier,
  3356. // lets find it now. Note, that we cannot use the PS2 object if we don't
  3357. // find the PS3 object.
  3358. //
  3359. powerInfo->PowerObject[PowerDeviceD3] =
  3360. ACPIAmliGetNamedChild(
  3361. deviceExtension->AcpiObject,
  3362. PACKED_PS3
  3363. );
  3364. //
  3365. // We must be holding a spinlock for the following
  3366. //
  3367. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  3368. //
  3369. // For each S state, walk PR0 to PR2 until you find a resource that
  3370. // cannot be ON in S state. The next lighter D state is then the lightest
  3371. // D state for the given S state.
  3372. //
  3373. for ( ; matrixIndex <= PowerSystemHibernate ; matrixIndex++ ) {
  3374. //
  3375. // Loop on all members of the PowerNode
  3376. //
  3377. for (i = PowerDeviceD0; i <= PowerDeviceD2; i++ ) {
  3378. //
  3379. // Are there any resources to look at?
  3380. //
  3381. deviceNode = powerInfo->PowerNode[i];
  3382. if (deviceNode == NULL) {
  3383. continue;
  3384. }
  3385. while (deviceNode != NULL &&
  3386. deviceNode->SystemState >= matrixIndex) {
  3387. deviceNode = deviceNode->Next;
  3388. }
  3389. //
  3390. // If we have had a device node, but don't have now, that means
  3391. // that we found a D level that is compliant for this S-state
  3392. //
  3393. if (deviceNode == NULL) {
  3394. ACPIDevPrint( (
  3395. ACPI_PRINT_LOADING,
  3396. deviceExtension,
  3397. "ACPIBuildDeviceProcessPhasePsc: D%x <-> S%x\n",
  3398. (i - PowerDeviceD0),
  3399. matrixIndex - PowerSystemWorking
  3400. ) );
  3401. //
  3402. // This device can be in Di state while in SmatrixIndex state
  3403. //
  3404. powerInfo->DevicePowerMatrix[matrixIndex] = i;
  3405. break;
  3406. }
  3407. } // for (i = PowerDeviceD0 ...
  3408. } // for ( ; matrixIndex ...
  3409. //
  3410. // Now that we have built the matrix, we can figure out what D-level the
  3411. // device can support wake with.
  3412. //
  3413. powerInfo->DeviceWakeLevel =
  3414. powerInfo->DevicePowerMatrix[powerInfo->SystemWakeLevel];
  3415. //
  3416. // Done with the lock
  3417. //
  3418. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  3419. //
  3420. // At this point, we have to decide what to do based on the result of
  3421. // the _PSC. The first step is assume that the device is in the D0 state
  3422. //
  3423. i = PowerDeviceD0;
  3424. //
  3425. // We will override the above if there is a bit that says that the device
  3426. // should start in the D3 state
  3427. //
  3428. if (deviceExtension->Flags & DEV_CAP_START_IN_D3) {
  3429. //
  3430. // Go directly to D3
  3431. //
  3432. i = PowerDeviceD3;
  3433. goto ACPIBuildProcessDevicePhasePscBuild;
  3434. }
  3435. //
  3436. // Did we have an object to run?
  3437. //
  3438. if (BuildRequest->CurrentObject == NULL) {
  3439. //
  3440. // No? Then there is no work for us to do here
  3441. //
  3442. goto ACPIBuildProcessDevicePhasePscBuild;
  3443. }
  3444. //
  3445. // If we didn't succeed the control method, assume that the device
  3446. // should be in the D0 state
  3447. //
  3448. if (!NT_SUCCESS(BuildRequest->Status)) {
  3449. goto ACPIBuildProcessDevicePhasePscBuild;
  3450. }
  3451. //
  3452. // Also, if we know that the device must always be in the D0 state, then
  3453. // we must ignore whatever the _PSC says
  3454. //
  3455. if (deviceExtension->Flags & DEV_CAP_ALWAYS_PS0) {
  3456. //
  3457. // Free the buffer
  3458. //
  3459. AMLIFreeDataBuffs( result, 1 );
  3460. deviceExtension->PowerInfo.PowerState = i;
  3461. goto ACPIBuildProcessDevicePhasePscBuild;
  3462. }
  3463. //
  3464. // Did the request what we expected?
  3465. //
  3466. if (result->dwDataType != OBJTYPE_INTDATA) {
  3467. //
  3468. // A bios must return an integer for a _PSC
  3469. //
  3470. KeBugCheckEx(
  3471. ACPI_BIOS_ERROR,
  3472. ACPI_EXPECTED_INTEGER,
  3473. (ULONG_PTR) deviceExtension,
  3474. (ULONG_PTR) BuildRequest->CurrentObject,
  3475. result->dwDataType
  3476. );
  3477. goto ACPIBuildProcessDevicePhasePscExit;
  3478. }
  3479. //
  3480. // Turn the power state into something that we can understand
  3481. //
  3482. i = ACPIDeviceMapPowerState( result->uipDataValue );
  3483. //
  3484. // No longer need the buffer
  3485. //
  3486. AMLIFreeDataBuffs( result, 1 );
  3487. ACPIBuildProcessDevicePhasePscBuild:
  3488. //
  3489. // Queue the request
  3490. //
  3491. status = ACPIDeviceInternalDelayedDeviceRequest(
  3492. deviceExtension,
  3493. i,
  3494. NULL,
  3495. NULL
  3496. );
  3497. ACPIBuildProcessDevicePhasePscExit:
  3498. ACPIDevPrint( (
  3499. ACPI_PRINT_LOADING,
  3500. deviceExtension,
  3501. "ACPIBuildProcessDevicePhasePsc: Status = %08lx\n",
  3502. status
  3503. ) );
  3504. //
  3505. // We won't actually need to call the interpreter, but we will call
  3506. // the generic callback so that we don't have to duplicate code
  3507. //
  3508. ACPIBuildCompleteGeneric(
  3509. NULL,
  3510. status,
  3511. NULL,
  3512. BuildRequest
  3513. );
  3514. //
  3515. // Done
  3516. //
  3517. return status;
  3518. }
  3519. NTSTATUS
  3520. ACPIBuildProcessDevicePhaseSta(
  3521. IN PACPI_BUILD_REQUEST BuildRequest
  3522. )
  3523. /*++
  3524. This routine is called by the interpreter once it has evaluate the _STA
  3525. method. This routine then determines the current power state of the
  3526. device
  3527. Path: PhaseSta -> PhaseEjd
  3528. Arguments:
  3529. BuildRequest - The request that we will try to fill
  3530. Return Value:
  3531. NTSTATUS
  3532. --*/
  3533. {
  3534. NTSTATUS status = STATUS_SUCCESS;
  3535. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  3536. //
  3537. // The next stage is to start running the _EJD
  3538. //
  3539. BuildRequest->NextWorkDone = WORK_DONE_EJD;
  3540. //
  3541. // What happened
  3542. ACPIDevPrint( (
  3543. ACPI_PRINT_LOADING,
  3544. deviceExtension,
  3545. "ACPIBuildProcessDevicePhaseSta: Status = %08lx\n",
  3546. status
  3547. ) );
  3548. //
  3549. // See if the device conforms to the ACPI specification for HIDs and UIDs
  3550. // We do this at this point because we now know wether or not the device
  3551. // is present or not and that is an important test because the OEM is
  3552. // allowed to have 2 devices with the same HID/UID as long as both aren't
  3553. // present at the same time.
  3554. //
  3555. ACPIDetectDuplicateHID(
  3556. deviceExtension
  3557. );
  3558. //
  3559. // We won't actually need to call the interpreter, but we will call
  3560. // the generic callback so that we don't have to duplicate code
  3561. //
  3562. ACPIBuildCompleteMustSucceed(
  3563. NULL,
  3564. status,
  3565. NULL,
  3566. BuildRequest
  3567. );
  3568. //
  3569. // Done
  3570. //
  3571. return status;
  3572. }
  3573. NTSTATUS
  3574. ACPIBuildProcessDevicePhaseUid(
  3575. IN PACPI_BUILD_REQUEST BuildRequest
  3576. )
  3577. /*++
  3578. Routine Description:
  3579. This routine is called by the interpreter once it has evaluate the _UID
  3580. method.
  3581. Path: PhaseUid --> PhaseHid
  3582. Arguments:
  3583. BuildRequest - The request that we will try to fill
  3584. Return Value:
  3585. NTSTATUS
  3586. --*/
  3587. {
  3588. NTSTATUS status = STATUS_SUCCESS;
  3589. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  3590. PNSOBJ nsObject;
  3591. //
  3592. // Remember that we have an UID
  3593. //
  3594. ACPIInternalUpdateFlags(
  3595. &(deviceExtension->Flags),
  3596. DEV_PROP_UID,
  3597. FALSE
  3598. );
  3599. //
  3600. // Lets see if there is a _HID to run
  3601. //
  3602. nsObject = ACPIAmliGetNamedChild(
  3603. deviceExtension->AcpiObject,
  3604. PACKED_HID
  3605. );
  3606. if (nsObject != NULL) {
  3607. //
  3608. // The next phase is to post process the _HID
  3609. //
  3610. BuildRequest->NextWorkDone = WORK_DONE_HID;
  3611. //
  3612. // Get the Device ID
  3613. //
  3614. status = ACPIGetDeviceIDAsync(
  3615. deviceExtension,
  3616. ACPIBuildCompleteMustSucceed,
  3617. BuildRequest,
  3618. &(deviceExtension->DeviceID),
  3619. NULL
  3620. );
  3621. } else {
  3622. //
  3623. // Not having an _HID is a fatal error
  3624. //
  3625. KeBugCheckEx(
  3626. ACPI_BIOS_ERROR,
  3627. ACPI_REQUIRED_METHOD_NOT_PRESENT,
  3628. (ULONG_PTR) deviceExtension,
  3629. PACKED_HID,
  3630. 0
  3631. );
  3632. }
  3633. //
  3634. // What happened
  3635. //
  3636. ACPIDevPrint( (
  3637. ACPI_PRINT_LOADING,
  3638. deviceExtension,
  3639. "ACPIBuildProcessDevicePhaseUid: Status = %08lx\n",
  3640. status
  3641. ) );
  3642. //
  3643. // Common code to handle the result of the 'Get' routine
  3644. //
  3645. if (status != STATUS_PENDING) {
  3646. ACPIBuildCompleteMustSucceed(
  3647. nsObject,
  3648. status,
  3649. NULL,
  3650. BuildRequest
  3651. );
  3652. } else {
  3653. status = STATUS_SUCCESS;
  3654. }
  3655. //
  3656. // Done
  3657. //
  3658. return status;
  3659. }
  3660. NTSTATUS
  3661. ACPIBuildProcessGenericComplete(
  3662. IN PACPI_BUILD_REQUEST BuildRequest
  3663. )
  3664. /*++
  3665. Routine Description:
  3666. This routine is called when we are done with the request
  3667. Arguments:
  3668. BuildRequest - The request that has just been completed
  3669. Return Value:
  3670. NTSTATUS
  3671. --*/
  3672. {
  3673. PACPI_BUILD_CALLBACK callBack = BuildRequest->CallBack;
  3674. //
  3675. // Invoke the callback, if there is any
  3676. //
  3677. if (callBack != NULL) {
  3678. (*callBack)(
  3679. BuildRequest->BuildContext,
  3680. BuildRequest->CallBackContext,
  3681. BuildRequest->Status
  3682. );
  3683. }
  3684. //
  3685. // Do we have to release a reference on this request?
  3686. //
  3687. if (BuildRequest->Flags & BUILD_REQUEST_RELEASE_REFERENCE) {
  3688. PDEVICE_EXTENSION deviceExtension;
  3689. LONG oldReferenceCount;
  3690. deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  3691. //
  3692. // We to have the device tree lock
  3693. //
  3694. KeAcquireSpinLockAtDpcLevel( &AcpiDeviceTreeLock );
  3695. //
  3696. // No longer need a reference to the device extension
  3697. //
  3698. InterlockedDecrement( &(deviceExtension->ReferenceCount) );
  3699. //
  3700. // Done with the device tree lock
  3701. //
  3702. KeReleaseSpinLockFromDpcLevel( &AcpiDeviceTreeLock );
  3703. }
  3704. //
  3705. // We need the spinlock for this
  3706. //
  3707. KeAcquireSpinLockAtDpcLevel( &AcpiBuildQueueLock );
  3708. //
  3709. // Remember that work was done --- this should be all that is required
  3710. // to have the currently running DPC process the next request
  3711. //
  3712. AcpiBuildWorkDone = TRUE;
  3713. //
  3714. // Remove the entry from the current list. We might not need to be
  3715. // hodling the lock to do this, but it doesn't pay to not do it while
  3716. // we can
  3717. //
  3718. RemoveEntryList( &(BuildRequest->ListEntry) );
  3719. //
  3720. // Done with the lock
  3721. //
  3722. KeReleaseSpinLockFromDpcLevel( &AcpiBuildQueueLock );
  3723. //
  3724. // We are done with the request memory
  3725. //
  3726. ExFreeToNPagedLookasideList(
  3727. &BuildRequestLookAsideList,
  3728. BuildRequest
  3729. );
  3730. //
  3731. // Done
  3732. //
  3733. return STATUS_SUCCESS;
  3734. }
  3735. NTSTATUS
  3736. ACPIBuildProcessGenericList(
  3737. IN PLIST_ENTRY ListEntry,
  3738. IN PACPI_BUILD_FUNCTION *DispatchTable
  3739. )
  3740. /*++
  3741. Routine Description:
  3742. This routine processes all the build requests through the various
  3743. phases required to build a complete device extension
  3744. Arguments:
  3745. None
  3746. Return Value:
  3747. NTSTATUS
  3748. --*/
  3749. {
  3750. BOOLEAN allWorkComplete = TRUE;
  3751. NTSTATUS status = STATUS_SUCCESS;
  3752. PACPI_BUILD_FUNCTION buildFunction = NULL;
  3753. PACPI_BUILD_REQUEST buildRequest;
  3754. PLIST_ENTRY currentEntry = ListEntry->Flink;
  3755. PLIST_ENTRY tempEntry;
  3756. ULONG workDone;
  3757. while (currentEntry != ListEntry) {
  3758. //
  3759. // Turn into a build request
  3760. //
  3761. buildRequest = CONTAINING_RECORD(
  3762. currentEntry,
  3763. ACPI_BUILD_REQUEST,
  3764. ListEntry
  3765. );
  3766. //
  3767. // Set the temp pointer to the next element. The reason that this
  3768. // gets done is because once we call the dispatch function, the
  3769. // current request can be completed (and thus freed), so we need
  3770. // to remember whom the next person to process is.
  3771. //
  3772. tempEntry = currentEntry->Flink;
  3773. //
  3774. // Check to see if we have any work to do on the request
  3775. //
  3776. workDone = InterlockedCompareExchange(
  3777. &(buildRequest->WorkDone),
  3778. WORK_DONE_PENDING,
  3779. WORK_DONE_PENDING
  3780. );
  3781. //
  3782. // Look at the dispatch table to see if there is a function to
  3783. // call
  3784. //
  3785. buildFunction = DispatchTable[ workDone ];
  3786. if (buildFunction != NULL) {
  3787. //
  3788. // Just to help us along, if we are going to the failure
  3789. // path, then we should not update the Current Work Done field.
  3790. // This gives us an easy means of find which step failed
  3791. //
  3792. if (workDone != WORK_DONE_FAILURE) {
  3793. //
  3794. // Mark the node as being in the state 'workDone'
  3795. //
  3796. buildRequest->CurrentWorkDone = workDone;
  3797. }
  3798. //
  3799. // Mark the request as pending
  3800. //
  3801. workDone = InterlockedCompareExchange(
  3802. &(buildRequest->WorkDone),
  3803. WORK_DONE_PENDING,
  3804. workDone
  3805. );
  3806. //
  3807. // Call the function
  3808. //
  3809. status = (buildFunction)( buildRequest );
  3810. } else {
  3811. //
  3812. // The work is not all complete, and we should look at the
  3813. // next element
  3814. //
  3815. allWorkComplete = FALSE;
  3816. currentEntry = tempEntry;
  3817. //
  3818. // Loop
  3819. //
  3820. continue;
  3821. }
  3822. //
  3823. // If we have completed the request, then we should look at the
  3824. // at the next request, otherwise, we need to look at the current
  3825. // request again
  3826. if ( workDone == WORK_DONE_COMPLETE || workDone == WORK_DONE_FAILURE) {
  3827. currentEntry = tempEntry;
  3828. }
  3829. } // while
  3830. //
  3831. // Have we completed all of our work?
  3832. //
  3833. return (allWorkComplete ? STATUS_SUCCESS : STATUS_PENDING );
  3834. }
  3835. NTSTATUS
  3836. ACPIBuildProcessorExtension(
  3837. IN PNSOBJ ProcessorObject,
  3838. IN PDEVICE_EXTENSION ParentExtension,
  3839. IN PDEVICE_EXTENSION *ResultExtension,
  3840. IN ULONG ProcessorIndex
  3841. )
  3842. /*++
  3843. Routine Description:
  3844. Since we leverage ACPIBuildDeviceExtension for the core of the processor
  3845. extension, we don't have much to do here. However, we are responsible
  3846. for making sure that we do tasks that don't require calling the interpreter,
  3847. and an id unique to the processor
  3848. N.B. This function is called with AcpiDeviceTreeLock being held
  3849. Arguments:
  3850. ProcessorObject - The object which represents the processor
  3851. ParentExtension - Who our parent is
  3852. ResultExtension - Where to store the extension that we build
  3853. ProcessorIndex - Where do we find the processor in the ProcessorList
  3854. Return Value:
  3855. NTSTATUS
  3856. --*/
  3857. {
  3858. NTSTATUS status;
  3859. PDEVICE_EXTENSION deviceExtension;
  3860. //
  3861. // If we did not get the correct ID out of the registry earlier, fail now.
  3862. //
  3863. if (AcpiProcessorString.Buffer == NULL) {
  3864. return(STATUS_OBJECT_NAME_NOT_FOUND);
  3865. }
  3866. //
  3867. // Build the extension
  3868. //
  3869. status = ACPIBuildDeviceExtension(
  3870. ProcessorObject,
  3871. ParentExtension,
  3872. ResultExtension
  3873. );
  3874. if (!NT_SUCCESS(status) || *ResultExtension == NULL) {
  3875. return status;
  3876. }
  3877. //
  3878. // Grab a pointer to the device extension for easy usage
  3879. //
  3880. deviceExtension = *ResultExtension;
  3881. //
  3882. // Make sure to remember that this is in fact a processor
  3883. //
  3884. ACPIInternalUpdateFlags(
  3885. &(deviceExtension->Flags),
  3886. (DEV_CAP_PROCESSOR | DEV_MASK_INTERNAL_DEVICE),
  3887. FALSE
  3888. );
  3889. //
  3890. // Remember the the Index of this processor object in the processor
  3891. // array table
  3892. //
  3893. deviceExtension->Processor.ProcessorIndex = ProcessorIndex;
  3894. //
  3895. // Allocate memory for the HID
  3896. //
  3897. deviceExtension->DeviceID = ExAllocatePoolWithTag(
  3898. NonPagedPool,
  3899. AcpiProcessorString.Length,
  3900. ACPI_STRING_POOLTAG
  3901. );
  3902. if (deviceExtension->DeviceID == NULL) {
  3903. ACPIDevPrint( (
  3904. ACPI_PRINT_CRITICAL,
  3905. deviceExtension,
  3906. "ACPIBuildProcessorExtension: failed to allocate %08 bytes\n",
  3907. AcpiProcessorString.Length
  3908. ) );
  3909. status = STATUS_INSUFFICIENT_RESOURCES;
  3910. goto ACPIBuildProcessorExtensionExit;
  3911. }
  3912. RtlCopyMemory(
  3913. deviceExtension->DeviceID,
  3914. AcpiProcessorString.Buffer,
  3915. AcpiProcessorString.Length
  3916. );
  3917. //
  3918. // Allocate memory for the CID
  3919. //
  3920. deviceExtension->Processor.CompatibleID = ExAllocatePoolWithTag(
  3921. NonPagedPool,
  3922. strlen(AcpiProcessorCompatId) + 1,
  3923. ACPI_STRING_POOLTAG
  3924. );
  3925. if (deviceExtension->Processor.CompatibleID == NULL) {
  3926. ACPIDevPrint( (
  3927. ACPI_PRINT_CRITICAL,
  3928. deviceExtension,
  3929. "ACPIBuildProcessorExtension: failed to allocate %08 bytes\n",
  3930. strlen(AcpiProcessorCompatId) + 1
  3931. ) );
  3932. status = STATUS_INSUFFICIENT_RESOURCES;
  3933. goto ACPIBuildProcessorExtensionExit;
  3934. }
  3935. RtlCopyMemory(
  3936. deviceExtension->Processor.CompatibleID,
  3937. AcpiProcessorCompatId,
  3938. strlen(AcpiProcessorCompatId) + 1
  3939. );
  3940. //
  3941. // Allocate memory for the UID
  3942. //
  3943. deviceExtension->InstanceID = ExAllocatePoolWithTag(
  3944. NonPagedPool,
  3945. 3,
  3946. ACPI_STRING_POOLTAG
  3947. );
  3948. if (deviceExtension->InstanceID == NULL) {
  3949. ACPIDevPrint( (
  3950. ACPI_PRINT_CRITICAL,
  3951. deviceExtension,
  3952. "ACPIBuildProcessorExtension: failed to allocate %08 bytes\n",
  3953. 3
  3954. ) );
  3955. status = STATUS_INSUFFICIENT_RESOURCES;
  3956. goto ACPIBuildProcessorExtensionExit;
  3957. }
  3958. sprintf(deviceExtension->InstanceID,"%2d", ProcessorIndex );
  3959. //
  3960. // Set the flags for the work that we have just done
  3961. //
  3962. ACPIInternalUpdateFlags(
  3963. &(deviceExtension->Flags),
  3964. (DEV_PROP_HID | DEV_PROP_FIXED_HID | DEV_PROP_FIXED_CID |
  3965. DEV_PROP_UID | DEV_PROP_FIXED_UID),
  3966. FALSE
  3967. );
  3968. ACPIBuildProcessorExtensionExit:
  3969. //
  3970. // Handle the case where we might have failed
  3971. //
  3972. if (!NT_SUCCESS(status)) {
  3973. ACPIDevPrint( (
  3974. ACPI_PRINT_FAILURE,
  3975. deviceExtension,
  3976. "ACPIBuildProcessorExtension: = %08lx\n",
  3977. status
  3978. ) );
  3979. if (deviceExtension->InstanceID != NULL) {
  3980. ACPIInternalUpdateFlags(
  3981. &(deviceExtension->Flags),
  3982. (DEV_PROP_UID | DEV_PROP_FIXED_UID),
  3983. TRUE
  3984. );
  3985. ExFreePool( deviceExtension->InstanceID );
  3986. deviceExtension->InstanceID = NULL;
  3987. }
  3988. if (deviceExtension->DeviceID != NULL) {
  3989. ACPIInternalUpdateFlags(
  3990. &(deviceExtension->Flags),
  3991. (DEV_PROP_HID | DEV_PROP_FIXED_HID),
  3992. TRUE
  3993. );
  3994. ExFreePool( deviceExtension->DeviceID );
  3995. deviceExtension->DeviceID = NULL;
  3996. }
  3997. if (deviceExtension->Processor.CompatibleID != NULL) {
  3998. ACPIInternalUpdateFlags(
  3999. &(deviceExtension->Flags),
  4000. (DEV_PROP_FIXED_CID),
  4001. TRUE
  4002. );
  4003. ExFreePool( deviceExtension->Processor.CompatibleID );
  4004. deviceExtension->Processor.CompatibleID = NULL;
  4005. }
  4006. //
  4007. // Remember that we failed init
  4008. //
  4009. ACPIInternalUpdateFlags(
  4010. &(deviceExtension->Flags),
  4011. DEV_PROP_FAILED_INIT,
  4012. TRUE
  4013. );
  4014. } else {
  4015. ACPIDevPrint( (
  4016. ACPI_PRINT_LOADING,
  4017. deviceExtension,
  4018. "ACPIBuildProcessorExtension: = %08lx\n",
  4019. status
  4020. ) );
  4021. }
  4022. //
  4023. // Done
  4024. //
  4025. return status;
  4026. }
  4027. NTSTATUS
  4028. ACPIBuildProcessorRequest(
  4029. IN PDEVICE_EXTENSION ProcessorExtension,
  4030. IN PACPI_BUILD_CALLBACK CallBack,
  4031. IN PVOID CallBackContext,
  4032. IN BOOLEAN RunDPC
  4033. )
  4034. /*++
  4035. Routine Description:
  4036. This routine is called when a processor is ready to be filled in.
  4037. This routine creates a request which is enqueued. When the DPC is fired,
  4038. the request will be processed
  4039. Note: AcpiDeviceTreeLock must be held to call this function
  4040. Arguments:
  4041. ThermalExtension - The thermal zone to process
  4042. CallBack - The function to call when done
  4043. CallBackContext - The argument to pass to that function
  4044. RunDPC - Should we enqueue the DPC immediately (if it is not
  4045. running?)
  4046. Return Value:
  4047. NTSTATUS
  4048. --*/
  4049. {
  4050. #if 0
  4051. PACPI_BUILD_REQUEST buildRequest;
  4052. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  4053. //
  4054. // Allocate a buildRequest structure
  4055. //
  4056. buildRequest = ExAllocateFromNPagedLookasideList(
  4057. &BuildRequestLookAsideList
  4058. );
  4059. if (buildRequest == NULL) {
  4060. return STATUS_INSUFFICIENT_RESOURCES;
  4061. }
  4062. //
  4063. // If the current reference is 0, that means that someone else beat
  4064. // use to the device extension that that we *CANNOT* touch it
  4065. //
  4066. if (ProcessorExtension->ReferenceCount == 0) {
  4067. ExFreeToNPagedLookasideList(
  4068. &BuildRequestLookAsideList,
  4069. buildRequest
  4070. );
  4071. return STATUS_DEVICE_REMOVED;
  4072. } else {
  4073. InterlockedIncrement( &(ProcessorExtension->ReferenceCount) );
  4074. }
  4075. //
  4076. // Fill in the structure
  4077. //
  4078. RtlZeroMemory( buildRequest, sizeof(ACPI_BUILD_REQUEST) );
  4079. buildRequest->Signature = ACPI_SIGNATURE;
  4080. buildRequest->TargetListEntry = &AcpiBuildDeviceList;
  4081. buildRequest->WorkDone = WORK_DONE_STEP_0;
  4082. buildRequest->Status = STATUS_SUCCESS;
  4083. buildRequest->CallBack = CallBack;
  4084. buildRequest->CallBackContext = CallBackContext;
  4085. buildRequest->BuildContext = ProcessorExtension;
  4086. buildRequest->Flags = BUILD_REQUEST_VALID_TARGET |
  4087. BUILD_REQUEST_RELEASE_REFERENCE;
  4088. //
  4089. // At this point, we need the spinlock
  4090. //
  4091. KeAcquireSpinLockAtDpcLevel( &AcpiBuildQueueLock );
  4092. //
  4093. // Add this to the list
  4094. //
  4095. InsertTailList(
  4096. &AcpiBuildQueueList,
  4097. &(buildRequest->ListEntry)
  4098. );
  4099. //
  4100. // Do we need to queue up the DPC?
  4101. //
  4102. if (RunDPC && !AcpiBuildDpcRunning) {
  4103. KeInsertQueueDpc( &AcpiBuildDpc, 0, 0 );
  4104. }
  4105. //
  4106. // Done with the lock
  4107. //
  4108. KeReleaseSpinLockFromDpcLevel( &AcpiBuildQueueLock );
  4109. #endif
  4110. //
  4111. // Done
  4112. //
  4113. return STATUS_PENDING;
  4114. }
  4115. NTSTATUS
  4116. ACPIBuildProcessPowerResourceFailure(
  4117. IN PACPI_BUILD_REQUEST BuildRequest
  4118. )
  4119. /*++
  4120. Routine Description:
  4121. This routine is run when we detect a failure in the Power Resource
  4122. initialization code path
  4123. Arguments:
  4124. BuildRequest - The request that we have just failed
  4125. Return Value:
  4126. NTSTATUS
  4127. --*/
  4128. {
  4129. NTSTATUS status = BuildRequest->Status;
  4130. PACPI_POWER_DEVICE_NODE powerNode = (PACPI_POWER_DEVICE_NODE) BuildRequest->BuildContext;
  4131. //
  4132. // Make sure that the node is marked as not being present and not having
  4133. // been initialized
  4134. //
  4135. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  4136. ACPIInternalUpdateFlags(
  4137. &(powerNode->Flags),
  4138. (DEVICE_NODE_INITIALIZED | DEVICE_NODE_PRESENT),
  4139. TRUE
  4140. );
  4141. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  4142. //
  4143. // call the generic completion handler
  4144. //
  4145. status = ACPIBuildProcessGenericComplete( BuildRequest );
  4146. //
  4147. // Done
  4148. //
  4149. return status;
  4150. }
  4151. NTSTATUS
  4152. ACPIBuildProcessPowerResourcePhase0(
  4153. IN PACPI_BUILD_REQUEST BuildRequest
  4154. )
  4155. /*++
  4156. Routine Description:
  4157. This routine finds the pointers to the _ON, _OFF, and _STA objects for
  4158. the associated power nodes. If these pointers cannot be found, the system
  4159. will bugcheck.
  4160. Once the pointers are found, the _STA method is evaluated
  4161. Arguments:
  4162. BuildRequest - The request that we are processing
  4163. Return Value:
  4164. NTSTATUS
  4165. --*/
  4166. {
  4167. NTSTATUS status = STATUS_ACPI_FATAL;
  4168. PACPI_POWER_DEVICE_NODE powerNode = (PACPI_POWER_DEVICE_NODE) BuildRequest->BuildContext;
  4169. PNSOBJ nsObject;
  4170. POBJDATA resultData = &(BuildRequest->DeviceRequest.ResultData);
  4171. //
  4172. // The next state is Phase1
  4173. //
  4174. BuildRequest->NextWorkDone = WORK_DONE_STEP_1;
  4175. //
  4176. // Get the _OFF object
  4177. //
  4178. nsObject = ACPIAmliGetNamedChild(
  4179. powerNode->PowerObject,
  4180. PACKED_OFF
  4181. );
  4182. if (nsObject == NULL) {
  4183. KeBugCheckEx(
  4184. ACPI_BIOS_ERROR,
  4185. ACPI_POWER_NODE_REQUIRED_METHOD_NOT_PRESENT,
  4186. (ULONG_PTR) powerNode->PowerObject,
  4187. PACKED_OFF,
  4188. 0
  4189. );
  4190. goto ACPIBuildProcessPowerResourcePhase0Exit;
  4191. }
  4192. powerNode->PowerOffObject = nsObject;
  4193. //
  4194. // Get the _ON object
  4195. //
  4196. nsObject = ACPIAmliGetNamedChild(
  4197. powerNode->PowerObject,
  4198. PACKED_ON
  4199. );
  4200. if (nsObject == NULL) {
  4201. KeBugCheckEx(
  4202. ACPI_BIOS_ERROR,
  4203. ACPI_POWER_NODE_REQUIRED_METHOD_NOT_PRESENT,
  4204. (ULONG_PTR) powerNode->PowerObject,
  4205. PACKED_ON,
  4206. 0
  4207. );
  4208. goto ACPIBuildProcessPowerResourcePhase0Exit;
  4209. }
  4210. powerNode->PowerOnObject = nsObject;
  4211. //
  4212. // Get the _STA object
  4213. //
  4214. nsObject = ACPIAmliGetNamedChild(
  4215. powerNode->PowerObject,
  4216. PACKED_STA
  4217. );
  4218. if (nsObject == NULL) {
  4219. KeBugCheckEx(
  4220. ACPI_BIOS_ERROR,
  4221. ACPI_POWER_NODE_REQUIRED_METHOD_NOT_PRESENT,
  4222. (ULONG_PTR) powerNode->PowerObject,
  4223. PACKED_STA,
  4224. 0
  4225. );
  4226. goto ACPIBuildProcessPowerResourcePhase0Exit;
  4227. }
  4228. //
  4229. // Make sure that our result data structure is 'clean'
  4230. //
  4231. RtlZeroMemory( resultData, sizeof(OBJDATA) );
  4232. //
  4233. // Remember the current object that we will evalute
  4234. //
  4235. BuildRequest->CurrentObject = nsObject;
  4236. //
  4237. // Evalute the _STA object
  4238. //
  4239. status = AMLIAsyncEvalObject(
  4240. nsObject,
  4241. resultData,
  4242. 0,
  4243. NULL,
  4244. ACPIBuildCompleteGeneric,
  4245. BuildRequest
  4246. );
  4247. ACPIBuildProcessPowerResourcePhase0Exit:
  4248. //
  4249. // If we didn't get pending back, then call the method ourselves
  4250. //
  4251. if (status != STATUS_PENDING) {
  4252. ACPIBuildCompleteGeneric(
  4253. nsObject,
  4254. status,
  4255. resultData,
  4256. BuildRequest
  4257. );
  4258. }
  4259. //
  4260. // Done
  4261. //
  4262. return status;
  4263. }
  4264. NTSTATUS
  4265. ACPIBuildProcessPowerResourcePhase1(
  4266. IN PACPI_BUILD_REQUEST BuildRequest
  4267. )
  4268. /*++
  4269. Routine Description:
  4270. This routine is run after we have finished the _STA method
  4271. Arguments:
  4272. BuildRequest - The request that we are processing
  4273. Return Value:
  4274. NTSTATUS
  4275. --*/
  4276. {
  4277. NTSTATUS status = STATUS_SUCCESS;
  4278. PACPI_POWER_DEVICE_NODE powerNode = (PACPI_POWER_DEVICE_NODE) BuildRequest->BuildContext;
  4279. POBJDATA result = &(BuildRequest->DeviceRequest.ResultData);
  4280. //
  4281. // The next stage is Complete
  4282. //
  4283. BuildRequest->NextWorkDone = WORK_DONE_COMPLETE;
  4284. //
  4285. // Do we have an integer?
  4286. //
  4287. if (result->dwDataType != OBJTYPE_INTDATA) {
  4288. KeBugCheckEx(
  4289. ACPI_BIOS_ERROR,
  4290. ACPI_EXPECTED_INTEGER,
  4291. (ULONG_PTR) powerNode->PowerObject,
  4292. (ULONG_PTR) BuildRequest->CurrentObject,
  4293. result->dwDataType
  4294. );
  4295. status = STATUS_ACPI_FATAL;
  4296. goto ACPIBuildProcessPowerResourcePhase1Exit;
  4297. }
  4298. //
  4299. // We need the spinlock to do the following
  4300. //
  4301. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  4302. //
  4303. // Marked the node as having been initialized
  4304. //
  4305. ACPIInternalUpdateFlags(
  4306. &(powerNode->Flags),
  4307. DEVICE_NODE_INITIALIZED,
  4308. FALSE
  4309. );
  4310. //
  4311. // Check the device status?
  4312. //
  4313. ACPIInternalUpdateFlags(
  4314. &(powerNode->Flags),
  4315. DEVICE_NODE_PRESENT,
  4316. (BOOLEAN) ((result->uipDataValue & STA_STATUS_PRESENT) ? FALSE : TRUE)
  4317. );
  4318. //
  4319. // Done with the lock
  4320. //
  4321. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  4322. ACPIBuildProcessPowerResourcePhase1Exit:
  4323. //
  4324. // Do not leave objects lying around without having free'ed them first
  4325. //
  4326. AMLIFreeDataBuffs( result, 1 );
  4327. //
  4328. // We don't actually need to call the interpreter, but we will call
  4329. // the generic callback so that we don't have duplicate code
  4330. //
  4331. ACPIBuildCompleteGeneric(
  4332. NULL,
  4333. status,
  4334. NULL,
  4335. BuildRequest
  4336. );
  4337. //
  4338. // Done
  4339. //
  4340. return status;
  4341. }
  4342. NTSTATUS
  4343. ACPIBuildProcessQueueList(
  4344. VOID
  4345. )
  4346. /*++
  4347. Routine Description:
  4348. This routine looks at all the items on the Queue list and places them
  4349. on the appropriate build list
  4350. N.B: This routine is called with AcpiBuildQueueLock being owned
  4351. Arguments:
  4352. None
  4353. Return Value:
  4354. NTSTATUS
  4355. --*/
  4356. {
  4357. PACPI_BUILD_REQUEST buildRequest;
  4358. PLIST_ENTRY currentEntry = AcpiBuildQueueList.Flink;
  4359. //
  4360. // Look at all the items in the list
  4361. //
  4362. while (currentEntry != &AcpiBuildQueueList) {
  4363. //
  4364. // Crack the data structure
  4365. //
  4366. buildRequest = CONTAINING_RECORD(
  4367. currentEntry,
  4368. ACPI_BUILD_REQUEST,
  4369. ListEntry
  4370. );
  4371. //
  4372. // Remove this entry from the Queue List
  4373. //
  4374. RemoveEntryList( currentEntry );
  4375. //
  4376. // Move this entry onto its new list
  4377. //
  4378. InsertTailList( buildRequest->TargetListEntry, currentEntry );
  4379. //
  4380. // We no longer need the TargetListEntry, so lets zero it to make
  4381. // sure that we don't run into problems
  4382. //
  4383. buildRequest->Flags &= ~BUILD_REQUEST_VALID_TARGET;
  4384. buildRequest->TargetListEntry = NULL;
  4385. //
  4386. // Look at the head of the list again
  4387. //
  4388. currentEntry = AcpiBuildQueueList.Flink;
  4389. }
  4390. //
  4391. // Done
  4392. //
  4393. return STATUS_SUCCESS;
  4394. }
  4395. NTSTATUS
  4396. ACPIBuildProcessRunMethodPhaseCheckBridge(
  4397. IN PACPI_BUILD_REQUEST BuildRequest
  4398. )
  4399. /*++
  4400. Routine Description:
  4401. This routine determines if the current object is present or not
  4402. Arguments:
  4403. BuildRequest - The request that we are processing
  4404. Return Value:
  4405. NTSTATUS
  4406. --*/
  4407. {
  4408. NTSTATUS status = STATUS_SUCCESS;
  4409. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  4410. //
  4411. // Check the flags to see if we need to check the result of the device
  4412. // presence test
  4413. //
  4414. if (BuildRequest->RunRequest.Flags & RUN_REQUEST_CHECK_STATUS) {
  4415. //
  4416. // Is the device present?
  4417. //
  4418. if ( (deviceExtension->Flags & DEV_TYPE_NOT_PRESENT) ) {
  4419. BuildRequest->NextWorkDone = WORK_DONE_COMPLETE;
  4420. goto ACPIBuildProcessRunMethodPhaseCheckBridgeExit;
  4421. }
  4422. }
  4423. //
  4424. // The next state is Phase2
  4425. //
  4426. BuildRequest->NextWorkDone = WORK_DONE_STEP_2;
  4427. //
  4428. // Do we have to check the device status?
  4429. //
  4430. if (BuildRequest->RunRequest.Flags & RUN_REQUEST_STOP_AT_BRIDGES) {
  4431. //
  4432. // Get the device status
  4433. //
  4434. BuildRequest->Integer = 0;
  4435. status = IsPciBusAsync(
  4436. deviceExtension->AcpiObject,
  4437. ACPIBuildCompleteMustSucceed,
  4438. BuildRequest,
  4439. (BOOLEAN *) &(BuildRequest->Integer)
  4440. );
  4441. //
  4442. // What happened?
  4443. //
  4444. ACPIDevPrint( (
  4445. ACPI_PRINT_LOADING,
  4446. deviceExtension,
  4447. "ACPIBuildProcessRunMethodPhaseCheckBridge: Status = %08lx\n",
  4448. status
  4449. ) );
  4450. if (status == STATUS_PENDING) {
  4451. return status;
  4452. }
  4453. }
  4454. ACPIBuildProcessRunMethodPhaseCheckBridgeExit:
  4455. //
  4456. // Common code to handle the result of the 'Get' routine
  4457. //
  4458. ACPIBuildCompleteMustSucceed(
  4459. NULL,
  4460. status,
  4461. NULL,
  4462. BuildRequest
  4463. );
  4464. //
  4465. // Done
  4466. //
  4467. return status;
  4468. }
  4469. NTSTATUS
  4470. ACPIBuildProcessRunMethodPhaseCheckSta(
  4471. IN PACPI_BUILD_REQUEST BuildRequest
  4472. )
  4473. /*++
  4474. Routine Description:
  4475. This routine determines if the current object is present or not
  4476. Arguments:
  4477. BuildRequest - The request that we are processing
  4478. Return Value:
  4479. NTSTATUS
  4480. --*/
  4481. {
  4482. NTSTATUS status = STATUS_SUCCESS;
  4483. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  4484. //
  4485. // The next state is Phase1
  4486. //
  4487. BuildRequest->NextWorkDone = WORK_DONE_STEP_1;
  4488. //
  4489. // Is this a device with a 'fake' PDO?
  4490. //
  4491. if (deviceExtension->Flags & DEV_PROP_NO_OBJECT) {
  4492. BuildRequest->NextWorkDone = WORK_DONE_COMPLETE;
  4493. goto ACPIBuildProcessRunMethodPhaseCheckStaExit;
  4494. }
  4495. //
  4496. // Do we have to check the device status?
  4497. //
  4498. if (BuildRequest->RunRequest.Flags & RUN_REQUEST_CHECK_STATUS) {
  4499. //
  4500. // Get the device status
  4501. //
  4502. status = ACPIGetDevicePresenceAsync(
  4503. deviceExtension,
  4504. ACPIBuildCompleteMustSucceed,
  4505. BuildRequest,
  4506. (PVOID *) &(BuildRequest->Integer),
  4507. NULL
  4508. );
  4509. //
  4510. // What happened?
  4511. //
  4512. ACPIDevPrint( (
  4513. ACPI_PRINT_LOADING,
  4514. deviceExtension,
  4515. "ACPIBuildProcessRunMethodPhaseCheckSta: Status = %08lx\n",
  4516. status
  4517. ) );
  4518. if (status == STATUS_PENDING) {
  4519. return status;
  4520. }
  4521. }
  4522. ACPIBuildProcessRunMethodPhaseCheckStaExit:
  4523. //
  4524. // Common code to handle the result of the 'Get' routine
  4525. //
  4526. ACPIBuildCompleteMustSucceed(
  4527. NULL,
  4528. status,
  4529. NULL,
  4530. BuildRequest
  4531. );
  4532. //
  4533. // Done
  4534. //
  4535. return status;
  4536. }
  4537. NTSTATUS
  4538. ACPIBuildProcessRunMethodPhaseRecurse(
  4539. IN PACPI_BUILD_REQUEST BuildRequest
  4540. )
  4541. /*++
  4542. Routine Description:
  4543. This routine does the recursion
  4544. Arguments:
  4545. BuildRequest - The request that we are processing
  4546. Return Value:
  4547. NTSTATUS
  4548. --*/
  4549. {
  4550. EXTENSIONLIST_ENUMDATA eled ;
  4551. NTSTATUS status = STATUS_SUCCESS;
  4552. PDEVICE_EXTENSION childExtension;
  4553. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  4554. //
  4555. // We are done after this
  4556. //
  4557. BuildRequest->NextWorkDone = WORK_DONE_COMPLETE;
  4558. //
  4559. // Do we recurse or not?
  4560. //
  4561. if (BuildRequest->RunRequest.Flags & RUN_REQUEST_RECURSIVE) {
  4562. //
  4563. // Walk children
  4564. //
  4565. ACPIExtListSetupEnum(
  4566. &eled,
  4567. &(deviceExtension->ChildDeviceList),
  4568. &AcpiDeviceTreeLock,
  4569. SiblingDeviceList,
  4570. WALKSCHEME_HOLD_SPINLOCK
  4571. ) ;
  4572. for(childExtension = ACPIExtListStartEnum(&eled);
  4573. ACPIExtListTestElement(&eled, (BOOLEAN) NT_SUCCESS(status));
  4574. childExtension = ACPIExtListEnumNext(&eled)) {
  4575. //
  4576. // Make a request to run the control method on this child
  4577. //
  4578. status = ACPIBuildRunMethodRequest(
  4579. childExtension,
  4580. NULL,
  4581. NULL,
  4582. BuildRequest->RunRequest.ControlMethodName,
  4583. BuildRequest->RunRequest.Flags,
  4584. FALSE
  4585. );
  4586. }
  4587. }
  4588. //
  4589. // What happened
  4590. //
  4591. ACPIDevPrint( (
  4592. ACPI_PRINT_LOADING,
  4593. deviceExtension,
  4594. "ACPIBuildProcessRunMethodPhaseRecurse: Status = %08lx\n",
  4595. status
  4596. ) );
  4597. //
  4598. // Common code
  4599. //
  4600. ACPIBuildCompleteMustSucceed(
  4601. NULL,
  4602. status,
  4603. NULL,
  4604. BuildRequest
  4605. );
  4606. //
  4607. // Done
  4608. //
  4609. return status;
  4610. }
  4611. NTSTATUS
  4612. ACPIBuildProcessRunMethodPhaseRunMethod(
  4613. IN PACPI_BUILD_REQUEST BuildRequest
  4614. )
  4615. /*++
  4616. Routine Description:
  4617. This routine determines if there is a control method to run
  4618. Arguments:
  4619. BuildRequest - The request that we are processing
  4620. Return Value:
  4621. NTSTATUS
  4622. --*/
  4623. {
  4624. NTSTATUS status = STATUS_SUCCESS;
  4625. OBJDATA objData[2];
  4626. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  4627. PNSOBJ nsObj = NULL;
  4628. POBJDATA args = NULL;
  4629. ULONGLONG originalFlags;
  4630. ULONG numArgs = 0;
  4631. //
  4632. // Check the flags to see if we need to check the result of the device
  4633. // presence test
  4634. //
  4635. if (BuildRequest->RunRequest.Flags & RUN_REQUEST_STOP_AT_BRIDGES) {
  4636. //
  4637. // Is this a PCI-PCI bridge?
  4638. //
  4639. if (BuildRequest->Integer) {
  4640. ACPIDevPrint( (
  4641. ACPI_PRINT_LOADING,
  4642. deviceExtension,
  4643. "ACPIBuildProcessRunMethodPhaseRunMethod: Is PCI-PCI bridge\n",
  4644. status
  4645. ) );
  4646. BuildRequest->NextWorkDone = WORK_DONE_COMPLETE;
  4647. goto ACPIBuildProcessRunMethodPhaseRunMethodExit;
  4648. }
  4649. }
  4650. //
  4651. // From here, we need to go one more step
  4652. //
  4653. BuildRequest->NextWorkDone = WORK_DONE_STEP_3;
  4654. //
  4655. // If there an object present?
  4656. //
  4657. nsObj = ACPIAmliGetNamedChild(
  4658. deviceExtension->AcpiObject,
  4659. BuildRequest->RunRequest.ControlMethodName
  4660. );
  4661. if (nsObj == NULL) {
  4662. //
  4663. // There is no method to run. Lets skip to the next stage then
  4664. //
  4665. goto ACPIBuildProcessRunMethodPhaseRunMethodExit;
  4666. }
  4667. //
  4668. // Do we need to mark the node with the _INI flags?
  4669. //
  4670. if (BuildRequest->RunRequest.Flags & RUN_REQUEST_MARK_INI) {
  4671. //
  4672. // Attempt to set the flag so that we don't run the method twice
  4673. //
  4674. originalFlags = ACPIInternalUpdateFlags(
  4675. &(deviceExtension->Flags),
  4676. DEV_PROP_RAN_INI,
  4677. FALSE
  4678. );
  4679. if ( (originalFlags & DEV_PROP_RAN_INI) ) {
  4680. //
  4681. // If the flag was already set, then there is nothing for
  4682. // us to do here
  4683. //
  4684. goto ACPIBuildProcessRunMethodPhaseRunMethodExit;
  4685. }
  4686. } else if (BuildRequest->RunRequest.Flags & RUN_REQUEST_CHECK_WAKE_COUNT) {
  4687. //
  4688. // Do we need to check the Wake count?
  4689. //
  4690. if (deviceExtension->PowerInfo.WakeSupportCount == 0) {
  4691. //
  4692. // Nothing to do
  4693. //
  4694. goto ACPIBuildProcessRunMethodPhaseRunMethodExit;
  4695. }
  4696. //
  4697. // Setup the arguments that we will pass to the method
  4698. //
  4699. RtlZeroMemory( objData, sizeof(OBJDATA) );
  4700. objData[0].uipDataValue = DATAVALUE_ONE;
  4701. objData[0].dwDataType = OBJTYPE_INTDATA;
  4702. //
  4703. // Remember that we have 1 argument
  4704. //
  4705. args = &objData[0];
  4706. numArgs = 1;
  4707. } else if (BuildRequest->RunRequest.Flags & RUN_REQUEST_REG_METHOD_ON ||
  4708. BuildRequest->RunRequest.Flags & RUN_REQUEST_REG_METHOD_OFF) {
  4709. //
  4710. // First thing is to make sure that we will never recurse past a pci
  4711. // PCI-PCI bridge
  4712. //
  4713. BuildRequest->RunRequest.Flags |= RUN_REQUEST_STOP_AT_BRIDGES;
  4714. //
  4715. // Next is that we have to initialize the arguments that we will
  4716. // pass to the function. For historical reasons, we will only
  4717. // pass in a REGSPACE_PCIFCFG registration
  4718. //
  4719. RtlZeroMemory( objData, sizeof(objData) );
  4720. objData[0].uipDataValue = REGSPACE_PCICFG;
  4721. objData[0].dwDataType = OBJTYPE_INTDATA;
  4722. objData[1].dwDataType = OBJTYPE_INTDATA;
  4723. if (BuildRequest->RunRequest.Flags & RUN_REQUEST_REG_METHOD_ON) {
  4724. objData[1].uipDataValue = 1;
  4725. } else {
  4726. objData[1].uipDataValue = 0;
  4727. }
  4728. //
  4729. // Remember that we have two arguments
  4730. //
  4731. args = &objData[0];
  4732. numArgs = 2;
  4733. }
  4734. //
  4735. // Remember that we are running this control method
  4736. //
  4737. BuildRequest->CurrentObject = nsObj;
  4738. //
  4739. // Run the control method
  4740. //
  4741. status = AMLIAsyncEvalObject(
  4742. nsObj,
  4743. NULL,
  4744. numArgs,
  4745. args,
  4746. ACPIBuildCompleteMustSucceed,
  4747. BuildRequest
  4748. );
  4749. ACPIBuildProcessRunMethodPhaseRunMethodExit:
  4750. //
  4751. // What happened
  4752. //
  4753. ACPIDevPrint( (
  4754. ACPI_PRINT_LOADING,
  4755. deviceExtension,
  4756. "ACPIBuildProcessRunMethodPhaseRunMethod: Status = %08lx\n",
  4757. status
  4758. ) );
  4759. //
  4760. // Common code to handle the result of the 'Get' routine
  4761. //
  4762. if (status != STATUS_PENDING) {
  4763. ACPIBuildCompleteMustSucceed(
  4764. nsObj,
  4765. status,
  4766. NULL,
  4767. BuildRequest
  4768. );
  4769. } else {
  4770. status = STATUS_SUCCESS;
  4771. }
  4772. //
  4773. // Done
  4774. //
  4775. return status;
  4776. }
  4777. NTSTATUS
  4778. ACPIBuildProcessSynchronizationList(
  4779. IN PLIST_ENTRY ListEntry
  4780. )
  4781. /*++
  4782. Routine Description:
  4783. This routine looks at the elements in the synchronize list and
  4784. determines if the can be completed
  4785. Arguments:
  4786. None
  4787. Return Value:
  4788. NTSTATUS
  4789. --*/
  4790. {
  4791. BOOLEAN allWorkComplete = TRUE;
  4792. NTSTATUS status = STATUS_SUCCESS;
  4793. PACPI_BUILD_REQUEST buildRequest;
  4794. PDEVICE_EXTENSION deviceExtension;
  4795. PLIST_ENTRY currentEntry = ListEntry->Flink;
  4796. while (currentEntry != ListEntry) {
  4797. //
  4798. // Turn into a build request
  4799. //
  4800. buildRequest = CONTAINING_RECORD(
  4801. currentEntry,
  4802. ACPI_BUILD_REQUEST,
  4803. ListEntry
  4804. );
  4805. //
  4806. // Set the temp pointer to the next element
  4807. //
  4808. currentEntry = currentEntry->Flink;
  4809. //
  4810. // Is the list pointed by this entry empty?
  4811. //
  4812. if (!IsListEmpty( (buildRequest->SynchronizeRequest.SynchronizeListEntry) ) ) {
  4813. allWorkComplete = FALSE;
  4814. continue;
  4815. }
  4816. //
  4817. // Let the world know
  4818. //
  4819. deviceExtension = (PDEVICE_EXTENSION) buildRequest->BuildContext;
  4820. ACPIDevPrint( (
  4821. ACPI_PRINT_LOADING,
  4822. deviceExtension,
  4823. "ACPIBuildProcessSynchronizationList(%4s) = %08lx\n",
  4824. buildRequest->SynchronizeRequest.SynchronizeMethodNameAsUchar,
  4825. status
  4826. ) );
  4827. //
  4828. // Complete the request
  4829. //
  4830. ACPIBuildProcessGenericComplete( buildRequest );
  4831. } // while
  4832. //
  4833. // Have we completed all of our work?
  4834. //
  4835. return (allWorkComplete ? STATUS_SUCCESS : STATUS_PENDING );
  4836. }
  4837. NTSTATUS
  4838. ACPIBuildProcessThermalZonePhase0(
  4839. IN PACPI_BUILD_REQUEST BuildRequest
  4840. )
  4841. /*++
  4842. Routine Description:
  4843. This routine is run after we have build the thermal zone extension
  4844. Arguments:
  4845. BuildRequest - The request that we are processing
  4846. Return Value:
  4847. NTSTATUS
  4848. --*/
  4849. {
  4850. NTSTATUS status = STATUS_SUCCESS;
  4851. PDEVICE_EXTENSION thermalExtension = (PDEVICE_EXTENSION) BuildRequest->BuildContext;
  4852. PTHRM_INFO info;
  4853. //
  4854. // Remember to set a pointer to the next state
  4855. //
  4856. BuildRequest->NextWorkDone = WORK_DONE_COMPLETE;
  4857. //
  4858. // We need a pointer to the thermal info
  4859. //
  4860. info = thermalExtension->Thermal.Info;
  4861. //
  4862. // We need the _TMP object
  4863. //
  4864. info->TempMethod = ACPIAmliGetNamedChild(
  4865. thermalExtension->AcpiObject,
  4866. PACKED_TMP
  4867. );
  4868. if (info->TempMethod == NULL) {
  4869. //
  4870. // If we don't have one... bugcheck
  4871. //
  4872. KeBugCheckEx(
  4873. ACPI_BIOS_ERROR,
  4874. ACPI_REQUIRED_METHOD_NOT_PRESENT,
  4875. (ULONG_PTR) thermalExtension,
  4876. PACKED_TMP,
  4877. 0
  4878. );
  4879. goto ACPIBuildProcessThermalZonePhase0Exit;
  4880. }
  4881. ACPIBuildProcessThermalZonePhase0Exit:
  4882. ACPIDevPrint( (
  4883. ACPI_PRINT_LOADING,
  4884. thermalExtension,
  4885. "ACPIBuildProcessThermalZonePhase0: Status = %08lx\n",
  4886. status
  4887. ) );
  4888. //
  4889. // We won't actually need to call the interpreter, but we will call
  4890. // the generic callback so that we don't have to duplicate code
  4891. //
  4892. ACPIBuildCompleteGeneric(
  4893. NULL,
  4894. status,
  4895. NULL,
  4896. BuildRequest
  4897. );
  4898. //
  4899. // Done
  4900. //
  4901. return status;
  4902. }
  4903. NTSTATUS
  4904. ACPIBuildDockExtension(
  4905. IN PNSOBJ CurrentObject,
  4906. IN PDEVICE_EXTENSION ParentDeviceExtension
  4907. )
  4908. /*++
  4909. Routine Description:
  4910. This routine creates a device for CurrentObject, if it is an NameSpace
  4911. object that ACPI might be interested as, and links into the tree of
  4912. ParentDeviceExtension
  4913. Argument Description:
  4914. CurrentObject - The object that we are current interested in
  4915. ParentDeviceExtension - Where to link the deviceExtension into
  4916. Return Value:
  4917. NTSTATUS
  4918. --*/
  4919. {
  4920. NTSTATUS status = STATUS_NO_SUCH_DEVICE;
  4921. PDEVICE_EXTENSION deviceExtension = NULL;
  4922. PUCHAR deviceID = NULL;
  4923. PUCHAR instanceID = NULL;
  4924. //
  4925. // Build the device extension
  4926. //
  4927. status = ACPIBuildDeviceExtension(
  4928. NULL,
  4929. ParentDeviceExtension,
  4930. &deviceExtension
  4931. );
  4932. if (!NT_SUCCESS(status) || deviceExtension == NULL) {
  4933. return status;
  4934. }
  4935. //
  4936. // At this point, we care about this device, so we will allocate some
  4937. // memory for the deviceID, which we will build this off the ACPI node
  4938. // name.
  4939. //
  4940. deviceID = ExAllocatePoolWithTag(
  4941. NonPagedPool,
  4942. 21,
  4943. ACPI_STRING_POOLTAG
  4944. );
  4945. if (deviceID == NULL) {
  4946. ACPIPrint( (
  4947. ACPI_PRINT_FAILURE,
  4948. "ACPIBuildDockExtension: Cannot allocate 0x%04x "
  4949. "bytes for deviceID\n",
  4950. 21
  4951. ) );
  4952. status = STATUS_INSUFFICIENT_RESOURCES;
  4953. goto ACPIBuildDockExtensionExit;
  4954. }
  4955. //
  4956. // The format for a deviceID is
  4957. // ACPI\DockDevice
  4958. // the ACPI node name will form the instance ID
  4959. strcpy( deviceID, "ACPI\\DockDevice") ;
  4960. deviceExtension->DeviceID = deviceID;
  4961. //
  4962. // Form the instance ID
  4963. //
  4964. status = ACPIAmliBuildObjectPathname(CurrentObject, &instanceID) ;
  4965. if (!NT_SUCCESS(status)) {
  4966. ACPIDevPrint( (
  4967. ACPI_PRINT_FAILURE,
  4968. deviceExtension,
  4969. "ACPIBuildDockExtension: Path = %08lx\n",
  4970. status
  4971. ) );
  4972. goto ACPIBuildDockExtensionExit;
  4973. }
  4974. deviceExtension->InstanceID = instanceID;
  4975. //
  4976. // And make sure we are pointed to the correct docking node
  4977. //
  4978. deviceExtension->Dock.CorrospondingAcpiDevice =
  4979. (PDEVICE_EXTENSION) CurrentObject->Context ;
  4980. //
  4981. // By default, we update profiles only on eject
  4982. //
  4983. deviceExtension->Dock.ProfileDepartureStyle = PDS_UPDATE_ON_EJECT;
  4984. //
  4985. // If we are booting, or the device has just come back we assume _DCK has
  4986. // already been ran if we find the device with _STA == present. We will
  4987. // only override this assumption if Notify(Dock, 0) is called.
  4988. //
  4989. deviceExtension->Dock.IsolationState = IS_UNKNOWN;
  4990. //
  4991. // Make sure that we remember that we are a dock
  4992. //
  4993. ACPIInternalUpdateFlags(
  4994. &(deviceExtension->Flags),
  4995. DEV_TYPE_NOT_FOUND |
  4996. DEV_PROP_UID | DEV_PROP_FIXED_UID |
  4997. DEV_PROP_HID | DEV_PROP_FIXED_HID |
  4998. DEV_PROP_NO_OBJECT | DEV_PROP_DOCK | DEV_CAP_RAW,
  4999. FALSE
  5000. );
  5001. ACPIBuildDockExtensionExit:
  5002. //
  5003. // Free any resources that we don't need because we failed. Note
  5004. // that the way this is structured, we won't have to acquire a spinlock
  5005. // since by the time we attempt to link in the tree, we cannot fail
  5006. //
  5007. if (!NT_SUCCESS(status)) {
  5008. ACPIDevPrint( (
  5009. ACPI_PRINT_FAILURE,
  5010. deviceExtension,
  5011. "ACPIBuildDockExtension: = %08lx\n",
  5012. status
  5013. ) );
  5014. if (instanceID != NULL ) {
  5015. ACPIInternalUpdateFlags(
  5016. &(deviceExtension->Flags),
  5017. (DEV_PROP_HID | DEV_PROP_FIXED_HID),
  5018. TRUE
  5019. );
  5020. ExFreePool( instanceID );
  5021. deviceExtension->InstanceID = NULL;
  5022. }
  5023. if (deviceID != NULL) {
  5024. ACPIInternalUpdateFlags(
  5025. &(deviceExtension->Flags),
  5026. (DEV_PROP_HID | DEV_PROP_FIXED_HID),
  5027. TRUE
  5028. );
  5029. ExFreePool( deviceID );
  5030. deviceExtension->DeviceID = NULL;
  5031. }
  5032. //
  5033. // Remember that we failed init
  5034. //
  5035. ACPIInternalUpdateFlags(
  5036. &(deviceExtension->Flags),
  5037. DEV_PROP_FAILED_INIT,
  5038. TRUE
  5039. );
  5040. } else {
  5041. ACPIDevPrint( (
  5042. ACPI_PRINT_LOADING,
  5043. deviceExtension,
  5044. "ACPIBuildDockExtension: = %08lx\n",
  5045. status
  5046. ) );
  5047. }
  5048. //
  5049. // Done
  5050. //
  5051. return status;
  5052. }
  5053. NTSTATUS
  5054. ACPIBuildRegRequest(
  5055. IN PDEVICE_OBJECT DeviceObject,
  5056. IN PIRP Irp,
  5057. IN PACPI_BUILD_CALLBACK CallBack
  5058. )
  5059. /*++
  5060. Routine Description:
  5061. This routine is called when a device is turned on, and we need to tell
  5062. the AML that the regionspace behind it are available
  5063. Arguments:
  5064. DeviceObject - The target device object
  5065. Irp - The target irp
  5066. CallBack - The routine to call when done
  5067. Return Value:
  5068. NTSTATUS
  5069. --*/
  5070. {
  5071. DEVICE_POWER_STATE deviceState;
  5072. KIRQL oldIrql;
  5073. NTSTATUS status;
  5074. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  5075. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
  5076. ULONG methodFlags;
  5077. //
  5078. // Grab the requested device state and power action
  5079. //
  5080. deviceState = irpStack->Parameters.Power.State.DeviceState;
  5081. //
  5082. // Let the user know what is going on
  5083. //
  5084. ACPIDevPrint( (
  5085. ACPI_PRINT_POWER,
  5086. deviceExtension,
  5087. "(0x%08lx): ACPIBuildRegRequest - Handle D%d\n",
  5088. Irp,
  5089. (deviceState - PowerDeviceD0)
  5090. ) );
  5091. //
  5092. // Do we need to mark the irp as pending?
  5093. //
  5094. if (Irp->PendingReturned) {
  5095. IoMarkIrpPending( Irp );
  5096. }
  5097. //
  5098. // Lets us look at the current status code for the request. On error,
  5099. // we will just call the completion right now, and it is responsible
  5100. // for doing the 'right' thing
  5101. //
  5102. status = Irp->IoStatus.Status;
  5103. if (!NT_SUCCESS(status)) {
  5104. //
  5105. // Call the completion routine and return
  5106. //
  5107. if (*CallBack != NULL ) {
  5108. (*CallBack)(
  5109. deviceExtension,
  5110. Irp,
  5111. status
  5112. );
  5113. }
  5114. return status;
  5115. }
  5116. //
  5117. // Calculate the flags that we will use
  5118. //
  5119. methodFlags = (RUN_REQUEST_CHECK_STATUS | RUN_REQUEST_RECURSIVE);
  5120. if (deviceState == PowerDeviceD0) {
  5121. methodFlags |= RUN_REQUEST_REG_METHOD_ON;
  5122. } else {
  5123. methodFlags |= RUN_REQUEST_REG_METHOD_OFF;
  5124. }
  5125. //
  5126. // Queue the request --- this function will always return
  5127. // MORE_PROCESSING_REQUIRED instead of PENDING, so we don't have
  5128. // to mess with it
  5129. //
  5130. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  5131. status = ACPIBuildRunMethodRequest(
  5132. deviceExtension,
  5133. CallBack,
  5134. (PVOID) Irp,
  5135. PACKED_REG,
  5136. methodFlags,
  5137. TRUE
  5138. );
  5139. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  5140. if (status == STATUS_PENDING) {
  5141. status = STATUS_MORE_PROCESSING_REQUIRED;
  5142. }
  5143. return status;
  5144. }
  5145. NTSTATUS
  5146. ACPIBuildRegOffRequest(
  5147. IN PDEVICE_OBJECT DeviceObject,
  5148. IN PIRP Irp,
  5149. IN PACPI_BUILD_CALLBACK CallBack
  5150. )
  5151. /*++
  5152. Routine Description:
  5153. This routine is called when a device is turned off, and we need to tell
  5154. the AML that the regionspace behind it are not available
  5155. Arguments:
  5156. DeviceObject - The target device object
  5157. Irp - The target irp
  5158. CallBack - The routine to call when done
  5159. Return Value:
  5160. NTSTATUS
  5161. --*/
  5162. {
  5163. return ACPIBuildRegRequest( DeviceObject, Irp, CallBack );
  5164. }
  5165. NTSTATUS
  5166. ACPIBuildRegOnRequest(
  5167. IN PDEVICE_OBJECT DeviceObject,
  5168. IN PIRP Irp,
  5169. IN PACPI_BUILD_CALLBACK CallBack
  5170. )
  5171. /*++
  5172. Routine Description:
  5173. This routine is called when a device is turned on, and we need to tell
  5174. the AML that the regionspace behind it are now available
  5175. Arguments:
  5176. DeviceObject - The target device object
  5177. Irp - The target irp
  5178. CallBack - The routine to call when done
  5179. Return Value:
  5180. NTSTATUS
  5181. --*/
  5182. {
  5183. ACPIBuildRegRequest( DeviceObject, Irp, CallBack );
  5184. return STATUS_MORE_PROCESSING_REQUIRED;
  5185. }
  5186. NTSTATUS
  5187. ACPIBuildRunMethodRequest(
  5188. IN PDEVICE_EXTENSION DeviceExtension,
  5189. IN PACPI_BUILD_CALLBACK CallBack,
  5190. IN PVOID CallBackContext,
  5191. IN ULONG MethodName,
  5192. IN ULONG MethodFlags,
  5193. IN BOOLEAN RunDPC
  5194. )
  5195. /*++
  5196. Routine Description:
  5197. This routine is called to request that a control method be run
  5198. recursively on the device tree
  5199. Note: AcpiDeviceTreeLock must be held to call this function
  5200. Arguments:
  5201. DeviceExtension - The device extension to run the method on
  5202. MethodName - The name of the method to run
  5203. RunDpc - Should we run the dpc?
  5204. Return Value:
  5205. NTSTATUS
  5206. --*/
  5207. {
  5208. PACPI_BUILD_REQUEST buildRequest;
  5209. PACPI_BUILD_REQUEST syncRequest;
  5210. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  5211. //
  5212. // Allocate a buildRequest structure
  5213. //
  5214. buildRequest = ExAllocateFromNPagedLookasideList(
  5215. &BuildRequestLookAsideList
  5216. );
  5217. if (buildRequest == NULL) {
  5218. if (CallBack != NULL) {
  5219. (*CallBack)(
  5220. DeviceExtension,
  5221. CallBackContext,
  5222. STATUS_INSUFFICIENT_RESOURCES
  5223. );
  5224. }
  5225. return STATUS_INSUFFICIENT_RESOURCES;
  5226. }
  5227. //
  5228. // Do we need to have the 2nd buildrequest structure?
  5229. //
  5230. if (CallBack != NULL) {
  5231. syncRequest = ExAllocateFromNPagedLookasideList(
  5232. &BuildRequestLookAsideList
  5233. );
  5234. if (syncRequest == NULL) {
  5235. ExFreeToNPagedLookasideList(
  5236. &BuildRequestLookAsideList,
  5237. buildRequest
  5238. );
  5239. (*CallBack)(
  5240. DeviceExtension,
  5241. CallBackContext,
  5242. STATUS_INSUFFICIENT_RESOURCES
  5243. );
  5244. return STATUS_INSUFFICIENT_RESOURCES;
  5245. }
  5246. }
  5247. //
  5248. // If the current reference is 0, that means that someone else beat
  5249. // use to the device extension that that we *CANNOT* touch it
  5250. //
  5251. if (DeviceExtension->ReferenceCount == 0) {
  5252. ExFreeToNPagedLookasideList(
  5253. &BuildRequestLookAsideList,
  5254. buildRequest
  5255. );
  5256. if (CallBack != NULL) {
  5257. ExFreeToNPagedLookasideList(
  5258. &BuildRequestLookAsideList,
  5259. syncRequest
  5260. );
  5261. (*CallBack)(
  5262. DeviceExtension,
  5263. CallBackContext,
  5264. STATUS_DEVICE_REMOVED
  5265. );
  5266. }
  5267. return STATUS_DEVICE_REMOVED;
  5268. } else {
  5269. InterlockedIncrement( &(DeviceExtension->ReferenceCount) );
  5270. if (CallBack != NULL) {
  5271. //
  5272. // Grab second reference
  5273. //
  5274. InterlockedIncrement( &(DeviceExtension->ReferenceCount) );
  5275. }
  5276. }
  5277. //
  5278. // Fill in the structure
  5279. //
  5280. RtlZeroMemory( buildRequest, sizeof(ACPI_BUILD_REQUEST) );
  5281. buildRequest->Signature = ACPI_SIGNATURE;
  5282. buildRequest->TargetListEntry = &AcpiBuildRunMethodList;
  5283. buildRequest->WorkDone = WORK_DONE_STEP_0;
  5284. buildRequest->Status = STATUS_SUCCESS;
  5285. buildRequest->BuildContext = DeviceExtension;
  5286. buildRequest->RunRequest.ControlMethodName = MethodName;
  5287. buildRequest->RunRequest.Flags = MethodFlags;
  5288. buildRequest->Flags = BUILD_REQUEST_VALID_TARGET |
  5289. BUILD_REQUEST_RUN |
  5290. BUILD_REQUEST_RELEASE_REFERENCE;
  5291. //
  5292. // Do we have to call the callback? If so, we need a 2nd request to
  5293. // queue up to the synchronize list
  5294. //
  5295. if (CallBack != NULL) {
  5296. //
  5297. // Fill in the structure
  5298. //
  5299. RtlZeroMemory( syncRequest, sizeof(ACPI_BUILD_REQUEST) );
  5300. syncRequest->Signature = ACPI_SIGNATURE;
  5301. syncRequest->TargetListEntry = &AcpiBuildSynchronizationList;
  5302. syncRequest->WorkDone = WORK_DONE_STEP_0;
  5303. syncRequest->NextWorkDone = WORK_DONE_COMPLETE;
  5304. syncRequest->Status = STATUS_SUCCESS;
  5305. syncRequest->CallBack = CallBack;
  5306. syncRequest->CallBackContext = CallBackContext;
  5307. syncRequest->BuildContext = DeviceExtension;
  5308. syncRequest->SynchronizeRequest.SynchronizeListEntry =
  5309. &AcpiBuildRunMethodList;
  5310. syncRequest->SynchronizeRequest.SynchronizeMethodName =
  5311. MethodName;
  5312. syncRequest->Flags = BUILD_REQUEST_VALID_TARGET |
  5313. BUILD_REQUEST_SYNC |
  5314. BUILD_REQUEST_RELEASE_REFERENCE;
  5315. syncRequest->SynchronizeRequest.Flags = SYNC_REQUEST_HAS_METHOD;
  5316. }
  5317. //
  5318. // At this point, we need the spinlock
  5319. //
  5320. KeAcquireSpinLockAtDpcLevel( &AcpiBuildQueueLock );
  5321. //
  5322. // Add this to the list
  5323. //
  5324. InsertTailList(
  5325. &AcpiBuildQueueList,
  5326. &(buildRequest->ListEntry)
  5327. );
  5328. if (CallBack != NULL) {
  5329. InsertTailList(
  5330. &AcpiBuildQueueList,
  5331. &(syncRequest->ListEntry)
  5332. );
  5333. }
  5334. //
  5335. // Do we need to queue up the DPC?
  5336. //
  5337. if (RunDPC && !AcpiBuildDpcRunning) {
  5338. KeInsertQueueDpc( &AcpiBuildDpc, 0, 0 );
  5339. }
  5340. //
  5341. // Done with the lock
  5342. //
  5343. KeReleaseSpinLockFromDpcLevel( &AcpiBuildQueueLock );
  5344. //
  5345. // Done
  5346. //
  5347. return STATUS_PENDING;
  5348. }
  5349. NTSTATUS
  5350. ACPIBuildSurpriseRemovedExtension(
  5351. IN PDEVICE_EXTENSION DeviceExtension
  5352. )
  5353. /*++
  5354. Routine Description:
  5355. This routine is called when the system wants to turn the above
  5356. extension into a surprised removed one
  5357. Arguments:
  5358. DeviceExtension - The extension that is being surprised removed
  5359. Return Value:
  5360. NTSTATUS
  5361. --*/
  5362. {
  5363. KIRQL oldIrql;
  5364. PDEVICE_EXTENSION dockExtension;
  5365. PDEVICE_EXTENSION parentExtension, childExtension;
  5366. EXTENSIONLIST_ENUMDATA eled;
  5367. //
  5368. // This device might have a corrosponding fake extension. Find out now - if
  5369. // it exists we must nuke it.
  5370. //
  5371. dockExtension = ACPIDockFindCorrespondingDock( DeviceExtension );
  5372. if (dockExtension) {
  5373. //
  5374. // We have a fake dock, nuke it too since it's underlying hardware is
  5375. // gone.
  5376. //
  5377. dockExtension->DeviceState = SurpriseRemoved;
  5378. ACPIBuildSurpriseRemovedExtension( dockExtension );
  5379. }
  5380. ACPIExtListSetupEnum(
  5381. &eled,
  5382. &(DeviceExtension->ChildDeviceList),
  5383. &AcpiDeviceTreeLock,
  5384. SiblingDeviceList,
  5385. WALKSCHEME_REFERENCE_ENTRIES
  5386. );
  5387. for(childExtension = ACPIExtListStartEnum(&eled);
  5388. ACPIExtListTestElement(&eled, TRUE);
  5389. childExtension = ACPIExtListEnumNext(&eled)) {
  5390. ACPIBuildSurpriseRemovedExtension(childExtension);
  5391. }
  5392. //
  5393. // We also want to flush the power queue to insure that any events
  5394. // dealing with the removed object go away as fast as possible...
  5395. //
  5396. ACPIDevicePowerFlushQueue( DeviceExtension );
  5397. //
  5398. // At this point, we don't think the device is coming back, so we
  5399. // need to fully remove this extension. The first step to do that
  5400. // is mark the extension as appropriate, and to do that, we need
  5401. // the device spin lock
  5402. //
  5403. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  5404. //
  5405. // Clear the flags for this extension
  5406. //
  5407. if (DeviceExtension->Flags & DEV_TYPE_PDO) {
  5408. ACPIInternalUpdateFlags( &(DeviceExtension->Flags), DEV_MASK_TYPE, TRUE );
  5409. ACPIInternalUpdateFlags(
  5410. &(DeviceExtension->Flags),
  5411. (DEV_TYPE_PDO | DEV_TYPE_SURPRISE_REMOVED | DEV_PROP_NO_OBJECT | DEV_TYPE_NOT_ENUMERATED),
  5412. FALSE
  5413. );
  5414. DeviceExtension->DispatchTable = &AcpiSurpriseRemovedPdoIrpDispatch;
  5415. } else if (DeviceExtension->Flags & DEV_TYPE_FILTER) {
  5416. ACPIInternalUpdateFlags( &(DeviceExtension->Flags), DEV_MASK_TYPE, TRUE );
  5417. ACPIInternalUpdateFlags(
  5418. &(DeviceExtension->Flags),
  5419. (DEV_TYPE_FILTER | DEV_TYPE_SURPRISE_REMOVED | DEV_PROP_NO_OBJECT | DEV_TYPE_NOT_ENUMERATED),
  5420. FALSE
  5421. );
  5422. DeviceExtension->DispatchTable = &AcpiSurpriseRemovedFilterIrpDispatch;
  5423. }
  5424. //
  5425. // At this point, we are going to have to make a call ---
  5426. // do we re-build the original device extension in the tree
  5427. // or do we forget about it. We have to forget about it if the
  5428. // table is being unloaded. We need to make this decision while
  5429. // we still have a pointer to the parent extension...
  5430. //
  5431. if (!(DeviceExtension->Flags & DEV_PROP_UNLOADING) ) {
  5432. //
  5433. // Set the bit to cause the parent to rebuild missing
  5434. // children on QDR
  5435. //
  5436. parentExtension = DeviceExtension->ParentExtension;
  5437. if (parentExtension) {
  5438. ACPIInternalUpdateFlags(
  5439. &(parentExtension->Flags),
  5440. DEV_PROP_REBUILD_CHILDREN,
  5441. FALSE
  5442. );
  5443. if (DeviceExtension->AcpiObject &&
  5444. ACPIDockIsDockDevice(DeviceExtension->AcpiObject)) {
  5445. ASSERT(parentExtension->PhysicalDeviceObject != NULL);
  5446. //
  5447. // This will cause us to rebuild this extension afterwards. We
  5448. // need this because notify attempts on docks require fully
  5449. // built and processed device extensions.
  5450. //
  5451. IoInvalidateDeviceRelations(
  5452. parentExtension->PhysicalDeviceObject,
  5453. SingleBusRelations
  5454. );
  5455. }
  5456. }
  5457. }
  5458. //
  5459. // Remove this extension from the tree. This will nuke the pointer
  5460. // to the parent extension (that's the link that gets cut from the
  5461. // tree)
  5462. //
  5463. ACPIInitRemoveDeviceExtension( DeviceExtension );
  5464. //
  5465. // Remember to make sure that the ACPI Object no longer points to this
  5466. // device extension
  5467. //
  5468. if (DeviceExtension->AcpiObject) {
  5469. DeviceExtension->AcpiObject->Context = NULL;
  5470. }
  5471. //
  5472. // Are we a thermal zone?
  5473. //
  5474. if (DeviceExtension->Flags & DEV_CAP_THERMAL_ZONE) {
  5475. //
  5476. // Do Some Clean-up by flushing all the currently queued requests
  5477. //
  5478. ACPIThermalCompletePendingIrps(
  5479. DeviceExtension,
  5480. DeviceExtension->Thermal.Info
  5481. );
  5482. }
  5483. //
  5484. // Done with the lock
  5485. //
  5486. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  5487. //
  5488. // Done
  5489. //
  5490. return STATUS_SUCCESS;
  5491. }
  5492. NTSTATUS
  5493. ACPIBuildSynchronizationRequest(
  5494. IN PDEVICE_EXTENSION DeviceExtension,
  5495. IN PACPI_BUILD_CALLBACK CallBack,
  5496. IN PVOID CallBackContext,
  5497. IN PLIST_ENTRY SynchronizeListEntry,
  5498. IN BOOLEAN RunDPC
  5499. )
  5500. /*++
  5501. Routine Description:
  5502. This routine is called when the system wants to know when the DPC routine
  5503. has been completed.
  5504. Arguments:
  5505. DeviceExtension - This is the device extension that we are
  5506. typically interested in. Usually, it will be the
  5507. root node
  5508. CallBack - The function to call when done
  5509. CallBackContext - The argument to pass to that function
  5510. Event - The event to notify when done
  5511. RunDpc - Should we run the dpc?
  5512. Return Value:
  5513. NTSTATUS
  5514. --*/
  5515. {
  5516. KIRQL oldIrql;
  5517. PACPI_BUILD_REQUEST buildRequest;
  5518. //
  5519. // Allocate a buildRequest structure
  5520. //
  5521. buildRequest = ExAllocateFromNPagedLookasideList(
  5522. &BuildRequestLookAsideList
  5523. );
  5524. if (buildRequest == NULL) {
  5525. return STATUS_INSUFFICIENT_RESOURCES;
  5526. }
  5527. //
  5528. // We need the device tree lock while we look at the device
  5529. //
  5530. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  5531. //
  5532. // If the current reference is 0, that means that someone else beat
  5533. // use to the device extension that that we *CANNOT* touch it
  5534. //
  5535. if (DeviceExtension->ReferenceCount == 0) {
  5536. ExFreeToNPagedLookasideList(
  5537. &BuildRequestLookAsideList,
  5538. buildRequest
  5539. );
  5540. return STATUS_DEVICE_REMOVED;
  5541. } else {
  5542. InterlockedIncrement( &(DeviceExtension->ReferenceCount) );
  5543. }
  5544. //
  5545. // Fill in the structure
  5546. //
  5547. RtlZeroMemory( buildRequest, sizeof(ACPI_BUILD_REQUEST) );
  5548. buildRequest->Signature = ACPI_SIGNATURE;
  5549. buildRequest->TargetListEntry = &AcpiBuildSynchronizationList;
  5550. buildRequest->WorkDone = WORK_DONE_STEP_0;
  5551. buildRequest->NextWorkDone = WORK_DONE_COMPLETE;
  5552. buildRequest->Status = STATUS_SUCCESS;
  5553. buildRequest->CallBack = CallBack;
  5554. buildRequest->CallBackContext = CallBackContext;
  5555. buildRequest->BuildContext = DeviceExtension;
  5556. buildRequest->SynchronizeRequest.SynchronizeListEntry =
  5557. SynchronizeListEntry;
  5558. buildRequest->Flags = BUILD_REQUEST_VALID_TARGET |
  5559. BUILD_REQUEST_SYNC |
  5560. BUILD_REQUEST_RELEASE_REFERENCE;
  5561. //
  5562. // Done looking at the device
  5563. //
  5564. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  5565. //
  5566. // At this point, we need the build queue spinlock
  5567. //
  5568. KeAcquireSpinLock( &AcpiBuildQueueLock, &oldIrql );
  5569. //
  5570. // Add this to the list. We add the request to the head
  5571. // of the list because we want to guarantee a LIFO ordering
  5572. //
  5573. InsertHeadList(
  5574. &AcpiBuildQueueList,
  5575. &(buildRequest->ListEntry)
  5576. );
  5577. //
  5578. // Do we need to queue up the DPC?
  5579. //
  5580. if (RunDPC && !AcpiBuildDpcRunning) {
  5581. KeInsertQueueDpc( &AcpiBuildDpc, 0, 0 );
  5582. }
  5583. //
  5584. // Done with the lock
  5585. //
  5586. KeReleaseSpinLock( &AcpiBuildQueueLock, oldIrql );
  5587. //
  5588. // Done
  5589. //
  5590. return STATUS_PENDING;
  5591. }
  5592. NTSTATUS
  5593. ACPIBuildThermalZoneExtension(
  5594. IN PNSOBJ ThermalObject,
  5595. IN PDEVICE_EXTENSION ParentExtension,
  5596. IN PDEVICE_EXTENSION *ResultExtension
  5597. )
  5598. /*++
  5599. Routine Description:
  5600. Since we leverage ACPIBuildDeviceExtension for the core of the thermal
  5601. extension, we don't have much to do here. However, we are responsible
  5602. for making sure that we do tasks that don't require calling the interpreter,
  5603. and a unique to the ThermalZone here
  5604. N.B. This function is called with AcpiDeviceTreeLock being held
  5605. Arguments:
  5606. ThermalObject - The object we care about
  5607. ParentExtension - Who our parent is
  5608. ResultExtension - Where to store the extension that we build
  5609. Return Value:
  5610. NTSTATUS
  5611. --*/
  5612. {
  5613. NTSTATUS status;
  5614. PDEVICE_EXTENSION thermalExtension;
  5615. PTHRM_INFO info;
  5616. //
  5617. // Build the extension
  5618. //
  5619. status = ACPIBuildDeviceExtension(
  5620. ThermalObject,
  5621. ParentExtension,
  5622. ResultExtension
  5623. );
  5624. if (!NT_SUCCESS(status) || *ResultExtension == NULL) {
  5625. return status;
  5626. }
  5627. thermalExtension = *ResultExtension;
  5628. //
  5629. // Make sure to remember that this is in fact a thermal zone
  5630. //
  5631. ACPIInternalUpdateFlags(
  5632. &(thermalExtension->Flags),
  5633. (DEV_CAP_THERMAL_ZONE | DEV_MASK_THERMAL | DEV_CAP_RAW | DEV_CAP_NO_STOP),
  5634. FALSE
  5635. );
  5636. //
  5637. // Allocate the additional thermal device storage
  5638. //
  5639. info = thermalExtension->Thermal.Info = ExAllocatePoolWithTag(
  5640. NonPagedPool,
  5641. sizeof(THRM_INFO),
  5642. ACPI_THERMAL_POOLTAG
  5643. );
  5644. if (thermalExtension->Thermal.Info == NULL) {
  5645. ACPIDevPrint( (
  5646. ACPI_PRINT_CRITICAL,
  5647. thermalExtension,
  5648. "ACPIBuildThermalZoneExtension: failed to allocate %08 bytes\n",
  5649. sizeof(THRM_INFO)
  5650. ) );
  5651. status = STATUS_INSUFFICIENT_RESOURCES;
  5652. goto ACPIBuildThermalZoneExtensionExit;
  5653. }
  5654. //
  5655. // Make sure that the memory is freshly scrubbed
  5656. //
  5657. RtlZeroMemory( thermalExtension->Thermal.Info, sizeof(THRM_INFO) );
  5658. //
  5659. // Allocate memory for the HID
  5660. //
  5661. thermalExtension->DeviceID = ExAllocatePoolWithTag(
  5662. NonPagedPool,
  5663. strlen(ACPIThermalZoneId) + 1,
  5664. ACPI_STRING_POOLTAG
  5665. );
  5666. if (thermalExtension->DeviceID == NULL) {
  5667. ACPIDevPrint( (
  5668. ACPI_PRINT_CRITICAL,
  5669. thermalExtension,
  5670. "ACPIBuildThermalZoneExtension: failed to allocate %08 bytes\n",
  5671. strlen(ACPIThermalZoneId) + 1
  5672. ) );
  5673. status = STATUS_INSUFFICIENT_RESOURCES;
  5674. goto ACPIBuildThermalZoneExtensionExit;
  5675. }
  5676. RtlCopyMemory(
  5677. thermalExtension->DeviceID,
  5678. ACPIThermalZoneId,
  5679. strlen(ACPIThermalZoneId) + 1
  5680. );
  5681. //
  5682. // Allocate memory for the UID
  5683. //
  5684. thermalExtension->InstanceID = ExAllocatePoolWithTag(
  5685. NonPagedPool,
  5686. 5,
  5687. ACPI_STRING_POOLTAG
  5688. );
  5689. if (thermalExtension->InstanceID == NULL) {
  5690. ACPIDevPrint( (
  5691. ACPI_PRINT_CRITICAL,
  5692. thermalExtension,
  5693. "ACPIBuildThermalZoneExtension: failed to allocate %08 bytes\n",
  5694. 5
  5695. ) );
  5696. status = STATUS_INSUFFICIENT_RESOURCES;
  5697. goto ACPIBuildThermalZoneExtensionExit;
  5698. }
  5699. RtlCopyMemory(
  5700. thermalExtension->InstanceID,
  5701. (PUCHAR) &(thermalExtension->AcpiObject->dwNameSeg),
  5702. 4
  5703. );
  5704. thermalExtension->InstanceID[4] = '\0';
  5705. //
  5706. // Set the flags for the work that we have just done
  5707. //
  5708. ACPIInternalUpdateFlags(
  5709. &(thermalExtension->Flags),
  5710. (DEV_PROP_HID | DEV_PROP_FIXED_HID | DEV_PROP_UID | DEV_PROP_FIXED_UID),
  5711. FALSE
  5712. );
  5713. ACPIBuildThermalZoneExtensionExit:
  5714. //
  5715. // Handle the case where we might have failed
  5716. //
  5717. if (!NT_SUCCESS(status)) {
  5718. ACPIDevPrint( (
  5719. ACPI_PRINT_FAILURE,
  5720. thermalExtension,
  5721. "ACPIBuildThermalZoneExtension: = %08lx\n",
  5722. status
  5723. ) );
  5724. if (thermalExtension->InstanceID != NULL) {
  5725. ACPIInternalUpdateFlags(
  5726. &(thermalExtension->Flags),
  5727. (DEV_PROP_UID | DEV_PROP_FIXED_UID),
  5728. TRUE
  5729. );
  5730. ExFreePool( thermalExtension->InstanceID );
  5731. thermalExtension->InstanceID = NULL;
  5732. }
  5733. if (thermalExtension->DeviceID != NULL) {
  5734. ACPIInternalUpdateFlags(
  5735. &(thermalExtension->Flags),
  5736. (DEV_PROP_HID | DEV_PROP_FIXED_HID),
  5737. TRUE
  5738. );
  5739. ExFreePool( thermalExtension->DeviceID );
  5740. thermalExtension->DeviceID = NULL;
  5741. }
  5742. if (thermalExtension->Thermal.Info != NULL) {
  5743. ExFreePool( thermalExtension->Thermal.Info );
  5744. thermalExtension->Thermal.Info = NULL;
  5745. }
  5746. //
  5747. // Remember that we failed init
  5748. //
  5749. ACPIInternalUpdateFlags(
  5750. &(thermalExtension->Flags),
  5751. DEV_PROP_FAILED_INIT,
  5752. TRUE
  5753. );
  5754. } else {
  5755. ACPIDevPrint( (
  5756. ACPI_PRINT_LOADING,
  5757. thermalExtension,
  5758. "ACPIBuildThermalZoneExtension: = %08lx\n",
  5759. status
  5760. ) );
  5761. }
  5762. //
  5763. // Done
  5764. //
  5765. return status;
  5766. }
  5767. NTSTATUS
  5768. ACPIBuildThermalZoneRequest(
  5769. IN PDEVICE_EXTENSION ThermalExtension,
  5770. IN PACPI_BUILD_CALLBACK CallBack,
  5771. IN PVOID CallBackContext,
  5772. IN BOOLEAN RunDPC
  5773. )
  5774. /*++
  5775. Routine Description:
  5776. This routine is called when a thermal zone is ready to be filled in.
  5777. This routine creates a request which is enqueued. When the DPC is fired,
  5778. the request will be processed
  5779. Note: AcpiDeviceTreeLock must be held to call this function
  5780. Arguments:
  5781. ThermalExtension - The thermal zone to process
  5782. CallBack - The function to call when done
  5783. CallBackContext - The argument to pass to that function
  5784. RunDPC - Should we enqueue the DPC immediately (if it is not
  5785. running?)
  5786. Return Value:
  5787. NTSTATUS
  5788. --*/
  5789. {
  5790. PACPI_BUILD_REQUEST buildRequest;
  5791. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  5792. //
  5793. // Allocate a buildRequest structure
  5794. //
  5795. buildRequest = ExAllocateFromNPagedLookasideList(
  5796. &BuildRequestLookAsideList
  5797. );
  5798. if (buildRequest == NULL) {
  5799. return STATUS_INSUFFICIENT_RESOURCES;
  5800. }
  5801. //
  5802. // If the current reference is 0, that means that someone else beat
  5803. // use to the device extension that that we *CANNOT* touch it
  5804. //
  5805. if (ThermalExtension->ReferenceCount == 0) {
  5806. ExFreeToNPagedLookasideList(
  5807. &BuildRequestLookAsideList,
  5808. buildRequest
  5809. );
  5810. return STATUS_DEVICE_REMOVED;
  5811. } else {
  5812. InterlockedIncrement( &(ThermalExtension->ReferenceCount) );
  5813. }
  5814. //
  5815. // Fill in the structure
  5816. //
  5817. RtlZeroMemory( buildRequest, sizeof(ACPI_BUILD_REQUEST) );
  5818. buildRequest->Signature = ACPI_SIGNATURE;
  5819. buildRequest->TargetListEntry = &AcpiBuildThermalZoneList;
  5820. buildRequest->WorkDone = WORK_DONE_STEP_0;
  5821. buildRequest->Status = STATUS_SUCCESS;
  5822. buildRequest->CallBack = CallBack;
  5823. buildRequest->CallBackContext = CallBackContext;
  5824. buildRequest->BuildContext = ThermalExtension;
  5825. buildRequest->Flags = BUILD_REQUEST_VALID_TARGET |
  5826. BUILD_REQUEST_RELEASE_REFERENCE;
  5827. //
  5828. // At this point, we need the spinlock
  5829. //
  5830. KeAcquireSpinLockAtDpcLevel( &AcpiBuildQueueLock );
  5831. //
  5832. // Add this to the list
  5833. //
  5834. InsertTailList(
  5835. &AcpiBuildQueueList,
  5836. &(buildRequest->ListEntry)
  5837. );
  5838. //
  5839. // Do we need to queue up the DPC?
  5840. //
  5841. if (RunDPC && !AcpiBuildDpcRunning) {
  5842. KeInsertQueueDpc( &AcpiBuildDpc, 0, 0 );
  5843. }
  5844. //
  5845. // Done with the lock
  5846. //
  5847. KeReleaseSpinLockFromDpcLevel( &AcpiBuildQueueLock );
  5848. //
  5849. // Done
  5850. //
  5851. return STATUS_PENDING;
  5852. }