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.

621 lines
14 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. table.c
  5. Abstract:
  6. All the function related to actually loading an ACPI table
  7. are included herein.
  8. This, however, is mostly bookkeeping since the actual mechanics
  9. of creating device extensions, and the name space tree are
  10. handled elsewhere
  11. Author:
  12. Stephane Plante (splante)
  13. Environment:
  14. Kernel Mode Only
  15. Revision History:
  16. 03/22/00 - Created (from code in callback.c)
  17. --*/
  18. #include "pch.h"
  19. NTSTATUS
  20. ACPITableLoad(
  21. VOID
  22. )
  23. /*++
  24. Routine Description:
  25. This routine is called when the AML interpreter has finished loading
  26. a Differentiated Data Block
  27. Arguments:
  28. None
  29. Return Value:
  30. NTSTATUS
  31. --*/
  32. {
  33. BOOLEAN runRootIni = FALSE;
  34. KIRQL oldIrql;
  35. NTSTATUS status;
  36. PDEVICE_EXTENSION fixedButtonExtension = NULL;
  37. PNSOBJ iniObject;
  38. PNSOBJ nsObject;
  39. //
  40. // At this point, we should do everything that we need to do once the
  41. // name space has been loaded. Note that we need to make sure that we
  42. // only do those things once...
  43. //
  44. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  45. //
  46. // We need the ACPI object for the _SB tree
  47. //
  48. status = AMLIGetNameSpaceObject( "\\_SB", NULL, &nsObject, 0 );
  49. if (!NT_SUCCESS(status)) {
  50. //
  51. // Ooops. Failure
  52. //
  53. ACPIPrint( (
  54. ACPI_PRINT_CRITICAL,
  55. "ACPICallBackLoadUnloadDDB: No SB Object!\n"
  56. ) );
  57. ACPIInternalError( ACPI_CALLBACK );
  58. return STATUS_SUCCESS;
  59. }
  60. //
  61. // Make sure that the root device extension's object points to the correct
  62. // thing. We only want to run through this code path once...
  63. //
  64. if (RootDeviceExtension->AcpiObject == NULL) {
  65. runRootIni = TRUE;
  66. InterlockedIncrement( &(RootDeviceExtension->ReferenceCount) );
  67. RootDeviceExtension->AcpiObject = nsObject;
  68. nsObject->Context = RootDeviceExtension;
  69. //
  70. // Now, enumerate the fixed button
  71. //
  72. status = ACPIBuildFixedButtonExtension(
  73. RootDeviceExtension,
  74. &fixedButtonExtension
  75. );
  76. if (NT_SUCCESS(status) &&
  77. fixedButtonExtension != NULL) {
  78. //
  79. // Incremement the reference count on the node. We do this because
  80. // we are going to be doing work (which will take a long time
  81. // to complete, anyways), and we don't want to hold the lock for that
  82. // entire time. If we incr the reference count, then we guarantee that
  83. // no one can come along and kick the feet out from underneath us
  84. //
  85. InterlockedIncrement( &(fixedButtonExtension->ReferenceCount) );
  86. }
  87. }
  88. //
  89. // We now want to run the _INI through the entire tree, starting at
  90. // the _SB
  91. //
  92. status = ACPIBuildRunMethodRequest(
  93. RootDeviceExtension,
  94. NULL,
  95. NULL,
  96. PACKED_INI,
  97. (RUN_REQUEST_CHECK_STATUS | RUN_REQUEST_RECURSIVE | RUN_REQUEST_MARK_INI),
  98. FALSE
  99. );
  100. if (!NT_SUCCESS(status)) {
  101. ACPIInternalError( ACPI_CALLBACK );
  102. }
  103. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  104. //
  105. // We also need to run the _INI method off of the root name space entry
  106. //
  107. if (runRootIni) {
  108. iniObject = ACPIAmliGetNamedChild( nsObject->pnsParent, PACKED_INI );
  109. if (iniObject) {
  110. AMLIAsyncEvalObject(
  111. iniObject,
  112. NULL,
  113. 0,
  114. NULL,
  115. NULL,
  116. NULL
  117. );
  118. }
  119. }
  120. //
  121. // We need a synchronization point after we finish running the
  122. // DPC engine. We want to be able to move anything in the Delayed
  123. // Power Queue over to the Power DPC engine
  124. //
  125. status = ACPIBuildSynchronizationRequest(
  126. RootDeviceExtension,
  127. ACPITableLoadCallBack,
  128. NULL,
  129. &AcpiBuildDeviceList,
  130. FALSE
  131. );
  132. if (!NT_SUCCESS(status)) {
  133. ACPIInternalError( ACPI_CALLBACK );
  134. }
  135. //
  136. // We need to hold this spinlock
  137. //
  138. KeAcquireSpinLock( &AcpiBuildQueueLock, &oldIrql );
  139. //
  140. // Do we need to run the DPC?
  141. //
  142. if (!AcpiBuildDpcRunning) {
  143. KeInsertQueueDpc( &AcpiBuildDpc, 0, 0);
  144. }
  145. //
  146. // Done with the lock
  147. //
  148. KeReleaseSpinLock( &AcpiBuildQueueLock, oldIrql );
  149. //
  150. // Done
  151. //
  152. return STATUS_SUCCESS;
  153. }
  154. VOID
  155. ACPITableLoadCallBack(
  156. IN PVOID BuildContext,
  157. IN PVOID Context,
  158. IN NTSTATUS Status
  159. )
  160. /*++
  161. Routine Description:
  162. This routine is called when we have emptied all of the elements
  163. within the AcpiBuildDeviceList. This is a good time to move items
  164. from the AcpiPowerDelayedQueueList to the AcpiPowerQueueList.
  165. Arguments:
  166. BuildContext - Not used (it is the RootDeviceExtension)
  167. Context - NULL
  168. Status - Status of the operation
  169. Return Value:
  170. None
  171. --*/
  172. {
  173. UNREFERENCED_PARAMETER( BuildContext );
  174. UNREFERENCED_PARAMETER( Context );
  175. UNREFERENCED_PARAMETER( Status );
  176. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  177. //
  178. // We want to rebuilt the device based GPE mask here, so
  179. // we need the following locks
  180. //
  181. KeAcquireSpinLockAtDpcLevel( &AcpiDeviceTreeLock );
  182. KeAcquireSpinLockAtDpcLevel( &GpeTableLock );
  183. //
  184. // Now, we need to walk the device namespace and find which events
  185. // are special, which are wake events, and which are run-time events
  186. // As a matter of practical theory, its not possible for there to
  187. // be a _PRW on the root device extension, so we should be safely
  188. // able to walk only the Root's children and thereon
  189. //
  190. ACPIGpeBuildWakeMasks(RootDeviceExtension);
  191. //
  192. // We don't need these particular spin locks anymore
  193. //
  194. KeReleaseSpinLockFromDpcLevel( &GpeTableLock );
  195. KeReleaseSpinLockFromDpcLevel( &AcpiDeviceTreeLock );
  196. //
  197. // We need the power lock to touch these Power Queues
  198. //
  199. KeAcquireSpinLockAtDpcLevel( &AcpiPowerQueueLock );
  200. //
  201. // If we there are items on the delayed list, we need to put them
  202. // on the main list
  203. //
  204. if (!IsListEmpty( &AcpiPowerDelayedQueueList ) ) {
  205. //
  206. // Move the list
  207. //
  208. ACPIInternalMoveList(
  209. &AcpiPowerDelayedQueueList,
  210. &AcpiPowerQueueList
  211. );
  212. //
  213. // Schedule the DPC, if necessary
  214. ///
  215. if (!AcpiPowerDpcRunning) {
  216. KeInsertQueueDpc( &AcpiPowerDpc, 0, 0 );
  217. }
  218. }
  219. //
  220. // Done with the lock
  221. //
  222. KeReleaseSpinLockFromDpcLevel( &AcpiPowerQueueLock );
  223. }
  224. NTSTATUS
  225. EXPORT
  226. ACPITableNotifyFreeObject(
  227. ULONG Event,
  228. PVOID Context,
  229. ULONG ObjectType
  230. )
  231. /*++
  232. Routine Description:
  233. This routine is called when interpreter tells us that an
  234. object has been freed
  235. Arguments:
  236. Event - the step in unload
  237. Object - the object being unloaded
  238. ObjectType - the type of the object
  239. --*/
  240. {
  241. LONG oldReferenceCount;
  242. PDEVICE_EXTENSION deviceExtension;
  243. PDEVICE_EXTENSION parentExtension;
  244. PKIRQL oldIrql;
  245. PNSOBJ object;
  246. //
  247. // Start case
  248. //
  249. if (Event == DESTROYOBJ_START) {
  250. ACPIPrint( (
  251. ACPI_PRINT_CRITICAL,
  252. "Unloading: Start\n"
  253. ) );
  254. oldIrql = (PKIRQL) Context;
  255. KeAcquireSpinLock( &AcpiDeviceTreeLock, oldIrql );
  256. return STATUS_SUCCESS;
  257. }
  258. if (Event == DESTROYOBJ_END) {
  259. ACPIPrint( (
  260. ACPI_PRINT_CRITICAL,
  261. "Unloading: End\n"
  262. ) );
  263. oldIrql = (PKIRQL) Context;
  264. KeReleaseSpinLock( &AcpiDeviceTreeLock, *oldIrql );
  265. return STATUS_SUCCESS;
  266. }
  267. //
  268. // At this point, we have a either a valid unload request or
  269. // a bugcheck request
  270. //
  271. object = (PNSOBJ) Context;
  272. //
  273. // Let the world Know...
  274. //
  275. ACPIPrint( (
  276. ACPI_PRINT_CRITICAL,
  277. "%x: Unloading: %x %x %x\n",
  278. (object ? object->Context : 0),
  279. object,
  280. ObjectType,
  281. Event
  282. ) );
  283. //
  284. // Handle the bugcheck cases
  285. //
  286. if (Event == DESTROYOBJ_CHILD_NOT_FREED) {
  287. KeBugCheckEx(
  288. ACPI_BIOS_ERROR,
  289. ACPI_TABLE_UNLOAD,
  290. (ULONG_PTR) object,
  291. 0,
  292. 0
  293. );
  294. }
  295. if (Event == DESTROYOBJ_BOGUS_PARENT) {
  296. KeBugCheckEx(
  297. ACPI_BIOS_ERROR,
  298. ACPI_TABLE_UNLOAD,
  299. (ULONG_PTR) object,
  300. 1,
  301. 0
  302. );
  303. }
  304. //
  305. // We only understand processors, thermal zones, and devices for right
  306. // now, we will have to add power resources at a later point
  307. //
  308. if (ObjectType == OBJTYPE_POWERRES) {
  309. return STATUS_SUCCESS;
  310. }
  311. //
  312. // Grab the device extension, and make sure that one exists
  313. //
  314. deviceExtension = object->Context;
  315. if (deviceExtension == NULL) {
  316. //
  317. // No device extension, so we can free this thing *now*
  318. //
  319. AMLIDestroyFreedObjs( object );
  320. return STATUS_SUCCESS;
  321. }
  322. //
  323. // Mark the extension as no longer existing
  324. //
  325. ACPIInternalUpdateFlags(
  326. &(deviceExtension->Flags),
  327. DEV_PROP_UNLOADING,
  328. FALSE
  329. );
  330. //
  331. // Does this device have a parent extension? It might not
  332. // have an extension if the parent has been marked for removal
  333. //
  334. parentExtension = deviceExtension->ParentExtension;
  335. if (parentExtension != NULL) {
  336. //
  337. // Mark the parent's relations as invalid
  338. //
  339. ACPIInternalUpdateFlags(
  340. &(parentExtension->Flags),
  341. DEV_PROP_INVALID_RELATIONS,
  342. FALSE
  343. );
  344. }
  345. //
  346. // Finally, decrement the reference count on the device...
  347. //
  348. oldReferenceCount = InterlockedDecrement(
  349. &(deviceExtension->ReferenceCount)
  350. );
  351. if (oldReferenceCount == 0) {
  352. //
  353. // Free this extension
  354. //
  355. ACPIInitDeleteDeviceExtension( deviceExtension );
  356. }
  357. //
  358. // Done
  359. //
  360. return STATUS_SUCCESS;
  361. }
  362. NTSTATUS
  363. ACPITableUnload(
  364. VOID
  365. )
  366. /*++
  367. Routine Description:
  368. This routine is called after a table has been unloaded.
  369. The purpose of this routine is to go out and issue the invalidate
  370. device relations on all elements of the table whose children are
  371. going away...
  372. Arguments:
  373. None
  374. Return value:
  375. NTSTATUS
  376. --*/
  377. {
  378. KIRQL oldIrql;
  379. PDEVICE_EXTENSION deviceExtension;
  380. //
  381. // We will need to hold the device tree lock for the following
  382. //
  383. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  384. //
  385. // Check to see if we have to invalid the root's device extension?
  386. //
  387. deviceExtension = RootDeviceExtension;
  388. if (deviceExtension && !(deviceExtension->Flags & DEV_TYPE_NOT_FOUND) ) {
  389. if (deviceExtension->Flags & DEV_PROP_INVALID_RELATIONS) {
  390. ACPIInternalUpdateFlags(
  391. &(deviceExtension->Flags),
  392. DEV_PROP_INVALID_RELATIONS,
  393. TRUE
  394. );
  395. IoInvalidateDeviceRelations(
  396. deviceExtension->PhysicalDeviceObject,
  397. BusRelations
  398. );
  399. } else {
  400. //
  401. // Walk the namespace looking for bogus relations
  402. //
  403. ACPITableUnloadInvalidateRelations( deviceExtension );
  404. }
  405. }
  406. //
  407. // Done with the lock
  408. //
  409. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  410. //
  411. // And with the function
  412. //
  413. return STATUS_SUCCESS;
  414. }
  415. NTSTATUS
  416. ACPITableUnloadInvalidateRelations(
  417. IN PDEVICE_EXTENSION DeviceExtension
  418. )
  419. /*++
  420. Routine Description:
  421. This recursive routine is called to walke the namespace and issue
  422. the appropriate invalidates.
  423. The device tree lock is owned during this call...
  424. Arguments:
  425. DeviceExtension - The device whose child extension we have to check
  426. Return Value:
  427. NTSTATUS
  428. --*/
  429. {
  430. EXTENSIONLIST_ENUMDATA eled;
  431. PDEVICE_EXTENSION childExtension;
  432. //
  433. // Setup the data structures that we will use to walk the
  434. // device extension tree
  435. //
  436. ACPIExtListSetupEnum(
  437. &eled,
  438. &(DeviceExtension->ChildDeviceList),
  439. NULL,
  440. SiblingDeviceList,
  441. WALKSCHEME_NO_PROTECTION
  442. );
  443. //
  444. // Look at all the children of the current device extension
  445. //
  446. for (childExtension = ACPIExtListStartEnum( &eled) ;
  447. ACPIExtListTestElement( &eled, TRUE);
  448. childExtension = ACPIExtListEnumNext( &eled) ) {
  449. //
  450. // Does this object have any device objects?
  451. //
  452. if (!(childExtension->Flags & DEV_TYPE_NOT_FOUND) ) {
  453. continue;
  454. }
  455. //
  456. // Do we have to invalidate this object's relations?
  457. //
  458. if (childExtension->Flags & DEV_PROP_INVALID_RELATIONS) {
  459. ACPIInternalUpdateFlags(
  460. &(childExtension->Flags),
  461. DEV_PROP_INVALID_RELATIONS,
  462. TRUE
  463. );
  464. IoInvalidateDeviceRelations(
  465. childExtension->PhysicalDeviceObject,
  466. BusRelations
  467. );
  468. continue;
  469. }
  470. //
  471. // Recurse
  472. //
  473. ACPITableUnloadInvalidateRelations( childExtension );
  474. } // for ( ... )
  475. //
  476. // Done
  477. //
  478. return STATUS_SUCCESS;
  479. }