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.

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