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.

1651 lines
39 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. isopwr.c
  5. Abstract:
  6. The power management related processing.
  7. The Power Manager uses IRPs to direct drivers to change system
  8. and device power levels, to respond to system wake-up events,
  9. and to query drivers about their devices. All power IRPs have
  10. the major function code IRP_MJ_POWER.
  11. Most function and filter drivers perform some processing for
  12. each power IRP, then pass the IRP down to the next lower driver
  13. without completing it. Eventually the IRP reaches the bus driver,
  14. which physically changes the power state of the device and completes
  15. the IRP.
  16. When the IRP has been completed, the I/O Manager calls any
  17. IoCompletion routines set by drivers as the IRP traveled
  18. down the device stack. Whether a driver needs to set a completion
  19. routine depends upon the type of IRP and the driver's individual
  20. requirements.
  21. This code is not USB specific. It is essential for every WDM driver
  22. to handle power irps.
  23. Environment:
  24. Kernel mode
  25. Notes:
  26. Copyright (c) 2000 Microsoft Corporation.
  27. All Rights Reserved.
  28. --*/
  29. #include "isousb.h"
  30. #include "isopnp.h"
  31. #include "isopwr.h"
  32. #include "isodev.h"
  33. #include "isowmi.h"
  34. #include "isousr.h"
  35. #include "isorwr.h"
  36. #include "isostrm.h"
  37. NTSTATUS
  38. IsoUsb_DispatchPower(
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN PIRP Irp
  41. )
  42. /*++
  43. Routine Description:
  44. The power dispatch routine.
  45. Arguments:
  46. DeviceObject - pointer to a device object.
  47. Irp - pointer to an I/O Request Packet.
  48. Return Value:
  49. NT status code
  50. --*/
  51. {
  52. NTSTATUS ntStatus;
  53. PIO_STACK_LOCATION irpStack;
  54. PUNICODE_STRING tagString;
  55. PDEVICE_EXTENSION deviceExtension;
  56. //
  57. // initialize the variables
  58. //
  59. irpStack = IoGetCurrentIrpStackLocation(Irp);
  60. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  61. //
  62. // We don't queue power Irps, we'll only check if the
  63. // device was removed, otherwise we'll take appropriate
  64. // action and send it to the next lower driver. In general
  65. // drivers should not cause long delays while handling power
  66. // IRPs. If a driver cannot handle a power IRP in a brief time,
  67. // it should return STATUS_PENDING and queue all incoming
  68. // IRPs until the IRP completes.
  69. //
  70. if(Removed == deviceExtension->DeviceState) {
  71. //
  72. // Even if a driver fails the IRP, it must nevertheless call
  73. // PoStartNextPowerIrp to inform the Power Manager that it
  74. // is ready to handle another power IRP.
  75. //
  76. PoStartNextPowerIrp(Irp);
  77. Irp->IoStatus.Status = ntStatus = STATUS_DELETE_PENDING;
  78. Irp->IoStatus.Information = 0;
  79. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  80. return ntStatus;
  81. }
  82. if(NotStarted == deviceExtension->DeviceState) {
  83. //
  84. // if the device is not started yet, pass it down
  85. //
  86. PoStartNextPowerIrp(Irp);
  87. IoSkipCurrentIrpStackLocation(Irp);
  88. return PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  89. }
  90. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchPower::"));
  91. IsoUsb_IoIncrement(deviceExtension);
  92. switch(irpStack->MinorFunction) {
  93. case IRP_MN_SET_POWER:
  94. //
  95. // The Power Manager sends this IRP for one of the
  96. // following reasons:
  97. // 1) To notify drivers of a change to the system power state.
  98. // 2) To change the power state of a device for which
  99. // the Power Manager is performing idle detection.
  100. // A driver sends IRP_MN_SET_POWER to change the power
  101. // state of its device if it's a power policy owner for the
  102. // device.
  103. //
  104. // Mark the Irp as pending and return STATUS_PENDING if we change the
  105. // nature of the irp in the completion routine (asynchroniticity).
  106. // In such cases, do not return the status returned by the lower driver.
  107. // returning STATUS_MORE_PROCESSING_REQUIRED in the completion routine
  108. // transforms the nature of the irp to asynchronous irp.
  109. //
  110. IoMarkIrpPending(Irp);
  111. switch(irpStack->Parameters.Power.Type) {
  112. case SystemPowerState:
  113. HandleSystemSetPower(DeviceObject, Irp);
  114. ntStatus = STATUS_PENDING;
  115. break;
  116. case DevicePowerState:
  117. HandleDeviceSetPower(DeviceObject, Irp);
  118. ntStatus = STATUS_PENDING;
  119. break;
  120. }
  121. break;
  122. case IRP_MN_QUERY_POWER:
  123. //
  124. // The Power Manager sends a power IRP with the minor
  125. // IRP code IRP_MN_QUERY_POWER to determine whether it
  126. // can safely change to the specified system power state
  127. // (S1-S5) and to allow drivers to prepare for such a change.
  128. // If a driver can put its device in the requested state,
  129. // it sets status to STATUS_SUCCESS and passes the IRP down.
  130. //
  131. IoMarkIrpPending(Irp);
  132. switch(irpStack->Parameters.Power.Type) {
  133. case SystemPowerState:
  134. HandleSystemQueryPower(DeviceObject, Irp);
  135. ntStatus = STATUS_PENDING;
  136. break;
  137. case DevicePowerState:
  138. HandleDeviceQueryPower(DeviceObject, Irp);
  139. ntStatus = STATUS_PENDING;
  140. break;
  141. }
  142. break;
  143. case IRP_MN_WAIT_WAKE:
  144. //
  145. // The minor power IRP code IRP_MN_WAIT_WAKE provides
  146. // for waking a device or waking the system. Drivers
  147. // of devices that can wake themselves or the system
  148. // send IRP_MN_WAIT_WAKE. The system sends IRP_MN_WAIT_WAKE
  149. // only to devices that always wake the system, such as
  150. // the power-on switch.
  151. //
  152. IoMarkIrpPending(Irp);
  153. IoCopyCurrentIrpStackLocationToNext(Irp);
  154. IoSetCompletionRoutine(
  155. Irp,
  156. (PIO_COMPLETION_ROUTINE)WaitWakeCompletionRoutine,
  157. deviceExtension,
  158. TRUE,
  159. TRUE,
  160. TRUE);
  161. PoStartNextPowerIrp(Irp);
  162. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  163. if(!NT_SUCCESS(ntStatus)) {
  164. IsoUsb_DbgPrint(1, ("Lower drivers failed this Irp\n"));
  165. }
  166. ntStatus = STATUS_PENDING;
  167. //
  168. // push back the count HERE and NOT in completion routine
  169. // a pending Wait Wake Irp should not impede stopping the device
  170. //
  171. IsoUsb_DbgPrint(3, ("IRP_MN_WAIT_WAKE::"));
  172. IsoUsb_IoDecrement(deviceExtension);
  173. break;
  174. case IRP_MN_POWER_SEQUENCE:
  175. //
  176. // A driver sends this IRP as an optimization to determine
  177. // whether its device actually entered a specific power state.
  178. // This IRP is optional. Power Manager cannot send this IRP.
  179. //
  180. default:
  181. PoStartNextPowerIrp(Irp);
  182. IoSkipCurrentIrpStackLocation(Irp);
  183. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  184. if(!NT_SUCCESS(ntStatus)) {
  185. IsoUsb_DbgPrint(1, ("Lower drivers failed this Irp\n"));
  186. }
  187. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchPower::"));
  188. IsoUsb_IoDecrement(deviceExtension);
  189. break;
  190. }
  191. return ntStatus;
  192. }
  193. NTSTATUS
  194. HandleSystemQueryPower(
  195. IN PDEVICE_OBJECT DeviceObject,
  196. IN PIRP Irp
  197. )
  198. /*++
  199. Routine Description:
  200. This routine handles the irp with minor function of type IRP_MN_QUERY_POWER
  201. for the system power states.
  202. Arguments:
  203. DeviceObject - pointer to device object
  204. Irp - I/O request packet sent by the power manager.
  205. Return Value:
  206. NT status value
  207. --*/
  208. {
  209. NTSTATUS ntStatus;
  210. PDEVICE_EXTENSION deviceExtension;
  211. SYSTEM_POWER_STATE systemState;
  212. PIO_STACK_LOCATION irpStack;
  213. IsoUsb_DbgPrint(3, ("HandleSystemQueryPower - begins\n"));
  214. //
  215. // initialize variables
  216. //
  217. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  218. irpStack = IoGetCurrentIrpStackLocation(Irp);
  219. systemState = irpStack->Parameters.Power.State.SystemState;
  220. IsoUsb_DbgPrint(3, ("Query for system power state S%X\n"
  221. "Current system power state S%X\n",
  222. systemState - 1,
  223. deviceExtension->SysPower - 1));
  224. //
  225. // if querying for a lower S-state, issue a wait-wake
  226. //
  227. if((systemState > deviceExtension->SysPower) &&
  228. (deviceExtension->WaitWakeEnable)) {
  229. IssueWaitWake(deviceExtension);
  230. }
  231. IoCopyCurrentIrpStackLocationToNext(Irp);
  232. IoSetCompletionRoutine(
  233. Irp,
  234. (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
  235. deviceExtension,
  236. TRUE,
  237. TRUE,
  238. TRUE);
  239. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  240. IsoUsb_DbgPrint(3, ("HandleSystemQueryPower - ends\n"));
  241. return STATUS_PENDING;
  242. }
  243. NTSTATUS
  244. HandleSystemSetPower(
  245. IN PDEVICE_OBJECT DeviceObject,
  246. IN PIRP Irp
  247. )
  248. /*++
  249. Routine Description:
  250. This routine services irps of minor type IRP_MN_SET_POWER
  251. for the system power state
  252. Arguments:
  253. DeviceObject - pointer to device object
  254. Irp - I/O request packet sent by the power manager
  255. Return Value:
  256. NT status value
  257. --*/
  258. {
  259. NTSTATUS ntStatus;
  260. PDEVICE_EXTENSION deviceExtension;
  261. SYSTEM_POWER_STATE systemState;
  262. PIO_STACK_LOCATION irpStack;
  263. IsoUsb_DbgPrint(3, ("HandleSystemSetPower - begins\n"));
  264. //
  265. // initialize variables
  266. //
  267. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  268. irpStack = IoGetCurrentIrpStackLocation(Irp);
  269. systemState = irpStack->Parameters.Power.State.SystemState;
  270. IsoUsb_DbgPrint(3, ("Set request for system power state S%X\n"
  271. "Current system power state S%X\n",
  272. systemState - 1,
  273. deviceExtension->SysPower - 1));
  274. IoCopyCurrentIrpStackLocationToNext(Irp);
  275. IoSetCompletionRoutine(
  276. Irp,
  277. (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
  278. deviceExtension,
  279. TRUE,
  280. TRUE,
  281. TRUE);
  282. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  283. IsoUsb_DbgPrint(3, ("HandleSystemSetPower - ends\n"));
  284. return STATUS_PENDING;
  285. }
  286. NTSTATUS
  287. HandleDeviceQueryPower(
  288. PDEVICE_OBJECT DeviceObject,
  289. PIRP Irp
  290. )
  291. /*++
  292. Routine Description:
  293. This routine services irps of minor type IRP_MN_QUERY_POWER
  294. for the device power state
  295. Arguments:
  296. DeviceObject - pointer to device object
  297. Irp - I/O request packet sent by the power manager
  298. Return Value:
  299. NT status value
  300. --*/
  301. {
  302. NTSTATUS ntStatus;
  303. PDEVICE_EXTENSION deviceExtension;
  304. PIO_STACK_LOCATION irpStack;
  305. DEVICE_POWER_STATE deviceState;
  306. IsoUsb_DbgPrint(3, ("HandleDeviceQueryPower - begins\n"));
  307. //
  308. // initialize variables
  309. //
  310. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  311. irpStack = IoGetCurrentIrpStackLocation(Irp);
  312. deviceState = irpStack->Parameters.Power.State.DeviceState;
  313. IsoUsb_DbgPrint(3, ("Query for device power state D%X\n"
  314. "Current device power state D%X\n",
  315. deviceState - 1,
  316. deviceExtension->DevPower - 1));
  317. if(deviceState < deviceExtension->DevPower) {
  318. ntStatus = STATUS_SUCCESS;
  319. }
  320. else {
  321. ntStatus = HoldIoRequests(DeviceObject, Irp);
  322. if(STATUS_PENDING == ntStatus) {
  323. return ntStatus;
  324. }
  325. }
  326. //
  327. // on error complete the Irp.
  328. // on success pass it to the lower layers
  329. //
  330. PoStartNextPowerIrp(Irp);
  331. Irp->IoStatus.Status = ntStatus;
  332. Irp->IoStatus.Information = 0;
  333. if(!NT_SUCCESS(ntStatus)) {
  334. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  335. }
  336. else {
  337. IoSkipCurrentIrpStackLocation(Irp);
  338. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  339. }
  340. IsoUsb_DbgPrint(3, ("HandleDeviceQueryPower::"));
  341. IsoUsb_IoDecrement(deviceExtension);
  342. IsoUsb_DbgPrint(3, ("HandleDeviceQueryPower - ends\n"));
  343. return ntStatus;
  344. }
  345. NTSTATUS
  346. SysPoCompletionRoutine(
  347. IN PDEVICE_OBJECT DeviceObject,
  348. IN PIRP Irp,
  349. IN PDEVICE_EXTENSION DeviceExtension
  350. )
  351. /*++
  352. Routine Description:
  353. This is the completion routine for the system power irps of minor
  354. function types IRP_MN_QUERY_POWER and IRP_MN_SET_POWER.
  355. This completion routine sends the corresponding device power irp and
  356. returns STATUS_MORE_PROCESSING_REQUIRED. The system irp is passed as a
  357. context to the device power irp completion routine and is completed in
  358. the device power irp completion routine.
  359. Arguments:
  360. DeviceObject - pointer to device object
  361. Irp - I/O request packet
  362. DeviceExtension - pointer to device extension
  363. Return Value:
  364. NT status value
  365. --*/
  366. {
  367. NTSTATUS ntStatus;
  368. PIO_STACK_LOCATION irpStack;
  369. //
  370. // initialize variables
  371. //
  372. ntStatus = Irp->IoStatus.Status;
  373. irpStack = IoGetCurrentIrpStackLocation(Irp);
  374. IsoUsb_DbgPrint(3, ("SysPoCompletionRoutine - begins\n"));
  375. //
  376. // lower drivers failed this Irp
  377. //
  378. if(!NT_SUCCESS(ntStatus)) {
  379. PoStartNextPowerIrp(Irp);
  380. IsoUsb_DbgPrint(3, ("SysPoCompletionRoutine::"));
  381. IsoUsb_IoDecrement(DeviceExtension);
  382. return STATUS_SUCCESS;
  383. }
  384. //
  385. // ..otherwise update the cached system power state (IRP_MN_SET_POWER)
  386. //
  387. if(irpStack->MinorFunction == IRP_MN_SET_POWER) {
  388. DeviceExtension->SysPower = irpStack->Parameters.Power.State.SystemState;
  389. }
  390. //
  391. // queue device irp and return STATUS_MORE_PROCESSING_REQUIRED
  392. //
  393. SendDeviceIrp(DeviceObject, Irp);
  394. IsoUsb_DbgPrint(3, ("SysPoCompletionRoutine - ends\n"));
  395. return STATUS_MORE_PROCESSING_REQUIRED;
  396. }
  397. VOID
  398. SendDeviceIrp(
  399. IN PDEVICE_OBJECT DeviceObject,
  400. IN PIRP SIrp
  401. )
  402. /*++
  403. Routine Description:
  404. This routine is invoked from the completion routine of the system power
  405. irp. This routine will PoRequest a device power irp. The system irp is
  406. passed as a context to the the device power irp.
  407. Arguments:
  408. DeviceObject - pointer to device object
  409. SIrp - system power irp.
  410. Return Value:
  411. None
  412. --*/
  413. {
  414. NTSTATUS ntStatus;
  415. POWER_STATE powState;
  416. PDEVICE_EXTENSION deviceExtension;
  417. PIO_STACK_LOCATION irpStack;
  418. SYSTEM_POWER_STATE systemState;
  419. DEVICE_POWER_STATE devState;
  420. PPOWER_COMPLETION_CONTEXT powerContext;
  421. //
  422. // initialize variables
  423. //
  424. irpStack = IoGetCurrentIrpStackLocation(SIrp);
  425. systemState = irpStack->Parameters.Power.State.SystemState;
  426. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  427. IsoUsb_DbgPrint(3, ("SendDeviceIrp - begins\n"));
  428. //
  429. // Read out the D-IRP out of the S->D mapping array captured in QueryCap's.
  430. // we can choose deeper sleep states than our mapping but never choose
  431. // lighter ones.
  432. //
  433. devState = deviceExtension->DeviceCapabilities.DeviceState[systemState];
  434. powState.DeviceState = devState;
  435. powerContext = (PPOWER_COMPLETION_CONTEXT)
  436. ExAllocatePool(NonPagedPool,
  437. sizeof(POWER_COMPLETION_CONTEXT));
  438. if(!powerContext) {
  439. IsoUsb_DbgPrint(1, ("Failed to alloc memory for powerContext\n"));
  440. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  441. }
  442. else {
  443. powerContext->DeviceObject = DeviceObject;
  444. powerContext->SIrp = SIrp;
  445. //
  446. // in win2k PoRequestPowerIrp can take fdo or pdo.
  447. //
  448. ntStatus = PoRequestPowerIrp(
  449. deviceExtension->PhysicalDeviceObject,
  450. irpStack->MinorFunction,
  451. powState,
  452. (PREQUEST_POWER_COMPLETE)DevPoCompletionRoutine,
  453. powerContext,
  454. NULL);
  455. }
  456. if(!NT_SUCCESS(ntStatus)) {
  457. if(powerContext) {
  458. ExFreePool(powerContext);
  459. }
  460. PoStartNextPowerIrp(SIrp);
  461. SIrp->IoStatus.Status = ntStatus;
  462. SIrp->IoStatus.Information = 0;
  463. IoCompleteRequest(SIrp, IO_NO_INCREMENT);
  464. IsoUsb_DbgPrint(3, ("SendDeviceIrp::"));
  465. IsoUsb_IoDecrement(deviceExtension);
  466. }
  467. IsoUsb_DbgPrint(3, ("SendDeviceIrp - ends\n"));
  468. }
  469. VOID
  470. DevPoCompletionRoutine(
  471. IN PDEVICE_OBJECT DeviceObject,
  472. IN UCHAR MinorFunction,
  473. IN POWER_STATE PowerState,
  474. IN PVOID Context,
  475. IN PIO_STATUS_BLOCK IoStatus
  476. )
  477. /*++
  478. Routine Description:
  479. This is the PoRequest - completion routine for the device power irp.
  480. This routine is responsible for completing the system power irp,
  481. received as a context.
  482. Arguments:
  483. DeviceObject - pointer to device object
  484. MinorFunction - minor function of the irp.
  485. PowerState - power state of the irp.
  486. Context - context passed to the completion routine.
  487. IoStatus - status of the device power irp.
  488. Return Value:
  489. None
  490. --*/
  491. {
  492. PIRP sIrp;
  493. PDEVICE_EXTENSION deviceExtension;
  494. PPOWER_COMPLETION_CONTEXT powerContext;
  495. //
  496. // initialize variables
  497. //
  498. powerContext = (PPOWER_COMPLETION_CONTEXT) Context;
  499. sIrp = powerContext->SIrp;
  500. deviceExtension = powerContext->DeviceObject->DeviceExtension;
  501. IsoUsb_DbgPrint(3, ("DevPoCompletionRoutine - begins\n"));
  502. //
  503. // copy the D-Irp status into S-Irp
  504. //
  505. sIrp->IoStatus.Status = IoStatus->Status;
  506. //
  507. // complete the system Irp
  508. //
  509. PoStartNextPowerIrp(sIrp);
  510. sIrp->IoStatus.Information = 0;
  511. IoCompleteRequest(sIrp, IO_NO_INCREMENT);
  512. //
  513. // cleanup
  514. //
  515. IsoUsb_DbgPrint(3, ("DevPoCompletionRoutine::"));
  516. IsoUsb_IoDecrement(deviceExtension);
  517. ExFreePool(powerContext);
  518. IsoUsb_DbgPrint(3, ("DevPoCompletionRoutine - ends\n"));
  519. }
  520. NTSTATUS
  521. HandleDeviceSetPower(
  522. IN PDEVICE_OBJECT DeviceObject,
  523. IN PIRP Irp
  524. )
  525. /*++
  526. Routine Description:
  527. This routine services irps of minor type IRP_MN_SET_POWER
  528. for the device power state
  529. Arguments:
  530. DeviceObject - pointer to device object
  531. Irp - I/O request packet sent by the power manager
  532. Return Value:
  533. NT status value
  534. --*/
  535. {
  536. KIRQL oldIrql;
  537. NTSTATUS ntStatus;
  538. POWER_STATE newState;
  539. PIO_STACK_LOCATION irpStack;
  540. PDEVICE_EXTENSION deviceExtension;
  541. DEVICE_POWER_STATE newDevState,
  542. oldDevState;
  543. IsoUsb_DbgPrint(3, ("HandleDeviceSetPower - begins\n"));
  544. //
  545. // initialize variables
  546. //
  547. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  548. irpStack = IoGetCurrentIrpStackLocation(Irp);
  549. oldDevState = deviceExtension->DevPower;
  550. newState = irpStack->Parameters.Power.State;
  551. newDevState = newState.DeviceState;
  552. IsoUsb_DbgPrint(3, ("Set request for device power state D%X\n"
  553. "Current device power state D%X\n",
  554. newDevState - 1,
  555. deviceExtension->DevPower - 1));
  556. if(newDevState < oldDevState) {
  557. //
  558. // adding power
  559. //
  560. IsoUsb_DbgPrint(3, ("Adding power to the device\n"));
  561. //
  562. // send the power IRP to the next driver in the stack
  563. //
  564. IoCopyCurrentIrpStackLocationToNext(Irp);
  565. IoSetCompletionRoutine(
  566. Irp,
  567. (PIO_COMPLETION_ROUTINE)FinishDevPoUpIrp,
  568. deviceExtension,
  569. TRUE,
  570. TRUE,
  571. TRUE);
  572. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  573. }
  574. else {
  575. IsoUsb_DbgPrint(3, ("Removing power or SetD0\n"));
  576. //
  577. // newDevState >= oldDevState
  578. //
  579. // hold I/O if transition from D0 -> DX (X = 1, 2, 3)
  580. // if transition from D1 or D2 to deeper sleep states,
  581. // I/O queue is already on hold.
  582. //
  583. if(PowerDeviceD0 == oldDevState && newDevState > oldDevState) {
  584. //
  585. // D0 -> DX transition
  586. //
  587. ntStatus = HoldIoRequests(DeviceObject, Irp);
  588. if(!NT_SUCCESS(ntStatus)) {
  589. PoStartNextPowerIrp(Irp);
  590. Irp->IoStatus.Status = ntStatus;
  591. Irp->IoStatus.Information = 0;
  592. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  593. IsoUsb_DbgPrint(3, ("HandleDeviceSetPower::"));
  594. IsoUsb_IoDecrement(deviceExtension);
  595. return ntStatus;
  596. }
  597. else {
  598. goto HandleDeviceSetPower_Exit;
  599. }
  600. }
  601. else if(PowerDeviceD0 == oldDevState && PowerDeviceD0 == newDevState) {
  602. //
  603. // D0 -> D0
  604. // unblock the queue which may have been blocked processing
  605. // query irp
  606. //
  607. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  608. deviceExtension->QueueState = AllowRequests;
  609. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  610. ProcessQueuedRequests(deviceExtension);
  611. }
  612. IoCopyCurrentIrpStackLocationToNext(Irp);
  613. IoSetCompletionRoutine(
  614. Irp,
  615. (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
  616. deviceExtension,
  617. TRUE,
  618. TRUE,
  619. TRUE);
  620. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  621. if(!NT_SUCCESS(ntStatus)) {
  622. IsoUsb_DbgPrint(1, ("Lower drivers failed a power Irp\n"));
  623. }
  624. }
  625. HandleDeviceSetPower_Exit:
  626. IsoUsb_DbgPrint(3, ("HandleDeviceSetPower - ends\n"));
  627. return STATUS_PENDING;
  628. }
  629. NTSTATUS
  630. FinishDevPoUpIrp(
  631. IN PDEVICE_OBJECT DeviceObject,
  632. IN PIRP Irp,
  633. IN PDEVICE_EXTENSION DeviceExtension
  634. )
  635. /*++
  636. Routine Description:
  637. completion routine for the device power UP irp with minor function
  638. IRP_MN_SET_POWER.
  639. Arguments:
  640. DeviceObject - pointer to device object
  641. Irp - I/O request packet
  642. DeviceExtension - pointer to device extension
  643. Return Value:
  644. NT status value
  645. --*/
  646. {
  647. NTSTATUS ntStatus;
  648. //
  649. // initialize variables
  650. //
  651. ntStatus = Irp->IoStatus.Status;
  652. IsoUsb_DbgPrint(3, ("FinishDevPoUpIrp - begins\n"));
  653. if(Irp->PendingReturned) {
  654. IoMarkIrpPending(Irp);
  655. }
  656. if(!NT_SUCCESS(ntStatus)) {
  657. PoStartNextPowerIrp(Irp);
  658. IsoUsb_DbgPrint(3, ("FinishDevPoUpIrp::"));
  659. IsoUsb_IoDecrement(DeviceExtension);
  660. return STATUS_SUCCESS;
  661. }
  662. SetDeviceFunctional(DeviceObject, Irp, DeviceExtension);
  663. IsoUsb_DbgPrint(3, ("FinishDevPoUpIrp - ends\n"));
  664. return STATUS_MORE_PROCESSING_REQUIRED;
  665. }
  666. NTSTATUS
  667. SetDeviceFunctional(
  668. IN PDEVICE_OBJECT DeviceObject,
  669. IN PIRP Irp,
  670. IN PDEVICE_EXTENSION DeviceExtension
  671. )
  672. /*++
  673. Routine Description:
  674. This routine processes queue of pending irps.
  675. Arguments:
  676. DeviceObject - pointer to device object
  677. Irp - I/O request packet
  678. DeviceExtension - pointer to device extension
  679. Return Value:
  680. NT status value
  681. --*/
  682. {
  683. KIRQL oldIrql;
  684. NTSTATUS ntStatus;
  685. POWER_STATE newState;
  686. PIO_STACK_LOCATION irpStack;
  687. DEVICE_POWER_STATE newDevState,
  688. oldDevState;
  689. //
  690. // initialize variables
  691. //
  692. ntStatus = Irp->IoStatus.Status;
  693. irpStack = IoGetCurrentIrpStackLocation(Irp);
  694. newState = irpStack->Parameters.Power.State;
  695. newDevState = newState.DeviceState;
  696. oldDevState = DeviceExtension->DevPower;
  697. IsoUsb_DbgPrint(3, ("SetDeviceFunctional - begins\n"));
  698. //
  699. // update the cached state
  700. //
  701. DeviceExtension->DevPower = newDevState;
  702. //
  703. // restore appropriate amount of state to our h/w
  704. // this driver does not implement partial context
  705. // save/restore.
  706. //
  707. PoSetPowerState(DeviceObject, DevicePowerState, newState);
  708. if(PowerDeviceD0 == newDevState) {
  709. //
  710. // empty existing queue of all pending irps.
  711. //
  712. KeAcquireSpinLock(&DeviceExtension->DevStateLock, &oldIrql);
  713. DeviceExtension->QueueState = AllowRequests;
  714. KeReleaseSpinLock(&DeviceExtension->DevStateLock, oldIrql);
  715. ProcessQueuedRequests(DeviceExtension);
  716. }
  717. PoStartNextPowerIrp(Irp);
  718. Irp->IoStatus.Status = STATUS_SUCCESS;
  719. Irp->IoStatus.Information = 0;
  720. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  721. IsoUsb_DbgPrint(3, ("SetDeviceFunctional::"));
  722. IsoUsb_IoDecrement(DeviceExtension);
  723. IsoUsb_DbgPrint(3, ("SetDeviceFunctional - ends\n"));
  724. return STATUS_SUCCESS;
  725. }
  726. NTSTATUS
  727. FinishDevPoDnIrp(
  728. IN PDEVICE_OBJECT DeviceObject,
  729. IN PIRP Irp,
  730. IN PDEVICE_EXTENSION DeviceExtension
  731. )
  732. /*++
  733. Routine Description:
  734. This routine is the completion routine for device power DOWN irp.
  735. Arguments:
  736. DeviceObject - pointer to device object
  737. Irp - I/O request packet
  738. DeviceExtension - pointer to device extension
  739. Return Value:
  740. NT status value
  741. --*/
  742. {
  743. NTSTATUS ntStatus;
  744. POWER_STATE newState;
  745. PIO_STACK_LOCATION irpStack;
  746. //
  747. // initialize variables
  748. //
  749. ntStatus = Irp->IoStatus.Status;
  750. irpStack = IoGetCurrentIrpStackLocation(Irp);
  751. newState = irpStack->Parameters.Power.State;
  752. IsoUsb_DbgPrint(3, ("FinishDevPoDnIrp - begins\n"));
  753. if(NT_SUCCESS(ntStatus) && irpStack->MinorFunction == IRP_MN_SET_POWER) {
  754. //
  755. // update the cache;
  756. //
  757. IsoUsb_DbgPrint(3, ("updating cache..\n"));
  758. DeviceExtension->DevPower = newState.DeviceState;
  759. PoSetPowerState(DeviceObject, DevicePowerState, newState);
  760. }
  761. PoStartNextPowerIrp(Irp);
  762. IsoUsb_DbgPrint(3, ("FinishDevPoDnIrp::"));
  763. IsoUsb_IoDecrement(DeviceExtension);
  764. IsoUsb_DbgPrint(3, ("FinishDevPoDnIrp - ends\n"));
  765. return STATUS_SUCCESS;
  766. }
  767. NTSTATUS
  768. HoldIoRequests(
  769. IN PDEVICE_OBJECT DeviceObject,
  770. IN PIRP Irp
  771. )
  772. /*++
  773. Routine Description:
  774. This routine is called on query or set power DOWN irp for the device.
  775. This routine queues a workitem.
  776. Arguments:
  777. DeviceObject - pointer to device object
  778. Irp - I/O request packet
  779. Return Value:
  780. NT status value
  781. --*/
  782. {
  783. NTSTATUS ntStatus;
  784. PIO_WORKITEM item;
  785. PDEVICE_EXTENSION deviceExtension;
  786. PWORKER_THREAD_CONTEXT context;
  787. //
  788. // initialize variables
  789. //
  790. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  791. IsoUsb_DbgPrint(3, ("HoldIoRequests - begins\n"));
  792. deviceExtension->QueueState = HoldRequests;
  793. context = ExAllocatePool(NonPagedPool, sizeof(WORKER_THREAD_CONTEXT));
  794. if(context) {
  795. item = IoAllocateWorkItem(DeviceObject);
  796. context->Irp = Irp;
  797. context->DeviceObject = DeviceObject;
  798. context->WorkItem = item;
  799. if(item) {
  800. IoMarkIrpPending(Irp);
  801. IoQueueWorkItem(item, HoldIoRequestsWorkerRoutine,
  802. DelayedWorkQueue, context);
  803. ntStatus = STATUS_PENDING;
  804. }
  805. else {
  806. IsoUsb_DbgPrint(3, ("Failed to allocate memory for workitem\n"));
  807. ExFreePool(context);
  808. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  809. }
  810. }
  811. else {
  812. IsoUsb_DbgPrint(1, ("Failed to alloc memory for worker thread context\n"));
  813. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  814. }
  815. IsoUsb_DbgPrint(3, ("HoldIoRequests - ends\n"));
  816. return ntStatus;
  817. }
  818. VOID
  819. HoldIoRequestsWorkerRoutine(
  820. IN PDEVICE_OBJECT DeviceObject,
  821. IN PVOID Context
  822. )
  823. /*++
  824. Routine Description:
  825. This routine waits for the I/O in progress to finish and then
  826. sends the device power irp (query/set) down the stack.
  827. Arguments:
  828. DeviceObject - pointer to device object
  829. Context - context passed to the work-item.
  830. Return Value:
  831. None
  832. --*/
  833. {
  834. PIRP irp;
  835. NTSTATUS ntStatus;
  836. PDEVICE_EXTENSION deviceExtension;
  837. PWORKER_THREAD_CONTEXT context;
  838. IsoUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine - begins\n"));
  839. //
  840. // initialize variables
  841. //
  842. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  843. context = (PWORKER_THREAD_CONTEXT) Context;
  844. irp = (PIRP) context->Irp;
  845. //
  846. // wait for I/O in progress to finish.
  847. // the stop event is signalled when the counter drops to 1.
  848. // invoke IsoUsb_IoDecrement twice: once each for the S-Irp and D-Irp.
  849. //
  850. IsoUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine::"));
  851. IsoUsb_IoDecrement(deviceExtension);
  852. IsoUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine::"));
  853. IsoUsb_IoDecrement(deviceExtension);
  854. KeWaitForSingleObject(&deviceExtension->StopEvent, Executive,
  855. KernelMode, FALSE, NULL);
  856. //
  857. // Increment twice to restore the count
  858. //
  859. IsoUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine::"));
  860. IsoUsb_IoIncrement(deviceExtension);
  861. IsoUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine::"));
  862. IsoUsb_IoIncrement(deviceExtension);
  863. //
  864. // now send the Irp down
  865. //
  866. IoCopyCurrentIrpStackLocationToNext(irp);
  867. IoSetCompletionRoutine(irp, (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
  868. deviceExtension, TRUE, TRUE, TRUE);
  869. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
  870. if(!NT_SUCCESS(ntStatus)) {
  871. IsoUsb_DbgPrint(1, ("Lower driver fail a power Irp\n"));
  872. }
  873. IoFreeWorkItem(context->WorkItem);
  874. ExFreePool((PVOID)context);
  875. IsoUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine - ends\n"));
  876. }
  877. NTSTATUS
  878. QueueRequest(
  879. IN OUT PDEVICE_EXTENSION DeviceExtension,
  880. IN PIRP Irp
  881. )
  882. /*++
  883. Routine Description:
  884. Queue the Irp in the device queue
  885. Arguments:
  886. DeviceExtension - pointer to device extension
  887. Irp - I/O request packet.
  888. Return Value:
  889. NT status value
  890. --*/
  891. {
  892. KIRQL oldIrql;
  893. NTSTATUS ntStatus;
  894. //
  895. // initialize variables
  896. //
  897. ntStatus = STATUS_PENDING;
  898. IsoUsb_DbgPrint(3, ("QueueRequests - begins\n"));
  899. ASSERT(HoldRequests == DeviceExtension->QueueState);
  900. KeAcquireSpinLock(&DeviceExtension->QueueLock, &oldIrql);
  901. InsertTailList(&DeviceExtension->NewRequestsQueue,
  902. &Irp->Tail.Overlay.ListEntry);
  903. IoMarkIrpPending(Irp);
  904. //
  905. // Set the cancel routine
  906. //
  907. IoSetCancelRoutine(Irp, CancelQueued);
  908. KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
  909. IsoUsb_DbgPrint(3, ("QueueRequests - ends\n"));
  910. return ntStatus;
  911. }
  912. VOID
  913. CancelQueued(
  914. IN PDEVICE_OBJECT DeviceObject,
  915. IN PIRP Irp
  916. )
  917. /*++
  918. Routine Description:
  919. This routine removes the irp from the queue and completes it with
  920. STATUS_CANCELLED
  921. Arguments:
  922. DeviceObject - pointer to device object
  923. Irp - I/O request packet
  924. Return Value:
  925. None.
  926. --*/
  927. {
  928. PDEVICE_EXTENSION deviceExtension;
  929. KIRQL oldIrql;
  930. //
  931. // initialize variables
  932. //
  933. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  934. oldIrql = Irp->CancelIrql;
  935. IsoUsb_DbgPrint(3, ("CancelQueued - begins\n"));
  936. //
  937. // Release the cancel spin lock
  938. //
  939. IoReleaseCancelSpinLock(Irp->CancelIrql);
  940. //
  941. // Acquire the queue lock
  942. //
  943. KeAcquireSpinLockAtDpcLevel(&deviceExtension->QueueLock);
  944. //
  945. // Remove the cancelled Irp from queue and release the lock
  946. //
  947. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  948. KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql);
  949. //
  950. // complete with STATUS_CANCELLED
  951. //
  952. Irp->IoStatus.Status = STATUS_CANCELLED;
  953. Irp->IoStatus.Information = 0;
  954. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  955. IsoUsb_DbgPrint(3, ("CancelQueued - ends\n"));
  956. return;
  957. }
  958. NTSTATUS
  959. IssueWaitWake(
  960. IN PDEVICE_EXTENSION DeviceExtension
  961. )
  962. /*++
  963. Routine Description:
  964. This routine will PoRequest a WAIT WAKE irp for the device
  965. Arguments:
  966. DeviceExtension - pointer to device extension
  967. Return Value:
  968. NT status value.
  969. --*/
  970. {
  971. POWER_STATE poState;
  972. NTSTATUS ntStatus;
  973. IsoUsb_DbgPrint(3, ("IssueWaitWake - begins\n"));
  974. if(InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 1)) {
  975. return STATUS_DEVICE_BUSY;
  976. }
  977. InterlockedExchange(&DeviceExtension->FlagWWCancel, 0);
  978. //
  979. // lowest state from which this Irp will wake the system
  980. //
  981. poState.SystemState = DeviceExtension->DeviceCapabilities.SystemWake;
  982. ntStatus = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
  983. IRP_MN_WAIT_WAKE,
  984. poState,
  985. (PREQUEST_POWER_COMPLETE) WaitWakeCallback,
  986. DeviceExtension,
  987. &DeviceExtension->WaitWakeIrp);
  988. if(!NT_SUCCESS(ntStatus)) {
  989. InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 0);
  990. }
  991. IsoUsb_DbgPrint(3, ("IssueWaitWake - ends\n"));
  992. return ntStatus;
  993. }
  994. VOID
  995. CancelWaitWake(
  996. IN PDEVICE_EXTENSION DeviceExtension
  997. )
  998. /*++
  999. Routine Description:
  1000. This routine cancels the Wait Wake request.
  1001. Arguments:
  1002. DeviceExtension - pointer to the device extension
  1003. Return Value:
  1004. None.
  1005. --*/
  1006. {
  1007. PIRP Irp;
  1008. IsoUsb_DbgPrint(3, ("CancelWaitWake - begins\n"));
  1009. Irp = (PIRP) InterlockedExchangePointer(&DeviceExtension->WaitWakeIrp,
  1010. NULL);
  1011. if(Irp) {
  1012. IoCancelIrp(Irp);
  1013. if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1)) {
  1014. PoStartNextPowerIrp(Irp);
  1015. Irp->IoStatus.Status = STATUS_CANCELLED;
  1016. Irp->IoStatus.Information = 0;
  1017. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1018. }
  1019. }
  1020. IsoUsb_DbgPrint(3, ("CancelWaitWake - ends\n"));
  1021. }
  1022. NTSTATUS
  1023. WaitWakeCompletionRoutine(
  1024. IN PDEVICE_OBJECT DeviceObject,
  1025. IN PIRP Irp,
  1026. IN PDEVICE_EXTENSION DeviceExtension
  1027. )
  1028. /*++
  1029. Routine Description:
  1030. This is the IoSet completion routine for the wait wake irp.
  1031. Arguments:
  1032. DeviceObject - pointer to device object
  1033. Irp - I/O request packet
  1034. DeviceExtension - pointer to device extension
  1035. Return Value:
  1036. NT status value
  1037. --*/
  1038. {
  1039. IsoUsb_DbgPrint(3, ("WaitWakeCompletionRoutine - begins\n"));
  1040. if(Irp->PendingReturned) {
  1041. IoMarkIrpPending(Irp);
  1042. }
  1043. //
  1044. // Nullify the WaitWakeIrp pointer-the Irp is released
  1045. // as part of the completion process. If it's already NULL,
  1046. // avoid race with the CancelWaitWake routine.
  1047. //
  1048. if(InterlockedExchangePointer(&DeviceExtension->WaitWakeIrp, NULL)) {
  1049. PoStartNextPowerIrp(Irp);
  1050. return STATUS_SUCCESS;
  1051. }
  1052. //
  1053. // CancelWaitWake has run.
  1054. // If FlagWWCancel != 0, complete the Irp.
  1055. // If FlagWWCancel == 0, CancelWaitWake completes it.
  1056. //
  1057. if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1)) {
  1058. PoStartNextPowerIrp(Irp);
  1059. return STATUS_CANCELLED;
  1060. }
  1061. IsoUsb_DbgPrint(3, ("WaitWakeCompletionRoutine - ends\n"));
  1062. return STATUS_MORE_PROCESSING_REQUIRED;
  1063. }
  1064. VOID
  1065. WaitWakeCallback(
  1066. IN PDEVICE_OBJECT DeviceObject,
  1067. IN UCHAR MinorFunction,
  1068. IN POWER_STATE PowerState,
  1069. IN PVOID Context,
  1070. IN PIO_STATUS_BLOCK IoStatus
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. This is the PoRequest completion routine for the wait wake irp.
  1075. Arguments:
  1076. DeviceObject - pointer to device object
  1077. MinorFunction - irp minor function
  1078. PowerState - power state of the irp.
  1079. Context - context passed to the completion routine.
  1080. IoStatus - status block.
  1081. Return Value:
  1082. None
  1083. --*/
  1084. {
  1085. NTSTATUS ntStatus;
  1086. POWER_STATE powerState;
  1087. PDEVICE_EXTENSION deviceExtension;
  1088. IsoUsb_DbgPrint(3, ("WaitWakeCallback - begins\n"));
  1089. deviceExtension = (PDEVICE_EXTENSION) Context;
  1090. InterlockedExchange(&deviceExtension->FlagWWOutstanding, 0);
  1091. if(!NT_SUCCESS(IoStatus->Status)) {
  1092. return;
  1093. }
  1094. //
  1095. // wake up the device
  1096. //
  1097. if(deviceExtension->DevPower == PowerDeviceD0) {
  1098. IsoUsb_DbgPrint(3, ("device already powered up...\n"));
  1099. return;
  1100. }
  1101. IsoUsb_DbgPrint(3, ("WaitWakeCallback::"));
  1102. IsoUsb_IoIncrement(deviceExtension);
  1103. powerState.DeviceState = PowerDeviceD0;
  1104. ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
  1105. IRP_MN_SET_POWER,
  1106. powerState,
  1107. (PREQUEST_POWER_COMPLETE) WWIrpCompletionFunc,
  1108. deviceExtension,
  1109. NULL);
  1110. if(deviceExtension->WaitWakeEnable) {
  1111. IssueWaitWake(deviceExtension);
  1112. }
  1113. IsoUsb_DbgPrint(3, ("WaitWakeCallback - ends\n"));
  1114. return;
  1115. }
  1116. PCHAR
  1117. PowerMinorFunctionString (
  1118. IN UCHAR MinorFunction
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. Arguments:
  1123. Return Value:
  1124. --*/
  1125. {
  1126. switch (MinorFunction) {
  1127. case IRP_MN_SET_POWER:
  1128. return "IRP_MN_SET_POWER\n";
  1129. case IRP_MN_QUERY_POWER:
  1130. return "IRP_MN_QUERY_POWER\n";
  1131. case IRP_MN_POWER_SEQUENCE:
  1132. return "IRP_MN_POWER_SEQUENCE\n";
  1133. case IRP_MN_WAIT_WAKE:
  1134. return "IRP_MN_WAIT_WAKE\n";
  1135. default:
  1136. return "IRP_MN_?????\n";
  1137. }
  1138. }