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.

1275 lines
40 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. pocall
  5. Abstract:
  6. PoCallDriver and related routines.
  7. Author:
  8. Bryan Willman (bryanwi) 14-Nov-1996
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. PIRP
  13. PopFindIrpByInrush(
  14. );
  15. NTSTATUS
  16. PopPresentIrp(
  17. PIO_STACK_LOCATION IrpSp,
  18. PIRP Irp
  19. );
  20. VOID
  21. PopPassivePowerCall(
  22. PVOID Parameter
  23. );
  24. NTSTATUS
  25. PopCompleteRequestIrp (
  26. IN PDEVICE_OBJECT DeviceObject,
  27. IN PIRP Irp,
  28. IN PVOID Context
  29. );
  30. #if 0
  31. #define PATHTEST(a) DbgPrint(a)
  32. #else
  33. #define PATHTEST(a)
  34. #endif
  35. #ifdef ALLOC_PRAGMA
  36. #pragma alloc_text(PAGELK, PopSystemIrpDispatchWorker)
  37. #endif
  38. NTKERNELAPI
  39. NTSTATUS
  40. PoCallDriver (
  41. IN PDEVICE_OBJECT DeviceObject,
  42. IN OUT PIRP Irp
  43. )
  44. /*++
  45. Routine Description:
  46. This is the routine that must be used to send an
  47. IRP_MJ_POWER irp to device drivers.
  48. It performs specialized synchronization on power operations
  49. for device drivers.
  50. NOTE WELL:
  51. All callers to PoCallDriver MUST set the current io
  52. stack location parameter value SystemContext to 0,
  53. unless they are passing on an IRP to lower drivers,
  54. in which case they must copy the value from above.
  55. Arguments:
  56. DeviceObject - the device object the irp is to be routed to
  57. Irp - pointer to the irp of interest
  58. Return Value:
  59. Normal NTSTATUS data.
  60. --*/
  61. {
  62. NTSTATUS status;
  63. PIO_STACK_LOCATION irpsp;
  64. PDEVOBJ_EXTENSION doe;
  65. PWORK_QUEUE_ITEM pwi;
  66. KIRQL oldIrql;
  67. ASSERT(KeGetCurrentIrql()<=DISPATCH_LEVEL);
  68. PopLockIrpSerialList(&oldIrql);
  69. irpsp = IoGetNextIrpStackLocation(Irp);
  70. doe = DeviceObject->DeviceObjectExtension;
  71. irpsp->DeviceObject = DeviceObject;
  72. ASSERT(irpsp->MajorFunction == IRP_MJ_POWER);
  73. PoPowerTrace(POWERTRACE_CALL,DeviceObject,Irp,irpsp);
  74. if (DeviceObject->Flags & DO_POWER_NOOP) {
  75. PATHTEST("PoCallDriver #01\n");
  76. Irp->IoStatus.Status = STATUS_SUCCESS;
  77. Irp->IoStatus.Information = 0L;
  78. // we *don't* need to call PoStartNextPowerIrp() because we'll
  79. // never enqueue anything for this DO, so there will never be
  80. // any other IRP to run.
  81. IoCompleteRequest(Irp, 0);
  82. PopUnlockIrpSerialList(oldIrql);
  83. return STATUS_SUCCESS;
  84. }
  85. if (irpsp->MinorFunction != IRP_MN_SET_POWER &&
  86. irpsp->MinorFunction != IRP_MN_QUERY_POWER) {
  87. PopUnlockIrpSerialList(oldIrql);
  88. return IoCallDriver (DeviceObject, Irp);
  89. }
  90. //
  91. // We never query going up, so being inrush sensitive
  92. // only matters for SET_POWER to D0
  93. // If this is an inrush sensitive DevObj, and we're going TO PowerDeviceD0,
  94. // then serialize on the gobal Inrush flag.
  95. //
  96. if ((irpsp->MinorFunction == IRP_MN_SET_POWER) &&
  97. (irpsp->Parameters.Power.Type == DevicePowerState) &&
  98. (irpsp->Parameters.Power.State.DeviceState == PowerDeviceD0) &&
  99. (PopGetDoDevicePowerState(doe) != PowerDeviceD0) &&
  100. (DeviceObject->Flags & DO_POWER_INRUSH))
  101. {
  102. PATHTEST("PoCallDriver #02\n");
  103. if (PopInrushIrpPointer == Irp) {
  104. //
  105. // This irp has already been identified as an INRUSH irp,
  106. // and it is the active inrush irp,
  107. // so it can actually just continue on, after we increment
  108. // the ref count
  109. //
  110. PATHTEST("PoCallDriver #03\n");
  111. ASSERT((irpsp->Parameters.Power.SystemContext & POP_INRUSH_CONTEXT) == POP_INRUSH_CONTEXT);
  112. PopInrushIrpReferenceCount++;
  113. if (PopInrushIrpReferenceCount > 256) {
  114. PopInternalAddToDumpFile ( irpsp, sizeof(IO_STACK_LOCATION), DeviceObject, NULL, NULL, NULL );
  115. KeBugCheckEx(INTERNAL_POWER_ERROR, 0x400, 1, (ULONG_PTR)irpsp, (ULONG_PTR)DeviceObject);
  116. }
  117. } else if ((!PopInrushIrpPointer) && (!PopInrushPending)) {
  118. //
  119. // This is a freshly starting inrush IRP, AND there is not
  120. // already an inrush irp, so mark this as an inrush irp,
  121. // note that inrush is active, and continue
  122. //
  123. PATHTEST("PoCallDriver #04\n");
  124. PopInrushIrpPointer = Irp;
  125. PopInrushIrpReferenceCount = 1;
  126. irpsp->Parameters.Power.SystemContext = POP_INRUSH_CONTEXT;
  127. //
  128. // Inrush irps will cause us to free the processor throttling.
  129. //
  130. PopPerfHandleInrush ( TRUE );
  131. } else {
  132. PATHTEST("PoCallDriver #05\n");
  133. ASSERT(PopInrushIrpPointer || PopInrushPending);
  134. //
  135. // There is already an active Inrush irp, and this one isn't it.
  136. // OR there is an inrush irp blocked on the queue, in either case,
  137. // mark this as an inrush irp and enqueue it.
  138. //
  139. doe->PowerFlags |= POPF_DEVICE_PENDING;
  140. irpsp->Parameters.Power.SystemContext = POP_INRUSH_CONTEXT;
  141. InsertTailList(
  142. &PopIrpSerialList,
  143. &(Irp->Tail.Overlay.ListEntry)
  144. );
  145. PopIrpSerialListLength++;
  146. #if DBG
  147. if (PopIrpSerialListLength > 10) {
  148. DbgPrint("WARNING: PopIrpSerialListLength > 10!!!\n");
  149. }
  150. if (PopIrpSerialListLength > 100) {
  151. DbgPrint("WARNING: PopIrpSerialListLength > **100**!!!\n");
  152. PopInternalAddToDumpFile ( &PopIrpSerialList, PAGE_SIZE, DeviceObject, NULL, NULL, NULL );
  153. KeBugCheckEx(INTERNAL_POWER_ERROR, 0x401, 2, (ULONG_PTR)&PopIrpSerialList, (ULONG_PTR)DeviceObject);
  154. }
  155. #endif
  156. PopInrushPending = TRUE;
  157. PopUnlockIrpSerialList(oldIrql);
  158. return STATUS_PENDING;
  159. }
  160. }
  161. //
  162. // See if there is already a power irp active for this
  163. // device object. If not, send this one on. If so, enqueue
  164. // it to wait.
  165. //
  166. if (irpsp->Parameters.Power.Type == SystemPowerState) {
  167. PATHTEST("PoCallDriver #06\n");
  168. if (doe->PowerFlags & POPF_SYSTEM_ACTIVE) {
  169. //
  170. // we already have one active system power state irp for the devobj,
  171. // so enqueue this one on the global power irp holding list,
  172. // and set the pending bit.
  173. //
  174. PATHTEST("PoCallDriver #07\n");
  175. doe->PowerFlags |= POPF_SYSTEM_PENDING;
  176. InsertTailList(
  177. &PopIrpSerialList,
  178. (&(Irp->Tail.Overlay.ListEntry))
  179. );
  180. PopIrpSerialListLength++;
  181. #if DBG
  182. if (PopIrpSerialListLength > 10) {
  183. DbgPrint("WARNING: PopIrpSerialListLength > 10!!!\n");
  184. }
  185. if (PopIrpSerialListLength > 100) {
  186. DbgPrint("WARNING: PopIrpSerialListLength > **100**!!!\n");
  187. PopInternalAddToDumpFile ( &PopIrpSerialList, PAGE_SIZE, DeviceObject, NULL, NULL, NULL );
  188. KeBugCheckEx(INTERNAL_POWER_ERROR, 0x402, 3, (ULONG_PTR)&PopIrpSerialList, (ULONG_PTR)DeviceObject);
  189. }
  190. #endif
  191. PopUnlockIrpSerialList(oldIrql);
  192. return STATUS_PENDING;
  193. } else {
  194. PATHTEST("PoCallDriver #08\n");
  195. doe->PowerFlags |= POPF_SYSTEM_ACTIVE;
  196. }
  197. }
  198. if (irpsp->Parameters.Power.Type == DevicePowerState) {
  199. PATHTEST("PoCallDriver #09\n");
  200. if ((doe->PowerFlags & POPF_DEVICE_ACTIVE) ||
  201. (doe->PowerFlags & POPF_DEVICE_PENDING))
  202. {
  203. //
  204. // we already have one active device power state irp for the devobj,
  205. // OR we're behind an inrush irp (if pending but not active)
  206. // so enqueue this irp on the global power irp holdinglist,
  207. // and set the pending bit.
  208. //
  209. PATHTEST("PoCallDriver #10\n");
  210. doe->PowerFlags |= POPF_DEVICE_PENDING;
  211. InsertTailList(
  212. &PopIrpSerialList,
  213. &(Irp->Tail.Overlay.ListEntry)
  214. );
  215. PopIrpSerialListLength++;
  216. #if DBG
  217. if (PopIrpSerialListLength > 10) {
  218. DbgPrint("WARNING: PopIrpSerialListLength > 10!!!\n");
  219. }
  220. if (PopIrpSerialListLength > 100) {
  221. DbgPrint("WARNING: PopIrpSerialListLength > **100**!!!\n");
  222. PopInternalAddToDumpFile ( &PopIrpSerialList, PAGE_SIZE, DeviceObject, NULL, NULL, NULL );
  223. KeBugCheckEx(INTERNAL_POWER_ERROR, 0x403, 4, (ULONG_PTR)&PopIrpSerialList, (ULONG_PTR)DeviceObject);
  224. }
  225. #endif
  226. PopUnlockIrpSerialList(oldIrql);
  227. return STATUS_PENDING;
  228. } else {
  229. PATHTEST("PoCallDriver #11\n");
  230. doe->PowerFlags |= POPF_DEVICE_ACTIVE;
  231. }
  232. }
  233. //
  234. // If we get here it's time to send this IRP on to the driver.
  235. // If the driver is NOT marked INRUSH and it IS marked PAGABLE
  236. // (which is hopefully the normal case) we will arrange to call
  237. // it from PASSIVE_LEVEL.
  238. //
  239. // If it is NOT pagable or IS INRUSH, we will arrange to call
  240. // it from DPC level.
  241. //
  242. // Note that if a driver is marked INRUSH, it will ALWAYS be called
  243. // from DPC level with power irps, even though some of them may not
  244. // be inrush irps.
  245. //
  246. // having your driver be both PAGABLE and INRUSH is incorrect
  247. //
  248. ASSERT(irpsp->DeviceObject->DeviceObjectExtension->PowerFlags & (POPF_DEVICE_ACTIVE | POPF_SYSTEM_ACTIVE));
  249. PopUnlockIrpSerialList(oldIrql);
  250. status = PopPresentIrp(irpsp, Irp);
  251. return status;
  252. }
  253. NTSTATUS
  254. PopPresentIrp(
  255. PIO_STACK_LOCATION IrpSp,
  256. PIRP Irp
  257. )
  258. /*++
  259. Routine Description:
  260. When PoCallDriver, PoCompleteRequest, etc, need to actually present
  261. an Irp to a devobj, they call PopPresentIrp.
  262. This routine will compute whether the Irp should be presented at
  263. PASSIVE or DISPATCH level, and make an appropriately structured call
  264. Arguments:
  265. IrpSp - provides current stack location in Irp of interest
  266. Irp - provides irp of interest
  267. Return Value:
  268. Normal NTSTATUS data.
  269. --*/
  270. {
  271. NTSTATUS status;
  272. PWORK_QUEUE_ITEM pwi;
  273. PDEVICE_OBJECT devobj;
  274. BOOLEAN PassiveLevel;
  275. KIRQL OldIrql;
  276. PATHTEST("PopPresentIrp #01\n");
  277. devobj = IrpSp->DeviceObject;
  278. ASSERT (IrpSp->MajorFunction == IRP_MJ_POWER);
  279. PassiveLevel = TRUE;
  280. if (IrpSp->MinorFunction == IRP_MN_SET_POWER &&
  281. (!(devobj->Flags & DO_POWER_PAGABLE) || (devobj->Flags & DO_POWER_INRUSH)) ) {
  282. if ((PopCallSystemState & PO_CALL_NON_PAGED) ||
  283. ( (IrpSp->Parameters.Power.Type == DevicePowerState &&
  284. IrpSp->Parameters.Power.State.DeviceState == PowerDeviceD0) ||
  285. (IrpSp->Parameters.Power.Type == SystemPowerState &&
  286. IrpSp->Parameters.Power.State.SystemState == PowerSystemWorking)) ) {
  287. PassiveLevel = FALSE;
  288. }
  289. }
  290. PoPowerTrace(POWERTRACE_PRESENT,devobj,Irp,IrpSp);
  291. if (PassiveLevel)
  292. {
  293. //
  294. // WARNING: A WORK_QUEUE_ITEM must fit in the DriverContext field of an IRP
  295. //
  296. ASSERT(sizeof(WORK_QUEUE_ITEM) <= sizeof(Irp->Tail.Overlay.DriverContext));
  297. #if DBG
  298. if ((IrpSp->Parameters.Power.SystemContext & POP_INRUSH_CONTEXT) == POP_INRUSH_CONTEXT) {
  299. //
  300. // we are sending an inrush irp off to a passive dispatch devobj
  301. // this is *probably* a bug
  302. //
  303. KdPrint(("PopPresentIrp: inrush irp to passive level dispatch!!!\n"));
  304. PopInternalAddToDumpFile ( IrpSp, sizeof(IO_STACK_LOCATION), devobj, NULL, NULL, NULL );
  305. KeBugCheckEx(INTERNAL_POWER_ERROR, 0x404, 5, (ULONG_PTR)IrpSp, (ULONG_PTR)devobj);
  306. }
  307. #endif
  308. PATHTEST("PopPresentIrp #02\n");
  309. //
  310. // If we're already at passive level, just dispatch the irp
  311. //
  312. if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
  313. status = IoCallDriver(IrpSp->DeviceObject, Irp);
  314. } else {
  315. //
  316. // Irp needs to be queued to some worker thread before
  317. // it can be dispatched. Mark it pending
  318. //
  319. IrpSp->Control |= SL_PENDING_RETURNED;
  320. status = STATUS_PENDING;
  321. PopLockWorkerQueue(&OldIrql);
  322. if (PopCallSystemState & PO_CALL_SYSDEV_QUEUE) {
  323. //
  324. // Queue to dedicated system power worker thread
  325. //
  326. InsertTailList (&PopAction.DevState->PresentIrpQueue, &(Irp->Tail.Overlay.ListEntry));
  327. KeSetEvent (&PopAction.DevState->Event, IO_NO_INCREMENT, FALSE);
  328. } else {
  329. //
  330. // Queue to generic system worker thread
  331. //
  332. pwi = (PWORK_QUEUE_ITEM)(&(Irp->Tail.Overlay.DriverContext[0]));
  333. ExInitializeWorkItem(pwi, PopPassivePowerCall, Irp);
  334. ExQueueWorkItem(pwi, DelayedWorkQueue);
  335. }
  336. PopUnlockWorkerQueue(OldIrql);
  337. }
  338. } else {
  339. //
  340. // Non-blocking request. To ensure proper behaviour, dispatch
  341. // the irp from dispatch_level
  342. //
  343. PATHTEST("PopPresentIrp #03\n");
  344. #if DBG
  345. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  346. status = IoCallDriver(IrpSp->DeviceObject, Irp);
  347. KeLowerIrql(OldIrql);
  348. #else
  349. status = IoCallDriver(IrpSp->DeviceObject, Irp);
  350. #endif
  351. }
  352. return status;
  353. }
  354. VOID
  355. PopPassivePowerCall(
  356. PVOID Parameter
  357. )
  358. {
  359. PIO_STACK_LOCATION irpsp;
  360. PIRP Irp;
  361. PDEVICE_OBJECT devobj;
  362. NTSTATUS status;
  363. //
  364. // Parameter points to Irp we are to send to driver
  365. //
  366. PATHTEST("PopPassivePowerCall #01\n");
  367. Irp = (PIRP)Parameter;
  368. irpsp = IoGetNextIrpStackLocation(Irp);
  369. devobj = irpsp->DeviceObject;
  370. status = IoCallDriver(devobj, Irp);
  371. return;
  372. }
  373. NTKERNELAPI
  374. VOID
  375. PoStartNextPowerIrp(
  376. IN PIRP Irp
  377. )
  378. /*++
  379. Routine Description:
  380. This procedure must be applied to every power irp, and only
  381. power irps, when a driver is finished with them.
  382. It will force post-irp completion items relevent to the irp
  383. to execute:
  384. a. If the irp is an inrush irp, and this is the top of the
  385. inrush irp stack, then this particular inrush irp is done,
  386. and we go find the next inrush irp (if any) and dispatch it.
  387. b. If step a. did NOT send an irp to the dev obj we came
  388. from, it is eligible for step c, otherwise it is not.
  389. c. If anything is pending on the dev obj, of the type that
  390. just completed, find the waiting irp and post it to the
  391. driver.
  392. This routine will NOT complete the Irp, the driver must do that.
  393. Arguments:
  394. Irp - pointer to the irp of interest
  395. Return Value:
  396. VOID.
  397. --*/
  398. {
  399. PIO_STACK_LOCATION irpsp;
  400. PIO_STACK_LOCATION nextsp;
  401. PIO_STACK_LOCATION secondsp;
  402. PDEVICE_OBJECT deviceObject;
  403. PDEVOBJ_EXTENSION doe;
  404. KIRQL oldirql;
  405. PIRP nextirp;
  406. PIRP secondirp;
  407. PIRP hangirp;
  408. irpsp = IoGetCurrentIrpStackLocation(Irp);
  409. ASSERT(irpsp->MajorFunction == IRP_MJ_POWER);
  410. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  411. deviceObject = irpsp->DeviceObject;
  412. doe = deviceObject->DeviceObjectExtension;
  413. nextirp = NULL;
  414. secondirp = NULL;
  415. PoPowerTrace(POWERTRACE_STARTNEXT,deviceObject,Irp,irpsp);
  416. //
  417. // a. if (partially completed inrush irp)
  418. // run any pending non-inrush irps on this DeviceObject, would be queued up
  419. // as DevicePowerState irps since inrush is always DevicePowerState
  420. //
  421. // b. else if (fully complete inrush irp)
  422. // clear the ir busy flag
  423. // find next inrush irp that applies to any DeviceObject
  424. // find any irps in queue for same DeviceObject ahead of inrush irp
  425. // if no leader, and target DeviceObject not DEVICE_ACTIVE, present inrush irp
  426. // else an active normal irp will unplug it all, so ignore that DeviceObject
  427. // [this makes sure next inrush is unstuck, wherever it is]
  428. // if no irp was presented, or an irp was presented to a DeviceObject other than us
  429. // look for next pending (non-inrush) irp to run on this DeviceObject
  430. // [this makes sure this DeviceObject is unstuck]
  431. //
  432. // c. else [normal irp has just completed]
  433. // find next irp of same type that applies to this DeviceObject
  434. // if (it's an inrush irp) && (inrush flag is set)
  435. // don't try to present anything
  436. // else
  437. // present the irp
  438. //
  439. PATHTEST("PoStartNextPowerIrp #01\n");
  440. PopLockIrpSerialList(&oldirql);
  441. if (PopInrushIrpPointer == Irp) {
  442. ASSERT((irpsp->Parameters.Power.SystemContext & POP_INRUSH_CONTEXT) == POP_INRUSH_CONTEXT);
  443. PATHTEST("PoStartNextPowerIrp #02\n");
  444. if (PopInrushIrpReferenceCount > 1) {
  445. //
  446. // case a.
  447. // we have an inrush irp, and it has NOT completed all of its power
  448. // management work. therefore, do NOT try to run the next inrush
  449. // irp, but do try to run any non-inrush irp pending on this
  450. // device object
  451. //
  452. PATHTEST("PoStartNextPowerIrp #03\n");
  453. PopInrushIrpReferenceCount--;
  454. ASSERT(PopInrushIrpReferenceCount >= 0);
  455. nextirp = PopFindIrpByDeviceObject(deviceObject, DevicePowerState);
  456. if (nextirp) {
  457. PATHTEST("PoStartNextPowerIrp #04\n");
  458. nextsp = IoGetNextIrpStackLocation(nextirp);
  459. if ( ! ((nextsp->Parameters.Power.SystemContext & POP_INRUSH_CONTEXT) == POP_INRUSH_CONTEXT)) {
  460. PATHTEST("PoStartNextPowerIrp #05\n");
  461. RemoveEntryList((&(nextirp->Tail.Overlay.ListEntry)));
  462. PopIrpSerialListLength--;
  463. } else {
  464. PATHTEST("PoStartNextPowerIrp #06\n");
  465. nextirp = NULL;
  466. }
  467. }
  468. if (!nextirp) {
  469. //
  470. // there's no more device irp waiting for this do, so
  471. // we can clear DO pending and active
  472. // but what if there's another inrush irp! no worries, it
  473. // will be run when the one we just partially finished completes.
  474. //
  475. PATHTEST("PoStartNextPowerIrp #07\n");
  476. doe->PowerFlags = doe->PowerFlags & ~POPF_DEVICE_ACTIVE;
  477. doe->PowerFlags = doe->PowerFlags & ~POPF_DEVICE_PENDING;
  478. }
  479. PopUnlockIrpSerialList(oldirql);
  480. if (nextirp) {
  481. PATHTEST("PoStartNextPowerIrp #08\n");
  482. ASSERT(nextsp->DeviceObject->DeviceObjectExtension->PowerFlags & POPF_DEVICE_ACTIVE);
  483. PopPresentIrp(nextsp, nextirp);
  484. }
  485. return; // end of case a.
  486. } else {
  487. //
  488. // case b.
  489. // we've just completed the last work item of an inrush irp, so we
  490. // want to try to make the next inrush irp runnable.
  491. //
  492. PATHTEST("PoStartNextPowerIrp #09\n");
  493. PopInrushIrpReferenceCount--;
  494. ASSERT(PopInrushIrpReferenceCount == 0);
  495. nextirp = PopFindIrpByInrush();
  496. if (nextirp) {
  497. PATHTEST("PoStartNextPowerIrp #10\n");
  498. ASSERT(PopInrushPending);
  499. nextsp = IoGetNextIrpStackLocation(nextirp);
  500. hangirp = PopFindIrpByDeviceObject(nextsp->DeviceObject, DevicePowerState);
  501. if (hangirp) {
  502. //
  503. // if we get where, there is a non inrush irp in front of the next inrush
  504. // irp, so try to run the non-inrush one, and set flags for later
  505. //
  506. PATHTEST("PoStartNextPowerIrp #11\n");
  507. nextirp = hangirp;
  508. PopInrushIrpPointer = NULL;
  509. PopInrushIrpReferenceCount = 0;
  510. nextsp = IoGetNextIrpStackLocation(nextirp);
  511. //
  512. // Can allow processor voltages to swing again
  513. //
  514. PopPerfHandleInrush ( FALSE );
  515. if (!(nextsp->DeviceObject->DeviceObjectExtension->PowerFlags & POPF_DEVICE_ACTIVE)) {
  516. PATHTEST("PoStartNextPowerIrp #12\n");
  517. RemoveEntryList((&(nextirp->Tail.Overlay.ListEntry)));
  518. nextsp->DeviceObject->DeviceObjectExtension->PowerFlags |= POPF_DEVICE_ACTIVE;
  519. PopIrpSerialListLength--;
  520. } else {
  521. PATHTEST("PoStartNextPowerIrp #13\n");
  522. nextirp = NULL;
  523. nextsp = NULL;
  524. }
  525. } else {
  526. //
  527. // we did find another inrush irp, and it's NOT block by a normal
  528. // irp, so we will run it.
  529. //
  530. PATHTEST("PoStartNextPowerIrp #14\n");
  531. RemoveEntryList((&(nextirp->Tail.Overlay.ListEntry)));
  532. nextsp->DeviceObject->DeviceObjectExtension->PowerFlags |= POPF_DEVICE_ACTIVE;
  533. PopIrpSerialListLength--;
  534. PopInrushIrpPointer = nextirp;
  535. PopInrushIrpReferenceCount = 1;
  536. }
  537. } else { // nextirp
  538. //
  539. // this inrush irp is done, and we didn't find any others
  540. //
  541. PATHTEST("PoStartNextPowerIrp #15\n");
  542. nextsp = NULL;
  543. PopInrushIrpPointer = NULL;
  544. PopInrushIrpReferenceCount = 0;
  545. //
  546. // Can allow processor voltages to swing again
  547. //
  548. PopPerfHandleInrush ( FALSE );
  549. }
  550. //
  551. // see if *either* of the above possible irps is posted against
  552. // this devobj. if not, see if there's one to run here
  553. //
  554. if ( ! ((nextsp) && (nextsp->DeviceObject == deviceObject))) {
  555. //
  556. // same is if nextsp == null or nextsp->do != do..
  557. // either case, there may be one more irp to run
  558. //
  559. PATHTEST("PoStartNextPowerIrp #16\n");
  560. secondirp = PopFindIrpByDeviceObject(deviceObject, DevicePowerState);
  561. if (secondirp) {
  562. PATHTEST("PoStartNextPowerIrp #17\n");
  563. secondsp = IoGetNextIrpStackLocation(secondirp);
  564. RemoveEntryList((&(secondirp->Tail.Overlay.ListEntry)));
  565. secondsp->DeviceObject->DeviceObjectExtension->PowerFlags |= POPF_DEVICE_ACTIVE;
  566. PopIrpSerialListLength--;
  567. } else {
  568. PATHTEST("PoStartNextPowerIrp #18\n");
  569. secondsp = NULL;
  570. //
  571. // nextsp/nextirp are not pending against us AND
  572. // secondsp/secondirp are not pending against us, SO
  573. // clear both pending and active flags
  574. //
  575. doe->PowerFlags = doe->PowerFlags & ~POPF_DEVICE_ACTIVE;
  576. doe->PowerFlags = doe->PowerFlags & ~POPF_DEVICE_PENDING;
  577. }
  578. } else {
  579. PATHTEST("PoStartNextPowerIrp #19\n");
  580. secondirp = NULL;
  581. secondsp = NULL;
  582. //
  583. // nextsp/nextirp is coming right at us, so pending/active stay set
  584. //
  585. }
  586. } // end of case b.
  587. } else if (irpsp->MinorFunction == IRP_MN_SET_POWER ||
  588. irpsp->MinorFunction == IRP_MN_QUERY_POWER) {
  589. //
  590. // case c.
  591. //
  592. // might be pending inrush to run, might be just non-inrush to run
  593. //
  594. if (irpsp->Parameters.Power.Type == DevicePowerState) {
  595. PATHTEST("PoStartNextPowerIrp #20\n");
  596. if ((PopInrushIrpPointer == NULL) && (PopInrushPending)) {
  597. //
  598. // it may be that the completion of the ordinary irp
  599. // that brought us here has made some inrush irp runnable, AND
  600. // there isn't currently an active inrush irp, and there might be one pending
  601. // so try to find and run the next inrush irp
  602. //
  603. PATHTEST("PoStartNextPowerIrp #21\n");
  604. nextirp = PopFindIrpByInrush();
  605. if (nextirp) {
  606. PATHTEST("PoStartNextPowerIrp #22\n");
  607. nextsp = IoGetNextIrpStackLocation(nextirp);
  608. if (!(nextsp->DeviceObject->DeviceObjectExtension->PowerFlags & POPF_DEVICE_ACTIVE)) {
  609. //
  610. // we've found an inrush irp, and it's runnable...
  611. //
  612. PATHTEST("PoStartNextPowerIrp #23\n");
  613. RemoveEntryList((&(nextirp->Tail.Overlay.ListEntry)));
  614. PopIrpSerialListLength--;
  615. nextsp->DeviceObject->DeviceObjectExtension->PowerFlags |= POPF_DEVICE_ACTIVE;
  616. PopInrushIrpPointer = nextirp;
  617. PopInrushIrpReferenceCount = 1;
  618. //
  619. // Running Inrush irp. Disable processor throttling.
  620. //
  621. PopPerfHandleInrush ( TRUE );
  622. } else {
  623. PATHTEST("PoStartNextPowerIrp #24\n");
  624. nextirp = NULL;
  625. nextsp = NULL;
  626. }
  627. } else {
  628. //
  629. // no more inrush irps in queue
  630. //
  631. PATHTEST("PoStartNextPowerIrp #25\n");
  632. nextsp = NULL;
  633. PopInrushPending = FALSE;
  634. }
  635. } else { // end of inrush
  636. PATHTEST("PoStartNextPowerIrp #26\n");
  637. nextirp = NULL;
  638. nextsp = NULL;
  639. }
  640. //
  641. // look for for next devicepowerstate irp for this DeviceObject
  642. // unless we're already found an inrush irp, and it's for us
  643. //
  644. if ( ! ((nextirp) && (nextsp->DeviceObject == deviceObject))) {
  645. PATHTEST("PoStartNextPowerIrp #27\n");
  646. secondirp = PopFindIrpByDeviceObject(deviceObject, DevicePowerState);
  647. if (!secondirp) {
  648. PATHTEST("PoStartNextPowerIrp #28\n");
  649. doe->PowerFlags = doe->PowerFlags & ~POPF_DEVICE_ACTIVE;
  650. doe->PowerFlags = doe->PowerFlags & ~POPF_DEVICE_PENDING;
  651. }
  652. } else {
  653. PATHTEST("PoStartNextPowerIrp #29\n");
  654. secondirp = NULL;
  655. }
  656. } else if (irpsp->Parameters.Power.Type == SystemPowerState) {
  657. //
  658. // look for next systempowerstate irp for this DeviceObject
  659. //
  660. PATHTEST("PoStartNextPowerIrp #30\n");
  661. nextirp = NULL;
  662. nextsp = NULL;
  663. secondirp = PopFindIrpByDeviceObject(deviceObject, SystemPowerState);
  664. if (!secondirp) {
  665. PATHTEST("PoStartNextPowerIrp #31\n");
  666. doe->PowerFlags = doe->PowerFlags & ~POPF_SYSTEM_ACTIVE;
  667. doe->PowerFlags = doe->PowerFlags & ~POPF_SYSTEM_PENDING;
  668. }
  669. }
  670. if (secondirp) {
  671. PATHTEST("PoStartNextPowerIrp #33\n");
  672. secondsp = IoGetNextIrpStackLocation(secondirp);
  673. RemoveEntryList((&(secondirp->Tail.Overlay.ListEntry)));
  674. PopIrpSerialListLength--;
  675. }
  676. } else { // end of case c.
  677. PoPrint(PO_POCALL, ("PoStartNextPowerIrp: Irp @ %08x, minor function %d\n",
  678. Irp, irpsp->MinorFunction
  679. ));
  680. }
  681. PopUnlockIrpSerialList(oldirql);
  682. //
  683. // case b. and case c. might both make two pending irps runnable,
  684. // could be a normal irp and an inrush irp, or only 1 of the two, or neither of the two
  685. //
  686. if (nextirp || secondirp) {
  687. if (nextirp) {
  688. PATHTEST("PoStartNextPowerIrp #34\n");
  689. ASSERT(nextsp->DeviceObject->DeviceObjectExtension->PowerFlags & (POPF_DEVICE_ACTIVE | POPF_SYSTEM_ACTIVE));
  690. PopPresentIrp(nextsp, nextirp);
  691. }
  692. if (secondirp) {
  693. PATHTEST("PoStartNextPowerIrp #35\n");
  694. ASSERT(secondsp->DeviceObject->DeviceObjectExtension->PowerFlags & (POPF_DEVICE_ACTIVE | POPF_SYSTEM_ACTIVE));
  695. PopPresentIrp(secondsp, secondirp);
  696. }
  697. }
  698. return;
  699. }
  700. PIRP
  701. PopFindIrpByInrush(
  702. )
  703. /*++
  704. Routine Description:
  705. This procedure runs the irp serial list (which contains all
  706. waiting irps, be they queued up on a single device object or
  707. multiple inrush irps) looking for the first inrush irp.
  708. If one is found, it's address is returned, with it still enqueued
  709. in the list.
  710. Caller must be holding PopIrpSerialList lock.
  711. Arguments:
  712. Return Value:
  713. --*/
  714. {
  715. PLIST_ENTRY item;
  716. PIRP irp;
  717. PIO_STACK_LOCATION irpsp;
  718. item = PopIrpSerialList.Flink;
  719. while (item != &PopIrpSerialList) {
  720. irp = CONTAINING_RECORD(item, IRP, Tail.Overlay.ListEntry);
  721. irpsp = IoGetNextIrpStackLocation(irp);
  722. if ((irpsp->Parameters.Power.SystemContext & POP_INRUSH_CONTEXT) == POP_INRUSH_CONTEXT) {
  723. //
  724. // we've found an inrush irp
  725. //
  726. return irp;
  727. }
  728. item = item->Flink;
  729. }
  730. return NULL;
  731. }
  732. PIRP
  733. PopFindIrpByDeviceObject(
  734. PDEVICE_OBJECT DeviceObject,
  735. POWER_STATE_TYPE Type
  736. )
  737. /*++
  738. Routine Description:
  739. This procedure runs the irp serial list (which contains all
  740. waiting irps, be they queued up on a single device object or
  741. multiple inrush irps) looking for the first irp that applies
  742. the the supplied device driver. If one is found, its address,
  743. while still in the list, is returned. Else, null is returned.
  744. Caller must be holding PopIrpSerialList lock.
  745. Arguments:
  746. DeviceObject - address of device object we're looking for the next irp for
  747. Type - whether an irp of type SystemPowerState, DevicePowerState, etc, is wanted
  748. Return Value:
  749. address of found irp, or null if none.
  750. --*/
  751. {
  752. PLIST_ENTRY item;
  753. PIRP irp;
  754. PIO_STACK_LOCATION irpsp;
  755. for(item = PopIrpSerialList.Flink;
  756. item != &PopIrpSerialList;
  757. item = item->Flink)
  758. {
  759. irp = CONTAINING_RECORD(item, IRP, Tail.Overlay.ListEntry);
  760. irpsp = IoGetNextIrpStackLocation(irp);
  761. if (irpsp->DeviceObject == DeviceObject) {
  762. //
  763. // we've found a waiting irp that applies to the device object
  764. // the caller is interested in
  765. //
  766. if (irpsp->Parameters.Power.Type == Type) {
  767. //
  768. // irp is of the type that the caller wants
  769. //
  770. return irp;
  771. }
  772. }
  773. }
  774. return NULL;
  775. }
  776. NTSTATUS
  777. PoRequestPowerIrp (
  778. IN PDEVICE_OBJECT DeviceObject,
  779. IN UCHAR MinorFunction,
  780. IN POWER_STATE PowerState,
  781. IN PREQUEST_POWER_COMPLETE CompletionFunction,
  782. IN PVOID Context,
  783. OUT PIRP *ResultIrp OPTIONAL
  784. )
  785. /*++
  786. Routine Description:
  787. This allocates a device power irp and sends it to the top of the
  788. PDO stack for the passed device object. When the irp completes,
  789. the CompletionFunction is called.
  790. Arguments:
  791. DeviceObject - address of a device object who's stack is to get the
  792. device power irp
  793. MinorFunction - Minor fuction code for power irp
  794. DeviceState - The DeviceState to send in the irp
  795. CompletionFunction- The requestors completion function to invoke once the
  796. irp has completed
  797. Context - The requestors context for the completion function
  798. Irp - Irp which is only valid until CompletionFunction is called
  799. Return Value:
  800. Status of the request
  801. --*/
  802. {
  803. PIRP Irp;
  804. PIO_STACK_LOCATION IrpSp;
  805. PDEVICE_OBJECT TargetDevice;
  806. POWER_ACTION IrpAction;
  807. TargetDevice = IoGetAttachedDeviceReference (DeviceObject);
  808. Irp = IoAllocateIrp ((CCHAR) (TargetDevice->StackSize+2), FALSE);
  809. if (!Irp) {
  810. ObDereferenceObject (TargetDevice);
  811. return STATUS_INSUFFICIENT_RESOURCES;
  812. }
  813. SPECIALIRP_WATERMARK_IRP(Irp, IRP_SYSTEM_RESTRICTED);
  814. //
  815. // For debugging, keep a list of all outstanding irps allocated
  816. // through this function
  817. //
  818. IrpSp = IoGetNextIrpStackLocation(Irp);
  819. ExInterlockedInsertTailList(
  820. &PopRequestedIrps,
  821. (PLIST_ENTRY) &IrpSp->Parameters.Others.Argument1,
  822. &PopIrpSerialLock
  823. );
  824. IrpSp->Parameters.Others.Argument3 = Irp;
  825. IoSetNextIrpStackLocation (Irp);
  826. //
  827. // Save the datum needed to complete this request
  828. //
  829. IrpSp = IoGetNextIrpStackLocation(Irp);
  830. IrpSp->DeviceObject = TargetDevice;
  831. IrpSp->Parameters.Others.Argument1 = (PVOID) DeviceObject;
  832. IrpSp->Parameters.Others.Argument2 = (PVOID) MinorFunction;
  833. IrpSp->Parameters.Others.Argument3 = (PVOID) PowerState.DeviceState;
  834. IrpSp->Parameters.Others.Argument4 = (PVOID) Context;
  835. IoSetNextIrpStackLocation (Irp);
  836. //
  837. // Build the power irp
  838. //
  839. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
  840. IrpSp = IoGetNextIrpStackLocation(Irp);
  841. IrpSp->MajorFunction = IRP_MJ_POWER;
  842. IrpSp->MinorFunction = MinorFunction;
  843. IrpSp->DeviceObject = TargetDevice;
  844. switch (MinorFunction) {
  845. case IRP_MN_WAIT_WAKE:
  846. IrpSp->Parameters.WaitWake.PowerState = PowerState.SystemState;
  847. break;
  848. case IRP_MN_SET_POWER:
  849. case IRP_MN_QUERY_POWER:
  850. IrpSp->Parameters.Power.SystemContext = POP_DEVICE_REQUEST;
  851. IrpSp->Parameters.Power.Type = DevicePowerState;
  852. IrpSp->Parameters.Power.State.DeviceState = PowerState.DeviceState;
  853. //
  854. // N.B.
  855. //
  856. // You would think we stamp every D-state IRP with
  857. // PowerActionNone. However, we have a special scenario to consider
  858. // for hibernation. Let's say S4 goes to a stack. If the device is
  859. // on the hibernate path, one of two designs for WDM is possible:
  860. // (BTW, we chose the 2nd)
  861. //
  862. // 1) The FDO sees an S-IRP but because it's device is on the
  863. // hibernate path, it simply forwards the S Irp down. The PDO
  864. // takes note of the S-IRP being PowerSystemHibernate, and it
  865. // records hardware settings. Upon wake-up, the stack receives
  866. // an S0 IRP, which the FDO converts into a D0 request. Upon
  867. // receiving the D0 IRP, the PDO restores the settings.
  868. // 2) The FDO *always* requests the corresponding D IRP, regardless
  869. // of if it's on the hibernate path. The D-IRP also comes stamped
  870. // with the PowerAction in ShutdownType (ie, PowerActionSleeping,
  871. // PowerActionShutdown, PowerActionHibernate). Now the PDO can
  872. // identify transitions to D3 for the purpose of hibernation. The
  873. // PDO would *not* actually transition into D3, but it would save
  874. // it's state, and restore it at D0 time.
  875. //
  876. // < These are mutually exclusive designs >
  877. //
  878. // The reason we choose #2 as a design is so miniport models can
  879. // expose only D IRPs as neccessary, and S IRPs can be abstracted
  880. // out. There is a penalty for this design in that PoRequestPowerIrp
  881. // doesn't *take* a PowerAction or the old S-IRP, so we pick up the
  882. // existing action that the system is already undertaking.
  883. // Therefore, if the device powers itself on when the system decides
  884. // to begin a hibernation. the stack may receive nonsensical data
  885. // like an IRP_MN_SET_POWER(DevicePower, D0, PowerActionHibernate).
  886. //
  887. IrpAction = PopMapInternalActionToIrpAction (
  888. PopAction.Action,
  889. PopAction.SystemState,
  890. TRUE // UnmapWarmEject
  891. );
  892. IrpSp->Parameters.Power.ShutdownType = IrpAction;
  893. //
  894. // Log the call.
  895. //
  896. if (PERFINFO_IS_GROUP_ON(PERF_POWER)) {
  897. PopLogNotifyDevice(TargetDevice, NULL, Irp);
  898. }
  899. break;
  900. default:
  901. ObDereferenceObject (TargetDevice);
  902. IoFreeIrp (Irp);
  903. return STATUS_INVALID_PARAMETER_2;
  904. }
  905. IoSetCompletionRoutine(
  906. Irp,
  907. PopCompleteRequestIrp,
  908. (PVOID) CompletionFunction,
  909. TRUE,
  910. TRUE,
  911. TRUE
  912. );
  913. if (ResultIrp) {
  914. *ResultIrp = Irp;
  915. }
  916. PoCallDriver(TargetDevice, Irp);
  917. return STATUS_PENDING;
  918. }
  919. NTSTATUS
  920. PopCompleteRequestIrp (
  921. IN PDEVICE_OBJECT DeviceObject,
  922. IN PIRP Irp,
  923. IN PVOID Context
  924. )
  925. /*++
  926. Routine Description:
  927. Completion routine for PoRequestPowerChange. Invokes the
  928. requestors completion routine, and free resources associated
  929. with the request
  930. Arguments:
  931. DeviceObject - The target device which the request was sent
  932. Irp - The irp completing
  933. Context - The requestors completion routine
  934. Return Value:
  935. STATUS_MORE_PROCESSING_REQUIRED is return to IO
  936. --*/
  937. {
  938. PIO_STACK_LOCATION IrpSp;
  939. PREQUEST_POWER_COMPLETE CompletionFunction;
  940. POWER_STATE PowerState;
  941. KIRQL OldIrql;
  942. //
  943. // Log the completion.
  944. //
  945. if (PERFINFO_IS_GROUP_ON(PERF_POWER)) {
  946. PERFINFO_PO_NOTIFY_DEVICE_COMPLETE LogEntry;
  947. LogEntry.Irp = Irp;
  948. LogEntry.Status = Irp->IoStatus.Status;
  949. PerfInfoLogBytes(PERFINFO_LOG_TYPE_PO_NOTIFY_DEVICE_COMPLETE,
  950. &LogEntry,
  951. sizeof(LogEntry));
  952. }
  953. //
  954. // Dispatch to requestors completion function
  955. //
  956. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  957. CompletionFunction = (PREQUEST_POWER_COMPLETE) Context;
  958. PowerState.DeviceState = (DEVICE_POWER_STATE) ((ULONG_PTR)IrpSp->Parameters.Others.Argument3);
  959. if (CompletionFunction) {
  960. CompletionFunction (
  961. (PDEVICE_OBJECT) IrpSp->Parameters.Others.Argument1,
  962. (UCHAR) (ULONG_PTR)IrpSp->Parameters.Others.Argument2,
  963. PowerState,
  964. (PVOID) IrpSp->Parameters.Others.Argument4,
  965. &Irp->IoStatus
  966. );
  967. }
  968. //
  969. // Cleanup
  970. //
  971. IoSkipCurrentIrpStackLocation(Irp);
  972. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  973. KeAcquireSpinLock (&PopIrpSerialLock, &OldIrql);
  974. RemoveEntryList ((PLIST_ENTRY) &IrpSp->Parameters.Others.Argument1);
  975. KeReleaseSpinLock (&PopIrpSerialLock, OldIrql);
  976. //
  977. // Mark the irp CurrentLocation as completed (to catch multiple completes)
  978. //
  979. Irp->CurrentLocation = (CCHAR) (Irp->StackCount + 2);
  980. ObDereferenceObject (DeviceObject);
  981. IoFreeIrp (Irp);
  982. return STATUS_MORE_PROCESSING_REQUIRED;
  983. }
  984. VOID
  985. PopSystemIrpDispatchWorker (
  986. IN BOOLEAN LastCall
  987. )
  988. /*++
  989. Routine Description:
  990. This routine runs whenever the policy manager calls us to tell us
  991. that a big burst of system irps, which need to be dispatched from
  992. a private thread (this one) rather than from an executive worker
  993. thread. This is mostly to avoid deadlocks at sleep time.
  994. Globals:
  995. PopWorkerLock - protects access to the queue, and avoids races
  996. over using this routine or using exec worker
  997. PopWorkerItemQueue - list of irps to send off...
  998. Arguments:
  999. LastCall - Indicates irps are to be sent normally
  1000. Return Value:
  1001. --*/
  1002. {
  1003. PLIST_ENTRY Item;
  1004. PIRP Irp;
  1005. KIRQL OldIrql;
  1006. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1007. PopLockWorkerQueue(&OldIrql);
  1008. //
  1009. // Dispatch everything on the queue
  1010. //
  1011. if (PopAction.DevState != NULL) {
  1012. while (!IsListEmpty(&PopAction.DevState->PresentIrpQueue)) {
  1013. Item = RemoveHeadList(&PopAction.DevState->PresentIrpQueue);
  1014. Irp = CONTAINING_RECORD(Item, IRP, Tail.Overlay.ListEntry);
  1015. PopUnlockWorkerQueue(OldIrql);
  1016. PopPassivePowerCall(Irp);
  1017. PopLockWorkerQueue(&OldIrql);
  1018. }
  1019. }
  1020. if (LastCall) {
  1021. PopCallSystemState = 0;
  1022. }
  1023. PopUnlockWorkerQueue(OldIrql);
  1024. }