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.

404 lines
11 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. DBPOWER.C
  5. Abstract:
  6. class driver for device bay controllers
  7. This module has all the code to deal with
  8. the ever changing and confusing WDM power
  9. management model.
  10. Some notes on power management:
  11. 1. We currently just put ow device in D3 (OFF) when we
  12. receive a system poer state message and restore
  13. it D0 when we receive a systemWorking state message.
  14. 2. Waking the system by a device bay controller does not
  15. really fit the Microsoft ideal system ie there is
  16. some debate as to if inserting a device or pressing
  17. the buttons should wake the system.
  18. 3. This code should only support WAKEUP on WDM10 ie Windows
  19. 2k. The ACPI power support in win9x is unreliable an
  20. support for it should not be attempted.
  21. Environment:
  22. kernel mode only
  23. Notes:
  24. Revision History:
  25. --*/
  26. #include <wdm.h>
  27. #include "stdarg.h"
  28. #include "stdio.h"
  29. #include "dbci.h"
  30. #include "dbclass.h" //private data strutures
  31. #include "dbfilter.h"
  32. #include "usbioctl.h"
  33. NTSTATUS
  34. DBCLASS_PoRequestCompletion(
  35. IN PDEVICE_OBJECT DeviceObject,
  36. IN UCHAR MinorFunction,
  37. IN POWER_STATE PowerState,
  38. IN PVOID Context,
  39. IN PIO_STATUS_BLOCK IoStatus
  40. )
  41. /*++
  42. Routine Description:
  43. This routine is called when the port driver completes an IRP.
  44. Arguments:
  45. DeviceObject - Pointer to the device object for the class device.
  46. Context - Driver defined context.
  47. Return Value:
  48. The function value is the final status from the operation.
  49. --*/
  50. {
  51. PIRP irp;
  52. PDBC_CONTEXT dbcContext = Context;
  53. NTSTATUS ntStatus;
  54. irp = dbcContext->PowerIrp;
  55. ntStatus = IoStatus->Status;
  56. DBCLASS_KdPrint((1, "'>>DBC PoRequestComplete\n"));
  57. LOGENTRY(LOG_MISC, 'wPWe', dbcContext, 0, 0);
  58. KeSetEvent(&dbcContext->PowerEvent,
  59. 1,
  60. FALSE);
  61. dbcContext->LastSetDXntStatus = ntStatus;
  62. return ntStatus;
  63. }
  64. NTSTATUS
  65. DBCLASS_ClassPower(
  66. IN PDEVICE_OBJECT ControllerFdo,
  67. IN PIRP Irp,
  68. IN PBOOLEAN HandledByClass
  69. )
  70. /*++
  71. Routine Description:
  72. Arguments:
  73. Return Value:
  74. None
  75. --*/
  76. {
  77. PIO_STACK_LOCATION irpStack;
  78. NTSTATUS ntStatus;
  79. PDBC_CONTEXT dbcContext;
  80. DEVICE_POWER_STATE deviceState;
  81. *HandledByClass = FALSE;
  82. dbcContext = DBCLASS_GetDbcContext(ControllerFdo);
  83. ntStatus = Irp->IoStatus.Status;
  84. irpStack = IoGetCurrentIrpStackLocation (Irp);
  85. DBCLASS_ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
  86. switch (irpStack->MinorFunction) {
  87. case IRP_MN_WAIT_WAKE:
  88. //
  89. // someone is enabling us for wakeup
  90. //
  91. *HandledByClass = TRUE;
  92. TEST_TRAP();
  93. // no wakeup support
  94. // failt the request
  95. Irp->IoStatus.Status = ntStatus = STATUS_NOT_SUPPORTED;
  96. IoCompleteRequest(Irp,
  97. IO_NO_INCREMENT);
  98. break;
  99. case IRP_MN_SET_POWER:
  100. switch (irpStack->Parameters.Power.Type) {
  101. case SystemPowerState:
  102. //
  103. // find the appropriate power state for this system
  104. // state
  105. //
  106. {
  107. POWER_STATE powerState;
  108. DBCLASS_KdPrint((1, "'>DBC System Power State: current state %d\n",
  109. dbcContext->CurrentDevicePowerState));
  110. switch (irpStack->Parameters.Power.State.SystemState) {
  111. case PowerSystemSleeping1:
  112. case PowerSystemSleeping2:
  113. case PowerSystemSleeping3:
  114. // just go off
  115. powerState.DeviceState = PowerDeviceD3;
  116. break;
  117. case PowerSystemWorking:
  118. powerState.DeviceState = PowerDeviceD0;
  119. break;
  120. case PowerSystemShutdown:
  121. DBCLASS_KdPrint((1, "'>>DBC Shutdown detected\n"));
  122. powerState.DeviceState = PowerDeviceD3;
  123. // disable bay locks here
  124. if (dbcContext->Flags |= DBCLASS_FLAG_RELEASE_ON_SHUTDOWN) {
  125. USHORT bay;
  126. for (bay = 1; bay <= NUMBER_OF_BAYS(dbcContext); bay++)
  127. {
  128. PDRB drb;
  129. //
  130. // notify filter of a stop
  131. // note that the filter may not veto the stop
  132. //
  133. drb = DbcExAllocatePool(NonPagedPool,
  134. sizeof(struct _DRB_START_DEVICE_IN_BAY));
  135. if (drb)
  136. {
  137. drb->DrbHeader.Length = sizeof(struct _DRB_STOP_DEVICE_IN_BAY);
  138. drb->DrbHeader.Function = DRB_FUNCTION_STOP_DEVICE_IN_BAY;
  139. drb->DrbHeader.Flags = 0;
  140. drb->DrbStartDeviceInBay.BayNumber = bay;
  141. // make the request
  142. ntStatus = DBCLASS_SyncSubmitDrb(dbcContext,
  143. dbcContext->TopOfStack,
  144. drb);
  145. DbcExFreePool(drb);
  146. }
  147. // just pop out the device --
  148. // surprise remove is OK at this point
  149. DBCLASS_EjectBay(dbcContext, bay);
  150. // DBCLASS_PostChangeRequest(dbcContext);
  151. #if 0
  152. DBCLASS_KdPrint((1, "'>>>disengage interlock bay[%d]\n", bay));
  153. DBCLASS_SyncBayFeatureRequest(dbcContext,
  154. DRB_FUNCTION_CLEAR_BAY_FEATURE,
  155. bay,
  156. LOCK_CTL);
  157. #endif
  158. }
  159. }
  160. break;
  161. case PowerSystemUnspecified:
  162. case PowerSystemHibernate:
  163. default:
  164. powerState.DeviceState = PowerDeviceD3;
  165. break;
  166. }
  167. *HandledByClass = TRUE;
  168. //
  169. // are we already in this state?
  170. //
  171. //
  172. if (powerState.DeviceState !=
  173. dbcContext->CurrentDevicePowerState) {
  174. // No,
  175. // request that we be put into this state
  176. // save the system state irp so we can pass it on
  177. // when our D-STATE request completes
  178. dbcContext->PowerIrp = Irp;
  179. KeInitializeEvent(&dbcContext->PowerEvent,
  180. NotificationEvent, FALSE);
  181. ntStatus = PoRequestPowerIrp(dbcContext->ControllerPdo,
  182. IRP_MN_SET_POWER,
  183. powerState,
  184. DBCLASS_PoRequestCompletion,
  185. dbcContext,
  186. NULL);
  187. KeWaitForSingleObject(
  188. &dbcContext->PowerEvent,
  189. Suspended,
  190. KernelMode,
  191. FALSE,
  192. NULL);
  193. // check the status of the power on request
  194. if (NT_SUCCESS(dbcContext->LastSetDXntStatus) &&
  195. powerState.DeviceState == PowerDeviceD0) {
  196. // we are back 'ON'
  197. // re-start the controller
  198. ntStatus = DBCLASS_StartController(dbcContext,
  199. Irp,
  200. HandledByClass);
  201. }
  202. IoCopyCurrentIrpStackLocationToNext(Irp);
  203. // call down the original system state request
  204. PoStartNextPowerIrp(Irp);
  205. PoCallDriver(dbcContext->TopOfPdoStack,
  206. Irp);
  207. // dbcContext->PowerIrp = NULL;
  208. } else {
  209. // Yes,
  210. // just pass it on
  211. IoCopyCurrentIrpStackLocationToNext(Irp);
  212. PoStartNextPowerIrp(Irp);
  213. ntStatus = PoCallDriver(dbcContext->TopOfPdoStack,
  214. Irp);
  215. }
  216. } /* SystemPowerState */
  217. break;
  218. case DevicePowerState:
  219. // this is a D state message sent to ourselves
  220. deviceState = irpStack->Parameters.Power.State.DeviceState;
  221. switch (deviceState) {
  222. case PowerDeviceD3:
  223. //
  224. // device will be going OFF, save any state now.
  225. //
  226. DBCLASS_KdPrint((0, "'Set DevicePowerState = D3\n"));
  227. dbcContext->CurrentDevicePowerState = deviceState;
  228. //cancel our outstanding notication
  229. ntStatus = DBCLASS_StopController(dbcContext,
  230. Irp,
  231. HandledByClass);
  232. break;
  233. case PowerDeviceD1:
  234. case PowerDeviceD2:
  235. //
  236. // device will be going in to a low power state
  237. //
  238. DBCLASS_KdPrint((0, "'Set DevicePowerState = D%d\n",
  239. deviceState-1));
  240. dbcContext->CurrentDevicePowerState = deviceState;
  241. //cancel our outstanding notication
  242. ntStatus = DBCLASS_StopController(dbcContext,
  243. Irp,
  244. HandledByClass);
  245. break;
  246. case PowerDeviceD0:
  247. //
  248. // OS will call us when the SET_Dx state
  249. // request is complete.
  250. //
  251. break;
  252. default:
  253. DBCLASS_KdPrint((0, "'Invalid D-state passed in\n"));
  254. TRAP();
  255. break;
  256. } /* case deviceState */
  257. break;
  258. } /* case irpStack->Parameters.Power.Type */
  259. break;
  260. case IRP_MN_QUERY_POWER:
  261. *HandledByClass = TRUE;
  262. IoCopyCurrentIrpStackLocationToNext(Irp);
  263. PoStartNextPowerIrp(Irp);
  264. ntStatus = PoCallDriver(dbcContext->TopOfPdoStack,
  265. Irp);
  266. break; /* IRP_MN_QUERY_POWER */
  267. default:
  268. *HandledByClass = TRUE;
  269. IoCopyCurrentIrpStackLocationToNext(Irp);
  270. //
  271. // All PNP_POWER POWER messages get passed to
  272. // TopOfStackDeviceObject
  273. //
  274. // pass on to our PDO
  275. PoStartNextPowerIrp(Irp);
  276. ntStatus = PoCallDriver(dbcContext->TopOfPdoStack,
  277. Irp);
  278. } /* irpStack->MinorFunction */
  279. return ntStatus;
  280. }
  281.