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.

904 lines
22 KiB

  1. /*--------------------------------------------------------------------------
  2. *
  3. * Copyright (C) Cyclades Corporation, 2000-2001.
  4. * All rights reserved.
  5. *
  6. * Cyclades-Z Port Driver
  7. *
  8. * This file: cyzpower.c
  9. *
  10. * Description: This module contains the code that handles the power
  11. * IRPs for the Cyclades-Z Port driver.
  12. *
  13. * Notes: This code supports Windows 2000 and Windows XP,
  14. * x86 and IA64 processors.
  15. *
  16. * Complies with Cyclades SW Coding Standard rev 1.3.
  17. *
  18. *--------------------------------------------------------------------------
  19. */
  20. /*-------------------------------------------------------------------------
  21. *
  22. * Change History
  23. *
  24. *--------------------------------------------------------------------------
  25. * Initial implementatin based on Microsoft sample code.
  26. *
  27. *--------------------------------------------------------------------------
  28. */
  29. #include "precomp.h"
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text(PAGESRP0, CyzGotoPowerState)
  32. #pragma alloc_text(PAGESRP0, CyzPowerDispatch)
  33. #pragma alloc_text(PAGESRP0, CyzSetPowerD0)
  34. //#pragma alloc_text(PAGESRP0, CyzSetPowerD3) Not pageable because it gets spin lock
  35. #pragma alloc_text(PAGESRP0, CyzSaveDeviceState)
  36. //#pragma alloc_text(PAGESRP0, CyzRestoreDeviceState) Not pageable because it gets spin lock.
  37. #pragma alloc_text(PAGESRP0, CyzSendWaitWake)
  38. #endif // ALLOC_PRAGMA
  39. typedef struct _POWER_COMPLETION_CONTEXT {
  40. PDEVICE_OBJECT DeviceObject;
  41. PIRP SIrp;
  42. } POWER_COMPLETION_CONTEXT, *PPOWER_COMPLETION_CONTEXT;
  43. NTSTATUS
  44. CyzSetPowerEvent(IN PDEVICE_OBJECT PDevObj, UCHAR MinorFunction,
  45. IN POWER_STATE PowerState, IN PVOID Context,
  46. PIO_STATUS_BLOCK IoStatus)
  47. /*++
  48. Routine Description:
  49. This routine is the completion routine for PoRequestPowerIrp calls
  50. in this module.
  51. Arguments:
  52. PDevObj - Pointer to the device object the irp is completing for
  53. MinorFunction - IRP_MN_XXXX value requested
  54. PowerState - Power state request was made of
  55. Context - Event to set or NULL if no setting required
  56. IoStatus - Status block from request
  57. Return Value:
  58. VOID
  59. --*/
  60. {
  61. if (Context != NULL) {
  62. KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, 0);
  63. }
  64. return STATUS_SUCCESS;
  65. }
  66. VOID
  67. CyzSaveDeviceState(IN PCYZ_DEVICE_EXTENSION PDevExt)
  68. /*++
  69. Routine Description:
  70. This routine saves the device state of the UART
  71. Arguments:
  72. PDevExt - Pointer to the device extension for the devobj to save the state
  73. for.
  74. Return Value:
  75. VOID
  76. --*/
  77. {
  78. PCYZ_DEVICE_STATE pDevState = &PDevExt->DeviceState;
  79. struct CH_CTRL *ch_ctrl;
  80. PAGED_CODE();
  81. CyzDbgPrintEx(CYZTRACECALLS, "Entering CyzSaveDeviceState\n");
  82. #if 0
  83. ch_ctrl = PDevExt->ChCtrl;
  84. pDevState->op_mode = CYZ_READ_ULONG(&ch_ctrl->op_mode);
  85. pDevState->intr_enable = CYZ_READ_ULONG(&ch_ctrl->intr_enable);
  86. pDevState->sw_flow = CYZ_READ_ULONG(&ch_ctrl->sw_flow);
  87. pDevState->comm_baud = CYZ_READ_ULONG(&ch_ctrl->comm_baud);
  88. pDevState->comm_parity = CYZ_READ_ULONG(&ch_ctrl->comm_parity);
  89. pDevState->comm_data_l = CYZ_READ_ULONG(&ch_ctrl->comm_data_l);
  90. pDevState->hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  91. pDevState->rs_control = CYZ_READ_ULONG(&ch_ctrl->rs_control);
  92. #endif
  93. CyzDbgPrintEx(CYZTRACECALLS, "Leaving CyzSaveDeviceState\n");
  94. }
  95. VOID
  96. CyzRestoreDeviceState(IN PCYZ_DEVICE_EXTENSION PDevExt)
  97. /*++
  98. Routine Description:
  99. This routine restores the device state of the UART
  100. Arguments:
  101. PDevExt - Pointer to the device PDevExt for the devobj to restore the
  102. state for.
  103. Return Value:
  104. VOID
  105. --*/
  106. {
  107. PCYZ_DEVICE_STATE pDevState = &PDevExt->DeviceState;
  108. struct CH_CTRL *ch_ctrl;
  109. PCYZ_DISPATCH pDispatch;
  110. KIRQL oldIrql;
  111. #ifndef POLL
  112. ULONG portindex;
  113. #endif
  114. PAGED_CODE();
  115. CyzDbgPrintEx(CYZTRACECALLS, "Enter CyzRestoreDeviceState\n");
  116. CyzDbgPrintEx(CYZTRACECALLS, "PDevExt: %x\n", PDevExt);
  117. #ifndef POLL
  118. //
  119. // While the device isn't open, disable all interrupts.
  120. //
  121. CYZ_WRITE_ULONG(&(PDevExt->ChCtrl)->intr_enable,C_IN_DISABLE); //1.0.0.11
  122. CyzIssueCmd(PDevExt,C_CM_IOCTL,0L,FALSE);
  123. pDispatch = (PCYZ_DISPATCH)PDevExt->OurIsrContext;
  124. for (portindex=0; portindex<pDispatch->NChannels; portindex++) {
  125. if (pDispatch->PoweredOn[portindex]) {
  126. break;
  127. }
  128. }
  129. if (portindex == pDispatch->NChannels)
  130. {
  131. // No port was powered on, this is the first port. Enable PLX interrupts
  132. ULONG intr_reg;
  133. intr_reg = CYZ_READ_ULONG(&(PDevExt->Runtime)->intr_ctrl_stat);
  134. intr_reg |= (0x00030B00UL);
  135. CYZ_WRITE_ULONG(&(PDevExt->Runtime)->intr_ctrl_stat,intr_reg);
  136. }
  137. pDispatch->PoweredOn[PDevExt->PortIndex] = TRUE;
  138. #endif
  139. if (PDevExt->DeviceState.Reopen == TRUE) {
  140. CyzDbgPrintEx(CYZPNPPOWER, "Reopening device\n");
  141. CyzReset(PDevExt);
  142. PDevExt->DeviceIsOpened = TRUE;
  143. PDevExt->DeviceState.Reopen = FALSE;
  144. #ifdef POLL
  145. //
  146. // This enables polling routine!
  147. //
  148. pDispatch = PDevExt->OurIsrContext;
  149. KeAcquireSpinLock(&pDispatch->PollingLock,&oldIrql);
  150. pDispatch->Extensions[PDevExt->PortIndex] = PDevExt;
  151. if (!pDispatch->PollingStarted) {
  152. // Start polling timer
  153. KeSetTimerEx(
  154. &pDispatch->PollingTimer,
  155. pDispatch->PollingTime,
  156. pDispatch->PollingPeriod,
  157. &pDispatch->PollingDpc
  158. );
  159. pDispatch->PollingStarted = TRUE;
  160. pDispatch->PollingDrained = FALSE;
  161. }
  162. KeReleaseSpinLock(&pDispatch->PollingLock,oldIrql);
  163. #endif
  164. //TODO: Should we re-start transmissions in interrupt mode?
  165. }
  166. }
  167. VOID
  168. CyzPowerRequestComplete(
  169. PDEVICE_OBJECT DeviceObject,
  170. UCHAR MinorFunction,
  171. POWER_STATE state,
  172. POWER_COMPLETION_CONTEXT* PowerContext,
  173. PIO_STATUS_BLOCK IoStatus
  174. )
  175. /*++
  176. Routine Description:
  177. Completion routine for D-IRP.
  178. Arguments:
  179. Return Value:
  180. NT status code
  181. --*/
  182. {
  183. PCYZ_DEVICE_EXTENSION pDevExt = (PCYZ_DEVICE_EXTENSION) PowerContext->DeviceObject->DeviceExtension;
  184. PIRP sIrp = PowerContext->SIrp;
  185. UNREFERENCED_PARAMETER (DeviceObject);
  186. UNREFERENCED_PARAMETER (MinorFunction);
  187. UNREFERENCED_PARAMETER (state);
  188. //
  189. // Cleanup
  190. //
  191. ExFreePool(PowerContext);
  192. //
  193. // Here we copy the D-IRP status into the S-IRP
  194. //
  195. sIrp->IoStatus.Status = IoStatus->Status;
  196. //
  197. // Release the IRP
  198. //
  199. PoStartNextPowerIrp(sIrp);
  200. CyzCompleteRequest(pDevExt,sIrp,IO_NO_INCREMENT);
  201. }
  202. NTSTATUS
  203. CyzSystemPowerComplete (
  204. IN PDEVICE_OBJECT DeviceObject,
  205. IN PIRP Irp,
  206. IN PVOID Context
  207. )
  208. /*++
  209. --*/
  210. {
  211. POWER_COMPLETION_CONTEXT* powerContext;
  212. POWER_STATE powerState;
  213. POWER_STATE_TYPE powerType;
  214. PIO_STACK_LOCATION stack;
  215. PCYZ_DEVICE_EXTENSION data;
  216. NTSTATUS status = Irp->IoStatus.Status;
  217. UNREFERENCED_PARAMETER (Context);
  218. data = DeviceObject->DeviceExtension;
  219. if (!NT_SUCCESS(status)) {
  220. PoStartNextPowerIrp(Irp);
  221. CyzIRPEpilogue(data);
  222. return STATUS_SUCCESS;
  223. }
  224. stack = IoGetCurrentIrpStackLocation (Irp);
  225. powerState = stack->Parameters.Power.State;
  226. switch (stack->Parameters.Power.State.SystemState) {
  227. case PowerSystemUnspecified:
  228. powerState.DeviceState = PowerDeviceUnspecified;
  229. break;
  230. case PowerSystemWorking:
  231. powerState.DeviceState = PowerDeviceD0;
  232. break;
  233. case PowerSystemSleeping1:
  234. case PowerSystemSleeping2:
  235. case PowerSystemSleeping3:
  236. case PowerSystemHibernate:
  237. case PowerSystemShutdown:
  238. case PowerSystemMaximum:
  239. powerState.DeviceState = data->DeviceStateMap[stack->Parameters.Power.State.SystemState];
  240. break;
  241. default:
  242. powerState.DeviceState = PowerDeviceD3;
  243. }
  244. //
  245. // Send IRP to change device state
  246. //
  247. powerContext = (POWER_COMPLETION_CONTEXT*)
  248. ExAllocatePool(NonPagedPool, sizeof(POWER_COMPLETION_CONTEXT));
  249. if (!powerContext) {
  250. status = STATUS_INSUFFICIENT_RESOURCES;
  251. } else {
  252. powerContext->DeviceObject = DeviceObject;
  253. powerContext->SIrp = Irp;
  254. status = PoRequestPowerIrp(DeviceObject, IRP_MN_SET_POWER, powerState, CyzPowerRequestComplete,
  255. powerContext, NULL);
  256. }
  257. if (!NT_SUCCESS(status)) {
  258. if (powerContext) {
  259. ExFreePool(powerContext);
  260. }
  261. PoStartNextPowerIrp(Irp);
  262. Irp->IoStatus.Status = status;
  263. CyzCompleteRequest(data,Irp,IO_NO_INCREMENT); // To be equal to toaster
  264. //CyzIRPEpilogue(data);
  265. //return status;
  266. }
  267. return STATUS_MORE_PROCESSING_REQUIRED;
  268. }
  269. NTSTATUS
  270. CyzDevicePowerComplete (
  271. IN PDEVICE_OBJECT DeviceObject,
  272. IN PIRP Irp,
  273. IN PVOID Context
  274. )
  275. /*++
  276. Routine Description:
  277. The completion routine for Power Up D-IRP.
  278. Arguments:
  279. DeviceObject - pointer to a device object.
  280. Irp - pointer to an I/O Request Packet.
  281. Context - context pointer
  282. Return Value:
  283. NT status code
  284. --*/
  285. {
  286. POWER_STATE powerState;
  287. POWER_STATE_TYPE powerType;
  288. PIO_STACK_LOCATION stack;
  289. PCYZ_DEVICE_EXTENSION pDevExt;
  290. UNREFERENCED_PARAMETER (Context);
  291. if (Irp->PendingReturned) {
  292. IoMarkIrpPending(Irp);
  293. }
  294. pDevExt = DeviceObject->DeviceExtension;
  295. stack = IoGetCurrentIrpStackLocation (Irp);
  296. powerType = stack->Parameters.Power.Type;
  297. powerState = stack->Parameters.Power.State;
  298. //
  299. // Restore the device
  300. //
  301. pDevExt->PowerState = PowerDeviceD0;
  302. //
  303. // Theoretically we could change states in the middle of processing
  304. // the restore which would result in a bad PKINTERRUPT being used
  305. // in CyzRestoreDeviceState().
  306. //
  307. if (pDevExt->PNPState == CYZ_PNP_STARTED) {
  308. CyzRestoreDeviceState(pDevExt);
  309. }
  310. //
  311. // Now that we are powered up, call PoSetPowerState
  312. //
  313. PoSetPowerState(DeviceObject, powerType, powerState);
  314. PoStartNextPowerIrp(Irp);
  315. CyzCompleteRequest(pDevExt, Irp, IO_NO_INCREMENT); // Code back
  316. return STATUS_MORE_PROCESSING_REQUIRED; // Code back
  317. //CyzIRPEpilogue(pDevExt); // Added and removed Fanny
  318. //return STATUS_SUCCESS; // Added and removed Fanny
  319. }
  320. NTSTATUS
  321. CyzPowerDispatch(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  322. /*++
  323. Routine Description:
  324. This is a dispatch routine for the IRPs that come to the driver with the
  325. IRP_MJ_POWER major code (power IRPs).
  326. Arguments:
  327. PDevObj - Pointer to the device object for this device
  328. PIrp - Pointer to the IRP for the current request
  329. Return Value:
  330. The function value is the final status of the call
  331. --*/
  332. {
  333. PCYZ_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  334. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  335. NTSTATUS status;
  336. PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject;
  337. PDEVICE_OBJECT pPdo = pDevExt->Pdo;
  338. BOOLEAN acceptingIRPs;
  339. PAGED_CODE();
  340. if ((status = CyzIRPPrologue(PIrp, pDevExt)) != STATUS_SUCCESS) {
  341. if (status != STATUS_PENDING) {
  342. PoStartNextPowerIrp(PIrp);
  343. CyzCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
  344. }
  345. return status;
  346. }
  347. status = STATUS_SUCCESS;
  348. switch (pIrpStack->MinorFunction) {
  349. case IRP_MN_WAIT_WAKE:
  350. CyzDbgPrintEx(CYZPNPPOWER, "Got IRP_MN_WAIT_WAKE Irp\n");
  351. break;
  352. case IRP_MN_POWER_SEQUENCE:
  353. CyzDbgPrintEx(CYZPNPPOWER, "Got IRP_MN_POWER_SEQUENCE Irp\n");
  354. break;
  355. case IRP_MN_SET_POWER:
  356. CyzDbgPrintEx(CYZPNPPOWER, "Got IRP_MN_SET_POWER Irp\n");
  357. //
  358. // Perform different ops if it was system or device
  359. //
  360. switch (pIrpStack->Parameters.Power.Type) {
  361. case SystemPowerState:
  362. CyzDbgPrintEx(CYZPNPPOWER, "SystemPowerState\n");
  363. IoMarkIrpPending(PIrp);
  364. IoCopyCurrentIrpStackLocationToNext (PIrp);
  365. IoSetCompletionRoutine (PIrp,
  366. CyzSystemPowerComplete,
  367. NULL,
  368. TRUE,
  369. TRUE,
  370. TRUE);
  371. PoCallDriver(pDevExt->LowerDeviceObject, PIrp);
  372. return STATUS_PENDING;
  373. case DevicePowerState:
  374. CyzDbgPrintEx(CYZPNPPOWER, "DevicePowerState\n");
  375. status = PIrp->IoStatus.Status = STATUS_SUCCESS;
  376. if (pDevExt->PowerState == pIrpStack->Parameters.Power.State.DeviceState) {
  377. // If we are already in the requested state, just pass the IRP down
  378. CyzDbgPrintEx(CYZPNPPOWER, "Already in requested power state\n");
  379. break;
  380. }
  381. switch (pIrpStack->Parameters.Power.State.DeviceState) {
  382. case PowerDeviceD0:
  383. if (pDevExt->OpenCount) {
  384. CyzDbgPrintEx(CYZPNPPOWER, "Going to power state D0\n");
  385. IoMarkIrpPending(PIrp);
  386. IoCopyCurrentIrpStackLocationToNext (PIrp);
  387. IoSetCompletionRoutine (PIrp,
  388. CyzDevicePowerComplete,
  389. NULL,
  390. TRUE,
  391. TRUE,
  392. TRUE);
  393. PoCallDriver(pDevExt->LowerDeviceObject, PIrp);
  394. return STATUS_PENDING;
  395. }
  396. //return CyzSetPowerD0(PDevObj, PIrp);
  397. break;
  398. case PowerDeviceD1:
  399. case PowerDeviceD2:
  400. case PowerDeviceD3:
  401. CyzDbgPrintEx(CYZPNPPOWER, "Going to power state D3\n");
  402. return CyzSetPowerD3(PDevObj, PIrp);
  403. }
  404. break;
  405. default:
  406. CyzDbgPrintEx(CYZPNPPOWER, "UNKNOWN PowerState\n");
  407. break;
  408. }
  409. break;
  410. case IRP_MN_QUERY_POWER:
  411. CyzDbgPrintEx (CYZPNPPOWER, "Got IRP_MN_QUERY_POWER Irp\n");
  412. //
  413. // Check if we have a wait-wake pending and if so,
  414. // ensure we don't power down too far.
  415. //
  416. if (pDevExt->PendingWakeIrp != NULL || pDevExt->SendWaitWake) {
  417. if (pIrpStack->Parameters.Power.Type == DevicePowerState
  418. && pIrpStack->Parameters.Power.State.DeviceState
  419. > pDevExt->DeviceWake) {
  420. status = PIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
  421. PoStartNextPowerIrp(PIrp);
  422. CyzCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
  423. return status;
  424. }
  425. }
  426. //
  427. // If no wait-wake, always successful
  428. //
  429. PIrp->IoStatus.Status = STATUS_SUCCESS;
  430. status = STATUS_SUCCESS;
  431. PoStartNextPowerIrp(PIrp);
  432. IoSkipCurrentIrpStackLocation(PIrp);
  433. return CyzPoCallDriver(pDevExt, pLowerDevObj, PIrp);
  434. } // switch (pIrpStack->MinorFunction)
  435. PoStartNextPowerIrp(PIrp);
  436. //
  437. // Pass to the lower driver
  438. //
  439. IoSkipCurrentIrpStackLocation(PIrp);
  440. status = CyzPoCallDriver(pDevExt, pLowerDevObj, PIrp);
  441. return status;
  442. }
  443. NTSTATUS
  444. CyzGotoPowerState(IN PDEVICE_OBJECT PDevObj,
  445. IN PCYZ_DEVICE_EXTENSION PDevExt,
  446. IN DEVICE_POWER_STATE DevPowerState)
  447. /*++
  448. Routine Description:
  449. This routine causes the driver to request the stack go to a particular
  450. power state.
  451. Arguments:
  452. PDevObj - Pointer to the device object for this device
  453. PDevExt - Pointer to the device extension we are working from
  454. DevPowerState - the power state we wish to go to
  455. Return Value:
  456. The function value is the final status of the call
  457. --*/
  458. {
  459. KEVENT gotoPowEvent;
  460. NTSTATUS status;
  461. POWER_STATE powerState;
  462. PAGED_CODE();
  463. CyzDbgPrintEx(CYZTRACECALLS, "In CyzGotoPowerState\n");
  464. powerState.DeviceState = DevPowerState;
  465. KeInitializeEvent(&gotoPowEvent, SynchronizationEvent, FALSE);
  466. status = PoRequestPowerIrp(PDevObj, IRP_MN_SET_POWER, powerState,
  467. CyzSetPowerEvent, &gotoPowEvent,
  468. NULL);
  469. if (status == STATUS_PENDING) {
  470. KeWaitForSingleObject(&gotoPowEvent, Executive, KernelMode, FALSE, NULL);
  471. status = STATUS_SUCCESS;
  472. }
  473. #if DBG
  474. if (!NT_SUCCESS(status)) {
  475. CyzDbgPrintEx(CYZPNPPOWER, "CyzGotoPowerState FAILED\n");
  476. }
  477. #endif
  478. CyzDbgPrintEx(CYZTRACECALLS, "Leaving CyzGotoPowerState\n");
  479. return status;
  480. }
  481. NTSTATUS
  482. CyzSetPowerD3(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  483. /*++
  484. Routine Description:
  485. This routine handles the SET_POWER minor function.
  486. Arguments:
  487. PDevObj - Pointer to the device object for this device
  488. PIrp - Pointer to the IRP for the current request
  489. Return Value:
  490. The function value is the final status of the call
  491. --*/
  492. {
  493. NTSTATUS status = STATUS_SUCCESS;
  494. PCYZ_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  495. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  496. PAGED_CODE();
  497. CyzDbgPrintEx(CYZDIAG3, "In CyzSetPowerD3\n");
  498. //
  499. // Send the wait wake now, just in time
  500. //
  501. if (pDevExt->SendWaitWake) {
  502. CyzSendWaitWake(pDevExt);
  503. }
  504. //
  505. // Before we power down, call PoSetPowerState
  506. //
  507. PoSetPowerState(PDevObj, pIrpStack->Parameters.Power.Type,
  508. pIrpStack->Parameters.Power.State);
  509. //
  510. // If the device is not closed, disable interrupts and allow the fifo's
  511. // to flush.
  512. //
  513. if (pDevExt->DeviceIsOpened == TRUE) {
  514. //LARGE_INTEGER charTime;
  515. pDevExt->DeviceIsOpened = FALSE;
  516. pDevExt->DeviceState.Reopen = TRUE;
  517. //charTime.QuadPart = -CyzGetCharTime(pDevExt).QuadPart;
  518. //
  519. // Shut down the chip
  520. //
  521. #ifdef POLL
  522. CyzTryToDisableTimer(pDevExt);
  523. #endif
  524. //TODO FANNY: SHOULD WE RESET THE CHANNEL HERE?
  525. // //
  526. // // Drain the device
  527. // //
  528. //
  529. // CyzDrainUART(pDevExt, &charTime);
  530. //
  531. // Save the device state
  532. //
  533. CyzSaveDeviceState(pDevExt);
  534. }
  535. #ifndef POLL
  536. {
  537. PCYZ_DISPATCH pDispatch;
  538. pDispatch = (PCYZ_DISPATCH)pDevExt->OurIsrContext;
  539. pDispatch->PoweredOn[pDevExt->PortIndex] = FALSE;
  540. }
  541. #endif
  542. //
  543. // If the device is not open, we don't need to save the state;
  544. // we can just reset the device on power-up
  545. //
  546. PIrp->IoStatus.Status = STATUS_SUCCESS;
  547. pDevExt->PowerState = PowerDeviceD3;
  548. //
  549. // For what we are doing, we don't need a completion routine
  550. // since we don't race on the power requests.
  551. //
  552. PIrp->IoStatus.Status = STATUS_SUCCESS;
  553. PoStartNextPowerIrp(PIrp);
  554. IoSkipCurrentIrpStackLocation(PIrp);
  555. return CyzPoCallDriver(pDevExt, pDevExt->LowerDeviceObject, PIrp);
  556. }
  557. NTSTATUS
  558. CyzSendWaitWake(PCYZ_DEVICE_EXTENSION PDevExt)
  559. /*++
  560. Routine Description:
  561. This routine causes a waitwake IRP to be sent
  562. Arguments:
  563. PDevExt - Pointer to the device extension for this device
  564. Return Value:
  565. STATUS_INVALID_DEVICE_STATE if one is already pending, else result
  566. of call to PoRequestPowerIrp.
  567. --*/
  568. {
  569. NTSTATUS status;
  570. PIRP pIrp;
  571. POWER_STATE powerState;
  572. PAGED_CODE();
  573. //
  574. // Make sure one isn't pending already -- serial will only handle one at
  575. // a time.
  576. //
  577. if (PDevExt->PendingWakeIrp != NULL) {
  578. return STATUS_INVALID_DEVICE_STATE;
  579. }
  580. //
  581. // Make sure we are capable of waking the machine
  582. //
  583. if (PDevExt->SystemWake <= PowerSystemWorking) {
  584. return STATUS_INVALID_DEVICE_STATE;
  585. }
  586. if (PDevExt->DeviceWake == PowerDeviceUnspecified) {
  587. return STATUS_INVALID_DEVICE_STATE;
  588. }
  589. //
  590. // Send IRP to request wait wake and add a pending irp flag
  591. //
  592. //
  593. InterlockedIncrement(&PDevExt->PendingIRPCnt);
  594. powerState.SystemState = PDevExt->SystemWake;
  595. status = PoRequestPowerIrp(PDevExt->Pdo, IRP_MN_WAIT_WAKE,
  596. powerState, CyzWakeCompletion, PDevExt, &pIrp);
  597. if (status == STATUS_PENDING) {
  598. status = STATUS_SUCCESS;
  599. PDevExt->PendingWakeIrp = pIrp;
  600. } else if (!NT_SUCCESS(status)) {
  601. CyzIRPEpilogue(PDevExt);
  602. }
  603. return status;
  604. }
  605. NTSTATUS
  606. CyzWakeCompletion(IN PDEVICE_OBJECT PDevObj, IN UCHAR MinorFunction,
  607. IN POWER_STATE PowerState, IN PVOID Context,
  608. IN PIO_STATUS_BLOCK IoStatus)
  609. /*++
  610. Routine Description:
  611. This routine handles completion of the waitwake IRP.
  612. Arguments:
  613. PDevObj - Pointer to the device object for this device
  614. MinorFunction - Minor function previously supplied to PoRequestPowerIrp
  615. PowerState - PowerState previously supplied to PoRequestPowerIrp
  616. Context - a pointer to the device extension
  617. IoStatus - current/final status of the waitwake IRP
  618. Return Value:
  619. The function value is the final status of attempting to process the
  620. waitwake.
  621. --*/
  622. {
  623. NTSTATUS status;
  624. PCYZ_DEVICE_EXTENSION pDevExt = (PCYZ_DEVICE_EXTENSION)Context;
  625. POWER_STATE powerState;
  626. status = IoStatus->Status;
  627. if (NT_SUCCESS(status)) {
  628. //
  629. // A wakeup has occurred -- powerup our stack
  630. //
  631. powerState.DeviceState = PowerDeviceD0;
  632. PoRequestPowerIrp(pDevExt->Pdo, IRP_MN_SET_POWER, powerState, NULL,
  633. NULL, NULL);
  634. }
  635. pDevExt->PendingWakeIrp = NULL;
  636. CyzIRPEpilogue(pDevExt);
  637. return status;
  638. }