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.

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