Source code of Windows XP (NT5)
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.

315 lines
7.7 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. switch.c
  5. Abstract:
  6. Button and lid support for the power policy manager
  7. Author:
  8. Ken Reneris (kenr) 17-Jan-1997
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. VOID
  13. PopTriggerSwitch (
  14. IN PPOP_SWITCH_DEVICE SwitchDevice,
  15. IN ULONG Flag,
  16. IN PPOWER_ACTION_POLICY Action
  17. );
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, PopSystemButtonHandler)
  20. #pragma alloc_text(PAGE, PopResetSwitchTriggers)
  21. #pragma alloc_text(PAGE, PopTriggerSwitch)
  22. #endif
  23. VOID
  24. PopSystemButtonHandler (
  25. IN PDEVICE_OBJECT DeviceObject,
  26. IN PIRP Irp,
  27. IN PVOID Context
  28. )
  29. /*++
  30. Routine Description:
  31. This function is the irp handler function to handle the completion
  32. if a query switch status irp. On completion this IRP is recycled
  33. to the next request.
  34. N.B. PopPolicyLock must be held.
  35. Arguments:
  36. DeviceObject - DeviceObject of the switch device
  37. Irp - Irp which has completed
  38. Context - type of switch device
  39. Return Value:
  40. None.
  41. --*/
  42. {
  43. PIO_STACK_LOCATION IrpSp;
  44. PPOWER_ACTION_POLICY ActionPolicy;
  45. PPOP_SWITCH_DEVICE SwitchDevice;
  46. ULONG IoctlCode;
  47. PLIST_ENTRY ListEntry;
  48. ULONG DisabledCaps;
  49. ASSERT_POLICY_LOCK_OWNED();
  50. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  51. SwitchDevice = (PPOP_SWITCH_DEVICE) Context;
  52. if (NT_SUCCESS (Irp->IoStatus.Status)) {
  53. if (!SwitchDevice->GotCaps) {
  54. //
  55. // This is a capabilities IRP, handle it
  56. //
  57. SwitchDevice->Caps = 0;
  58. if (SwitchDevice->IrpBuffer & SYS_BUTTON_POWER) {
  59. PopSetCapability (&PopCapabilities.PowerButtonPresent);
  60. SwitchDevice->Caps |= SYS_BUTTON_POWER;
  61. }
  62. if (SwitchDevice->IrpBuffer & SYS_BUTTON_SLEEP) {
  63. PopSetCapability (&PopCapabilities.SleepButtonPresent);
  64. SwitchDevice->Caps |= SYS_BUTTON_SLEEP;
  65. }
  66. if (SwitchDevice->IrpBuffer & SYS_BUTTON_LID) {
  67. PopSetCapability (&PopCapabilities.LidPresent);
  68. SwitchDevice->Caps |= SYS_BUTTON_LID;
  69. }
  70. SwitchDevice->IrpBuffer = 0;
  71. SwitchDevice->GotCaps = TRUE;
  72. //
  73. // If no capabilities, indicate failure to cause
  74. // the device to be closed
  75. //
  76. if (SwitchDevice->Caps == 0) {
  77. SwitchDevice->IsFailed = TRUE;
  78. }
  79. } else {
  80. //
  81. // Check for events
  82. //
  83. PopTriggerSwitch (SwitchDevice, SYS_BUTTON_LID, &PopPolicy->LidClose);
  84. PopTriggerSwitch (SwitchDevice, SYS_BUTTON_POWER, &PopPolicy->PowerButton);
  85. PopTriggerSwitch (SwitchDevice, SYS_BUTTON_SLEEP, &PopPolicy->SleepButton);
  86. //
  87. // If the wake button is signalled, drop the triggered states
  88. // and set the user as being present
  89. //
  90. if (SwitchDevice->IrpBuffer & SYS_BUTTON_WAKE) {
  91. SwitchDevice->TriggerState = 0;
  92. PopUserPresentSet (0);
  93. }
  94. }
  95. IoctlCode = IOCTL_GET_SYS_BUTTON_EVENT;
  96. } else {
  97. if (!SwitchDevice->IsInitializing) {
  98. //
  99. // Unexpected error
  100. //
  101. PoPrint (PO_ERROR, ("PopSystemButtonHandler: unexpected error %x\n", Irp->IoStatus.Status));
  102. SwitchDevice->GotCaps = FALSE;
  103. SwitchDevice->IsFailed = TRUE;
  104. } else {
  105. IoctlCode = IOCTL_GET_SYS_BUTTON_CAPS;
  106. SwitchDevice->IsInitializing = FALSE;
  107. }
  108. }
  109. if (SwitchDevice->IsFailed) {
  110. //
  111. // Close the device
  112. //
  113. PoPrint (PO_WARN, ("PopSystemButtonHandler: removing button device\n"));
  114. RemoveEntryList (&SwitchDevice->Link);
  115. IoFreeIrp (Irp);
  116. ObDereferenceObject (DeviceObject);
  117. //
  118. // Enumerate the remaining switch devices and disable capabilities
  119. // which no longer exist.
  120. //
  121. DisabledCaps = SwitchDevice->Caps;
  122. ExFreePool(SwitchDevice);
  123. ListEntry = PopSwitches.Flink;
  124. while (ListEntry != &PopSwitches) {
  125. SwitchDevice = CONTAINING_RECORD(ListEntry,
  126. POP_SWITCH_DEVICE,
  127. Link);
  128. DisabledCaps &= ~SwitchDevice->Caps;
  129. ListEntry = ListEntry->Flink;
  130. }
  131. if (DisabledCaps & SYS_BUTTON_POWER) {
  132. PoPrint(PO_WARN,("PopSystemButtonHandler : removing power button\n"));
  133. PopClearCapability (&PopCapabilities.PowerButtonPresent);
  134. }
  135. if (DisabledCaps & SYS_BUTTON_SLEEP) {
  136. PoPrint(PO_WARN,("PopSystemButtonHandler : removing sleep button\n"));
  137. PopClearCapability (&PopCapabilities.SleepButtonPresent);
  138. }
  139. if (DisabledCaps & SYS_BUTTON_LID) {
  140. PoPrint(PO_WARN,("PopSystemButtonHandler : removing lid switch\n"));
  141. PopClearCapability (&PopCapabilities.LidPresent);
  142. }
  143. } else {
  144. //
  145. // Send notify IRP to the device to wait for new switch state
  146. //
  147. IrpSp = IoGetNextIrpStackLocation(Irp);
  148. IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  149. IrpSp->Parameters.DeviceIoControl.IoControlCode = IoctlCode;
  150. IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(ULONG);
  151. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(ULONG);
  152. Irp->AssociatedIrp.SystemBuffer = &SwitchDevice->IrpBuffer;
  153. IoSetCompletionRoutine (Irp, PopCompletePolicyIrp, NULL, TRUE, TRUE, TRUE);
  154. IoCallDriver (DeviceObject, Irp);
  155. }
  156. }
  157. VOID
  158. PopTriggerSwitch (
  159. IN PPOP_SWITCH_DEVICE SwitchDevice,
  160. IN ULONG Flag,
  161. IN PPOWER_ACTION_POLICY Action
  162. )
  163. {
  164. POP_ACTION_TRIGGER Trigger;
  165. if ((SwitchDevice->Caps & SYS_BUTTON_LID) &&
  166. (Flag == SYS_BUTTON_LID)) {
  167. //
  168. // Somebody opened or closed a lid.
  169. //
  170. SwitchDevice->Opened = (SwitchDevice->Opened == TRUE) ?
  171. FALSE : TRUE;
  172. //
  173. // Notify the PowerState callback.
  174. //
  175. ExNotifyCallback (
  176. ExCbPowerState,
  177. UIntToPtr(PO_CB_LID_SWITCH_STATE),
  178. UIntToPtr(SwitchDevice->Opened)
  179. );
  180. }
  181. //
  182. // Check if event is signalled
  183. //
  184. if (SwitchDevice->IrpBuffer & Flag) {
  185. //
  186. // Check if event is recursing
  187. //
  188. if (SwitchDevice->TriggerState & Flag) {
  189. PopSetNotificationWork (PO_NOTIFY_BUTTON_RECURSE);
  190. } else {
  191. //
  192. // Initiate action for this event
  193. //
  194. RtlZeroMemory (&Trigger, sizeof(Trigger));
  195. Trigger.Type = PolicyDeviceSystemButton;
  196. Trigger.Flags = PO_TRG_SET;
  197. PopSetPowerAction (
  198. &Trigger,
  199. 0,
  200. Action,
  201. PowerSystemSleeping1,
  202. SubstituteLightestOverallDownwardBounded
  203. );
  204. SwitchDevice->TriggerState |= (UCHAR) Flag;
  205. }
  206. }
  207. }
  208. VOID
  209. PopResetSwitchTriggers (
  210. VOID
  211. )
  212. /*++
  213. Routine Description:
  214. This function clears the triggered status on all switch devices
  215. N.B. PopPolicyLock must be held.
  216. Arguments:
  217. None
  218. Return Value:
  219. Status
  220. --*/
  221. {
  222. PLIST_ENTRY Link;
  223. PPOP_SWITCH_DEVICE SwitchDevice;
  224. ASSERT_POLICY_LOCK_OWNED();
  225. //
  226. // Clear flag bits
  227. //
  228. for (Link = PopSwitches.Flink; Link != &PopSwitches; Link = Link->Flink) {
  229. SwitchDevice = CONTAINING_RECORD (Link, POP_SWITCH_DEVICE, Link);
  230. SwitchDevice->TriggerState = 0;
  231. }
  232. }