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.

1078 lines
27 KiB

  1. /*--------------------------------------------------------------------------
  2. *
  3. * Copyright (C) Cyclades Corporation, 1999-2001.
  4. * All rights reserved.
  5. *
  6. * Cyclom-Y Port Driver
  7. *
  8. * This file: cyypower.c
  9. *
  10. * Description: This module contains the code that handles the power
  11. * IRPs for the Cyclom-Y 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 implementation based on Microsoft sample code.
  26. *
  27. *--------------------------------------------------------------------------
  28. */
  29. #include "precomp.h"
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text(PAGESRP0, CyyGotoPowerState)
  32. #pragma alloc_text(PAGESRP0, CyyPowerDispatch)
  33. //#pragma alloc_text(PAGESRP0, CyySetPowerD0)
  34. #pragma alloc_text(PAGESRP0, CyySetPowerD3)
  35. //#pragma alloc_text(PAGESRP0, CyySaveDeviceState)
  36. //#pragma alloc_text(PAGESRP0, CyyRestoreDeviceState)
  37. #pragma alloc_text(PAGESRP0, CyySendWaitWake)
  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. CyySetPowerEvent(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. #if 0
  67. BOOLEAN
  68. CyyDisableInterruptInPLX(
  69. IN PVOID Context
  70. )
  71. /*++
  72. Routine Description:
  73. This routine disables the PLX interrupts and puts the hw in a "safe" state when
  74. not in use (like a close or powerdown).
  75. Arguments:
  76. Context - Really a pointer to the device extension.
  77. Return Value:
  78. This routine always returns FALSE.
  79. --*/
  80. {
  81. PCYY_DEVICE_EXTENSION PDevExt = Context;
  82. PUCHAR chip = PDevExt->Cd1400;
  83. ULONG bus = PDevExt->IsPci;
  84. if (PDevExt->IsPci){
  85. ULONG i;
  86. UCHAR plx_ver;
  87. ULONG original;
  88. PCYY_DISPATCH pDispatch;
  89. pDispatch = (PCYY_DISPATCH)PDevExt->OurIsrContext;
  90. pDispatch->Cd1400[PDevExt->PortIndex] = NULL;
  91. for (i = 0; i < CYY_MAX_PORTS; i++) {
  92. if (pDispatch->Cd1400[PDevExt->PortIndex] != NULL) {
  93. break;
  94. }
  95. }
  96. if (i == CYY_MAX_PORTS) {
  97. // This was the last port, disable Interrupts.
  98. CYY_CLEAR_INTERRUPT(PDevExt->BoardMemory,PDevExt->IsPci);
  99. plx_ver = CYY_READ_PCI_TYPE(PDevExt->BoardMemory);
  100. plx_ver &= 0x0f;
  101. switch(plx_ver) {
  102. case CYY_PLX9050:
  103. original = PLX9050_READ_INTERRUPT_CONTROL(PDevExt->Runtime);
  104. PLX9050_WRITE_INTERRUPT_CONTROL(PDevExt->Runtime,
  105. original&~PLX9050_INT_ENABLE);
  106. break;
  107. case CYY_PLX9060:
  108. case CYY_PLX9080:
  109. default:
  110. original = PLX9060_READ_INTERRUPT_CONTROL(PDevExt->Runtime);
  111. PLX9060_WRITE_INTERRUPT_CONTROL(PDevExt->Runtime,
  112. original&~PLX9060_INT_ENABLE);
  113. break;
  114. }
  115. }
  116. }
  117. // Disable interrupt mask in the CD1400
  118. CD1400_WRITE(chip,bus,CAR,PDevExt->CdChannel & 0x03);
  119. CD1400_WRITE(chip,bus,SRER,0x00);
  120. CyyCDCmd(PDevExt,CCR_RESET_CHANNEL); // Disables tx and rx, all FIFOs flushed.
  121. return FALSE;
  122. }
  123. BOOLEAN
  124. CyyFlushCd1400(IN PVOID Context)
  125. /*++
  126. Routine Description:
  127. This routine flushes the Tx FIFO.
  128. Arguments:
  129. Context - Really a pointer to the device extension.
  130. Return Value:
  131. This routine always returns FALSE.
  132. --*/
  133. {
  134. PCYY_DEVICE_EXTENSION extension = Context;
  135. PUCHAR chip = extension->Cd1400;
  136. ULONG bus = extension->IsPci;
  137. // Flush TX FIFO
  138. CD1400_WRITE(chip,bus,CAR,extension->CdChannel & 0x03);
  139. CyyCDCmd(extension,CCR_FLUSH_TXFIFO);
  140. return FALSE;
  141. }
  142. #endif
  143. BOOLEAN
  144. CyySaveDeviceState(
  145. IN PVOID Context
  146. )
  147. /*++
  148. Routine Description:
  149. This routine saves the device state of the UART
  150. Arguments:
  151. PDevExt - Pointer to the device extension for the devobj to save the state
  152. for.
  153. Return Value:
  154. VOID
  155. --*/
  156. {
  157. PCYY_DEVICE_EXTENSION PDevExt = Context;
  158. PCYY_DEVICE_STATE pDevState = &PDevExt->DeviceState;
  159. PUCHAR chip = PDevExt->Cd1400;
  160. ULONG bus = PDevExt->IsPci;
  161. CyyDbgPrintEx(CYYTRACECALLS, "Entering CyySaveDeviceState\n");
  162. if (PDevExt->IsPci){
  163. ULONG i;
  164. UCHAR plx_ver;
  165. ULONG original;
  166. PCYY_DISPATCH pDispatch;
  167. pDispatch = (PCYY_DISPATCH)PDevExt->OurIsrContext;
  168. pDispatch->Cd1400[PDevExt->PortIndex] = NULL;
  169. for (i = 0; i < CYY_MAX_PORTS; i++) {
  170. if (pDispatch->Cd1400[PDevExt->PortIndex] != NULL) {
  171. break;
  172. }
  173. }
  174. if (i == CYY_MAX_PORTS) {
  175. // This was the last port, disable Interrupts.
  176. CYY_CLEAR_INTERRUPT(PDevExt->BoardMemory,PDevExt->IsPci);
  177. plx_ver = CYY_READ_PCI_TYPE(PDevExt->BoardMemory);
  178. plx_ver &= 0x0f;
  179. switch(plx_ver) {
  180. case CYY_PLX9050:
  181. original = PLX9050_READ_INTERRUPT_CONTROL(PDevExt->Runtime);
  182. PLX9050_WRITE_INTERRUPT_CONTROL(PDevExt->Runtime,
  183. original&~PLX9050_INT_ENABLE);
  184. break;
  185. case CYY_PLX9060:
  186. case CYY_PLX9080:
  187. default:
  188. original = PLX9060_READ_INTERRUPT_CONTROL(PDevExt->Runtime);
  189. PLX9060_WRITE_INTERRUPT_CONTROL(PDevExt->Runtime,
  190. original&~PLX9060_INT_ENABLE);
  191. break;
  192. }
  193. }
  194. }
  195. // Flush TX FIFO
  196. CD1400_WRITE(chip,bus,CAR,PDevExt->CdChannel & 0x03);
  197. CyyCDCmd(PDevExt,CCR_FLUSH_TXFIFO);
  198. CD1400_WRITE(chip,bus,CAR,PDevExt->CdChannel & 0x03);
  199. pDevState->Srer = CD1400_READ(chip,bus,SRER);
  200. pDevState->Cor1 = CD1400_READ(chip,bus,COR1);
  201. pDevState->Cor2 = CD1400_READ(chip,bus,COR2);
  202. pDevState->Cor3 = CD1400_READ(chip,bus,COR3);
  203. pDevState->Schr1 = CD1400_READ(chip,bus,SCHR1);
  204. pDevState->Schr2 = CD1400_READ(chip,bus,SCHR2);
  205. pDevState->Mcor1 = CD1400_READ(chip,bus,MCOR1);
  206. pDevState->Mcor2 = CD1400_READ(chip,bus,MCOR2);
  207. pDevState->Rtpr = CD1400_READ(chip,bus,RTPR);
  208. pDevState->Msvr1 = CD1400_READ(chip,bus,MSVR1);
  209. pDevState->Msvr2 = CD1400_READ(chip,bus,MSVR2);
  210. pDevState->Rbpr = CD1400_READ(chip,bus,RBPR);
  211. pDevState->Tbpr = CD1400_READ(chip,bus,TBPR);
  212. pDevState->Rcor = CD1400_READ(chip,bus,RCOR);
  213. pDevState->Tcor = CD1400_READ(chip,bus,TCOR);
  214. // Disable interrupt mask in the CD1400
  215. CD1400_WRITE(chip,bus,CAR,PDevExt->CdChannel & 0x03);
  216. CD1400_WRITE(chip,bus,SRER,0x00);
  217. CyyCDCmd(PDevExt,CCR_RESET_CHANNEL); // Disables tx and rx, all FIFOs flushed.
  218. PDevExt->PowerState = PowerDeviceD3;
  219. CyyDbgPrintEx(CYYTRACECALLS, "Leaving CyySaveDeviceState\n");
  220. return FALSE;
  221. }
  222. VOID
  223. CyyEnableInterruptInPLX(
  224. IN PVOID Context
  225. )
  226. /*++
  227. Routine Description:
  228. This routine enables the PLX interrupts and puts the hw in a "safe" state when
  229. not in use (like a close or powerdown).
  230. Arguments:
  231. Context - Really a pointer to the device extension.
  232. Return Value:
  233. This routine always returns FALSE.
  234. --*/
  235. {
  236. PCYY_DEVICE_EXTENSION PDevExt = Context;
  237. if (PDevExt->IsPci){
  238. UCHAR plx_ver;
  239. ULONG original;
  240. plx_ver = CYY_READ_PCI_TYPE(PDevExt->BoardMemory);
  241. plx_ver &= 0x0f;
  242. switch(plx_ver) {
  243. case CYY_PLX9050:
  244. original = PLX9050_READ_INTERRUPT_CONTROL(PDevExt->Runtime);
  245. if ((original & PLX9050_INT_ENABLE) != PLX9050_INT_ENABLE) {
  246. PLX9050_WRITE_INTERRUPT_CONTROL(PDevExt->Runtime,
  247. original|PLX9050_INT_ENABLE);
  248. }
  249. break;
  250. case CYY_PLX9060:
  251. case CYY_PLX9080:
  252. default:
  253. original = PLX9060_READ_INTERRUPT_CONTROL(PDevExt->Runtime);
  254. if ((original & PLX9060_INT_ENABLE) != PLX9060_INT_ENABLE) {
  255. PLX9060_WRITE_INTERRUPT_CONTROL(PDevExt->Runtime,
  256. original|PLX9060_INT_ENABLE);
  257. }
  258. break;
  259. }
  260. }
  261. }
  262. BOOLEAN
  263. CyyRestoreDeviceState(
  264. IN PVOID Context
  265. )
  266. /*++
  267. Routine Description:
  268. This routine restores the device state of the UART
  269. Arguments:
  270. PDevExt - Pointer to the device PDevExt for the devobj to restore the
  271. state for.
  272. Return Value:
  273. VOID
  274. --*/
  275. {
  276. PCYY_DEVICE_EXTENSION PDevExt = Context;
  277. PCYY_DEVICE_STATE pDevState = &PDevExt->DeviceState;
  278. PUCHAR chip = PDevExt->Cd1400;
  279. ULONG bus = PDevExt->IsPci;
  280. PCYY_DISPATCH pDispatch = PDevExt->OurIsrContext;
  281. CyyDbgPrintEx(CYYTRACECALLS, "Enter CyyRestoreDeviceState\n");
  282. CyyDbgPrintEx(CYYTRACECALLS, "PDevExt: %x\n", PDevExt);
  283. CD1400_WRITE(chip,bus,CAR,PDevExt->CdChannel & 0x03);
  284. CD1400_WRITE(chip,bus,SRER,0x00);
  285. CyyCDCmd(PDevExt,CCR_RESET_CHANNEL);
  286. CYY_CLEAR_INTERRUPT(PDevExt->BoardMemory,bus);
  287. PDevExt->HoldingEmpty = TRUE;
  288. // Set Cd1400 address for the ISR
  289. pDispatch->Cd1400[PDevExt->PortIndex] = chip;
  290. CyyEnableInterruptInPLX(PDevExt);
  291. if (PDevExt->DeviceState.Reopen == TRUE) {
  292. CyyDbgPrintEx(CYYPNPPOWER, "Reopening device\n");
  293. PDevExt->DeviceIsOpened = TRUE;
  294. PDevExt->DeviceState.Reopen = FALSE;
  295. CD1400_WRITE(chip,bus,CAR,PDevExt->CdChannel & 0x03);
  296. CD1400_WRITE(chip,bus,COR1, pDevState->Cor1);
  297. CD1400_WRITE(chip,bus,COR2, pDevState->Cor2);
  298. CD1400_WRITE(chip,bus,COR3, pDevState->Cor3);
  299. CD1400_WRITE(chip,bus,SCHR1,pDevState->Schr1);
  300. CD1400_WRITE(chip,bus,SCHR2,pDevState->Schr2);
  301. CD1400_WRITE(chip,bus,MCOR1,pDevState->Mcor1);
  302. CD1400_WRITE(chip,bus,MCOR2,pDevState->Mcor2);
  303. CD1400_WRITE(chip,bus,RTPR, pDevState->Rtpr);
  304. CD1400_WRITE(chip,bus,MSVR1,pDevState->Msvr1);
  305. CD1400_WRITE(chip,bus,MSVR2,pDevState->Msvr2);
  306. CD1400_WRITE(chip,bus,RBPR, pDevState->Rbpr);
  307. CD1400_WRITE(chip,bus,TBPR, pDevState->Tbpr);
  308. CD1400_WRITE(chip,bus,RCOR, pDevState->Rcor);
  309. CD1400_WRITE(chip,bus,TCOR, pDevState->Tcor);
  310. CyyCDCmd(PDevExt,CCR_CORCHG_COR1_COR2_COR3);
  311. CyyCDCmd(PDevExt,CCR_ENA_TX_RX);
  312. //
  313. // This enables interrupts on the device!
  314. //
  315. CD1400_WRITE(chip,bus,SRER, pDevState->Srer);
  316. }
  317. return FALSE;
  318. }
  319. VOID
  320. CyyPowerRequestComplete(
  321. PDEVICE_OBJECT DeviceObject,
  322. UCHAR MinorFunction,
  323. POWER_STATE state,
  324. POWER_COMPLETION_CONTEXT* PowerContext,
  325. PIO_STATUS_BLOCK IoStatus
  326. )
  327. /*++
  328. Routine Description:
  329. Completion routine for D-IRP.
  330. Arguments:
  331. Return Value:
  332. NT status code
  333. --*/
  334. {
  335. PCYY_DEVICE_EXTENSION pDevExt = (PCYY_DEVICE_EXTENSION) PowerContext->DeviceObject->DeviceExtension;
  336. PIRP sIrp = PowerContext->SIrp;
  337. UNREFERENCED_PARAMETER (DeviceObject);
  338. UNREFERENCED_PARAMETER (MinorFunction);
  339. UNREFERENCED_PARAMETER (state);
  340. //
  341. // Cleanup
  342. //
  343. ExFreePool(PowerContext);
  344. //
  345. // Here we copy the D-IRP status into the S-IRP
  346. //
  347. sIrp->IoStatus.Status = IoStatus->Status;
  348. //
  349. // Release the IRP
  350. //
  351. PoStartNextPowerIrp(sIrp);
  352. CyyCompleteRequest(pDevExt,sIrp,IO_NO_INCREMENT);
  353. }
  354. NTSTATUS
  355. CyySystemPowerComplete (
  356. IN PDEVICE_OBJECT DeviceObject,
  357. IN PIRP Irp,
  358. IN PVOID Context
  359. )
  360. /*++
  361. --*/
  362. {
  363. POWER_COMPLETION_CONTEXT* powerContext;
  364. POWER_STATE powerState;
  365. POWER_STATE_TYPE powerType;
  366. PIO_STACK_LOCATION stack;
  367. PCYY_DEVICE_EXTENSION data;
  368. NTSTATUS status = Irp->IoStatus.Status;
  369. UNREFERENCED_PARAMETER (Context);
  370. data = DeviceObject->DeviceExtension;
  371. if (!NT_SUCCESS(status)) {
  372. PoStartNextPowerIrp(Irp);
  373. CyyIRPEpilogue(data);
  374. return STATUS_SUCCESS;
  375. }
  376. stack = IoGetCurrentIrpStackLocation (Irp);
  377. powerState = stack->Parameters.Power.State;
  378. switch (stack->Parameters.Power.State.SystemState) {
  379. case PowerSystemUnspecified:
  380. powerState.DeviceState = PowerDeviceUnspecified;
  381. break;
  382. case PowerSystemWorking:
  383. powerState.DeviceState = PowerDeviceD0;
  384. break;
  385. case PowerSystemSleeping1:
  386. case PowerSystemSleeping2:
  387. case PowerSystemSleeping3:
  388. case PowerSystemHibernate:
  389. case PowerSystemShutdown:
  390. case PowerSystemMaximum:
  391. powerState.DeviceState = data->DeviceStateMap[stack->Parameters.Power.State.SystemState];
  392. break;
  393. default:
  394. powerState.DeviceState = PowerDeviceD3;
  395. }
  396. //
  397. // Send IRP to change device state
  398. //
  399. powerContext = (POWER_COMPLETION_CONTEXT*)
  400. ExAllocatePool(NonPagedPool, sizeof(POWER_COMPLETION_CONTEXT));
  401. if (!powerContext) {
  402. status = STATUS_INSUFFICIENT_RESOURCES;
  403. } else {
  404. powerContext->DeviceObject = DeviceObject;
  405. powerContext->SIrp = Irp;
  406. status = PoRequestPowerIrp(DeviceObject, IRP_MN_SET_POWER, powerState, CyyPowerRequestComplete,
  407. powerContext, NULL);
  408. }
  409. if (!NT_SUCCESS(status)) {
  410. if (powerContext) {
  411. ExFreePool(powerContext);
  412. }
  413. PoStartNextPowerIrp(Irp);
  414. Irp->IoStatus.Status = status;
  415. CyyCompleteRequest(data,Irp,IO_NO_INCREMENT); // To be equal to toaster
  416. //CyyIRPEpilogue(data);
  417. //return status;
  418. }
  419. return STATUS_MORE_PROCESSING_REQUIRED;
  420. }
  421. NTSTATUS
  422. CyyDevicePowerComplete (
  423. IN PDEVICE_OBJECT DeviceObject,
  424. IN PIRP Irp,
  425. IN PVOID Context
  426. )
  427. /*++
  428. Routine Description:
  429. The completion routine for Power Up D-IRP.
  430. Arguments:
  431. DeviceObject - pointer to a device object.
  432. Irp - pointer to an I/O Request Packet.
  433. Context - context pointer
  434. Return Value:
  435. NT status code
  436. --*/
  437. {
  438. POWER_STATE powerState;
  439. POWER_STATE_TYPE powerType;
  440. PIO_STACK_LOCATION stack;
  441. PCYY_DEVICE_EXTENSION pDevExt;
  442. UNREFERENCED_PARAMETER (Context);
  443. if (Irp->PendingReturned) {
  444. IoMarkIrpPending(Irp);
  445. }
  446. pDevExt = DeviceObject->DeviceExtension;
  447. stack = IoGetCurrentIrpStackLocation (Irp);
  448. powerType = stack->Parameters.Power.Type;
  449. powerState = stack->Parameters.Power.State;
  450. //
  451. // Restore the device
  452. //
  453. pDevExt->PowerState = PowerDeviceD0;
  454. //
  455. // Theoretically we could change states in the middle of processing
  456. // the restore which would result in a bad PKINTERRUPT being used
  457. // in CyyRestoreDeviceState().
  458. //
  459. if (pDevExt->PNPState == CYY_PNP_STARTED) {
  460. KeSynchronizeExecution(
  461. pDevExt->Interrupt,
  462. CyyRestoreDeviceState,
  463. pDevExt
  464. );
  465. }
  466. //
  467. // Now that we are powered up, call PoSetPowerState
  468. //
  469. PoSetPowerState(DeviceObject, powerType, powerState);
  470. PoStartNextPowerIrp(Irp);
  471. CyyCompleteRequest(pDevExt, Irp, IO_NO_INCREMENT); // Code back
  472. return STATUS_MORE_PROCESSING_REQUIRED; // Code back
  473. //CyyIRPEpilogue(pDevExt); // Added and removed Fanny
  474. //return STATUS_SUCCESS; // Added and removed Fanny
  475. }
  476. NTSTATUS
  477. CyyPowerDispatch(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  478. /*++
  479. Routine Description:
  480. This is a dispatch routine for the IRPs that come to the driver with the
  481. IRP_MJ_POWER major code (power IRPs).
  482. Arguments:
  483. PDevObj - Pointer to the device object for this device
  484. PIrp - Pointer to the IRP for the current request
  485. Return Value:
  486. The function value is the final status of the call
  487. --*/
  488. {
  489. PCYY_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  490. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  491. NTSTATUS status;
  492. PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject;
  493. PDEVICE_OBJECT pPdo = pDevExt->Pdo;
  494. BOOLEAN acceptingIRPs;
  495. PAGED_CODE();
  496. if ((status = CyyIRPPrologue(PIrp, pDevExt)) != STATUS_SUCCESS) {
  497. if (status != STATUS_PENDING) {
  498. PoStartNextPowerIrp(PIrp);
  499. CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
  500. }
  501. return status;
  502. }
  503. status = STATUS_SUCCESS;
  504. switch (pIrpStack->MinorFunction) {
  505. case IRP_MN_WAIT_WAKE:
  506. CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_WAIT_WAKE Irp\n");
  507. break;
  508. case IRP_MN_POWER_SEQUENCE:
  509. CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_POWER_SEQUENCE Irp\n");
  510. break;
  511. case IRP_MN_SET_POWER:
  512. CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_SET_POWER Irp\n");
  513. switch (pIrpStack->Parameters.Power.Type) {
  514. case SystemPowerState:
  515. CyyDbgPrintEx(CYYPNPPOWER, "SystemPowerState\n");
  516. IoMarkIrpPending(PIrp);
  517. IoCopyCurrentIrpStackLocationToNext (PIrp);
  518. IoSetCompletionRoutine (PIrp,
  519. CyySystemPowerComplete,
  520. NULL,
  521. TRUE,
  522. TRUE,
  523. TRUE);
  524. PoCallDriver(pDevExt->LowerDeviceObject, PIrp);
  525. return STATUS_PENDING;
  526. case DevicePowerState:
  527. CyyDbgPrintEx(CYYPNPPOWER, "DevicePowerState\n");
  528. status = PIrp->IoStatus.Status = STATUS_SUCCESS;
  529. if (pDevExt->PowerState == pIrpStack->Parameters.Power.State.DeviceState) {
  530. // If we are already in the requested state, just pass the IRP down
  531. CyyDbgPrintEx(CYYPNPPOWER, "Already in requested power state\n");
  532. break;
  533. }
  534. switch (pIrpStack->Parameters.Power.State.DeviceState) {
  535. case PowerDeviceD0:
  536. if (pDevExt->OpenCount) {
  537. CyyDbgPrintEx(CYYPNPPOWER, "Going to power state D0\n");
  538. IoMarkIrpPending(PIrp);
  539. IoCopyCurrentIrpStackLocationToNext (PIrp);
  540. IoSetCompletionRoutine (PIrp,
  541. CyyDevicePowerComplete,
  542. NULL,
  543. TRUE,
  544. TRUE,
  545. TRUE);
  546. PoCallDriver(pDevExt->LowerDeviceObject, PIrp);
  547. return STATUS_PENDING;
  548. }
  549. //return CyySetPowerD0(PDevObj, PIrp);
  550. break;
  551. case PowerDeviceD1:
  552. case PowerDeviceD2:
  553. case PowerDeviceD3:
  554. CyyDbgPrintEx(CYYPNPPOWER, "Going to power state D3\n");
  555. return CyySetPowerD3(PDevObj, PIrp);
  556. }
  557. break;
  558. default:
  559. CyyDbgPrintEx(CYYPNPPOWER, "UNKNOWN PowerState\n");
  560. break;
  561. }
  562. break;
  563. case IRP_MN_QUERY_POWER:
  564. CyyDbgPrintEx (CYYPNPPOWER, "Got IRP_MN_QUERY_POWER Irp\n");
  565. //
  566. // Check if we have a wait-wake pending and if so,
  567. // ensure we don't power down too far.
  568. //
  569. if (pDevExt->PendingWakeIrp != NULL || pDevExt->SendWaitWake) {
  570. if (pIrpStack->Parameters.Power.Type == DevicePowerState
  571. && pIrpStack->Parameters.Power.State.DeviceState
  572. > pDevExt->DeviceWake) {
  573. status = PIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
  574. PoStartNextPowerIrp(PIrp);
  575. CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
  576. return status;
  577. }
  578. }
  579. //
  580. // If no wait-wake, always successful
  581. //
  582. PIrp->IoStatus.Status = STATUS_SUCCESS;
  583. status = STATUS_SUCCESS;
  584. PoStartNextPowerIrp(PIrp);
  585. IoSkipCurrentIrpStackLocation(PIrp);
  586. return CyyPoCallDriver(pDevExt, pLowerDevObj, PIrp);
  587. } // switch (pIrpStack->MinorFunction)
  588. PoStartNextPowerIrp(PIrp);
  589. //
  590. // Pass to the lower driver
  591. //
  592. IoSkipCurrentIrpStackLocation(PIrp);
  593. status = CyyPoCallDriver(pDevExt, pLowerDevObj, PIrp);
  594. return status;
  595. }
  596. NTSTATUS
  597. CyyGotoPowerState(IN PDEVICE_OBJECT PDevObj,
  598. IN PCYY_DEVICE_EXTENSION PDevExt,
  599. IN DEVICE_POWER_STATE DevPowerState)
  600. /*++
  601. Routine Description:
  602. This routine causes the driver to request the stack go to a particular
  603. power state.
  604. Arguments:
  605. PDevObj - Pointer to the device object for this device
  606. PDevExt - Pointer to the device extension we are working from
  607. DevPowerState - the power state we wish to go to
  608. Return Value:
  609. The function value is the final status of the call
  610. --*/
  611. {
  612. KEVENT gotoPowEvent;
  613. NTSTATUS status;
  614. POWER_STATE powerState;
  615. PAGED_CODE();
  616. CyyDbgPrintEx(CYYTRACECALLS, "In CyyGotoPowerState\n");
  617. powerState.DeviceState = DevPowerState;
  618. KeInitializeEvent(&gotoPowEvent, SynchronizationEvent, FALSE);
  619. status = PoRequestPowerIrp(PDevObj, IRP_MN_SET_POWER, powerState,
  620. CyySetPowerEvent, &gotoPowEvent,
  621. NULL);
  622. if (status == STATUS_PENDING) {
  623. KeWaitForSingleObject(&gotoPowEvent, Executive, KernelMode, FALSE, NULL);
  624. status = STATUS_SUCCESS;
  625. }
  626. #if DBG
  627. if (!NT_SUCCESS(status)) {
  628. CyyDbgPrintEx(CYYPNPPOWER, "CyyGotoPowerState FAILED\n");
  629. }
  630. #endif
  631. CyyDbgPrintEx(CYYTRACECALLS, "Leaving CyyGotoPowerState\n");
  632. return status;
  633. }
  634. NTSTATUS
  635. CyySetPowerD3(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  636. /*++
  637. Routine Description:
  638. This routine handles the SET_POWER minor function.
  639. Arguments:
  640. PDevObj - Pointer to the device object for this device
  641. PIrp - Pointer to the IRP for the current request
  642. Return Value:
  643. The function value is the final status of the call
  644. --*/
  645. {
  646. NTSTATUS status = STATUS_SUCCESS;
  647. PCYY_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  648. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  649. PAGED_CODE();
  650. CyyDbgPrintEx(CYYDIAG3, "In CyySetPowerD3\n");
  651. //
  652. // Send the wait wake now, just in time
  653. //
  654. if (pDevExt->SendWaitWake) {
  655. CyySendWaitWake(pDevExt);
  656. }
  657. //
  658. // Before we power down, call PoSetPowerState
  659. //
  660. PoSetPowerState(PDevObj, pIrpStack->Parameters.Power.Type,
  661. pIrpStack->Parameters.Power.State);
  662. //
  663. // If the device is not closed, disable interrupts and allow the fifo's
  664. // to flush.
  665. //
  666. if (pDevExt->DeviceIsOpened == TRUE) {
  667. LARGE_INTEGER charTime;
  668. pDevExt->DeviceIsOpened = FALSE;
  669. pDevExt->DeviceState.Reopen = TRUE;
  670. //
  671. // Save the device state
  672. //
  673. KeSynchronizeExecution(
  674. pDevExt->Interrupt,
  675. CyySaveDeviceState,
  676. pDevExt
  677. );
  678. }
  679. //
  680. // If the device is not open, we don't need to save the state;
  681. // we can just reset the device on power-up
  682. //
  683. pDevExt->PowerState = PowerDeviceD3;
  684. //
  685. // For what we are doing, we don't need a completion routine
  686. // since we don't race on the power requests.
  687. //
  688. PIrp->IoStatus.Status = STATUS_SUCCESS;
  689. PoStartNextPowerIrp(PIrp);
  690. IoSkipCurrentIrpStackLocation(PIrp);
  691. return CyyPoCallDriver(pDevExt, pDevExt->LowerDeviceObject, PIrp);
  692. }
  693. NTSTATUS
  694. CyySendWaitWake(PCYY_DEVICE_EXTENSION PDevExt)
  695. /*++
  696. Routine Description:
  697. This routine causes a waitwake IRP to be sent
  698. Arguments:
  699. PDevExt - Pointer to the device extension for this device
  700. Return Value:
  701. STATUS_INVALID_DEVICE_STATE if one is already pending, else result
  702. of call to PoRequestPowerIrp.
  703. --*/
  704. {
  705. NTSTATUS status;
  706. PIRP pIrp;
  707. POWER_STATE powerState;
  708. PAGED_CODE();
  709. //
  710. // Make sure one isn't pending already -- serial will only handle one at
  711. // a time.
  712. //
  713. if (PDevExt->PendingWakeIrp != NULL) {
  714. return STATUS_INVALID_DEVICE_STATE;
  715. }
  716. //
  717. // Make sure we are capable of waking the machine
  718. //
  719. if (PDevExt->SystemWake <= PowerSystemWorking) {
  720. return STATUS_INVALID_DEVICE_STATE;
  721. }
  722. if (PDevExt->DeviceWake == PowerDeviceUnspecified) {
  723. return STATUS_INVALID_DEVICE_STATE;
  724. }
  725. //
  726. // Send IRP to request wait wake and add a pending irp flag
  727. //
  728. //
  729. InterlockedIncrement(&PDevExt->PendingIRPCnt);
  730. powerState.SystemState = PDevExt->SystemWake;
  731. status = PoRequestPowerIrp(PDevExt->Pdo, IRP_MN_WAIT_WAKE,
  732. powerState, CyyWakeCompletion, PDevExt, &pIrp);
  733. if (status == STATUS_PENDING) {
  734. status = STATUS_SUCCESS;
  735. PDevExt->PendingWakeIrp = pIrp;
  736. } else if (!NT_SUCCESS(status)) {
  737. CyyIRPEpilogue(PDevExt);
  738. }
  739. return status;
  740. }
  741. NTSTATUS
  742. CyyWakeCompletion(IN PDEVICE_OBJECT PDevObj, IN UCHAR MinorFunction,
  743. IN POWER_STATE PowerState, IN PVOID Context,
  744. IN PIO_STATUS_BLOCK IoStatus)
  745. /*++
  746. Routine Description:
  747. This routine handles completion of the waitwake IRP.
  748. Arguments:
  749. PDevObj - Pointer to the device object for this device
  750. MinorFunction - Minor function previously supplied to PoRequestPowerIrp
  751. PowerState - PowerState previously supplied to PoRequestPowerIrp
  752. Context - a pointer to the device extension
  753. IoStatus - current/final status of the waitwake IRP
  754. Return Value:
  755. The function value is the final status of attempting to process the
  756. waitwake.
  757. --*/
  758. {
  759. NTSTATUS status;
  760. PCYY_DEVICE_EXTENSION pDevExt = (PCYY_DEVICE_EXTENSION)Context;
  761. POWER_STATE powerState;
  762. status = IoStatus->Status;
  763. if (NT_SUCCESS(status)) {
  764. //
  765. // A wakeup has occurred -- powerup our stack
  766. //
  767. powerState.DeviceState = PowerDeviceD0;
  768. PoRequestPowerIrp(pDevExt->Pdo, IRP_MN_SET_POWER, powerState, NULL,
  769. NULL, NULL);
  770. }
  771. pDevExt->PendingWakeIrp = NULL;
  772. CyyIRPEpilogue(pDevExt);
  773. return status;
  774. }