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.

1155 lines
27 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. cmbutton.c
  5. Abstract:
  6. Control Method Button support
  7. Author:
  8. Stephane Plante (splante)
  9. Environment:
  10. NT Kernel Model Driver only
  11. Revision History:
  12. July 7, 1997 - Complete Rewrite
  13. --*/
  14. #include "pch.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, ACPICMButtonStart)
  17. #pragma alloc_text(PAGE, ACPICMLidStart)
  18. #pragma alloc_text(PAGE, ACPICMPowerButtonStart)
  19. #pragma alloc_text(PAGE, ACPICMSleepButtonStart)
  20. #endif
  21. VOID
  22. ACPICMButtonNotify (
  23. IN PVOID Context,
  24. IN ULONG EventData
  25. )
  26. /*++
  27. Routine Description:
  28. AMLI device notification handler for control method button device
  29. Arguments:
  30. DeviceObject - fixed feature button device object
  31. EventData - The event code the device is notified with
  32. Return Value:
  33. NTSTATUS
  34. --*/
  35. {
  36. PDEVICE_EXTENSION deviceExtension;
  37. PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Context;
  38. ULONG capabilities;
  39. deviceExtension = ACPIInternalGetDeviceExtension(deviceObject);
  40. //
  41. // Handle event type
  42. //
  43. switch (EventData) {
  44. case 0x80:
  45. #if 0
  46. KeBugCheckEx(
  47. ACPI_BIOS_ERROR,
  48. 0,
  49. 0,
  50. 0,
  51. 0
  52. );
  53. #endif
  54. capabilities = deviceExtension->Button.Capabilities;
  55. if (capabilities & SYS_BUTTON_LID) {
  56. //
  57. // Get worker to check LID's status
  58. //
  59. ACPISetDeviceWorker( deviceExtension, LID_SIGNAL_EVENT);
  60. } else {
  61. //
  62. // Notify button was pressed
  63. //
  64. ACPIButtonEvent(
  65. deviceObject,
  66. capabilities & ~SYS_BUTTON_WAKE,
  67. NULL
  68. );
  69. }
  70. break;
  71. case 2:
  72. //
  73. // Signal wake button
  74. //
  75. ACPIButtonEvent (deviceObject, SYS_BUTTON_WAKE, NULL);
  76. break;
  77. default:
  78. ACPIDevPrint( (
  79. ACPI_PRINT_WARNING,
  80. deviceExtension,
  81. "ACPICMButtonNotify: Unknown CM butt notify code %d\n",
  82. EventData
  83. ) );
  84. break;
  85. }
  86. }
  87. NTSTATUS
  88. ACPICMButtonSetPower(
  89. IN PDEVICE_OBJECT DeviceObject,
  90. IN PIRP Irp
  91. )
  92. /*++
  93. Routine Description:
  94. This is the main routine for setting power to a button. It dispatches a
  95. WAIT_WAKE irp (if necessary) then calls the real worker function to
  96. put the button in the proper state
  97. Arguments:
  98. DeviceObject - The button device object
  99. Irp - The request that we are handling
  100. Return Value:
  101. NTSTATUS
  102. --*/
  103. {
  104. NTSTATUS status;
  105. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  106. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
  107. SYSTEM_POWER_STATE systemState;
  108. //
  109. // If this is request to go a specific D-state, pass that along and
  110. // return immediately --- there is nothing for us to do in this case
  111. //
  112. if (irpStack->Parameters.Power.Type == DevicePowerState) {
  113. goto ACPICMButtonSetPowerExit;
  114. }
  115. //
  116. // HACKHACK --- Some Vendors can't get their act together and need to
  117. // have _PSW(On) when the system boots, otherwise they cannot deliver
  118. // Button Press notification, so to accomodate those vendors, we have
  119. // enabled _PSW(On) for all button devices except lid switchs. So,
  120. // if we aren't a lid switch, then do nothing
  121. //
  122. if ( !(deviceExtension->Button.Capabilities & SYS_BUTTON_LID) ) {
  123. goto ACPICMButtonSetPowerExit;
  124. }
  125. //
  126. // If we don't support wake on the device, then there is nothing to do
  127. //
  128. if ( !(deviceExtension->Flags & DEV_CAP_WAKE) ) {
  129. goto ACPICMButtonSetPowerExit;
  130. }
  131. //
  132. // What system state are we going to go to?
  133. //
  134. systemState = irpStack->Parameters.Power.State.SystemState;
  135. if (systemState == PowerSystemWorking) {
  136. //
  137. // If we are transitioning back into D0, then we want to cancel
  138. // any outstanding WAIT_WAKE requests that we have
  139. //
  140. status = ACPICMButtonWaitWakeCancel( deviceExtension );
  141. if (!NT_SUCCESS(status)) {
  142. ACPIDevPrint( (
  143. ACPI_PRINT_FAILURE,
  144. deviceExtension,
  145. "%08lx: ACPICMButtonWaitWakeCancel = %08lx\n",
  146. Irp,
  147. status
  148. ) );
  149. goto ACPICMButtonSetPowerExit;
  150. }
  151. } else {
  152. //
  153. // Can we wake the system from this state?
  154. //
  155. if (deviceExtension->PowerInfo.SystemWakeLevel < systemState) {
  156. goto ACPICMButtonSetPowerExit;
  157. }
  158. //
  159. // Do not enable this behaviour by default
  160. //
  161. if ( (deviceExtension->Flags & DEV_PROP_NO_LID_ACTION) ) {
  162. goto ACPICMButtonSetPowerExit;
  163. #if 0
  164. //
  165. // If we are a lid switch and if the lid isn't closed
  166. // right now, then do not enable wake support.
  167. //
  168. if ( (deviceExtension->Button.LidState != 0) ) {
  169. //
  170. // The lid is open
  171. //
  172. goto ACPICMButtonSetPowerExit;
  173. }
  174. #endif
  175. }
  176. //
  177. // Send a WAIT_WAKE irp to ourselves
  178. //
  179. status = PoRequestPowerIrp(
  180. DeviceObject,
  181. IRP_MN_WAIT_WAKE,
  182. irpStack->Parameters.Power.State,
  183. ACPICMButtonWaitWakeComplete,
  184. NULL,
  185. NULL
  186. );
  187. if (!NT_SUCCESS(status)) {
  188. ACPIDevPrint( (
  189. ACPI_PRINT_FAILURE,
  190. deviceExtension,
  191. "(%08lx): ACPICMButtonSetPower - PoRequestPowerIrp = %08lx\n",
  192. Irp,
  193. status
  194. ) );
  195. goto ACPICMButtonSetPowerExit;
  196. }
  197. }
  198. ACPICMButtonSetPowerExit:
  199. //
  200. // Pass the irp to the normal dispatch point
  201. //
  202. return ACPIBusIrpSetPower(
  203. DeviceObject,
  204. Irp
  205. );
  206. }
  207. NTSTATUS
  208. ACPICMButtonStart (
  209. IN PDEVICE_OBJECT DeviceObject,
  210. IN PIRP Irp,
  211. IN ULONG ButtonType
  212. )
  213. /*++
  214. Routine Description:
  215. This is the main routine for starting a button. We remember what type
  216. of button we have then we start the button as we would any other device.
  217. We actually register device interfaces and the like in the worker function
  218. that the completion routine schedules for us.
  219. Arguments:
  220. DeviceObject - The device that is starting
  221. Irp - The start irp request
  222. ButtonType - What kind of button this is
  223. Return Value:
  224. NTSTATUS
  225. --*/
  226. {
  227. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  228. NTSTATUS status;
  229. PAGED_CODE();
  230. //
  231. // Initialize device support
  232. //
  233. KeInitializeSpinLock (&deviceExtension->Button.SpinLock);
  234. deviceExtension->Button.Capabilities = ButtonType;
  235. //
  236. // Start the device
  237. //
  238. status = ACPIInitStartDevice(
  239. DeviceObject,
  240. NULL,
  241. ACPICMButtonStartCompletion,
  242. Irp,
  243. Irp
  244. );
  245. if (NT_SUCCESS(status)) {
  246. return STATUS_PENDING;
  247. } else {
  248. return status;
  249. }
  250. }
  251. VOID
  252. ACPICMButtonStartCompletion(
  253. IN PDEVICE_EXTENSION DeviceExtension,
  254. IN PVOID Context,
  255. IN NTSTATUS Status
  256. )
  257. /*++
  258. Routine Description:
  259. This is the callback routine that is invoked when we have finished
  260. programming the resources.
  261. This routine queues the irp to a worker thread so that we can do the
  262. rest of the start device code. It will complete the irp, however, if
  263. the success is not STATUS_SUCCESS.
  264. Arguments:
  265. DeviceExtension - Extension of the device that was started
  266. Context - The Irp
  267. Status - The result
  268. Return Value:
  269. None
  270. --*/
  271. {
  272. PIRP irp = (PIRP) Context;
  273. PWORK_QUEUE_CONTEXT workContext = &(DeviceExtension->Pdo.WorkContext);
  274. irp->IoStatus.Status = Status;
  275. if (NT_SUCCESS(Status)) {
  276. DeviceExtension->DeviceState = Started;
  277. } else {
  278. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( irp );
  279. UCHAR minorFunction = irpStack->MinorFunction;
  280. //
  281. // Complete the irp --- we can do this at DPC level without problem
  282. //
  283. IoCompleteRequest( irp, IO_NO_INCREMENT );
  284. //
  285. // Let the world know
  286. //
  287. ACPIDevPrint( (
  288. ACPI_PRINT_IRP,
  289. DeviceExtension,
  290. "(0x%08lx): %s = 0x%08lx\n",
  291. irp,
  292. ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
  293. Status
  294. ) );
  295. return;
  296. }
  297. //
  298. // We can't run EnableDisableRegions at DPC level,
  299. // so queue a worker item.
  300. //
  301. ExInitializeWorkItem(
  302. &(workContext->Item),
  303. ACPICMButtonStartWorker,
  304. workContext
  305. );
  306. workContext->DeviceObject = DeviceExtension->DeviceObject;
  307. workContext->Irp = irp;
  308. ExQueueWorkItem(
  309. &(workContext->Item),
  310. DelayedWorkQueue
  311. );
  312. }
  313. VOID
  314. ACPICMButtonStartWorker(
  315. IN PVOID Context
  316. )
  317. /*++
  318. Routine Description:
  319. This routine is called at PASSIVE_LEVEL after we turned on the device
  320. It registers any interfaces we might need to use
  321. Arguments:
  322. Context - Contains the arguments passed to the START_DEVICE function
  323. Return Value:
  324. None
  325. --*/
  326. {
  327. NTSTATUS status;
  328. PDEVICE_EXTENSION deviceExtension;
  329. PDEVICE_OBJECT deviceObject;
  330. PIRP irp;
  331. PIO_STACK_LOCATION irpStack;
  332. PWORK_QUEUE_CONTEXT workContext = (PWORK_QUEUE_CONTEXT) Context;
  333. UCHAR minorFunction;
  334. //
  335. // Grab the parameters that we need out of the Context
  336. //
  337. deviceObject = workContext->DeviceObject;
  338. deviceExtension = ACPIInternalGetDeviceExtension(deviceObject);
  339. irp = workContext->Irp;
  340. irpStack = IoGetCurrentIrpStackLocation( irp );
  341. minorFunction = irpStack->MinorFunction;
  342. status = irp->IoStatus.Status;
  343. //
  344. // Update the status of the device
  345. //
  346. if (!NT_SUCCESS(status)) {
  347. goto ACPICMButtonStartWorkerExit;
  348. }
  349. //
  350. // If this is a lid switch, find out what the current state of
  351. // switch is
  352. //
  353. if (deviceExtension->Button.Capabilities & SYS_BUTTON_LID) {
  354. //
  355. // Register the callback. Ignore the return value as we will
  356. // don't really care if registration was successfull or not
  357. //
  358. status = ACPIInternalRegisterPowerCallBack(
  359. deviceExtension,
  360. (PCALLBACK_FUNCTION) ACPICMLidPowerStateCallBack
  361. );
  362. if (!NT_SUCCESS(status)) {
  363. status = STATUS_SUCCESS;
  364. }
  365. //
  366. // Force a callback to make sure that we initialize the lid to the
  367. // proper policy
  368. //
  369. ACPICMLidPowerStateCallBack(
  370. deviceExtension,
  371. PO_CB_SYSTEM_POWER_POLICY,
  372. 0
  373. );
  374. //
  375. // Note: Setting the events as 0x0 should just cause the
  376. // system to run ACPICMLidWorker() without causing any side
  377. // effects (like telling the system to go to sleep
  378. //
  379. ACPISetDeviceWorker( deviceExtension, 0 );
  380. } else {
  381. IO_STATUS_BLOCK ioStatus;
  382. KIRQL oldIrql;
  383. POWER_STATE powerState;
  384. //
  385. // Initialize the ioStatus block to enable the device's waitwake
  386. //
  387. ioStatus.Status = STATUS_SUCCESS;
  388. ioStatus.Information = 0;
  389. //
  390. // This is the S-state that we will try to wake the system from
  391. //
  392. KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
  393. powerState.SystemState = deviceExtension->PowerInfo.SystemWakeLevel;
  394. KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
  395. //
  396. // Start the WaitWake Loop
  397. //
  398. status = ACPIInternalWaitWakeLoop(
  399. deviceObject,
  400. IRP_MN_WAIT_WAKE,
  401. powerState,
  402. NULL,
  403. &ioStatus
  404. );
  405. if (!NT_SUCCESS(status)) {
  406. ACPIDevPrint( (
  407. ACPI_PRINT_FAILURE,
  408. deviceExtension,
  409. " - ACPIInternalWaitWakeLoop = %08lx\n",
  410. status
  411. ) );
  412. goto ACPICMButtonStartWorkerExit;
  413. }
  414. }
  415. //
  416. // Register for device notifies on this device
  417. //
  418. ACPIRegisterForDeviceNotifications(
  419. deviceObject,
  420. (PDEVICE_NOTIFY_CALLBACK) ACPICMButtonNotify,
  421. (PVOID) deviceObject
  422. );
  423. //
  424. // Register device as supporting system button ioctl
  425. //
  426. status = ACPIInternalSetDeviceInterface(
  427. deviceObject,
  428. (LPGUID) &GUID_DEVICE_SYS_BUTTON
  429. );
  430. if (!NT_SUCCESS(status)) {
  431. ACPIDevPrint( (
  432. ACPI_PRINT_WARNING,
  433. deviceExtension,
  434. "ACPICMButtonStartWorker: ACPIInternalSetDeviceInterface = %08lx\n",
  435. status
  436. ) );
  437. goto ACPICMButtonStartWorkerExit;
  438. }
  439. ACPICMButtonStartWorkerExit:
  440. //
  441. // Complete the request
  442. //
  443. irp->IoStatus.Status = status;
  444. irp->IoStatus.Information = (ULONG_PTR) NULL;
  445. IoCompleteRequest( irp, IO_NO_INCREMENT );
  446. //
  447. // Let the world know
  448. //
  449. ACPIDevPrint( (
  450. ACPI_PRINT_IRP,
  451. deviceExtension,
  452. "(0x%08lx): %s = 0x%08lx\n",
  453. irp,
  454. ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
  455. status
  456. ) );
  457. }
  458. NTSTATUS
  459. ACPICMButtonWaitWakeCancel(
  460. IN PDEVICE_EXTENSION DeviceExtension
  461. )
  462. /*++
  463. Routine Description:
  464. This routine cancels any outstanding WAIT_WAKE irp on the given
  465. device extension.
  466. The way that this code works is rather slimy. It is based on the
  467. assumption that the way that the Irp is cancelled doesn't really
  468. matter since the completion routine doesn't do anything interesting.
  469. So, the choice is that the driver can keep track of each WAIT WAKE
  470. irp the extension is associated with in the extension, write some
  471. complicated synchronization code to make sure that we don't cancel
  472. an IRP that could fire a WAIT WAKE, etc, etc, or we can simply fake
  473. a call that tells the OS that the device woke the system
  474. Arguments:
  475. DeviceExtension - The deviceExtension to cancel
  476. Return Value:
  477. NTSTATUS
  478. --*/
  479. { return OSNotifyDeviceWake( DeviceExtension->AcpiObject );
  480. }
  481. NTSTATUS
  482. ACPICMButtonWaitWakeComplete(
  483. IN PDEVICE_OBJECT DeviceObject,
  484. IN UCHAR MinorFunction,
  485. IN POWER_STATE PowerState,
  486. IN PVOID Context,
  487. IN PIO_STATUS_BLOCK IoStatus
  488. )
  489. /*++
  490. Routine Description:
  491. This routine is called when the button has awoken the system
  492. Arguments:
  493. DeviceObject - The device object which woke the computer
  494. MinorFunction - IRP_MN_WAIT_WAKE
  495. PowerState - The state that it woke the computer from
  496. Context - Not used
  497. IoStatus - The result of the request
  498. --*/
  499. {
  500. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  501. UNREFERENCED_PARAMETER( MinorFunction );
  502. UNREFERENCED_PARAMETER( PowerState );
  503. UNREFERENCED_PARAMETER( Context );
  504. if (!NT_SUCCESS(IoStatus->Status)) {
  505. ACPIDevPrint( (
  506. ACPI_PRINT_FAILURE,
  507. deviceExtension,
  508. "ACPICMButtonWaitWakeComplete - %08lx\n",
  509. IoStatus->Status
  510. ) );
  511. } else {
  512. ACPIDevPrint( (
  513. ACPI_PRINT_WAKE,
  514. deviceExtension,
  515. "ACPICMButtonWaitWakeComplete - %08lx\n",
  516. IoStatus->Status
  517. ) );
  518. }
  519. return IoStatus->Status;
  520. }
  521. VOID
  522. ACPICMLidPowerStateCallBack(
  523. IN PVOID CallBackContext,
  524. IN PVOID Argument1,
  525. IN PVOID Argument2
  526. )
  527. /*++
  528. Routine Description:
  529. This routine is called whenever the system changes the power policy.
  530. The purpose of this routine is to see wether or not the user placed
  531. an action on closing the lid. If there is, then we arm the behaviour
  532. that the lid should always wake up the computer. Otherwise, opening the
  533. lid should do nothing
  534. Arguments:
  535. CallBackContext - The DeviceExtension for the lid switch
  536. Argument1 - The action that is being undertaken
  537. Argument2 - Unused
  538. Return Value:
  539. None
  540. --*/
  541. {
  542. NTSTATUS status;
  543. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) CallBackContext;
  544. SYSTEM_POWER_POLICY powerPolicy;
  545. ULONG action = PtrToUlong(Argument1);
  546. UNREFERENCED_PARAMETER( Argument2 );
  547. //
  548. // We are looking for a PO_CB_SYSTEM_POWER_POLICY change
  549. //
  550. if (action != PO_CB_SYSTEM_POWER_POLICY) {
  551. return;
  552. }
  553. //
  554. // Get the information that we desired
  555. //
  556. status = ZwPowerInformation(
  557. SystemPowerPolicyCurrent,
  558. NULL,
  559. 0,
  560. &powerPolicy,
  561. sizeof(SYSTEM_POWER_POLICY)
  562. );
  563. if (!NT_SUCCESS(status)) {
  564. ACPIDevPrint( (
  565. ACPI_PRINT_FAILURE,
  566. deviceExtension,
  567. "ACPICMLidPowerStateCallBack - Failed ZwPowerInformation %8x\n",
  568. status
  569. ) );
  570. return;
  571. }
  572. //
  573. // Is there an action for the lid?
  574. //
  575. if (powerPolicy.LidClose.Action == PowerActionNone ||
  576. powerPolicy.LidClose.Action == PowerActionReserved) {
  577. ACPIInternalUpdateFlags(
  578. &(deviceExtension->Flags),
  579. DEV_PROP_NO_LID_ACTION,
  580. FALSE
  581. );
  582. } else {
  583. ACPIInternalUpdateFlags(
  584. &(deviceExtension->Flags),
  585. DEV_PROP_NO_LID_ACTION,
  586. TRUE
  587. );
  588. }
  589. }
  590. NTSTATUS
  591. ACPICMLidSetPower(
  592. IN PDEVICE_OBJECT DeviceObject,
  593. IN PIRP Irp
  594. )
  595. /*++
  596. Routine Description:
  597. This is the main routine for setting power to a lid. It dispatches a
  598. WAIT_WAKE irp (if necessary) then calls the real worker function to
  599. put the button in the proper state
  600. Arguments:
  601. DeviceObject - The button device object
  602. Irp - The request that we are handling
  603. Return Value:
  604. NTSTATUS
  605. --*/
  606. {
  607. NTSTATUS status;
  608. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  609. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
  610. PULONG lidState;
  611. //
  612. // If this is request to go a specific D-state, pass that along and
  613. // return immediately --- there is nothing for us to do in this case
  614. //
  615. if (irpStack->Parameters.Power.Type == DevicePowerState) {
  616. return ACPIBusIrpSetDevicePower( DeviceObject, Irp, irpStack );
  617. }
  618. //
  619. // HACKHACK
  620. //
  621. // We are going to want to know what the state of the lid is. We will
  622. // end up calling the interpreter at DPC level, so where we store the
  623. // lidState cannot be on the local stack. One nice place that we
  624. // can use is the Parameters.Power.Type field, since we already know
  625. // what the answer should be
  626. //
  627. lidState = (PULONG)&(irpStack->Parameters.Power.Type);
  628. //
  629. // Mark the irp as pending
  630. //
  631. IoMarkIrpPending( Irp );
  632. //
  633. // Evalute the integer
  634. //
  635. status = ACPIGetIntegerAsync(
  636. deviceExtension,
  637. PACKED_LID,
  638. ACPICMLidSetPowerCompletion,
  639. Irp,
  640. lidState,
  641. NULL
  642. );
  643. if (status != STATUS_PENDING) {
  644. ACPICMLidSetPowerCompletion(
  645. NULL,
  646. status,
  647. NULL,
  648. Irp
  649. );
  650. }
  651. //
  652. // Always return STATUS_PENDING --- if we complete the irp with
  653. // another status code, we will do so in another (maybe) context...
  654. //
  655. return STATUS_PENDING;
  656. }
  657. VOID
  658. EXPORT
  659. ACPICMLidSetPowerCompletion(
  660. IN PNSOBJ AcpiObject,
  661. IN NTSTATUS Status,
  662. IN POBJDATA Result,
  663. IN PVOID Context
  664. )
  665. /*++
  666. Routine Description:
  667. This routine is called when the system has finished fetching the
  668. current lid state for the switch
  669. Arguments:
  670. AcpiObject - The object that we ran (ie: _LID)
  671. Status - Did the operation succeed
  672. Result - The result of the operation
  673. Context - IRP
  674. Return Value:
  675. None
  676. --*/
  677. {
  678. BOOLEAN noticeStateChange = FALSE;
  679. KIRQL oldIrql;
  680. PDEVICE_EXTENSION deviceExtension;
  681. PDEVICE_OBJECT deviceObject;
  682. PIO_STACK_LOCATION irpStack;
  683. PIRP irp = (PIRP) Context;
  684. PULONG lidStateLocation;
  685. ULONG lidState;
  686. //
  687. // Get the current Irp Stack location
  688. //
  689. irpStack = IoGetCurrentIrpStackLocation( irp );
  690. //
  691. // Get the current device extension
  692. //
  693. deviceObject = irpStack->DeviceObject;
  694. deviceExtension = ACPIInternalGetDeviceExtension(deviceObject);
  695. //
  696. // Go and find the place were to told the OS to write the answer to the
  697. // _LID request. We should also reset this stack location to the proper
  698. // value
  699. //
  700. lidStateLocation = (PULONG)&(irpStack->Parameters.Power.Type);
  701. lidState = *lidStateLocation;
  702. *lidStateLocation = (ULONG) SystemPowerState;
  703. //
  704. // Did we succeed?
  705. //
  706. if (!NT_SUCCESS(Status)) {
  707. //
  708. // Note that we choose to pass the irp back to something
  709. // that will not send it a WAIT_WAKE irp
  710. //
  711. *lidStateLocation = (ULONG) SystemPowerState;
  712. ACPIBusIrpSetSystemPower( deviceObject, irp, irpStack );
  713. return;
  714. }
  715. //
  716. // Make sure that the lid state is a one or a zero
  717. //
  718. lidState = (lidState ? 1 : 0);
  719. //
  720. // Grab the button spinlock
  721. //
  722. KeAcquireSpinLock( &(deviceExtension->Button.SpinLock), &oldIrql );
  723. //
  724. // Did we the lid change state? Note that because we don't want the
  725. // user sleeping the machine, closing the lid, then the machine
  726. // waking up because of Wake-On-LAN causing the machine to go back
  727. // to sleep, the only state change that we care about is if the
  728. // lid went from the closed state to the open state
  729. //
  730. if (deviceExtension->Button.LidState == FALSE &&
  731. lidState == 1) {
  732. noticeStateChange = TRUE;
  733. }
  734. deviceExtension->Button.LidState = (BOOLEAN) lidState;
  735. //
  736. // Done with the lock
  737. //
  738. KeReleaseSpinLock( &(deviceExtension->Button.SpinLock), oldIrql );
  739. //
  740. // Did we notice a lid state change?
  741. //
  742. if (noticeStateChange) {
  743. ACPIButtonEvent (
  744. deviceObject,
  745. SYS_BUTTON_WAKE,
  746. NULL
  747. );
  748. }
  749. //
  750. // At this point, we are done, and we can pass the request off to
  751. // the proper dispatch point. Note that we will choose something that
  752. // can fire a WAIT_WAKE irp
  753. //
  754. ACPICMButtonSetPower( deviceObject, irp );
  755. return;
  756. }
  757. NTSTATUS
  758. ACPICMLidStart (
  759. IN PDEVICE_OBJECT DeviceObject,
  760. IN PIRP Irp
  761. )
  762. /*++
  763. Routine Description:
  764. This is the start routine for any lid device
  765. Arguments:
  766. DeviceObject - The device that is starting
  767. Irp - The start irp request
  768. Return Value:
  769. NTSTATUS
  770. --*/
  771. {
  772. PAGED_CODE();
  773. return ACPICMButtonStart (
  774. DeviceObject,
  775. Irp,
  776. SYS_BUTTON_LID
  777. );
  778. }
  779. VOID
  780. ACPICMLidWorker (
  781. IN PDEVICE_EXTENSION DeviceExtension,
  782. IN ULONG Events
  783. )
  784. /*++
  785. Routine Description:
  786. Worker thread function to get the current lid status
  787. Arguments:
  788. deviceExtension - The Device Extension for the lid
  789. Events - The event that occured
  790. Return Value:
  791. VOID
  792. --*/
  793. {
  794. KIRQL oldIrql;
  795. NTSTATUS status;
  796. ULONG lidState;
  797. //
  798. // Get the current lid status
  799. //
  800. status = ACPIGetIntegerSync(
  801. DeviceExtension,
  802. PACKED_LID,
  803. &lidState,
  804. NULL
  805. );
  806. if (!NT_SUCCESS(status)) {
  807. ACPIDevPrint( (
  808. ACPI_PRINT_FAILURE,
  809. DeviceExtension,
  810. " ACPICMLidWorker - ACPIGetIntegerSync = %08lx\n",
  811. status
  812. ) );
  813. return;
  814. }
  815. //
  816. // force the value to either a 1 or a 0
  817. //
  818. lidState = lidState ? 1 : 0;
  819. //
  820. // We need a spinlock since we can access/set this data from multiple
  821. // places
  822. //
  823. KeAcquireSpinLock( &(DeviceExtension->Button.SpinLock), &oldIrql );
  824. //
  825. // Set the new lid state
  826. //
  827. DeviceExtension->Button.LidState = (BOOLEAN) lidState;
  828. //
  829. // Done with the lock
  830. //
  831. KeReleaseSpinLock( &(DeviceExtension->Button.SpinLock), oldIrql );
  832. //
  833. // Further processing depends on what events are set
  834. //
  835. if (Events & LID_SIGNAL_EVENT) {
  836. //
  837. // Signal the event
  838. //
  839. ACPIButtonEvent (
  840. DeviceExtension->DeviceObject,
  841. lidState ? SYS_BUTTON_WAKE : SYS_BUTTON_LID,
  842. NULL
  843. );
  844. }
  845. }
  846. NTSTATUS
  847. ACPICMPowerButtonStart (
  848. IN PDEVICE_OBJECT DeviceObject,
  849. IN PIRP Irp
  850. )
  851. /*++
  852. Routine Description:
  853. This is the start routine for any power button
  854. Arguments:
  855. DeviceObject - The device that is starting
  856. Irp - The start irp request
  857. Return Value:
  858. NTSTATUS
  859. --*/
  860. {
  861. PAGED_CODE();
  862. return ACPICMButtonStart (
  863. DeviceObject,
  864. Irp,
  865. SYS_BUTTON_POWER | SYS_BUTTON_WAKE
  866. );
  867. }
  868. NTSTATUS
  869. ACPICMSleepButtonStart (
  870. IN PDEVICE_OBJECT DeviceObject,
  871. IN PIRP Irp
  872. )
  873. /*++
  874. Routine Description:
  875. This is the start routine for any sleep button
  876. Arguments:
  877. DeviceObject - The device that is starting
  878. Irp - The start irp request
  879. Return Value:
  880. NTSTATUS
  881. --*/
  882. {
  883. PAGED_CODE();
  884. return ACPICMButtonStart (
  885. DeviceObject,
  886. Irp,
  887. SYS_BUTTON_SLEEP | SYS_BUTTON_WAKE
  888. );
  889. }