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.

1134 lines
29 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. pdopower.c
  5. Abstract:
  6. This module contains code to handle
  7. IRP_MJ_POWER dispatches for PDOs
  8. enumerated by the PCMCIA bus driver
  9. Authors:
  10. Ravisankar Pudipeddi (ravisp) May 30, 1997
  11. Neil Sandlin (neilsa) June 1 1999
  12. Environment:
  13. Kernel mode only
  14. Notes:
  15. Revision History:
  16. Neil Sandlin (neilsa) 04-Mar-1999
  17. Made device power a state machine
  18. --*/
  19. #include "pch.h"
  20. //
  21. // Internal References
  22. //
  23. NTSTATUS
  24. PcmciaPdoWaitWake(
  25. IN PDEVICE_OBJECT Pdo,
  26. IN PIRP Irp,
  27. OUT BOOLEAN *CompleteIrp
  28. );
  29. VOID
  30. PcmciaPdoWaitWakeCancelRoutine(
  31. IN PDEVICE_OBJECT Pdo,
  32. IN OUT PIRP Irp
  33. );
  34. NTSTATUS
  35. PcmciaSetPdoPowerState(
  36. IN PDEVICE_OBJECT Pdo,
  37. IN OUT PIRP Irp
  38. );
  39. NTSTATUS
  40. PcmciaSetPdoSystemPowerState(
  41. IN PDEVICE_OBJECT Pdo,
  42. IN OUT PIRP Irp
  43. );
  44. NTSTATUS
  45. PcmciaPdoPowerWorker(
  46. IN PVOID Context,
  47. IN NTSTATUS DeferredStatus
  48. );
  49. VOID
  50. MoveToNextPdoPowerWorkerState(
  51. PPDO_EXTENSION pdoExtension
  52. );
  53. NTSTATUS
  54. PcmciaPdoPowerSentIrpComplete(
  55. IN PDEVICE_OBJECT Pdo,
  56. IN PIRP Irp,
  57. IN PVOID Context
  58. );
  59. NTSTATUS
  60. PcmciaPdoPowerCompletion(
  61. IN PDEVICE_OBJECT Pdo,
  62. IN PIRP Irp,
  63. IN PVOID Context
  64. );
  65. NTSTATUS
  66. PcmciaPdoCompletePowerIrp(
  67. IN PPDO_EXTENSION pdoExtension,
  68. IN PIRP Irp,
  69. IN NTSTATUS status
  70. );
  71. //
  72. //
  73. //
  74. NTSTATUS
  75. PcmciaPdoPowerDispatch(
  76. IN PDEVICE_OBJECT Pdo,
  77. IN PIRP Irp
  78. )
  79. /*++
  80. Routine Description:
  81. This routine handles power requests
  82. for the PDOs.
  83. Arguments:
  84. Pdo - pointer to the physical device object
  85. Irp - pointer to the io request packet
  86. Return Value:
  87. status
  88. --*/
  89. {
  90. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  91. NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
  92. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  93. if(IsDevicePhysicallyRemoved(pdoExtension) || IsDeviceDeleted(pdoExtension)) {
  94. // couldn't aquire RemoveLock - we're in the process of being removed - abort
  95. status = STATUS_NO_SUCH_DEVICE;
  96. PoStartNextPowerIrp( Irp );
  97. Irp->IoStatus.Status = status;
  98. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  99. return status;
  100. }
  101. InterlockedIncrement(&pdoExtension->DeletionLock);
  102. switch (irpStack->MinorFunction) {
  103. case IRP_MN_SET_POWER: {
  104. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x --> IRP_MN_SET_POWER\n", Pdo, Irp));
  105. DebugPrint((PCMCIA_DEBUG_POWER, " (%s%x, context %x)\n",
  106. (irpStack->Parameters.Power.Type == SystemPowerState) ?
  107. "S":
  108. ((irpStack->Parameters.Power.Type == DevicePowerState) ?
  109. "D" :
  110. "Unknown"),
  111. irpStack->Parameters.Power.State,
  112. irpStack->Parameters.Power.SystemContext
  113. ));
  114. status = PcmciaSetPdoPowerState(Pdo, Irp);
  115. break;
  116. }
  117. case IRP_MN_QUERY_POWER: {
  118. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x --> IRP_MN_QUERY_POWER\n", Pdo, Irp));
  119. DebugPrint((PCMCIA_DEBUG_POWER, " (%s%x, context %x)\n",
  120. (irpStack->Parameters.Power.Type == SystemPowerState) ?
  121. "S":
  122. ((irpStack->Parameters.Power.Type == DevicePowerState) ?
  123. "D" :
  124. "Unknown"),
  125. irpStack->Parameters.Power.State,
  126. irpStack->Parameters.Power.SystemContext
  127. ));
  128. status = PcmciaPdoCompletePowerIrp(pdoExtension, Irp, STATUS_SUCCESS);
  129. break;
  130. }
  131. case IRP_MN_WAIT_WAKE: {
  132. BOOLEAN completeIrp;
  133. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x --> IRP_MN_WAIT_WAKE\n", Pdo, Irp));
  134. //
  135. // Should not have a wake pending already
  136. //
  137. ASSERT (!(((PPDO_EXTENSION)Pdo->DeviceExtension)->Flags & PCMCIA_DEVICE_WAKE_PENDING));
  138. status = PcmciaPdoWaitWake(Pdo, Irp, &completeIrp);
  139. if (completeIrp) {
  140. InterlockedDecrement(&pdoExtension->DeletionLock);
  141. PoStartNextPowerIrp(Irp);
  142. Irp->IoStatus.Status = status;
  143. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  144. }
  145. break;
  146. }
  147. default: {
  148. //
  149. // Unhandled minor function
  150. //
  151. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  152. status = PcmciaPdoCompletePowerIrp(pdoExtension, Irp, Irp->IoStatus.Status);
  153. }
  154. }
  155. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x <-- %08x\n", Pdo, Irp, status));
  156. return status;
  157. }
  158. NTSTATUS
  159. PcmciaPdoWaitWake(
  160. IN PDEVICE_OBJECT Pdo,
  161. IN PIRP Irp,
  162. OUT BOOLEAN *CompleteIrp
  163. )
  164. /*++
  165. Routine Description
  166. Handles WAIT_WAKE for the given pc-card.
  167. Arguments
  168. Pdo - Pointer to the device object for the pc-card
  169. Irp - The IRP_MN_WAIT_WAKE Irp
  170. CompleteIrp - This routine will set this to TRUE if the IRP should be
  171. completed after this is called and FALSE if it should not be
  172. touched
  173. Return Value
  174. STATUS_PENDING - Wait wake is pending
  175. STATUS_SUCCESS - Wake is already asserted, wait wake IRP is completed
  176. in this case
  177. Any other status - Error
  178. --*/
  179. {
  180. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  181. PSOCKET socket = pdoExtension->Socket;
  182. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  183. NTSTATUS status;
  184. *CompleteIrp = FALSE;
  185. ASSERT (socket != NULL);
  186. if ((pdoExtension->DeviceCapabilities.DeviceWake == PowerDeviceUnspecified) ||
  187. (pdoExtension->DeviceCapabilities.DeviceWake < pdoExtension->DevicePowerState)) {
  188. //
  189. // Either we don't support wake at all OR the current device power state
  190. // of the PC-Card doesn't support wake
  191. //
  192. return STATUS_INVALID_DEVICE_STATE;
  193. }
  194. if (pdoExtension->Flags & PCMCIA_DEVICE_WAKE_PENDING) {
  195. //
  196. // A WAKE is already pending
  197. //
  198. return STATUS_DEVICE_BUSY;
  199. }
  200. status = PcmciaFdoArmForWake(socket->DeviceExtension);
  201. if (!NT_SUCCESS(status)) {
  202. return status;
  203. }
  204. //for the time being, expect STATUS_PENDING from FdoArmForWake
  205. ASSERT(status == STATUS_PENDING);
  206. //
  207. // Parent has one (more) waiter..
  208. //
  209. InterlockedIncrement(&fdoExtension->ChildWaitWakeCount);
  210. //for testing, make sure there is only one waiter
  211. ASSERT (fdoExtension->ChildWaitWakeCount == 1);
  212. pdoExtension->WaitWakeIrp = Irp;
  213. pdoExtension->Flags |= PCMCIA_DEVICE_WAKE_PENDING;
  214. //
  215. // Set Ring enable/cstschg for the card here..
  216. //
  217. (*socket->SocketFnPtr->PCBEnableDisableWakeupEvent)(socket, pdoExtension, TRUE);
  218. //
  219. // PCI currently does not do anything with a WW irp for a cardbus PDO. So we hack around
  220. // this here by not passing the irp down. Instead it is held pending here, so we can
  221. // set a cancel routine just like the read PDO driver would. If PCI were to do something
  222. // with the irp, we could code something like the following:
  223. //
  224. // if (IsCardBusCard(pdoExtension)) {
  225. // IoSetCompletionRoutine(Irp, PcmciaPdoWaitWakeCompletion, pdoExtension,TRUE,TRUE,TRUE);
  226. // IoCopyCurrentIrpStackLocationToNext(Irp);
  227. // status = IoCallDriver (pdoExtension->LowerDevice, Irp);
  228. // ASSERT (status == STATUS_PENDING);
  229. // return status;
  230. // }
  231. IoMarkIrpPending(Irp);
  232. //
  233. // Allow IRP to be cancelled..
  234. //
  235. IoSetCancelRoutine(Irp, PcmciaPdoWaitWakeCancelRoutine);
  236. IoSetCompletionRoutine(Irp,
  237. PcmciaPdoWaitWakeCompletion,
  238. pdoExtension,
  239. TRUE,
  240. TRUE,
  241. TRUE);
  242. return STATUS_PENDING;
  243. }
  244. NTSTATUS
  245. PcmciaPdoWaitWakeCompletion(
  246. IN PDEVICE_OBJECT Pdo,
  247. IN PIRP Irp,
  248. IN PPDO_EXTENSION PdoExtension
  249. )
  250. /*++
  251. Routine Description
  252. Completion routine called when a pending IRP_MN_WAIT_WAKE Irp completes
  253. Arguments
  254. Pdo - Pointer to the physical device object for the pc-card
  255. Irp - Pointer to the wait wake IRP
  256. PdoExtension - Pointer to the device extension for the Pdo
  257. Return Value
  258. Status from the IRP
  259. --*/
  260. {
  261. PSOCKET socket = PdoExtension->Socket;
  262. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  263. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x --> WaitWakeCompletion\n", Pdo, Irp));
  264. ASSERT (PdoExtension->Flags & PCMCIA_DEVICE_WAKE_PENDING);
  265. PdoExtension->Flags &= ~PCMCIA_DEVICE_WAKE_PENDING;
  266. PdoExtension->WaitWakeIrp = NULL;
  267. //
  268. // Reset ring enable/cstschg
  269. //
  270. (*socket->SocketFnPtr->PCBEnableDisableWakeupEvent)(socket, PdoExtension, FALSE);
  271. ASSERT (fdoExtension->ChildWaitWakeCount > 0);
  272. InterlockedDecrement(&fdoExtension->ChildWaitWakeCount);
  273. //
  274. // Wake completed
  275. //
  276. InterlockedDecrement(&PdoExtension->DeletionLock);
  277. return Irp->IoStatus.Status;
  278. }
  279. VOID
  280. PcmciaPdoWaitWakeCancelRoutine(
  281. IN PDEVICE_OBJECT Pdo,
  282. IN OUT PIRP Irp
  283. )
  284. /*++
  285. Routine Description:
  286. Cancel an outstanding (pending) WAIT_WAKE Irp.
  287. Note: The CancelSpinLock is held on entry
  288. Arguments:
  289. Pdo - Pointer to the physical device object for the pc-card
  290. on which the WAKE is pending
  291. Irp - Pointer to the WAIT_WAKE Irp to be cancelled
  292. Return Value
  293. None
  294. --*/
  295. {
  296. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  297. PSOCKET socket = pdoExtension->Socket;
  298. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  299. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x --> WaitWakeCancelRoutine\n", Pdo, Irp));
  300. IoReleaseCancelSpinLock(Irp->CancelIrql);
  301. if (pdoExtension->WaitWakeIrp == NULL) {
  302. //
  303. // Wait wake already completed/cancelled
  304. //
  305. return;
  306. }
  307. pdoExtension->Flags &= ~PCMCIA_DEVICE_WAKE_PENDING;
  308. pdoExtension->WaitWakeIrp = NULL;
  309. //
  310. // Reset ring enable, disabling wake..
  311. //
  312. (*socket->SocketFnPtr->PCBEnableDisableWakeupEvent)(socket, pdoExtension, FALSE);
  313. //
  314. // Since this is cancelled, see if parent's wait wake
  315. // needs to be cancelled too.
  316. // First, decrement the number of child waiters..
  317. //
  318. ASSERT (fdoExtension->ChildWaitWakeCount > 0);
  319. if (InterlockedDecrement(&fdoExtension->ChildWaitWakeCount) == 0) {
  320. //
  321. // No more waiters.. cancel the parent's wake IRP
  322. //
  323. ASSERT(fdoExtension->WaitWakeIrp);
  324. if (fdoExtension->WaitWakeIrp) {
  325. IoCancelIrp(fdoExtension->WaitWakeIrp);
  326. }
  327. }
  328. InterlockedDecrement(&pdoExtension->DeletionLock);
  329. //
  330. // Complete the IRP
  331. //
  332. Irp->IoStatus.Information = 0;
  333. //
  334. // Is this necessary?
  335. //
  336. PoStartNextPowerIrp(Irp);
  337. Irp->IoStatus.Status = STATUS_CANCELLED;
  338. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  339. }
  340. NTSTATUS
  341. PcmciaSetPdoPowerState(
  342. IN PDEVICE_OBJECT Pdo,
  343. IN OUT PIRP Irp
  344. )
  345. /*++
  346. Routine Description
  347. Dispatches the IRP based on whether a system power state
  348. or device power state transition is requested
  349. Arguments
  350. Pdo - Pointer to the physical device object for the pc-card
  351. Irp - Pointer to the Irp for the power dispatch
  352. Return value
  353. status
  354. --*/
  355. {
  356. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  357. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  358. PSOCKET socket = pdoExtension->Socket;
  359. PFDO_EXTENSION fdoExtension=socket->DeviceExtension;
  360. NTSTATUS status;
  361. PCMCIA_ACQUIRE_DEVICE_LOCK(fdoExtension);
  362. //
  363. // Don't handle any power requests for dead pdos
  364. //
  365. if (IsSocketFlagSet(socket, SOCKET_CARD_STATUS_CHANGE)) {
  366. PCMCIA_RELEASE_DEVICE_LOCK(fdoExtension);
  367. //
  368. // Card probably removed..
  369. //
  370. InterlockedDecrement(&pdoExtension->DeletionLock);
  371. status = STATUS_NO_SUCH_DEVICE;
  372. Irp->IoStatus.Status = status;
  373. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x comp %08x\n", Pdo, Irp, status));
  374. PoStartNextPowerIrp(Irp);
  375. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  376. return status;
  377. }
  378. PCMCIA_RELEASE_DEVICE_LOCK(fdoExtension);
  379. switch (irpStack->Parameters.Power.Type) {
  380. case DevicePowerState:
  381. PCMCIA_ACQUIRE_DEVICE_LOCK(fdoExtension);
  382. if (fdoExtension->DevicePowerState != PowerDeviceD0) {
  383. IoMarkIrpPending(Irp);
  384. status = STATUS_PENDING;
  385. InsertTailList(&fdoExtension->PdoPowerRetryList,
  386. (PLIST_ENTRY) Irp->Tail.Overlay.DriverContext);
  387. PCMCIA_RELEASE_DEVICE_LOCK(fdoExtension);
  388. } else {
  389. PCMCIA_RELEASE_DEVICE_LOCK(fdoExtension);
  390. status = PcmciaSetPdoDevicePowerState(Pdo, Irp);
  391. }
  392. break;
  393. case SystemPowerState:
  394. status = PcmciaSetPdoSystemPowerState(Pdo, Irp);
  395. break;
  396. default:
  397. status = PcmciaPdoCompletePowerIrp(pdoExtension, Irp, Irp->IoStatus.Status);
  398. }
  399. return status;
  400. }
  401. NTSTATUS
  402. PcmciaSetPdoDevicePowerState(
  403. IN PDEVICE_OBJECT Pdo,
  404. IN OUT PIRP Irp
  405. )
  406. /*++
  407. Routine Description
  408. Handles the device power state transition for the given pc-card.
  409. If the state corresponds to a power-up, the parent for this pc-card
  410. is requested to be powered up first. Similarily if this is a power-down
  411. the parent is notified so that it may power down if all the children
  412. are powered down.
  413. Arguments
  414. Pdo - Pointer to the physical device object for the pc-card
  415. Irp - Irp for the system state transition
  416. Return value
  417. status
  418. --*/
  419. {
  420. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  421. PSOCKET socket = pdoExtension->Socket;
  422. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  423. DEVICE_POWER_STATE newDevicePowerState;
  424. NTSTATUS status;
  425. BOOLEAN setPowerRequest;
  426. newDevicePowerState = irpStack->Parameters.Power.State.DeviceState;
  427. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x transitioning D state %d => %d\n",
  428. Pdo, pdoExtension->DevicePowerState, newDevicePowerState));
  429. setPowerRequest = FALSE;
  430. if (newDevicePowerState == PowerDeviceD0 ||
  431. newDevicePowerState == PowerDeviceD1 ||
  432. newDevicePowerState == PowerDeviceD2) {
  433. if (pdoExtension->DevicePowerState == PowerDeviceD3) {
  434. // D3 --> D0, D1 or D2 .. Wake up
  435. setPowerRequest = TRUE;
  436. SetDeviceFlag(pdoExtension, PCMCIA_POWER_WORKER_POWERUP);
  437. } else {
  438. //
  439. // Nothing to do here...
  440. //
  441. }
  442. } else { /* newDevicePowerState == D3 */
  443. if (pdoExtension->DevicePowerState != PowerDeviceD3) {
  444. //
  445. // We need to power down now.
  446. //
  447. setPowerRequest=TRUE;
  448. ResetDeviceFlag(pdoExtension, PCMCIA_POWER_WORKER_POWERUP);
  449. }
  450. }
  451. if (setPowerRequest) {
  452. if (pdoExtension->DevicePowerState == PowerDeviceD0) {
  453. //
  454. // Getting out of D0 - Call PoSetPowerState first
  455. //
  456. POWER_STATE newPowerState;
  457. newPowerState.DeviceState = newDevicePowerState;
  458. PoSetPowerState(Pdo,
  459. DevicePowerState,
  460. newPowerState);
  461. }
  462. ASSERT(pdoExtension->PowerWorkerState == PPW_Stopped);
  463. pdoExtension->PowerWorkerState = PPW_InitialState;
  464. pdoExtension->PendingPowerIrp = Irp;
  465. status = PcmciaPdoPowerWorker(pdoExtension, STATUS_SUCCESS);
  466. } else {
  467. status = PcmciaPdoCompletePowerIrp(pdoExtension, Irp, STATUS_SUCCESS);
  468. }
  469. return status;
  470. }
  471. NTSTATUS
  472. PcmciaPdoPowerWorker(
  473. IN PVOID Context,
  474. IN NTSTATUS status
  475. )
  476. /*++
  477. Routine Description
  478. State machine for executing the requested DevicePowerState change.
  479. Arguments
  480. Context - pdoExtension for the device
  481. DeferredStatus - status from last deferred operation
  482. Return Value
  483. status
  484. --*/
  485. {
  486. PPDO_EXTENSION pdoExtension = Context;
  487. PSOCKET socket = pdoExtension->Socket;
  488. PIRP Irp;
  489. UCHAR CurrentState = pdoExtension->PowerWorkerState;
  490. ULONG DelayTime = 0;
  491. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x power worker - %s\n", pdoExtension->DeviceObject,
  492. PDO_POWER_WORKER_STRING(CurrentState)));
  493. MoveToNextPdoPowerWorkerState(pdoExtension);
  494. if (!NT_SUCCESS(status)) {
  495. //
  496. // An error occurred previously. Skip to the end of the sequence
  497. //
  498. while((CurrentState != PPW_Exit) && (CurrentState != PPW_Stopped)) {
  499. CurrentState = pdoExtension->PowerWorkerState;
  500. MoveToNextPdoPowerWorkerState(pdoExtension);
  501. }
  502. }
  503. switch(CurrentState) {
  504. case PPW_InitialState:
  505. status = STATUS_SUCCESS;
  506. break;
  507. case PPW_PowerUp:
  508. status = PcmciaRequestSocketPower(pdoExtension, PcmciaPdoPowerWorker);
  509. break;
  510. case PPW_PowerUpComplete:
  511. if (!NT_SUCCESS(status)) {
  512. PcmciaReleaseSocketPower(pdoExtension, NULL);
  513. }
  514. break;
  515. case PPW_PowerDown:
  516. status = PcmciaReleaseSocketPower(pdoExtension, PcmciaPdoPowerWorker);
  517. break;
  518. case PPW_CardBusRefresh:
  519. //
  520. // Make sure the cardbus card is really working
  521. //
  522. status = PcmciaConfigureCardBusCard(pdoExtension);
  523. if (NT_SUCCESS(status) && pdoExtension->WaitWakeIrp) {
  524. //
  525. // Make sure stuff like PME_EN is on
  526. //
  527. (*socket->SocketFnPtr->PCBEnableDisableWakeupEvent)(socket, pdoExtension, TRUE);
  528. }
  529. break;
  530. case PPW_SendIrpDown:
  531. //
  532. // We're going to send the IRP down. Set completion routine
  533. // and copy the stack
  534. //
  535. if ((Irp=pdoExtension->PendingPowerIrp)!=NULL) {
  536. IoMarkIrpPending(Irp);
  537. IoCopyCurrentIrpStackLocationToNext(Irp);
  538. IoSetCompletionRoutine(Irp,
  539. PcmciaPdoPowerSentIrpComplete,
  540. pdoExtension,
  541. TRUE, TRUE, TRUE);
  542. status = PoCallDriver(pdoExtension->LowerDevice, Irp);
  543. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x sent irp returns %08x\n", pdoExtension->DeviceObject, Irp, status));
  544. ASSERT(NT_SUCCESS(status));
  545. status = STATUS_PENDING;
  546. }
  547. break;
  548. case PPW_CardBusDelay:
  549. //
  550. // Make sure the cardbus card is really working
  551. //
  552. {
  553. UCHAR BaseClass;
  554. GetPciConfigSpace(pdoExtension, CFGSPACE_CLASSCODE_BASECLASS, &BaseClass, 1)
  555. if (BaseClass == PCI_CLASS_SIMPLE_COMMS_CTLR) {
  556. //
  557. // Wait for modem to warm up
  558. //
  559. DelayTime = CBModemReadyDelay;
  560. }
  561. }
  562. break;
  563. case PPW_16BitConfigure:
  564. if (IsDeviceStarted(pdoExtension)) {
  565. status = PcmciaConfigurePcCard(pdoExtension, PcmciaPdoPowerWorker);
  566. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x 16bit configure returns %08x\n", pdoExtension->DeviceObject, status));
  567. }
  568. break;
  569. case PPW_Exit:
  570. if ((Irp=pdoExtension->PendingPowerIrp)!=NULL) {
  571. //
  572. // This is the IRP (for the pdo) that originally caused us to power up the parent
  573. // Complete it now
  574. //
  575. if (NT_SUCCESS(status)) {
  576. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  577. BOOLEAN callPoSetPowerState;
  578. callPoSetPowerState = TRUE;
  579. Irp->IoStatus.Information = irpStack->Parameters.Power.State.DeviceState;
  580. if (irpStack->Parameters.Power.Type == DevicePowerState) {
  581. if (pdoExtension->DevicePowerState == PowerDeviceD0) {
  582. //
  583. // PoSetPowerState is called before we power down
  584. //
  585. callPoSetPowerState = FALSE;
  586. }
  587. if (pdoExtension->DevicePowerState != irpStack->Parameters.Power.State.DeviceState) {
  588. DebugPrint ((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x transition D state complete: %d => %d\n",
  589. pdoExtension->DeviceObject, Irp, pdoExtension->DevicePowerState, irpStack->Parameters.Power.State.DeviceState));
  590. pdoExtension->DevicePowerState = (SYSTEM_POWER_STATE)Irp->IoStatus.Information;
  591. }
  592. }
  593. if (callPoSetPowerState) {
  594. //
  595. // we didn't get out of device D0 state. calling PoSetPowerState now
  596. //
  597. PoSetPowerState (
  598. pdoExtension->DeviceObject,
  599. irpStack->Parameters.Power.Type,
  600. irpStack->Parameters.Power.State
  601. );
  602. }
  603. } else {
  604. DebugPrint ((PCMCIA_DEBUG_FAIL,"PDO Ext 0x%x failed power Irp 0x%x. status = 0x%x\n", pdoExtension, Irp, status));
  605. if (status == STATUS_NO_SUCH_DEVICE) {
  606. PFDO_EXTENSION fdoExtension=socket->DeviceExtension;
  607. SetSocketFlag(socket, SOCKET_CARD_STATUS_CHANGE);
  608. IoInvalidateDeviceRelations(fdoExtension->Pdo, BusRelations);
  609. }
  610. }
  611. //
  612. // Finally, complete the irp
  613. //
  614. pdoExtension->PendingPowerIrp = NULL;
  615. Irp->IoStatus.Status = status;
  616. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x comp %08x\n", pdoExtension->DeviceObject, Irp, Irp->IoStatus.Status));
  617. InterlockedDecrement(&pdoExtension->DeletionLock);
  618. PoStartNextPowerIrp (Irp);
  619. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  620. }
  621. break;
  622. case PPW_Stopped:
  623. return status;
  624. default:
  625. ASSERT(FALSE);
  626. }
  627. if (status == STATUS_PENDING) {
  628. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x power worker exit %08x\n", pdoExtension->DeviceObject, status));
  629. //
  630. // Current action calls us back
  631. //
  632. if ((Irp=pdoExtension->PendingPowerIrp)!=NULL) {
  633. IoMarkIrpPending(Irp);
  634. }
  635. return status;
  636. }
  637. //
  638. // Not done yet. Recurse or call timer
  639. //
  640. if (DelayTime) {
  641. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x power worker delay type %s, %d usec\n", pdoExtension->DeviceObject,
  642. (KeGetCurrentIrql() < DISPATCH_LEVEL) ? "Wait" : "Timer",
  643. DelayTime));
  644. if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
  645. PcmciaWait(DelayTime);
  646. } else {
  647. LARGE_INTEGER dueTime;
  648. //
  649. // Running on a DPC, kick of a kernel timer
  650. //
  651. pdoExtension->PowerWorkerDpcStatus = status;
  652. dueTime.QuadPart = -((LONG) DelayTime*10);
  653. KeSetTimer(&pdoExtension->PowerWorkerTimer, dueTime, &pdoExtension->PowerWorkerDpc);
  654. //
  655. // We will reenter on timer dpc
  656. //
  657. if ((Irp=pdoExtension->PendingPowerIrp)!=NULL) {
  658. IoMarkIrpPending(Irp);
  659. }
  660. return STATUS_PENDING;
  661. }
  662. }
  663. //
  664. // recurse
  665. //
  666. return (PcmciaPdoPowerWorker(pdoExtension, status));
  667. }
  668. NTSTATUS
  669. PcmciaPdoPowerSentIrpComplete(
  670. IN PDEVICE_OBJECT Pdo,
  671. IN PIRP Irp,
  672. IN PVOID Context
  673. )
  674. /*++
  675. Routine Description
  676. This is the completion routine for the device power IRPs sent
  677. by PCMCIA to the underlying PCI PDO for cardbus cards.
  678. All this does currently is return STATUS_MORE_PROCESSING_REQUIRED
  679. to indicate that we'll complete the Irp later.
  680. Arguments
  681. Pdo - Pointer to device object for the cardbus card
  682. Irp - Pointer to the IRP
  683. Context - Unreferenced
  684. Return Value
  685. STATUS_MORE_PROCESSING_REQUIRED
  686. --*/
  687. {
  688. PPDO_EXTENSION pdoExtension = Context;
  689. #if !(DBG)
  690. UNREFERENCED_PARAMETER (Pdo);
  691. #endif
  692. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x irp %08x sent irp complete %08x\n", Pdo, Irp, Irp->IoStatus.Status));
  693. pdoExtension->PowerWorkerDpcStatus = Irp->IoStatus.Status;
  694. KeInsertQueueDpc(&pdoExtension->PowerWorkerDpc, NULL, NULL);
  695. return STATUS_MORE_PROCESSING_REQUIRED;
  696. }
  697. VOID
  698. PcmciaPdoPowerWorkerDpc(
  699. IN PKDPC Dpc,
  700. IN PVOID Context,
  701. IN PVOID SystemArgument1,
  702. IN PVOID SystemArgument2
  703. )
  704. /*++
  705. Routine Description
  706. This is the completion routine for socket power requests coming
  707. from the PdoPowerWorker.
  708. Arguments
  709. Return Value
  710. --*/
  711. {
  712. PPDO_EXTENSION pdoExtension = Context;
  713. NTSTATUS status;
  714. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x pdo power worker dpc\n", pdoExtension->DeviceObject));
  715. status = PcmciaPdoPowerWorker(pdoExtension, pdoExtension->PowerWorkerDpcStatus);
  716. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x pdo power worker dpc exit %08x\n", pdoExtension->DeviceObject, status));
  717. }
  718. VOID
  719. MoveToNextPdoPowerWorkerState(
  720. PPDO_EXTENSION pdoExtension
  721. )
  722. /*++
  723. Routine Description
  724. State machine for executing the requested DevicePowerState change.
  725. Arguments
  726. Context - pdoExtension for the device
  727. DeferredStatus - status from last deferred operation
  728. Return Value
  729. status
  730. --*/
  731. {
  732. static UCHAR PowerCardBusUpSequence[] = {PPW_CardBusRefresh,
  733. PPW_SendIrpDown,
  734. PPW_CardBusDelay,
  735. PPW_Exit,
  736. PPW_Stopped};
  737. static UCHAR PowerCardBusDownSequence[] = {PPW_SendIrpDown,
  738. PPW_Exit,
  739. PPW_Stopped};
  740. static UCHAR Power16BitUpSequence[] = {PPW_PowerUp,
  741. PPW_PowerUpComplete,
  742. PPW_16BitConfigure,
  743. PPW_Exit,
  744. PPW_Stopped};
  745. static UCHAR Power16BitDownSequence[] = {PPW_PowerDown,
  746. PPW_Exit,
  747. PPW_Stopped};
  748. if (pdoExtension->PowerWorkerState == PPW_InitialState) {
  749. //
  750. // Initialize sequence and phase
  751. //
  752. pdoExtension->PowerWorkerPhase = 0;
  753. pdoExtension->PowerWorkerSequence =
  754. IsCardBusCard(pdoExtension) ?
  755. (IsDeviceFlagSet(pdoExtension, PCMCIA_POWER_WORKER_POWERUP) ?
  756. PowerCardBusUpSequence : PowerCardBusDownSequence)
  757. :
  758. (IsDeviceFlagSet(pdoExtension, PCMCIA_POWER_WORKER_POWERUP) ?
  759. Power16BitUpSequence : Power16BitDownSequence);
  760. }
  761. //
  762. // The next state is pointed to by the current phase
  763. //
  764. pdoExtension->PowerWorkerState =
  765. pdoExtension->PowerWorkerSequence[ pdoExtension->PowerWorkerPhase ];
  766. //
  767. // Increment the phase, but not past the end of the sequence
  768. //
  769. if (pdoExtension->PowerWorkerState != PPW_Stopped) {
  770. pdoExtension->PowerWorkerPhase++;
  771. }
  772. }
  773. NTSTATUS
  774. PcmciaSetPdoSystemPowerState(
  775. IN PDEVICE_OBJECT Pdo,
  776. IN OUT PIRP Irp
  777. )
  778. /*++
  779. Routine Description
  780. Handles the system power state transition for the given pc-card.
  781. Arguments
  782. Pdo - Pointer to the physical device object for the pc-card
  783. Irp - Irp for the system state transition
  784. Return value
  785. status
  786. --*/
  787. {
  788. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  789. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  790. SYSTEM_POWER_STATE systemPowerState;
  791. systemPowerState = irpStack->Parameters.Power.State.SystemState;
  792. DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x transitioning S state %d => %d\n",
  793. Pdo, pdoExtension->SystemPowerState, systemPowerState));
  794. pdoExtension->SystemPowerState = systemPowerState;
  795. //
  796. // We are done.
  797. //
  798. return PcmciaPdoCompletePowerIrp(pdoExtension, Irp, STATUS_SUCCESS);
  799. }
  800. NTSTATUS
  801. PcmciaPdoCompletePowerIrp(
  802. IN PPDO_EXTENSION pdoExtension,
  803. IN PIRP Irp,
  804. IN NTSTATUS status
  805. )
  806. /*++
  807. Routine Description
  808. Completion routine for the Power Irp directed to the PDO of the
  809. pc-card.
  810. Arguments
  811. DeviceObject - Pointer to the PDO for the pc-card
  812. Irp - Irp that needs to be completed
  813. Return Value
  814. None
  815. --*/
  816. {
  817. if (IsCardBusCard(pdoExtension)) {
  818. //
  819. // Pass irp down the stack
  820. //
  821. InterlockedDecrement(&pdoExtension->DeletionLock);
  822. PoStartNextPowerIrp(Irp);
  823. IoSkipCurrentIrpStackLocation(Irp);
  824. status = PoCallDriver(pdoExtension->LowerDevice, Irp);
  825. } else {
  826. //
  827. // Complete the irp for R2 cards
  828. //
  829. InterlockedDecrement(&pdoExtension->DeletionLock);
  830. Irp->IoStatus.Status = status;
  831. PoStartNextPowerIrp(Irp);
  832. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  833. }
  834. return status;
  835. }