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.

597 lines
19 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1999 - 2001
  3. Module Name:
  4. power.c
  5. Abstract:
  6. Environment:
  7. kernel mode only
  8. Notes:
  9. Revision History:
  10. --*/
  11. #include <stdio.h>
  12. #include "stddef.h"
  13. #include "wdm.h"
  14. #include "usbscan.h"
  15. #include "usbd_api.h"
  16. #include "private.h"
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE, USPower)
  19. #endif
  20. NTSTATUS
  21. USPower(
  22. IN PDEVICE_OBJECT pDeviceObject,
  23. IN PIRP pIrp
  24. )
  25. /*++
  26. Routine Description:
  27. Process the Power IRPs sent to the PDO for this device.
  28. Arguments:
  29. pDeviceObject - pointer to the functional device object (FDO) for this device.
  30. pIrp - pointer to an I/O Request Packet
  31. Return Value:
  32. NT status code
  33. --*/
  34. {
  35. NTSTATUS Status;
  36. PUSBSCAN_DEVICE_EXTENSION pde;
  37. PIO_STACK_LOCATION pIrpStack;
  38. BOOLEAN hookIt = FALSE;
  39. POWER_STATE powerState;
  40. PAGED_CODE();
  41. DebugTrace(TRACE_PROC_ENTER,("USPower: Enter... \n"));
  42. USIncrementIoCount(pDeviceObject);
  43. pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
  44. pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
  45. Status = STATUS_SUCCESS;
  46. switch (pIrpStack -> MinorFunction) {
  47. case IRP_MN_SET_POWER:
  48. {
  49. DebugTrace(TRACE_STATUS,("USPower: IRP_MN_SET_POWER\n"));
  50. switch (pIrpStack -> Parameters.Power.Type) {
  51. case SystemPowerState:
  52. {
  53. DebugTrace(TRACE_STATUS,("USPower: SystemPowerState (0x%x)\n",pIrpStack->Parameters.Power.State.SystemState));
  54. //
  55. // Let lower layer know S IRP, we'll catch on the way up.
  56. //
  57. IoMarkIrpPending(pIrp);
  58. IoCopyCurrentIrpStackLocationToNext(pIrp);
  59. IoSetCompletionRoutine(pIrp,
  60. USSystemPowerIrpComplete,
  61. // always pass FDO to completion routine
  62. pDeviceObject,
  63. TRUE,
  64. TRUE,
  65. TRUE);
  66. PoCallDriver(pde ->pStackDeviceObject, pIrp);
  67. Status = STATUS_PENDING;
  68. goto USPower_return;
  69. } // case SystemPowerState:
  70. case DevicePowerState:
  71. {
  72. DebugTrace(TRACE_STATUS,("USPower: DevicePowerState\n"));
  73. Status = USSetDevicePowerState(pDeviceObject,
  74. pIrpStack -> Parameters.Power.State.DeviceState,
  75. &hookIt);
  76. if (hookIt) {
  77. DebugTrace(TRACE_STATUS,("USPower: Set PowerIrp Completion Routine\n"));
  78. IoCopyCurrentIrpStackLocationToNext(pIrp);
  79. IoSetCompletionRoutine(pIrp,
  80. USDevicePowerIrpComplete,
  81. // always pass FDO to completion routine
  82. pDeviceObject,
  83. hookIt,
  84. hookIt,
  85. hookIt);
  86. } else {
  87. PoStartNextPowerIrp(pIrp);
  88. IoSkipCurrentIrpStackLocation(pIrp);
  89. }
  90. Status = PoCallDriver(pde ->pStackDeviceObject, pIrp);
  91. if (!hookIt) {
  92. USDecrementIoCount(pDeviceObject);
  93. }
  94. goto USPower_return;
  95. } // case DevicePowerState:
  96. } /* case irpStack->Parameters.Power.Type */
  97. break; /* IRP_MN_SET_POWER */
  98. } // case IRP_MN_SET_POWER:
  99. case IRP_MN_QUERY_POWER:
  100. {
  101. DebugTrace(TRACE_STATUS,("USPower: IRP_MN_QUERY_POWER\n"));
  102. if(PowerDeviceD3 == pde -> DeviceCapabilities.DeviceState[pIrpStack->Parameters.Power.State.SystemState]){
  103. //
  104. // We're going down to D3 state, which we can't wake from. Cancel WaitWakeIRP.
  105. //
  106. USDisarmWake(pde);
  107. } // if(PowerDeviceD3 == pde -> DeviceCapabilities.DeviceState[irpStack->Parameters.Power.State.SystemState])
  108. PoStartNextPowerIrp(pIrp);
  109. IoSkipCurrentIrpStackLocation(pIrp);
  110. Status = PoCallDriver(pde -> pStackDeviceObject, pIrp);
  111. USDecrementIoCount(pDeviceObject);
  112. break; /* IRP_MN_QUERY_POWER */
  113. } // case IRP_MN_QUERY_POWER:
  114. case IRP_MN_WAIT_WAKE:
  115. {
  116. LONG oldWakeState;
  117. DebugTrace(TRACE_STATUS,("USPower: IRP_MN_WAIT_WAKE\n"));
  118. pde->pWakeIrp = pIrp;
  119. //
  120. // Now we're armed.
  121. //
  122. oldWakeState = InterlockedCompareExchange(&pde->WakeState,
  123. WAKESTATE_ARMED,
  124. WAKESTATE_WAITING);
  125. if(WAKESTATE_WAITING_CANCELLED == oldWakeState){
  126. //
  127. // We got disarmed, finish up and complete the IRP
  128. //
  129. pde->WakeState = WAKESTATE_COMPLETING;
  130. pIrp->IoStatus.Status = STATUS_CANCELLED;
  131. IoCompleteRequest(pIrp, IO_NO_INCREMENT );
  132. Status = STATUS_CANCELLED;
  133. USDecrementIoCount(pDeviceObject);
  134. break;
  135. } // if(WAKESTATE_WAITING_CANCELLED == oldWakeState)
  136. // We went from WAITING to ARMED. Set a completion routine and forward
  137. // the IRP. Note that our completion routine might complete the IRP
  138. // asynchronously, so we mark the IRP pending
  139. IoMarkIrpPending(pIrp);
  140. IoCopyCurrentIrpStackLocationToNext(pIrp);
  141. IoSetCompletionRoutine(pIrp,
  142. USWaitWakeIoCompletionRoutine,
  143. NULL,
  144. TRUE,
  145. TRUE,
  146. TRUE );
  147. PoCallDriver(pde->pStackDeviceObject, pIrp);
  148. Status = STATUS_PENDING;
  149. USDecrementIoCount(pDeviceObject);
  150. break;
  151. } // case IRP_MN_WAIT_WAKE:
  152. default:
  153. DebugTrace(TRACE_STATUS,("USPower: Unknown power message (%x)\n",pIrpStack->MinorFunction));
  154. PoStartNextPowerIrp(pIrp);
  155. IoSkipCurrentIrpStackLocation(pIrp);
  156. Status = PoCallDriver(pde -> pStackDeviceObject, pIrp);
  157. USDecrementIoCount(pDeviceObject);
  158. } /* pIrpStack -> MinorFunction */
  159. USPower_return:
  160. DebugTrace(TRACE_PROC_LEAVE,("USPower: Leaving... Status = 0x%x\n", Status));
  161. return Status;
  162. } // USPower()
  163. NTSTATUS
  164. USPoRequestCompletion(
  165. IN PDEVICE_OBJECT pPdo,
  166. IN UCHAR MinorFunction,
  167. IN POWER_STATE PowerState,
  168. IN PDEVICE_OBJECT pDeviceObject,
  169. IN PIO_STATUS_BLOCK pIoStatus
  170. )
  171. /*++
  172. Routine Description:
  173. This routine is called when the port driver completes an IRP.
  174. Arguments:
  175. Return Value:
  176. The function value is the final status from the operation.
  177. --*/
  178. {
  179. NTSTATUS Status;
  180. PUSBSCAN_DEVICE_EXTENSION pde;
  181. PIRP pIrp;
  182. DebugTrace(TRACE_PROC_ENTER,("USPoRequestCompletion: Enter...\n"));
  183. //
  184. // Initialize local.
  185. //
  186. pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
  187. pIrp = pde -> pPowerIrp;
  188. Status = pIoStatus -> Status;
  189. //
  190. // Copy status from D IRP to S IRP.
  191. //
  192. pIrp->IoStatus.Status = pIoStatus->Status;
  193. //
  194. // Complete S IRP.
  195. //
  196. PoStartNextPowerIrp(pIrp);
  197. IoCompleteRequest(pIrp, IO_NO_INCREMENT );
  198. USDecrementIoCount(pDeviceObject);
  199. DebugTrace(TRACE_PROC_LEAVE,("USPoRequestCompletion: Leaving... Status = 0x%x\n", Status));
  200. return Status;
  201. } // USPoRequestCompletion()
  202. NTSTATUS
  203. USDevicePowerIrpComplete(
  204. IN PDEVICE_OBJECT pPdo,
  205. IN PIRP pIrp,
  206. IN PDEVICE_OBJECT pDeviceObject
  207. )
  208. /*++
  209. Routine Description:
  210. This routine is called when the port driver completes SetD0 IRP.
  211. Arguments:
  212. Return Value:
  213. The function value is the final status from the operation.
  214. --*/
  215. {
  216. NTSTATUS Status;
  217. PUSBSCAN_DEVICE_EXTENSION pde;
  218. PIO_STACK_LOCATION pIrpStack;
  219. DebugTrace(TRACE_PROC_ENTER,("USDevicePowerIrpComplete: Enter...\n"));
  220. pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
  221. Status = STATUS_SUCCESS;
  222. if (pIrp -> PendingReturned) {
  223. IoMarkIrpPending(pIrp);
  224. } // if (pIrp -> PendingReturned)
  225. pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
  226. ASSERT(pIrpStack -> MajorFunction == IRP_MJ_POWER);
  227. ASSERT(pIrpStack -> MinorFunction == IRP_MN_SET_POWER);
  228. ASSERT(pIrpStack -> Parameters.Power.Type == DevicePowerState);
  229. ASSERT(pIrpStack -> Parameters.Power.State.DeviceState == PowerDeviceD0);
  230. //
  231. // This completion is called only for D0 IRP.
  232. //
  233. pde->CurrentDevicePowerState = PowerDeviceD0;
  234. pde->AcceptingRequests = TRUE;
  235. //
  236. // Now power is on. Rearm for wakeup.
  237. //
  238. USQueuePassiveLevelCallback(pde->pOwnDeviceObject, USPassiveLevelReArmCallbackWorker);
  239. //
  240. // Ready for next D IRP.
  241. //
  242. PoStartNextPowerIrp(pIrp);
  243. //
  244. // Leaving...
  245. //
  246. USDecrementIoCount(pDeviceObject);
  247. DebugTrace(TRACE_PROC_LEAVE,("USDevicePowerIrpComplete: Leaving... Status = 0x%x\n", Status));
  248. return Status;
  249. } // USDevicePowerIrpComplete()
  250. NTSTATUS
  251. USSystemPowerIrpComplete(
  252. IN PDEVICE_OBJECT pPdo,
  253. IN PIRP pIrp,
  254. IN PDEVICE_OBJECT pDeviceObject
  255. )
  256. /*++
  257. Routine Description:
  258. This routine is called when the port driver completes SetD0 IRP.
  259. Arguments:
  260. Return Value:
  261. The function value is the final status from the operation.
  262. --*/
  263. {
  264. NTSTATUS Status;
  265. PUSBSCAN_DEVICE_EXTENSION pde;
  266. PIO_STACK_LOCATION pIrpStack;
  267. POWER_STATE powerState;
  268. DebugTrace(TRACE_PROC_ENTER,("USSystemPowerIrpComplete: Enter... IRP(0x%p)\n", pIrp));
  269. //
  270. // Initialize local.
  271. //
  272. pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
  273. Status = pIrp->IoStatus.Status;
  274. pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
  275. ASSERT(pIrpStack -> MajorFunction == IRP_MJ_POWER);
  276. ASSERT(pIrpStack -> MinorFunction == IRP_MN_SET_POWER);
  277. ASSERT(pIrpStack -> Parameters.Power.Type == SystemPowerState);
  278. if(!NT_SUCCESS(Status)){
  279. DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: IRP failed (0x%x).\n", Status));
  280. Status = STATUS_SUCCESS;
  281. USDecrementIoCount(pDeviceObject);
  282. goto USSystemPowerIrpComplete_return;
  283. } // if(!NT_SUCCESS(Status))
  284. //
  285. // Now Request D IRP based on what we got.
  286. //
  287. if(TRUE == pde ->bEnabledForWakeup){
  288. DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: We have remote wakeup support, getting powerState from table.\n"));
  289. //
  290. // We support wakeup, we'll just follow device stated set by PDO.
  291. //
  292. powerState.DeviceState = pde -> DeviceCapabilities.DeviceState[pIrpStack->Parameters.Power.State.SystemState];
  293. } else { // if(TRUE == pde ->EnabledForWakeup)
  294. DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: We don't have remote wakeup support.\n"));
  295. //
  296. // We don't support remote wake, we're in D0 only when PowerSystemWorking.
  297. //
  298. if(PowerSystemWorking == pIrpStack -> Parameters.Power.State.SystemState){
  299. DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: PowerSystemWorking is requested, powering up to D0.\n"));
  300. powerState.DeviceState = PowerDeviceD0;
  301. } else { // if(PowerSystemWorking == pIrpStack -> Parameters.Power.State.SystemState)
  302. DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: Going other than PowerSystemWorking, turning off the device to D3.\n"));
  303. powerState.DeviceState = PowerDeviceD3;
  304. }
  305. } // else(TRUE == pde ->EnabledForWakeup)
  306. //
  307. // are we already in this state?
  308. //
  309. if(powerState.DeviceState != pde -> CurrentDevicePowerState){
  310. //
  311. // No, request that we be put into this state
  312. //
  313. DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: Requesting DevicePowerState(0x%x).\n", powerState.DeviceState));
  314. pde -> pPowerIrp = pIrp;
  315. Status = PoRequestPowerIrp(pde -> pPhysicalDeviceObject,
  316. IRP_MN_SET_POWER,
  317. powerState,
  318. USPoRequestCompletion,
  319. pDeviceObject,
  320. NULL);
  321. if(NT_SUCCESS(Status)){
  322. //
  323. // D IRP is successfully requested. S IRP will be completed in D IRP completion routine together.
  324. //
  325. Status = STATUS_MORE_PROCESSING_REQUIRED;
  326. } else { // if(NT_SUCCESS(Status))
  327. DebugTrace(TRACE_WARNING,("USSystemPowerIrpComplete: WARNING!! DevicePowerState(0x%x) request failed..\n", powerState.DeviceState));
  328. PoStartNextPowerIrp(pIrp);
  329. Status = STATUS_SUCCESS;
  330. USDecrementIoCount(pDeviceObject);
  331. }
  332. } else { // if(powerState.DeviceState != pde -> CurrentDevicePowerState)
  333. //
  334. // We're already in this device state, no need to issue D IRP.
  335. //
  336. PoStartNextPowerIrp(pIrp);
  337. Status = STATUS_SUCCESS;
  338. USDecrementIoCount(pDeviceObject);
  339. } // else(powerState.DeviceState != pde -> CurrentDevicePowerState)
  340. USSystemPowerIrpComplete_return:
  341. DebugTrace(TRACE_PROC_LEAVE,("USSystemPowerIrpComplete: Leaving... Status = 0x%x\n", Status));
  342. return Status;
  343. } // USSystemPowerIrpComplete()
  344. NTSTATUS
  345. USSetDevicePowerState(
  346. IN PDEVICE_OBJECT pDeviceObject,
  347. IN DEVICE_POWER_STATE DeviceState,
  348. IN PBOOLEAN pHookIt
  349. )
  350. /*++
  351. Routine Description:
  352. Arguments:
  353. pDeviceObject - Pointer to the device object for the class device.
  354. DeviceState - Device specific power state to set the device in to.
  355. Return Value:
  356. --*/
  357. {
  358. NTSTATUS Status;
  359. PUSBSCAN_DEVICE_EXTENSION pde;
  360. POWER_STATE PowerState;
  361. DebugTrace(TRACE_PROC_ENTER,("USSetDevicePowerState: Enter...\n"));
  362. pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
  363. Status = STATUS_SUCCESS;
  364. switch (DeviceState){
  365. case PowerDeviceD3:
  366. // ASSERT(pde -> AcceptingRequests);
  367. // pde -> AcceptingRequests = FALSE;
  368. // USCancelPipe(pDeviceObject, ALL_PIPE, TRUE);
  369. // pde -> CurrentDevicePowerState = DeviceState;
  370. // break;
  371. case PowerDeviceD1:
  372. case PowerDeviceD2:
  373. #if DBG
  374. if(PowerDeviceD3 == DeviceState){
  375. DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD3 (OFF)\n"));
  376. } else { // if(PowerDeviceD3 == DeviceState)
  377. DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD1/D2 (SUSPEND)\n"));
  378. } // else(PowerDeviceD3 == DeviceState)
  379. #endif
  380. USCancelPipe(pDeviceObject, NULL, ALL_PIPE, TRUE);
  381. //
  382. // power states D1,D2 translate to USB suspend
  383. // D3 transltes to OFF
  384. pde -> CurrentDevicePowerState = DeviceState;
  385. break;
  386. case PowerDeviceD0:
  387. DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD0 (ON)\n"));
  388. //
  389. // finish the rest in the completion routine
  390. //
  391. *pHookIt = TRUE;
  392. // pass on to PDO
  393. break;
  394. default:
  395. DebugTrace(TRACE_WARNING,("USSetDevicePowerState: Bogus DeviceState = %x\n", DeviceState));
  396. } // switch (DeviceState)
  397. DebugTrace(TRACE_PROC_LEAVE,("USSetDevicePowerState: Leaving... Status = 0x%x\n", Status));
  398. return Status;
  399. } // USSetDevicePowerState()
  400. NTSTATUS
  401. USWaitWakeIoCompletionRoutine(
  402. PDEVICE_OBJECT pDeviceObject,
  403. PIRP pIrp,
  404. PVOID pContext
  405. )
  406. {
  407. PUSBSCAN_DEVICE_EXTENSION pde;
  408. LONG oldWakeState;
  409. NTSTATUS Status;
  410. DebugTrace(TRACE_PROC_ENTER,("USWaitWakeIoCompletionRoutine: Enter...\n"));
  411. //
  412. // Initialize local.
  413. //
  414. pde = (PUSBSCAN_DEVICE_EXTENSION) pDeviceObject->DeviceExtension;
  415. oldWakeState = 0;
  416. Status = STATUS_SUCCESS;
  417. // Advance the state to completing
  418. oldWakeState = InterlockedExchange( &pde->WakeState, WAKESTATE_COMPLETING );
  419. if(WAKESTATE_ARMED == oldWakeState){
  420. // Normal case, IoCancelIrp isn�ft being called. Note that we already
  421. // marked the IRP pending in our dispatch routine
  422. Status = STATUS_SUCCESS;
  423. goto USWaitWakeIoCompletionRoutine_return;
  424. } else { // if(WAKESTATE_ARMED == oldWakeState)
  425. if(WAKESTATE_ARMING_CANCELLED != oldWakeState){
  426. DebugTrace(TRACE_ERROR,("USWaitWakeIoCompletionRoutine: ERROR!! wake IRP is completed but oldState(0x%x) isn't ARMED/CALCELLED.", oldWakeState));
  427. } else { // if(WAKESTATE_ARMING_CANCELLED != oldWakeState)
  428. DebugTrace(TRACE_STATUS,("USWaitWakeIoCompletionRoutine: WakeIRP is canceled.\n"));
  429. }
  430. // IoCancelIrp is being called RIGHT NOW. The disarm code will try
  431. // to put back the WAKESTATE_ARMED state. It will then see our
  432. // WAKESTATE_COMPLETED value, and complete the IRP itself!
  433. Status = STATUS_MORE_PROCESSING_REQUIRED;
  434. goto USWaitWakeIoCompletionRoutine_return;
  435. } // else(WAKESTATE_ARMED == oldWakeState)
  436. USWaitWakeIoCompletionRoutine_return:
  437. DebugTrace(TRACE_PROC_LEAVE,("USWaitWakeIoCompletionRoutine: Leaving... Status = 0x%x\n", Status));
  438. return Status;
  439. } // USWaitWakeIoCompletionRoutine(