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.

902 lines
21 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. power.c
  5. Abstract:
  6. This module contains the code that handles the power IRPs for the serial
  7. driver.
  8. Environment:
  9. Kernel mode
  10. Revision History :
  11. --*/
  12. #include "precomp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGESRP0, SerialGotoPowerState)
  15. #pragma alloc_text(PAGESRP0, SerialPowerDispatch)
  16. #pragma alloc_text(PAGESRP0, SerialSetPowerD0)
  17. #pragma alloc_text(PAGESRP0, SerialSetPowerD3)
  18. #pragma alloc_text(PAGESRP0, SerialSaveDeviceState)
  19. #pragma alloc_text(PAGESRP0, SerialRestoreDeviceState)
  20. #pragma alloc_text(PAGESRP0, SerialSendWaitWake)
  21. #endif // ALLOC_PRAGMA
  22. NTSTATUS
  23. SerialSystemPowerCompletion(IN PDEVICE_OBJECT PDevObj, UCHAR MinorFunction,
  24. IN POWER_STATE PowerState, IN PVOID Context,
  25. PIO_STATUS_BLOCK IoStatus)
  26. /*++
  27. Routine Description:
  28. This routine is the completion routine for PoRequestPowerIrp calls
  29. in this module.
  30. Arguments:
  31. PDevObj - Pointer to the device object the irp is completing for
  32. MinorFunction - IRP_MN_XXXX value requested
  33. PowerState - Power state request was made of
  34. Context - Event to set or NULL if no setting required
  35. IoStatus - Status block from request
  36. Return Value:
  37. VOID
  38. --*/
  39. {
  40. if (Context != NULL) {
  41. KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, 0);
  42. }
  43. return STATUS_SUCCESS;
  44. }
  45. VOID
  46. SerialSaveDeviceState(IN PSERIAL_DEVICE_EXTENSION PDevExt)
  47. /*++
  48. Routine Description:
  49. This routine saves the device state of the UART
  50. Arguments:
  51. PDevExt - Pointer to the device extension for the devobj to save the state
  52. for.
  53. Return Value:
  54. VOID
  55. --*/
  56. {
  57. PSERIAL_DEVICE_STATE pDevState = &PDevExt->DeviceState;
  58. #if defined(NEC_98)
  59. //
  60. // This argument use at MACRO only.
  61. //
  62. PSERIAL_DEVICE_EXTENSION Extension = PDevExt;
  63. #else
  64. #endif //defined(NEC_98)
  65. PAGED_CODE();
  66. SerialDump(SERTRACECALLS, ("SERIAL: Entering SerialSaveDeviceState\n"));
  67. //
  68. // Read necessary registers direct
  69. //
  70. #if defined(NEC_98)
  71. pDevState->IER = READ_INTERRUPT_ENABLE(Extension->Controller);
  72. #else
  73. pDevState->IER = READ_INTERRUPT_ENABLE(PDevExt->Controller);
  74. #endif //defined(NEC_98)
  75. pDevState->MCR = READ_MODEM_CONTROL(PDevExt->Controller);
  76. pDevState->LCR = READ_LINE_CONTROL(PDevExt->Controller);
  77. SerialDump(SERTRACECALLS, ("SERIAL: Leaving SerialSaveDeviceState\n"));
  78. }
  79. VOID
  80. SerialRestoreDeviceState(IN PSERIAL_DEVICE_EXTENSION PDevExt)
  81. /*++
  82. Routine Description:
  83. This routine restores the device state of the UART
  84. Arguments:
  85. PDevExt - Pointer to the device extension for the devobj to restore the
  86. state for.
  87. Return Value:
  88. VOID
  89. --*/
  90. {
  91. PSERIAL_DEVICE_STATE pDevState = &PDevExt->DeviceState;
  92. SHORT divisor;
  93. SERIAL_IOCTL_SYNC S;
  94. #if defined(NEC_98)
  95. //
  96. // This argument use at MACRO only.
  97. //
  98. PSERIAL_DEVICE_EXTENSION Extension = PDevExt;
  99. #else
  100. #endif //defined(NEC_98)
  101. PAGED_CODE();
  102. SerialDump(SERTRACECALLS, ("SERIAL: Enter SerialRestoreDeviceState\n"));
  103. SerialDump(SERTRACECALLS, ("------ PDevExt: %x\n", PDevExt));
  104. //
  105. // Disable interrupts both via OUT2 and IER
  106. //
  107. WRITE_MODEM_CONTROL(PDevExt->Controller, 0);
  108. DISABLE_ALL_INTERRUPTS(PDevExt->Controller);
  109. //
  110. // Set the baud rate
  111. //
  112. SerialGetDivisorFromBaud(PDevExt->ClockRate, PDevExt->CurrentBaud, &divisor);
  113. S.Extension = PDevExt;
  114. S.Data = (PVOID)divisor;
  115. SerialSetBaud(&S);
  116. //
  117. // Reset / Re-enable the FIFO's
  118. //
  119. if (PDevExt->FifoPresent) {
  120. WRITE_FIFO_CONTROL(PDevExt->Controller, (UCHAR)0);
  121. READ_RECEIVE_BUFFER(PDevExt->Controller);
  122. WRITE_FIFO_CONTROL(PDevExt->Controller,
  123. (UCHAR)(SERIAL_FCR_ENABLE | PDevExt->RxFifoTrigger
  124. | SERIAL_FCR_RCVR_RESET
  125. | SERIAL_FCR_TXMT_RESET));
  126. } else {
  127. WRITE_FIFO_CONTROL(PDevExt->Controller, (UCHAR)0);
  128. }
  129. //
  130. // In case we are dealing with a bitmasked multiportcard,
  131. // that has the mask register enabled, enable the
  132. // interrupts.
  133. //
  134. if (PDevExt->InterruptStatus) {
  135. if (PDevExt->Indexed) {
  136. WRITE_PORT_UCHAR(PDevExt->InterruptStatus, (UCHAR)0xFF);
  137. } else {
  138. //
  139. // Either we are standalone or already mapped
  140. //
  141. if (PDevExt->OurIsrContext == PDevExt) {
  142. //
  143. // This is a standalone
  144. //
  145. WRITE_PORT_UCHAR(PDevExt->InterruptStatus,
  146. (UCHAR)(1 << (PDevExt->PortIndex - 1)));
  147. } else {
  148. //
  149. // One of many
  150. //
  151. WRITE_PORT_UCHAR(PDevExt->InterruptStatus,
  152. (UCHAR)((PSERIAL_MULTIPORT_DISPATCH)PDevExt->
  153. OurIsrContext)->UsablePortMask);
  154. }
  155. }
  156. }
  157. //
  158. // Restore a couple more registers
  159. //
  160. #if defined(NEC_98)
  161. WRITE_INTERRUPT_ENABLE(Extension->Controller, pDevState->IER);
  162. #else
  163. WRITE_INTERRUPT_ENABLE(PDevExt->Controller, pDevState->IER);
  164. #endif //defined(NEC_98)
  165. WRITE_LINE_CONTROL(PDevExt->Controller, pDevState->LCR);
  166. //
  167. // Clear out any stale interrupts
  168. //
  169. READ_INTERRUPT_ID_REG(PDevExt->Controller);
  170. READ_LINE_STATUS(PDevExt->Controller);
  171. READ_MODEM_STATUS(PDevExt->Controller);
  172. if (PDevExt->DeviceState.Reopen == TRUE) {
  173. SerialDump(SERPNPPOWER, ("SERIAL: Reopening device\n"));
  174. PDevExt->DeviceIsOpened = TRUE;
  175. PDevExt->DeviceState.Reopen = FALSE;
  176. //
  177. // This enables interrupts on the device!
  178. //
  179. WRITE_MODEM_CONTROL(PDevExt->Controller,
  180. (UCHAR)(pDevState->MCR | SERIAL_MCR_OUT2));
  181. //
  182. // Refire the state machine
  183. //
  184. DISABLE_ALL_INTERRUPTS(PDevExt->Controller);
  185. ENABLE_ALL_INTERRUPTS(PDevExt->Controller);
  186. }
  187. }
  188. NTSTATUS
  189. SerialPowerDispatch(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  190. /*++
  191. Routine Description:
  192. This is a dispatch routine for the IRPs that come to the driver with the
  193. IRP_MJ_POWER major code (power IRPs).
  194. Arguments:
  195. PDevObj - Pointer to the device object for this device
  196. PIrp - Pointer to the IRP for the current request
  197. Return Value:
  198. The function value is the final status of the call
  199. --*/
  200. {
  201. PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  202. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  203. NTSTATUS status;
  204. PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject;
  205. PDEVICE_OBJECT pPdo = pDevExt->Pdo;
  206. BOOLEAN acceptingIRPs;
  207. PAGED_CODE();
  208. if ((status = SerialIRPPrologue(PIrp, pDevExt)) != STATUS_SUCCESS) {
  209. PoStartNextPowerIrp(PIrp);
  210. SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
  211. return status;
  212. }
  213. status = STATUS_SUCCESS;
  214. switch (pIrpStack->MinorFunction) {
  215. case IRP_MN_WAIT_WAKE:
  216. SerialDump(SERPNPPOWER, ("SERIAL: Got IRP_MN_WAIT_WAKE Irp\n"));
  217. break;
  218. case IRP_MN_POWER_SEQUENCE:
  219. SerialDump(SERPNPPOWER, ("SERIAL: Got IRP_MN_POWER_SEQUENCE Irp\n"));
  220. break;
  221. case IRP_MN_SET_POWER:
  222. SerialDump(SERPNPPOWER, ("SERIAL: Got IRP_MN_SET_POWER Irp\n"));
  223. //
  224. // Perform different ops if it was system or device
  225. //
  226. switch (pIrpStack->Parameters.Power.Type) {
  227. case SystemPowerState: {
  228. POWER_STATE powerState;
  229. //
  230. // They asked for a system power state change
  231. //
  232. SerialDump(SERPNPPOWER, ("------: SystemPowerState\n"));
  233. //
  234. // We will only service this if we are policy owner -- we
  235. // don't need to lock on this value since we only service
  236. // one power request at a time.
  237. //
  238. if (pDevExt->OwnsPowerPolicy != TRUE) {
  239. status = STATUS_SUCCESS;
  240. goto PowerExit;
  241. }
  242. switch (pIrpStack->Parameters.Power.State.SystemState) {
  243. case PowerSystemUnspecified:
  244. powerState.DeviceState = PowerDeviceUnspecified;
  245. break;
  246. case PowerSystemWorking:
  247. powerState.DeviceState = PowerDeviceD0;
  248. break;
  249. case PowerSystemSleeping1:
  250. case PowerSystemSleeping2:
  251. case PowerSystemSleeping3:
  252. case PowerSystemHibernate:
  253. case PowerSystemShutdown:
  254. case PowerSystemMaximum:
  255. powerState.DeviceState = PowerDeviceD3;
  256. break;
  257. default:
  258. status = STATUS_SUCCESS;
  259. goto PowerExit;
  260. break;
  261. }
  262. PoSetPowerState(PDevObj, pIrpStack->Parameters.Power.Type,
  263. pIrpStack->Parameters.Power.State);
  264. //
  265. // Send IRP to change device state if we should change
  266. //
  267. //
  268. // We only power up the stack if the device is open. This is based
  269. // on our policy of keeping the device powered down unless it is
  270. // open.
  271. //
  272. if (((powerState.DeviceState < pDevExt->PowerState)
  273. && pDevExt->OpenCount)) {
  274. PoRequestPowerIrp(pPdo, IRP_MN_SET_POWER, powerState, NULL, NULL,
  275. NULL);
  276. }else {
  277. //
  278. // If powering down, we can't go past wake state
  279. // if wait-wake pending
  280. //
  281. if (powerState.DeviceState >= pDevExt->PowerState) {
  282. //
  283. // Power down -- ensure there is no wake-wait pending OR
  284. // we can do down to that level and still wake the machine
  285. //
  286. if ((pDevExt->PendingWakeIrp == NULL && !pDevExt->SendWaitWake)
  287. || powerState.DeviceState <= pDevExt->DeviceWake) {
  288. PoRequestPowerIrp(pPdo, IRP_MN_SET_POWER, powerState, NULL,
  289. NULL, NULL);
  290. }
  291. }
  292. }
  293. status = STATUS_SUCCESS;
  294. goto PowerExit;
  295. }
  296. case DevicePowerState:
  297. SerialDump(SERPNPPOWER, ("------: DevicePowerState\n"));
  298. break;
  299. default:
  300. SerialDump(SERPNPPOWER, ("------: UNKNOWN PowerState\n"));
  301. status = STATUS_SUCCESS;
  302. goto PowerExit;
  303. }
  304. //
  305. // If we are already in the requested state, just pass the IRP down
  306. //
  307. if (pDevExt->PowerState
  308. == pIrpStack->Parameters.Power.State.DeviceState) {
  309. SerialDump(SERPNPPOWER, ("SERIAL: Already in requested power state\n")
  310. );
  311. status = STATUS_SUCCESS;
  312. break;
  313. }
  314. switch (pIrpStack->Parameters.Power.State.DeviceState) {
  315. case PowerDeviceD0:
  316. SerialDump(SERPNPPOWER, ("SERIAL: Going to power state D0\n"));
  317. return SerialSetPowerD0(PDevObj, PIrp);
  318. case PowerDeviceD1:
  319. case PowerDeviceD2:
  320. case PowerDeviceD3:
  321. SerialDump(SERPNPPOWER, ("SERIAL: Going to power state D3\n"));
  322. return SerialSetPowerD3(PDevObj, PIrp);
  323. default:
  324. break;
  325. }
  326. break;
  327. case IRP_MN_QUERY_POWER:
  328. SerialDump (SERPNPPOWER, ("SERIAL: Got IRP_MN_QUERY_POWER Irp\n"));
  329. //
  330. // Check if we have a wait-wake pending and if so,
  331. // ensure we don't power down too far.
  332. //
  333. if (pDevExt->PendingWakeIrp != NULL || pDevExt->SendWaitWake) {
  334. if (pIrpStack->Parameters.Power.Type == DevicePowerState
  335. && pIrpStack->Parameters.Power.State.DeviceState
  336. > pDevExt->DeviceWake) {
  337. status = PIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
  338. PoStartNextPowerIrp(PIrp);
  339. SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
  340. return status;
  341. }
  342. }
  343. //
  344. // If no wait-wake, always successful
  345. //
  346. PIrp->IoStatus.Status = STATUS_SUCCESS;
  347. status = STATUS_SUCCESS;
  348. PoStartNextPowerIrp(PIrp);
  349. IoSkipCurrentIrpStackLocation(PIrp);
  350. return SerialPoCallDriver(pDevExt, pLowerDevObj, PIrp);
  351. } // switch (pIrpStack->MinorFunction)
  352. PowerExit:;
  353. PoStartNextPowerIrp(PIrp);
  354. //
  355. // Pass to the lower driver
  356. //
  357. IoSkipCurrentIrpStackLocation(PIrp);
  358. status = SerialPoCallDriver(pDevExt, pLowerDevObj, PIrp);
  359. return status;
  360. }
  361. NTSTATUS
  362. SerialSetPowerD0(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  363. /*++
  364. Routine Description:
  365. This routine Decides if we need to pass the power Irp down the stack
  366. or not. It then either sets up a completion handler to finish the
  367. initialization or calls the completion handler directly.
  368. Arguments:
  369. PDevObj - Pointer to the devobj we are changing power state on
  370. PIrp - Pointer to the IRP for the current request
  371. Return Value:
  372. Return status of either PoCallDriver of the call to the initialization
  373. routine.
  374. --*/
  375. {
  376. PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  377. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  378. NTSTATUS status;
  379. PAGED_CODE();
  380. SerialDump(SERTRACECALLS, ("SERIAL: In SerialSetPowerD0\n"));
  381. SerialDump(SERPNPPOWER, ("SERIAL: SetPowerD0 has IRP %x\n", PIrp));
  382. ASSERT(pDevExt->LowerDeviceObject);
  383. //
  384. // Set up completion to init device when it is on
  385. //
  386. KeClearEvent(&pDevExt->PowerD0Event);
  387. IoCopyCurrentIrpStackLocationToNext(PIrp);
  388. IoSetCompletionRoutine(PIrp, SerialSyncCompletion, &pDevExt->PowerD0Event,
  389. TRUE, TRUE, TRUE);
  390. SerialDump(SERPNPPOWER, ("SERIAL: Calling next driver\n"));
  391. status = PoCallDriver(pDevExt->LowerDeviceObject, PIrp);
  392. if (status == STATUS_PENDING) {
  393. SerialDump(SERPNPPOWER, ("SERIAL: Waiting for next driver\n"));
  394. KeWaitForSingleObject (&pDevExt->PowerD0Event, Executive, KernelMode,
  395. FALSE, NULL);
  396. } else {
  397. if (!NT_SUCCESS(status)) {
  398. PIrp->IoStatus.Status = status;
  399. PoStartNextPowerIrp(PIrp);
  400. SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
  401. return status;
  402. }
  403. }
  404. if (!NT_SUCCESS(PIrp->IoStatus.Status)) {
  405. status = PIrp->IoStatus.Status;
  406. PoStartNextPowerIrp(PIrp);
  407. SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
  408. return status;
  409. }
  410. //
  411. // Restore the device
  412. //
  413. pDevExt->PowerState = PowerDeviceD0;
  414. //
  415. // Theoretically we could change states in the middle of processing
  416. // the restore which would result in a bad PKINTERRUPT being used
  417. // in SerialRestoreDeviceState().
  418. //
  419. if (pDevExt->PNPState == SERIAL_PNP_STARTED) {
  420. SerialRestoreDeviceState(pDevExt);
  421. }
  422. //
  423. // Now that we are powered up, call PoSetPowerState
  424. //
  425. PoSetPowerState(PDevObj, pIrpStack->Parameters.Power.Type,
  426. pIrpStack->Parameters.Power.State);
  427. PoStartNextPowerIrp(PIrp);
  428. SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
  429. SerialDump(SERTRACECALLS, ("SERIAL: Leaving SerialSetPowerD0\n"));
  430. return status;
  431. }
  432. NTSTATUS
  433. SerialGotoPowerState(IN PDEVICE_OBJECT PDevObj,
  434. IN PSERIAL_DEVICE_EXTENSION PDevExt,
  435. IN DEVICE_POWER_STATE DevPowerState)
  436. /*++
  437. Routine Description:
  438. This routine causes the driver to request the stack go to a particular
  439. power state.
  440. Arguments:
  441. PDevObj - Pointer to the device object for this device
  442. PDevExt - Pointer to the device extension we are working from
  443. DevPowerState - the power state we wish to go to
  444. Return Value:
  445. The function value is the final status of the call
  446. --*/
  447. {
  448. KEVENT gotoPowEvent;
  449. NTSTATUS status;
  450. POWER_STATE powerState;
  451. PAGED_CODE();
  452. SerialDump(SERTRACECALLS, ("SERIAL: In SerialGotoPowerState\n"));
  453. powerState.DeviceState = DevPowerState;
  454. KeInitializeEvent(&gotoPowEvent, SynchronizationEvent, FALSE);
  455. status = PoRequestPowerIrp(PDevObj, IRP_MN_SET_POWER, powerState,
  456. SerialSystemPowerCompletion, &gotoPowEvent,
  457. NULL);
  458. if (status == STATUS_PENDING) {
  459. KeWaitForSingleObject(&gotoPowEvent, Executive, KernelMode, FALSE, NULL);
  460. status = STATUS_SUCCESS;
  461. }
  462. #if DBG
  463. if (!NT_SUCCESS(status)) {
  464. SerialDump(SERPNPPOWER, ("SERIAL: SerialGotoPowerState FAILED\n"));
  465. }
  466. #endif
  467. SerialDump(SERTRACECALLS, ("SERIAL: Leaving SerialGotoPowerState\n"));
  468. return status;
  469. }
  470. NTSTATUS
  471. SerialSetPowerD3(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  472. /*++
  473. Routine Description:
  474. This routine handles the SET_POWER minor function.
  475. Arguments:
  476. PDevObj - Pointer to the device object for this device
  477. PIrp - Pointer to the IRP for the current request
  478. Return Value:
  479. The function value is the final status of the call
  480. --*/
  481. {
  482. NTSTATUS status = STATUS_SUCCESS;
  483. PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  484. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  485. PAGED_CODE();
  486. SerialDump(SERDIAG3, ("SERIAL: In SerialSetPowerD3\n"));
  487. //
  488. // Send the wait wake now, just in time
  489. //
  490. if (pDevExt->SendWaitWake) {
  491. SerialSendWaitWake(pDevExt);
  492. }
  493. //
  494. // Before we power down, call PoSetPowerState
  495. //
  496. PoSetPowerState(PDevObj, pIrpStack->Parameters.Power.Type,
  497. pIrpStack->Parameters.Power.State);
  498. //
  499. // If the device is not closed, disable interrupts and allow the fifo's
  500. // to flush.
  501. //
  502. if (pDevExt->DeviceIsOpened == TRUE) {
  503. LARGE_INTEGER charTime;
  504. pDevExt->DeviceIsOpened = FALSE;
  505. pDevExt->DeviceState.Reopen = TRUE;
  506. charTime.QuadPart = -SerialGetCharTime(pDevExt).QuadPart;
  507. //
  508. // Shut down the chip
  509. //
  510. SerialDisableUART(pDevExt);
  511. //
  512. // Drain the device
  513. //
  514. SerialDrainUART(pDevExt, &charTime);
  515. //
  516. // Save the device state
  517. //
  518. SerialSaveDeviceState(pDevExt);
  519. }
  520. //
  521. // If the device is not open, we don't need to save the state;
  522. // we can just reset the device on power-up
  523. //
  524. PIrp->IoStatus.Status = STATUS_SUCCESS;
  525. pDevExt->PowerState = PowerDeviceD3;
  526. //
  527. // For what we are doing, we don't need a completion routine
  528. // since we don't race on the power requests.
  529. //
  530. PIrp->IoStatus.Status = STATUS_SUCCESS;
  531. PoStartNextPowerIrp(PIrp);
  532. IoSkipCurrentIrpStackLocation(PIrp);
  533. return SerialPoCallDriver(pDevExt, pDevExt->LowerDeviceObject, PIrp);
  534. }
  535. NTSTATUS
  536. SerialSendWaitWake(PSERIAL_DEVICE_EXTENSION PDevExt)
  537. /*++
  538. Routine Description:
  539. This routine causes a waitwake IRP to be sent
  540. Arguments:
  541. PDevExt - Pointer to the device extension for this device
  542. Return Value:
  543. STATUS_INVALID_DEVICE_STATE if one is already pending, else result
  544. of call to PoRequestPowerIrp.
  545. --*/
  546. {
  547. NTSTATUS status;
  548. PIRP pIrp;
  549. POWER_STATE powerState;
  550. PAGED_CODE();
  551. //
  552. // Make sure one isn't pending already -- serial will only handle one at
  553. // a time.
  554. //
  555. if (PDevExt->PendingWakeIrp != NULL) {
  556. return STATUS_INVALID_DEVICE_STATE;
  557. }
  558. //
  559. // Make sure we are capable of waking the machine
  560. //
  561. if (PDevExt->SystemWake <= PowerSystemWorking) {
  562. return STATUS_INVALID_DEVICE_STATE;
  563. }
  564. if (PDevExt->DeviceWake == PowerDeviceUnspecified) {
  565. return STATUS_INVALID_DEVICE_STATE;
  566. }
  567. //
  568. // Send IRP to request wait wake and add a pending irp flag
  569. //
  570. //
  571. InterlockedIncrement(&PDevExt->PendingIRPCnt);
  572. powerState.SystemState = PDevExt->SystemWake;
  573. status = PoRequestPowerIrp(PDevExt->Pdo, IRP_MN_WAIT_WAKE,
  574. powerState, SerialWakeCompletion, PDevExt, &pIrp);
  575. if (status == STATUS_PENDING) {
  576. status = STATUS_SUCCESS;
  577. PDevExt->PendingWakeIrp = pIrp;
  578. } else if (!NT_SUCCESS(status)) {
  579. SerialIRPEpilogue(PDevExt);
  580. }
  581. return status;
  582. }
  583. NTSTATUS
  584. SerialWakeCompletion(IN PDEVICE_OBJECT PDevObj, IN UCHAR MinorFunction,
  585. IN POWER_STATE PowerState, IN PVOID Context,
  586. IN PIO_STATUS_BLOCK IoStatus)
  587. /*++
  588. Routine Description:
  589. This routine handles completion of the waitwake IRP.
  590. Arguments:
  591. PDevObj - Pointer to the device object for this device
  592. MinorFunction - Minor function previously supplied to PoRequestPowerIrp
  593. PowerState - PowerState previously supplied to PoRequestPowerIrp
  594. Context - a pointer to the device extension
  595. IoStatus - current/final status of the waitwake IRP
  596. Return Value:
  597. The function value is the final status of attempting to process the
  598. waitwake.
  599. --*/
  600. {
  601. NTSTATUS status;
  602. PSERIAL_DEVICE_EXTENSION pDevExt = (PSERIAL_DEVICE_EXTENSION)Context;
  603. POWER_STATE powerState;
  604. status = IoStatus->Status;
  605. if (NT_SUCCESS(status)) {
  606. //
  607. // A wakeup has occurred -- powerup our stack
  608. //
  609. powerState.DeviceState = PowerDeviceD0;
  610. PoRequestPowerIrp(pDevExt->Pdo, IRP_MN_SET_POWER, powerState, NULL,
  611. NULL, NULL);
  612. }
  613. pDevExt->PendingWakeIrp = NULL;
  614. SerialIRPEpilogue(pDevExt);
  615. return status;
  616. }