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.

326 lines
8.4 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. PPOP_SWITCH_DEVICE SwitchDevice;
  45. ULONG IoctlCode;
  46. PLIST_ENTRY ListEntry;
  47. ULONG DisabledCaps;
  48. ASSERT_POLICY_LOCK_OWNED();
  49. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  50. SwitchDevice = (PPOP_SWITCH_DEVICE) Context;
  51. if (NT_SUCCESS (Irp->IoStatus.Status)) {
  52. if (!SwitchDevice->GotCaps) {
  53. //
  54. // We have never gotten any button capabilities yet.
  55. // Try and get them now.
  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. // We've been called before so we know what the buttons are supposed
  82. // to do. Check to see if any of our buttons have triggered an
  83. // event.
  84. //
  85. PopTriggerSwitch (SwitchDevice, SYS_BUTTON_LID, &PopPolicy->LidClose);
  86. PopTriggerSwitch (SwitchDevice, SYS_BUTTON_POWER, &PopPolicy->PowerButton);
  87. PopTriggerSwitch (SwitchDevice, SYS_BUTTON_SLEEP, &PopPolicy->SleepButton);
  88. //
  89. // If the wake button is signalled, drop the triggered states
  90. // and set the user as being present
  91. //
  92. if (SwitchDevice->IrpBuffer & SYS_BUTTON_WAKE) {
  93. SwitchDevice->TriggerState = 0;
  94. PopUserPresentSet (0);
  95. }
  96. }
  97. IoctlCode = IOCTL_GET_SYS_BUTTON_EVENT;
  98. } else {
  99. if (!SwitchDevice->IsInitializing) {
  100. //
  101. // Unexpected error
  102. //
  103. PoPrint (PO_ERROR, ("PopSystemButtonHandler: unexpected error %x\n", Irp->IoStatus.Status));
  104. SwitchDevice->GotCaps = FALSE;
  105. SwitchDevice->IsFailed = TRUE;
  106. IoctlCode = 0;
  107. } else {
  108. IoctlCode = IOCTL_GET_SYS_BUTTON_CAPS;
  109. SwitchDevice->IsInitializing = FALSE;
  110. }
  111. }
  112. if (SwitchDevice->IsFailed) {
  113. //
  114. // Close the device
  115. //
  116. PoPrint (PO_WARN, ("PopSystemButtonHandler: removing button device\n"));
  117. RemoveEntryList (&SwitchDevice->Link);
  118. IoFreeIrp (Irp);
  119. ObDereferenceObject (DeviceObject);
  120. //
  121. // Enumerate the remaining switch devices and disable capabilities
  122. // which no longer exist.
  123. //
  124. DisabledCaps = SwitchDevice->Caps;
  125. ExFreePool(SwitchDevice);
  126. ListEntry = PopSwitches.Flink;
  127. while (ListEntry != &PopSwitches) {
  128. SwitchDevice = CONTAINING_RECORD(ListEntry,
  129. POP_SWITCH_DEVICE,
  130. Link);
  131. DisabledCaps &= ~SwitchDevice->Caps;
  132. ListEntry = ListEntry->Flink;
  133. }
  134. if (DisabledCaps & SYS_BUTTON_POWER) {
  135. PoPrint(PO_WARN,("PopSystemButtonHandler : removing power button\n"));
  136. PopClearCapability (&PopCapabilities.PowerButtonPresent);
  137. }
  138. if (DisabledCaps & SYS_BUTTON_SLEEP) {
  139. PoPrint(PO_WARN,("PopSystemButtonHandler : removing sleep button\n"));
  140. PopClearCapability (&PopCapabilities.SleepButtonPresent);
  141. }
  142. if (DisabledCaps & SYS_BUTTON_LID) {
  143. PoPrint(PO_WARN,("PopSystemButtonHandler : removing lid switch\n"));
  144. PopClearCapability (&PopCapabilities.LidPresent);
  145. }
  146. } else {
  147. //
  148. // Send notify IRP to the device to wait for new switch state
  149. //
  150. IrpSp = IoGetNextIrpStackLocation(Irp);
  151. IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  152. IrpSp->Parameters.DeviceIoControl.IoControlCode = IoctlCode;
  153. IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(ULONG);
  154. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(ULONG);
  155. Irp->AssociatedIrp.SystemBuffer = &SwitchDevice->IrpBuffer;
  156. IoSetCompletionRoutine (Irp, PopCompletePolicyIrp, NULL, TRUE, TRUE, TRUE);
  157. IoCallDriver (DeviceObject, Irp);
  158. }
  159. }
  160. VOID
  161. PopTriggerSwitch (
  162. IN PPOP_SWITCH_DEVICE SwitchDevice,
  163. IN ULONG Flag,
  164. IN PPOWER_ACTION_POLICY Action
  165. )
  166. {
  167. POP_ACTION_TRIGGER Trigger;
  168. if ((SwitchDevice->Caps & SYS_BUTTON_LID) &&
  169. (Flag == SYS_BUTTON_LID)) {
  170. //
  171. // Somebody opened or closed a lid.
  172. //
  173. SwitchDevice->Opened = !(SwitchDevice->Opened);
  174. //
  175. // Notify the PowerState callback.
  176. //
  177. ExNotifyCallback (
  178. ExCbPowerState,
  179. UIntToPtr(PO_CB_LID_SWITCH_STATE),
  180. UIntToPtr(SwitchDevice->Opened)
  181. );
  182. //
  183. // Now tell win32k.sys that the lid is open.
  184. //
  185. if( SwitchDevice->Opened ) {
  186. PopDisplayRequired(0);
  187. }
  188. }
  189. //
  190. // Check if event is signalled
  191. //
  192. if (SwitchDevice->IrpBuffer & Flag) {
  193. if (SwitchDevice->TriggerState & Flag) {
  194. //
  195. // We're in the middle of servicing an action
  196. // just like this one already.
  197. //
  198. PopSetNotificationWork (PO_NOTIFY_BUTTON_RECURSE);
  199. } else {
  200. //
  201. // Initiate action for this event
  202. //
  203. RtlZeroMemory (&Trigger, sizeof(Trigger));
  204. Trigger.Type = PolicyDeviceSystemButton;
  205. Trigger.Flags = PO_TRG_SET;
  206. PopSetPowerAction (
  207. &Trigger,
  208. 0,
  209. Action,
  210. PowerSystemSleeping1,
  211. SubstituteLightestOverallDownwardBounded
  212. );
  213. SwitchDevice->TriggerState |= (UCHAR) Flag;
  214. }
  215. }
  216. }
  217. VOID
  218. PopResetSwitchTriggers (
  219. VOID
  220. )
  221. /*++
  222. Routine Description:
  223. This function clears the triggered status on all switch devices
  224. N.B. PopPolicyLock must be held.
  225. Arguments:
  226. None
  227. Return Value:
  228. Status
  229. --*/
  230. {
  231. PLIST_ENTRY Link;
  232. PPOP_SWITCH_DEVICE SwitchDevice;
  233. ASSERT_POLICY_LOCK_OWNED();
  234. //
  235. // Clear flag bits
  236. //
  237. for (Link = PopSwitches.Flink; Link != &PopSwitches; Link = Link->Flink) {
  238. SwitchDevice = CONTAINING_RECORD (Link, POP_SWITCH_DEVICE, Link);
  239. SwitchDevice->TriggerState = 0;
  240. }
  241. }