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.

1533 lines
35 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. osnotify.c
  5. Abstract:
  6. This module implements all the callbacks that are NT specific from
  7. the AML Interpreter
  8. Environment
  9. Kernel mode only
  10. Revision History:
  11. 01-Mar-98 Initial Revision [split from callback.c]
  12. --*/
  13. #include "pch.h"
  14. //
  15. // Make sure that we have permanent storage for our fatal error context
  16. //
  17. ACPI_FATAL_ERROR_CONTEXT AcpiFatalContext;
  18. //
  19. // Spinlock to protect the entire thing
  20. KSPIN_LOCK AcpiFatalLock;
  21. //
  22. // Is there an outstanding Fatal Error Context?
  23. //
  24. BOOLEAN AcpiFatalOutstanding;
  25. NTSTATUS
  26. EXPORT
  27. OSNotifyCreate(
  28. IN ULONG ObjType,
  29. IN PNSOBJ AcpiObject
  30. )
  31. /*++
  32. Routine Description:
  33. This routine is called whenever a new object is created by the interpreter
  34. This routine dispatches based on what object type it is.
  35. Arguments:
  36. ObjType - What type of object it is
  37. AcpiObject - Pointer to the new ACPI Object
  38. Return Value:
  39. NTSTATUS
  40. --*/
  41. {
  42. KIRQL oldIrql;
  43. NTSTATUS status = STATUS_SUCCESS;
  44. ASSERT( AcpiObject != NULL );
  45. //
  46. // We will touch the device tree. So we need to hold the correct lock
  47. //
  48. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  49. switch(ObjType) {
  50. case OBJTYPE_DEVICE:
  51. status = OSNotifyCreateDevice( AcpiObject, 0 );
  52. break;
  53. case OBJTYPE_OPREGION:
  54. status = OSNotifyCreateOperationRegion( AcpiObject );
  55. break;
  56. case OBJTYPE_POWERRES:
  57. status = OSNotifyCreatePowerResource( AcpiObject );
  58. break;
  59. case OBJTYPE_PROCESSOR:
  60. status = OSNotifyCreateProcessor( AcpiObject, 0 );
  61. break;
  62. case OBJTYPE_THERMALZONE:
  63. status = OSNotifyCreateThermalZone( AcpiObject, 0 );
  64. break;
  65. default:
  66. ACPIPrint( (
  67. ACPI_PRINT_WARNING,
  68. "OSNotifyCreate: received unhandled type %x\n",
  69. ObjType
  70. ) );
  71. status = STATUS_SUCCESS;
  72. }
  73. //
  74. // Done with this lock
  75. //
  76. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  77. //
  78. // What happened?
  79. //
  80. ACPIPrint( (
  81. ACPI_PRINT_LOADING,
  82. "OSNotifyCreate: %p (%s) = %08lx\n",
  83. AcpiObject,
  84. ACPIAmliNameObject( AcpiObject ),
  85. status
  86. ) );
  87. //
  88. // Done --- Always succeed
  89. //
  90. return STATUS_SUCCESS;
  91. }
  92. NTSTATUS
  93. OSNotifyCreateDevice(
  94. IN PNSOBJ AcpiObject,
  95. IN ULONGLONG OptionalFlags
  96. )
  97. /*++
  98. Routine Description:
  99. This routine is called whenever a new device appears. This routine is
  100. callable at DispatchLevel.
  101. Arguments:
  102. AcpiObject - Pointer to new ACPI Object
  103. OptionalFlags - Properties of the Device Extension that should be
  104. set when its created.
  105. Return Value:
  106. NTSTATUS
  107. --*/
  108. {
  109. NTSTATUS status = STATUS_SUCCESS;
  110. PDEVICE_EXTENSION deviceExtension = NULL;
  111. PDEVICE_EXTENSION parentExtension;
  112. PNSOBJ parentObject;
  113. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  114. ASSERT( AcpiObject != NULL);
  115. //
  116. // First, we need a pointer to the parent node
  117. //
  118. parentObject = AcpiObject->pnsParent;
  119. ASSERT( parentObject != NULL );
  120. //
  121. // Grab the device extension associated with the parent. We need
  122. // this information to help link the parent properly into the tree
  123. //
  124. parentExtension = (PDEVICE_EXTENSION) parentObject->Context;
  125. if (parentExtension == NULL) {
  126. //
  127. // In this case, we can assume that the parent extension is the root
  128. // device extension.
  129. //
  130. parentExtension = RootDeviceExtension;
  131. }
  132. ASSERT( parentExtension != NULL );
  133. //
  134. // Now build an extension for the node
  135. //
  136. status = ACPIBuildDeviceExtension(
  137. AcpiObject,
  138. parentExtension,
  139. &deviceExtension
  140. );
  141. if (deviceExtension == NULL) {
  142. status = STATUS_UNSUCCESSFUL;
  143. }
  144. if (NT_SUCCESS(status)) {
  145. //
  146. // Incremement the reference count on the node. We do this because
  147. // we are going to be doing work (which will take a long time
  148. // to complete, anyways), and we don't want to hold the lock for that
  149. // entire time. If we incr the reference count, then we guarantee that
  150. // no one can come along and kick the feet out from underneath us
  151. //
  152. InterlockedIncrement( &(deviceExtension->ReferenceCount) );
  153. }
  154. //
  155. // What happend to the creation of the extension?
  156. //
  157. if (!NT_SUCCESS(status)) {
  158. //
  159. // We should have succeeded at whatever we are doing --- so this is
  160. // a bad place to be
  161. //
  162. ACPIPrint( (
  163. ACPI_PRINT_CRITICAL,
  164. "OSNotifyCreateDevice: NSObj %p Failed %08lx\n",
  165. AcpiObject,
  166. status
  167. ) );
  168. goto OSNotifyCreateDeviceExit;
  169. }
  170. //
  171. // Set the optional flags if there are any
  172. //
  173. ACPIInternalUpdateFlags(
  174. &(deviceExtension->Flags),
  175. OptionalFlags,
  176. FALSE
  177. );
  178. //
  179. // Make sure to queue the request
  180. //
  181. status = ACPIBuildDeviceRequest(
  182. deviceExtension,
  183. NULL,
  184. NULL,
  185. FALSE
  186. );
  187. if (!NT_SUCCESS(status)) {
  188. ACPIPrint( (
  189. ACPI_PRINT_CRITICAL,
  190. "OSNotifyCreateDevice: ACPIBuildDeviceRequest(%p) = %08lx\n",
  191. deviceExtension,
  192. status
  193. ) );
  194. goto OSNotifyCreateDeviceExit;
  195. }
  196. OSNotifyCreateDeviceExit:
  197. //
  198. // There is some work that will be done later
  199. //
  200. return status;
  201. }
  202. NTSTATUS
  203. OSNotifyCreateOperationRegion(
  204. IN PNSOBJ AcpiObject
  205. )
  206. /*++
  207. Routine Description:
  208. This routine is called whenever a new operation region is created.
  209. This routine is callable at DispatchLevel.
  210. Arguments:
  211. AcpiObject - Pointer to the new ACPI Operation Region Object
  212. Return Value:
  213. NTSTATUS
  214. --*/
  215. {
  216. PDEVICE_EXTENSION parentExtension;
  217. PNSOBJ parentObject;
  218. POPREGIONOBJ opRegion;
  219. //
  220. // Sanity Check
  221. //
  222. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  223. ASSERT( AcpiObject != NULL );
  224. ASSERT( NSGETOBJTYPE(AcpiObject) == OBJTYPE_OPREGION );
  225. ASSERT( AcpiObject->ObjData.pbDataBuff != NULL );
  226. //
  227. // Get the OpRegion Object from the namespace object
  228. //
  229. opRegion = (POPREGIONOBJ) AcpiObject->ObjData.pbDataBuff;
  230. if (opRegion->bRegionSpace != REGSPACE_PCIBARTARGET) {
  231. //
  232. // This isn't a PCI Bar Target Operation Region, so there
  233. // is nothing to do
  234. //
  235. return STATUS_SUCCESS;
  236. }
  237. //
  238. // There are two cases to consider. The first case is the
  239. // one where the Operation Region is "static" in nature and
  240. // thus exists under some sort of device. The second case is
  241. // the one where the Operation Region is "dynamic" in nature
  242. // and thus exists under some sort of method. So, we want to
  243. // look at parent objects until we hit one that isn't a method
  244. // or is a device...
  245. //
  246. parentObject = AcpiObject->pnsParent;
  247. while (parentObject != NULL) {
  248. //
  249. // If the parent object is a method, then look at its parent
  250. //
  251. if (NSGETOBJTYPE(parentObject) == OBJTYPE_METHOD) {
  252. parentObject = parentObject->pnsParent;
  253. continue;
  254. }
  255. //
  256. // If the parent object isn't a device, then stop...
  257. //
  258. if (NSGETOBJTYPE(parentObject) != OBJTYPE_DEVICE) {
  259. break;
  260. }
  261. //
  262. // Grab the device extension (bad things happen if it doesn't
  263. // already exist
  264. //
  265. parentExtension = (PDEVICE_EXTENSION) parentObject->Context;
  266. if (parentExtension) {
  267. ACPIInternalUpdateFlags(
  268. &(parentExtension->Flags),
  269. DEV_CAP_PCI_BAR_TARGET,
  270. FALSE
  271. );
  272. }
  273. break;
  274. }
  275. //
  276. // Done
  277. //
  278. return STATUS_SUCCESS;
  279. }
  280. NTSTATUS
  281. OSNotifyCreatePowerResource(
  282. IN PNSOBJ AcpiObject
  283. )
  284. /*++
  285. Routine Description:
  286. This routine is called whenever a new power resource appears. This routine
  287. is callable at DispatchLevel.
  288. Arguments:
  289. AcpiObject - Pointer to new ACPI Object
  290. Return Value:
  291. NTSTATUS
  292. --*/
  293. {
  294. NTSTATUS status;
  295. PACPI_POWER_DEVICE_NODE powerNode;
  296. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  297. ASSERT( AcpiObject != NULL);
  298. //
  299. // Build the power extension
  300. //
  301. status = ACPIBuildPowerResourceExtension( AcpiObject, &powerNode );
  302. //
  303. // What happened?
  304. //
  305. if (!NT_SUCCESS(status)) {
  306. ACPIPrint( (
  307. ACPI_PRINT_CRITICAL,
  308. "OSNotifyCreatePowerResource: %p = %08lx\n",
  309. AcpiObject,
  310. status
  311. ) );
  312. goto OSNotifyCreatePowerResourceExit;
  313. }
  314. //
  315. // Make sure to request that this node gets processed
  316. //
  317. status = ACPIBuildPowerResourceRequest(
  318. powerNode,
  319. NULL,
  320. NULL,
  321. FALSE
  322. );
  323. if (!NT_SUCCESS(status)) {
  324. ACPIPrint( (
  325. ACPI_PRINT_CRITICAL,
  326. "OSNotifyCreatePowerResource: "
  327. "ACPIBuildPowerResourceRequest(%p) = %08lx\n",
  328. powerNode,
  329. status
  330. ) );
  331. goto OSNotifyCreatePowerResourceExit;
  332. }
  333. OSNotifyCreatePowerResourceExit:
  334. //
  335. // Done
  336. //
  337. return status;
  338. }
  339. NTSTATUS
  340. OSNotifyCreateProcessor(
  341. IN PNSOBJ AcpiObject,
  342. IN ULONGLONG OptionalFlags
  343. )
  344. /*++
  345. Routine Description:
  346. This routine is called whenever a new processor appears. This routine
  347. is callable at DispatchLevel.
  348. Arguments:
  349. AcpiObject - Pointer to the new ACPI object
  350. OptionalFlags - Properties of the Device Extension that should be
  351. set when its created.
  352. Return Value:
  353. NTSTATUS
  354. --*/
  355. {
  356. NTSTATUS status = STATUS_SUCCESS;
  357. PDEVICE_EXTENSION deviceExtension = NULL;
  358. PDEVICE_EXTENSION parentExtension;
  359. PNSOBJ parentObject;
  360. UCHAR index = 0;
  361. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  362. ASSERT( AcpiObject != NULL);
  363. //
  364. // Note: ProcessorList is now implicitly protected by the device tree
  365. // lock since we need to acquire that lock before calling this function
  366. //
  367. //
  368. while (ProcessorList[index] && index < ACPI_SUPPORTED_PROCESSORS) {
  369. index++;
  370. }
  371. //
  372. // We must make sure that the current entry is empty...
  373. //
  374. if (index >= ACPI_SUPPORTED_PROCESSORS || ProcessorList[index] != NULL) {
  375. return STATUS_UNSUCCESSFUL;
  376. }
  377. ACPIPrint( (
  378. ACPI_PRINT_LOADING,
  379. "OSNotifyCreateProcessor: Processor Object #%x: %x\n",
  380. index+1,
  381. AcpiObject
  382. ) );
  383. //
  384. // Remember that to store where the new processor object is located
  385. //
  386. ProcessorList[index] = AcpiObject;
  387. //
  388. // First, we need a pointer to the parent node
  389. //
  390. parentObject = AcpiObject->pnsParent;
  391. ASSERT( parentObject != NULL );
  392. //
  393. // Grab the device extension associated with the parent. We need
  394. // this information to help link the parent properly into the tree
  395. //
  396. parentExtension = (PDEVICE_EXTENSION) parentObject->Context;
  397. if (parentExtension == NULL) {
  398. //
  399. // In this case, we can assume that the parent extension is the root
  400. // device extension.
  401. //
  402. parentExtension = RootDeviceExtension;
  403. }
  404. ASSERT( parentExtension != NULL );
  405. //
  406. // Now build an extension for the node
  407. //
  408. status = ACPIBuildProcessorExtension(
  409. AcpiObject,
  410. parentExtension,
  411. &deviceExtension,
  412. index
  413. );
  414. if (NT_SUCCESS(status)) {
  415. //
  416. // Incremement the reference count on the node. We do this because
  417. // we are going to be doing work (which will take a long time
  418. // to complete, anyways), and we don't want to hold the lock for that
  419. // entire time. If we incr the reference count, then we guarantee that
  420. // no one can come along and kick the feet out from underneath us
  421. //
  422. InterlockedIncrement( &(deviceExtension->ReferenceCount) );
  423. }
  424. //
  425. // What happend to the creation of the extension?
  426. //
  427. if (!NT_SUCCESS(status)) {
  428. //
  429. // We should have succeeded at whatever we are doing --- so this is
  430. // a bad place to be
  431. //
  432. ACPIPrint( (
  433. ACPI_PRINT_CRITICAL,
  434. "OSNotifyCreateProcessor: NSObj %p Failed %08lx\n",
  435. AcpiObject,
  436. status
  437. ) );
  438. goto OSNotifyCreateProcessorExit;
  439. }
  440. //
  441. // Set the optional flags if there are any
  442. //
  443. ACPIInternalUpdateFlags(
  444. &(deviceExtension->Flags),
  445. OptionalFlags,
  446. FALSE
  447. );
  448. //
  449. // Make sure to queue the request
  450. //
  451. status = ACPIBuildProcessorRequest(
  452. deviceExtension,
  453. NULL,
  454. NULL,
  455. FALSE
  456. );
  457. if (!NT_SUCCESS(status)) {
  458. ACPIPrint( (
  459. ACPI_PRINT_CRITICAL,
  460. "OSNotifyCreateProcessor: "
  461. "ACPIBuildProcessorRequest(%p) = %08lx\n",
  462. deviceExtension,
  463. status
  464. ) );
  465. goto OSNotifyCreateProcessorExit;
  466. }
  467. OSNotifyCreateProcessorExit:
  468. //
  469. // There is some work that will be done later
  470. //
  471. return status;
  472. }
  473. NTSTATUS
  474. OSNotifyCreateThermalZone(
  475. IN PNSOBJ AcpiObject,
  476. IN ULONGLONG OptionalFlags
  477. )
  478. /*++
  479. Routine Description:
  480. This routine is called whenever a new thermal zone appears. This routine is
  481. callable at DispatchLevel.
  482. Arguments:
  483. AcpiObject - Pointer to new ACPI Object
  484. OptionalFlags - Properties of the Device Extension that should be
  485. set when its created.
  486. Return Value:
  487. NTSTATUS
  488. --*/
  489. {
  490. NTSTATUS status = STATUS_SUCCESS;
  491. PDEVICE_EXTENSION deviceExtension = NULL;
  492. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  493. ASSERT( AcpiObject != NULL);
  494. //
  495. // Now build an extension for the node
  496. //
  497. status = ACPIBuildThermalZoneExtension(
  498. AcpiObject,
  499. RootDeviceExtension,
  500. &deviceExtension
  501. );
  502. if (NT_SUCCESS(status)) {
  503. //
  504. // Incremement the reference count on the node. We do this because
  505. // we are going to be doing work (which will take a long time
  506. // to complete, anyways), and we don't want to hold the lock for that
  507. // entire time. If we incr the reference count, then we guarantee that
  508. // no one can come along and kick the feet out from underneath us
  509. //
  510. InterlockedIncrement( &(deviceExtension->ReferenceCount) );
  511. }
  512. //
  513. // What happend to the creation of the extension?
  514. //
  515. if (!NT_SUCCESS(status)) {
  516. //
  517. // We should have succeeded at whatever we are doing --- so this is
  518. // a bad place to be
  519. //
  520. ACPIPrint( (
  521. ACPI_PRINT_CRITICAL,
  522. "OSNotifyCreateThermalZone: NSObj %p Failed %08lx\n",
  523. AcpiObject,
  524. status
  525. ) );
  526. goto OSNotifyCreateThermalZoneExit;
  527. }
  528. //
  529. // Set the optional flags if there are any
  530. //
  531. ACPIInternalUpdateFlags(
  532. &(deviceExtension->Flags),
  533. OptionalFlags,
  534. FALSE
  535. );
  536. //
  537. // Make sure to queue the request
  538. //
  539. status = ACPIBuildThermalZoneRequest(
  540. deviceExtension,
  541. NULL,
  542. NULL,
  543. FALSE
  544. );
  545. if (!NT_SUCCESS(status)) {
  546. ACPIPrint( (
  547. ACPI_PRINT_CRITICAL,
  548. "OSNotifyCreateThermalZone: "
  549. "ACPIBuildThermalZoneRequest(%p) = %08lx\n",
  550. deviceExtension,
  551. status
  552. ) );
  553. goto OSNotifyCreateThermalZoneExit;
  554. }
  555. OSNotifyCreateThermalZoneExit:
  556. //
  557. // There is some work that will be done later
  558. //
  559. return status;
  560. }
  561. NTSTATUS
  562. EXPORT
  563. OSNotifyDeviceCheck(
  564. IN PNSOBJ AcpiObject
  565. )
  566. /*++
  567. Routine Description:
  568. This routine is called when the AML Interpreter signals that the
  569. System should check the presence of a device. If the device remains
  570. present, nothing is done. If the device appears or disappears the
  571. appropriate action is taken.
  572. For legacy reasons, if the device is a dock we initiate an undock request.
  573. Newer ACPI BIOS's should use Notify(,3).
  574. Arguments:
  575. AcpiObject - The device we should check for new/missing children.
  576. Return Value:
  577. NTSTATUS
  578. --*/
  579. {
  580. PDEVICE_EXTENSION deviceExtension;
  581. ASSERT( AcpiObject != NULL );
  582. //
  583. // Let the world know
  584. //
  585. ACPIPrint( (
  586. ACPI_PRINT_PNP,
  587. "OSNotifyDeviceCheck: 0x%p (%s)\n",
  588. AcpiObject,
  589. ACPIAmliNameObject( AcpiObject )
  590. ) );
  591. deviceExtension = (PDEVICE_EXTENSION) AcpiObject->Context;
  592. if (deviceExtension == NULL) {
  593. return STATUS_SUCCESS;
  594. }
  595. //
  596. // Notify(,1) on a dock node is an eject request request. Handle specially.
  597. //
  598. if (ACPIDockIsDockDevice(AcpiObject)) {
  599. //
  600. // We only let BIOS's get away with this because we rev'd the spec
  601. // after Win98. Both OS's will agree with the release of NT5 and
  602. // Win98 SP1
  603. //
  604. ACPIPrint( (
  605. ACPI_PRINT_WARNING,
  606. "OSNotifyDeviceCheck: BIOS issued Notify(dock,1), should use "
  607. " Notify(dock,3) to request ejection of a dock.\n",
  608. AcpiObject,
  609. ACPIAmliNameObject( AcpiObject )
  610. ) );
  611. return OSNotifyDeviceEject(AcpiObject) ;
  612. }
  613. //
  614. // Search for the parent of the first device that the OS is aware, and
  615. // issue a device check notify
  616. //
  617. // N.B.
  618. // There is currently no way in WDM to do a "light" device check. Once
  619. // this is amended, the following code should be updated to do something
  620. // more efficient.
  621. //
  622. deviceExtension = deviceExtension->ParentExtension;
  623. while (deviceExtension) {
  624. if (!(deviceExtension->Flags & DEV_TYPE_NOT_FOUND)) {
  625. //
  626. // Invalid the device relations for this device tree
  627. //
  628. IoInvalidateDeviceRelations(
  629. deviceExtension->PhysicalDeviceObject,
  630. BusRelations
  631. );
  632. break;
  633. }
  634. //
  635. // Try the parent device
  636. //
  637. deviceExtension = deviceExtension->ParentExtension;
  638. }
  639. //
  640. // Done
  641. //
  642. return STATUS_SUCCESS;
  643. }
  644. NTSTATUS
  645. EXPORT
  646. OSNotifyDeviceEnum(
  647. IN PNSOBJ AcpiObject
  648. )
  649. /*++
  650. Routine Description:
  651. This routine is called when the AML Interpreter signals that the
  652. System should re-enumerate the device
  653. Arguments:
  654. AcpiObject - The device we should check for new/missing children.
  655. Return Value:
  656. NTSTATUS
  657. --*/
  658. {
  659. PDEVICE_EXTENSION deviceExtension;
  660. PDEVICE_EXTENSION dockExtension;
  661. ASSERT( AcpiObject != NULL );
  662. //
  663. // Let the world know
  664. //
  665. ACPIPrint( (
  666. ACPI_PRINT_PNP,
  667. "OSNotifyDeviceEnum: 0x%p (%s)\n",
  668. AcpiObject,
  669. ACPIAmliNameObject( AcpiObject )
  670. ) );
  671. deviceExtension = (PDEVICE_EXTENSION) AcpiObject->Context;
  672. if (deviceExtension == NULL) {
  673. return STATUS_SUCCESS;
  674. }
  675. //
  676. // Notify(,0) on a dock node is a dock request. Handle specially.
  677. //
  678. if (ACPIDockIsDockDevice(AcpiObject)) {
  679. dockExtension = ACPIDockFindCorrespondingDock( deviceExtension );
  680. if (!dockExtension) {
  681. ACPIPrint( (
  682. ACPI_PRINT_FAILURE,
  683. "OSNotifyDeviceEnum: Dock device 0x%p (%s) "
  684. "does not have a profile provider!\n",
  685. AcpiObject,
  686. ACPIAmliNameObject( AcpiObject )
  687. ) );
  688. return STATUS_SUCCESS;
  689. }
  690. //
  691. // If this node is marked "Unknown", move it to "Isolated" as
  692. // Notify(Dock,0) was ran. If we never saw Notify(Dock,0) but the
  693. // dock's _STA said "here", we would assume _DCK(0) was ran by the BIOS
  694. // itself.
  695. //
  696. InterlockedCompareExchange(
  697. (PULONG) &dockExtension->Dock.IsolationState,
  698. IS_ISOLATED,
  699. IS_UNKNOWN
  700. );
  701. if (dockExtension->Dock.IsolationState == IS_ISOLATED) {
  702. if (dockExtension->Flags&DEV_TYPE_NOT_FOUND) {
  703. //
  704. // We haven't made a PDO for the docking station yet. This may
  705. // be a request to bring it online. Mark the profile provider
  706. // so that we notice the new dock appearing
  707. //
  708. ACPIInternalUpdateFlags(
  709. &dockExtension->Flags,
  710. DEV_CAP_UNATTACHED_DOCK,
  711. FALSE
  712. );
  713. }
  714. //
  715. // Invalidate the beginning of the tree. This will cause our fake
  716. // dock node to start.
  717. //
  718. IoInvalidateDeviceRelations(
  719. RootDeviceExtension->PhysicalDeviceObject,
  720. SingleBusRelations
  721. );
  722. }
  723. return STATUS_SUCCESS;
  724. }
  725. //
  726. // Search for the parent of the first device that the OS is aware, and
  727. // issue a device check notify
  728. //
  729. while (deviceExtension) {
  730. if (!(deviceExtension->Flags & DEV_TYPE_NOT_FOUND)) {
  731. //
  732. // Invalid the device relations for this device tree
  733. //
  734. IoInvalidateDeviceRelations(
  735. deviceExtension->PhysicalDeviceObject,
  736. BusRelations
  737. );
  738. break;
  739. }
  740. //
  741. // Try the parent device
  742. //
  743. deviceExtension = deviceExtension->ParentExtension;
  744. }
  745. //
  746. // Done
  747. //
  748. return STATUS_SUCCESS;
  749. }
  750. NTSTATUS
  751. EXPORT
  752. OSNotifyDeviceEject(
  753. IN PNSOBJ AcpiObject
  754. )
  755. /*++
  756. Routine Description:
  757. This routine is called when the device's eject button is pressed
  758. Arguments:
  759. AcpiObject - The device to be ejected
  760. Return Value:
  761. NTSTATUS
  762. --*/
  763. {
  764. PDEVICE_EXTENSION deviceExtension;
  765. ASSERT( AcpiObject != NULL );
  766. //
  767. // Let the world know
  768. //
  769. ACPIPrint( (
  770. ACPI_PRINT_REMOVE,
  771. "OSNotifyDeviceEject: 0x%p (%s)\n",
  772. AcpiObject,
  773. ACPIAmliNameObject( AcpiObject )
  774. ) );
  775. //
  776. // Inform the OS of which device wants to go away. If the OS doesn't
  777. // know about the device, then don't bother
  778. //
  779. deviceExtension = (PDEVICE_EXTENSION) AcpiObject->Context;
  780. //
  781. // If this is a dock, queue the eject against the profile provider.
  782. //
  783. if (ACPIDockIsDockDevice(AcpiObject)) {
  784. deviceExtension = ACPIDockFindCorrespondingDock( deviceExtension );
  785. if (!deviceExtension) {
  786. ACPIPrint( (
  787. ACPI_PRINT_FAILURE,
  788. "OSNotifyDeviceEject: Dock device 0x%p (%s) "
  789. "does not have a profile provider!\n",
  790. AcpiObject,
  791. ACPIAmliNameObject( AcpiObject )
  792. ) );
  793. return STATUS_SUCCESS;
  794. }
  795. }
  796. if (deviceExtension && !(deviceExtension->Flags & DEV_TYPE_NOT_FOUND)) {
  797. IoRequestDeviceEject (deviceExtension->PhysicalDeviceObject);
  798. }
  799. //
  800. // Done
  801. //
  802. return STATUS_SUCCESS;
  803. }
  804. NTSTATUS
  805. EXPORT
  806. OSNotifyDeviceWake(
  807. IN PNSOBJ AcpiObject
  808. )
  809. /*++
  810. Routine Description:
  811. This is called when a device has woken the computer
  812. Arguments:
  813. AcpiObject - The device which woke the computer
  814. Return Value:
  815. NTSTATUS
  816. --*/
  817. {
  818. KIRQL oldIrql;
  819. NTSTATUS status = STATUS_SUCCESS;
  820. PDEVICE_EXTENSION deviceExtension;
  821. PLIST_ENTRY powerList;
  822. ASSERT( AcpiObject != NULL );
  823. //
  824. // Grab the device extension associated with this NS object
  825. //
  826. deviceExtension = (PDEVICE_EXTENSION) AcpiObject->Context;
  827. ASSERT( deviceExtension != NULL );
  828. //
  829. // Let the world know
  830. //
  831. ACPIDevPrint( (
  832. ACPI_PRINT_WAKE,
  833. deviceExtension,
  834. "OSNotifyDeviceWake - 0x%p (%s)\n",
  835. AcpiObject,
  836. ACPIAmliNameObject( AcpiObject )
  837. ) );
  838. //
  839. // Initialize the list that will hold the requests
  840. //
  841. powerList = ExAllocatePoolWithTag(
  842. NonPagedPool,
  843. sizeof(LIST_ENTRY),
  844. ACPI_MISC_POOLTAG
  845. );
  846. if (powerList == NULL) {
  847. ACPIDevPrint( (
  848. ACPI_PRINT_CRITICAL,
  849. deviceExtension,
  850. "OSNotifyDeviceWake - Cannot Allocate LIST_ENTRY\n"
  851. ) );
  852. return STATUS_SUCCESS;
  853. }
  854. InitializeListHead( powerList );
  855. //
  856. // Remove the affected requests from the wait list
  857. //
  858. IoAcquireCancelSpinLock( &oldIrql );
  859. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  860. ACPIWakeRemoveDevicesAndUpdate( deviceExtension, powerList );
  861. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  862. IoReleaseCancelSpinLock( oldIrql );
  863. //
  864. // If the list is non-empty, then disable those requests
  865. //
  866. if (!IsListEmpty( powerList ) ) {
  867. status = ACPIWakeDisableAsync(
  868. deviceExtension,
  869. powerList,
  870. OSNotifyDeviceWakeCallBack,
  871. powerList
  872. );
  873. if (status != STATUS_PENDING) {
  874. OSNotifyDeviceWakeCallBack(
  875. NULL,
  876. status,
  877. NULL,
  878. powerList
  879. );
  880. }
  881. ACPIDevPrint( (
  882. ACPI_PRINT_WAKE,
  883. deviceExtension,
  884. "OSNotifyDeviceWake - ACPIWakeDisableAsync = %08lx\n",
  885. status
  886. ) );
  887. } else {
  888. //
  889. // We must free this memory ourselves
  890. //
  891. ExFreePool( powerList );
  892. }
  893. //
  894. // Done
  895. //
  896. return STATUS_SUCCESS;
  897. }
  898. VOID
  899. EXPORT
  900. OSNotifyDeviceWakeCallBack(
  901. IN PNSOBJ AcpiObject,
  902. IN NTSTATUS Status,
  903. IN POBJDATA ObjectData,
  904. IN PVOID Context
  905. )
  906. /*++
  907. Routine Description:
  908. This routine is called when we have completed _PSW(off) on a device
  909. Arguments:
  910. AcpiObject - Points to the control method that was run
  911. Status - Result of the method
  912. ObjectData - Information about the result
  913. Context - P{DEVICE_EXTENSION
  914. Return Value:
  915. NTSTATUS
  916. --*/
  917. {
  918. #if DBG
  919. PACPI_POWER_REQUEST powerRequest;
  920. PDEVICE_EXTENSION deviceExtension;
  921. #endif
  922. PLIST_ENTRY powerList = (PLIST_ENTRY) Context;
  923. //
  924. // Do we have some work to do?
  925. //
  926. if (IsListEmpty( powerList ) ) {
  927. ACPIPrint( (
  928. ACPI_PRINT_WARNING,
  929. "OSNotifyDeviceWakeCallBack: %p is an empty list\n",
  930. powerList
  931. ) );
  932. ExFreePool( powerList );
  933. return;
  934. }
  935. #if DBG
  936. //
  937. // Get the first record, so that we have a clue as to the device
  938. // that was completed
  939. //
  940. powerRequest = CONTAINING_RECORD(
  941. powerList->Flink,
  942. ACPI_POWER_REQUEST,
  943. ListEntry
  944. );
  945. ASSERT( powerRequest->Signature == ACPI_SIGNATURE );
  946. //
  947. // Grab the device extension
  948. //
  949. deviceExtension = powerRequest->DeviceExtension;
  950. //
  951. // Tell the world
  952. //
  953. ACPIDevPrint( (
  954. ACPI_PRINT_WAKE,
  955. deviceExtension,
  956. "OSNotifyDeviceWakeCallBack = 0x%08lx\n",
  957. Status
  958. ) );
  959. #endif
  960. //
  961. // Complete the requests
  962. //
  963. ACPIWakeCompleteRequestQueue(
  964. powerList,
  965. Status
  966. );
  967. //
  968. // Free the list pointer
  969. //
  970. ExFreePool( powerList );
  971. }
  972. VOID
  973. EXPORT
  974. OSNotifyDeviceWakeByGPEEvent(
  975. IN ULONG GpeIndex,
  976. IN ULONG GpeRegister,
  977. IN ULONG GpeMask
  978. )
  979. /*++
  980. Routine Description:
  981. This is called when a device has woken the computer
  982. Arguments:
  983. GpeIndex - The index bit of the GPE that woke the computer
  984. GpeRegister - The register index
  985. GpeMask - The enabled bits for that register
  986. Return Value:
  987. NTSTATUS
  988. --*/
  989. {
  990. KIRQL oldIrql;
  991. NTSTATUS status;
  992. PACPI_POWER_REQUEST powerRequest;
  993. PDEVICE_EXTENSION deviceExtension;
  994. PLIST_ENTRY listEntry;
  995. PLIST_ENTRY powerList;
  996. //
  997. // Let the world know
  998. //
  999. ACPIPrint( (
  1000. ACPI_PRINT_WAKE,
  1001. "OSNotifyDeviceWakeByGPEEvent: %02lx[%x] & %02lx\n",
  1002. GpeRegister, GpeIndex, GpeMask
  1003. ) );
  1004. //
  1005. // Initialize the list that will hold the requests
  1006. //
  1007. powerList = ExAllocatePoolWithTag(
  1008. NonPagedPool,
  1009. sizeof(LIST_ENTRY),
  1010. ACPI_MISC_POOLTAG
  1011. );
  1012. if (powerList == NULL) {
  1013. ACPIPrint( (
  1014. ACPI_PRINT_CRITICAL,
  1015. "OSNotifyDeviceWakeByGPEEvent: Cannot Allocate LIST_ENTRY\n"
  1016. ) );
  1017. return;
  1018. }
  1019. InitializeListHead( powerList );
  1020. //
  1021. // We need to be holding these locks
  1022. //
  1023. IoAcquireCancelSpinLock( &oldIrql );
  1024. KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
  1025. //
  1026. // Look for a matching power request for this GPE
  1027. //
  1028. for (listEntry = AcpiPowerWaitWakeList.Flink;
  1029. listEntry != &AcpiPowerWaitWakeList;
  1030. listEntry = listEntry->Flink) {
  1031. //
  1032. // Grab the request
  1033. //
  1034. powerRequest = CONTAINING_RECORD(
  1035. listEntry,
  1036. ACPI_POWER_REQUEST,
  1037. ListEntry
  1038. );
  1039. ASSERT( powerRequest->Signature == ACPI_SIGNATURE );
  1040. deviceExtension = powerRequest->DeviceExtension;
  1041. //
  1042. // See if this request matches
  1043. //
  1044. if (deviceExtension->PowerInfo.WakeBit == GpeIndex) {
  1045. //
  1046. // Get all of the wait requests for this device
  1047. //
  1048. ACPIWakeRemoveDevicesAndUpdate( deviceExtension, powerList );
  1049. break;
  1050. }
  1051. }
  1052. //
  1053. // This is an exclusive wake gpe bit --- verify there are not multiple
  1054. // devices waiting for it, as that would be a design which could cause a
  1055. // deadlock
  1056. //
  1057. if (!IsListEmpty( powerList ) ) {
  1058. ASSERT( !(GpeWakeEnable[GpeRegister] & GpeMask) );
  1059. }
  1060. //
  1061. // No longer need these locks
  1062. //
  1063. KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
  1064. IoReleaseCancelSpinLock( oldIrql );
  1065. //
  1066. // If the list is non-empty, then disable those requests
  1067. //
  1068. if (!IsListEmpty( powerList ) ) {
  1069. status = ACPIWakeDisableAsync(
  1070. deviceExtension,
  1071. powerList,
  1072. OSNotifyDeviceWakeCallBack,
  1073. powerList
  1074. );
  1075. if (status != STATUS_PENDING) {
  1076. OSNotifyDeviceWakeCallBack(
  1077. NULL,
  1078. status,
  1079. NULL,
  1080. powerList
  1081. );
  1082. }
  1083. ACPIDevPrint( (
  1084. ACPI_PRINT_WAKE,
  1085. deviceExtension,
  1086. "OSNotifyDeviceWakeByGPEIndex - ACPIWakeDisableAsync = %08lx\n",
  1087. status
  1088. ) );
  1089. } else {
  1090. //
  1091. // We must free this memory ourselves
  1092. //
  1093. ExFreePool( powerList );
  1094. }
  1095. //
  1096. // Done
  1097. //
  1098. return;
  1099. }
  1100. NTSTATUS
  1101. EXPORT
  1102. OSNotifyFatalError(
  1103. IN ULONG Param1,
  1104. IN ULONG Param2,
  1105. IN ULONG Param3,
  1106. IN ULONG_PTR AmlContext,
  1107. IN ULONG_PTR Context
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. This routine is called whenever the AML code detects a condition that the
  1112. machine can no longer handle. It
  1113. --*/
  1114. {
  1115. KIRQL oldIrql;
  1116. //
  1117. // Acquire the spinlock and see if there is an outstanding fatal error
  1118. // pending already
  1119. //
  1120. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  1121. if (AcpiFatalOutstanding != FALSE) {
  1122. //
  1123. // There is one outstanding already... don't do anything
  1124. //
  1125. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  1126. return STATUS_SUCCESS;
  1127. }
  1128. //
  1129. // Remember that there is an outstanding fatal context and release the lock
  1130. AcpiFatalOutstanding = TRUE;
  1131. KeReleaseSpinLock(&AcpiPowerLock, oldIrql);
  1132. //
  1133. // Initialize the work queue
  1134. //
  1135. ExInitializeWorkItem(
  1136. &(AcpiFatalContext.Item),
  1137. OSNotifyFatalErrorWorker,
  1138. &AcpiFatalContext
  1139. );
  1140. AcpiFatalContext.Param1 = Param1;
  1141. AcpiFatalContext.Param2 = Param2;
  1142. AcpiFatalContext.Param3 = Param3;
  1143. AcpiFatalContext.Context = AmlContext;
  1144. //
  1145. // Queue the work item and return
  1146. //
  1147. ExQueueWorkItem( &(AcpiFatalContext.Item), DelayedWorkQueue );
  1148. return STATUS_SUCCESS;
  1149. }
  1150. VOID
  1151. OSNotifyFatalErrorWorker(
  1152. IN PVOID Context
  1153. )
  1154. /*++
  1155. Routine Description:
  1156. This is the routine that actually shuts down the machine on a fatal
  1157. error
  1158. Arguments:
  1159. Context - Points to the fatal error context
  1160. Return Value:
  1161. None
  1162. --*/
  1163. {
  1164. PACPI_FATAL_ERROR_CONTEXT fatal = (PACPI_FATAL_ERROR_CONTEXT) Context;
  1165. #if 0
  1166. PWCHAR stringData[1];
  1167. ULONG data[3];
  1168. //
  1169. // Generate the parameters for an error log message
  1170. //
  1171. stringData[0] = L"Acpi";
  1172. data[0] = fatal->Param1;
  1173. data[1] = fatal->Param2;
  1174. data[2] = fatal->Param3;
  1175. //
  1176. // Write the error log message
  1177. //
  1178. ACPIErrLogWriteEventLogEntry(
  1179. ACPI_ERR_BIOS_FATAL,
  1180. 0,
  1181. 1,
  1182. &stringData,
  1183. sizeof(ULONG) * 3,
  1184. data
  1185. );
  1186. #else
  1187. //
  1188. // Now, we can bugcheck
  1189. //
  1190. PoShutdownBugCheck(
  1191. TRUE,
  1192. ACPI_BIOS_FATAL_ERROR,
  1193. fatal->Param1,
  1194. fatal->Param2,
  1195. fatal->Param3,
  1196. fatal->Context
  1197. );
  1198. #endif
  1199. }