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.

694 lines
18 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. wake.c
  5. Abstract:
  6. This module contains code to handle
  7. IRP_MJ_POWER dispatches for SD controllers
  8. Authors:
  9. Neil Sandlin (neilsa) Jan 1, 2002
  10. Environment:
  11. Kernel mode only
  12. Notes:
  13. Revision History:
  14. --*/
  15. #include "pch.h"
  16. //
  17. // Internal References
  18. //
  19. NTSTATUS
  20. SdbusFdoWaitWakeIoCompletion(
  21. IN PDEVICE_OBJECT Fdo,
  22. IN PIRP Irp,
  23. IN PVOID Context
  24. );
  25. VOID
  26. SdbusPdoWaitWakeCancelRoutine(
  27. IN PDEVICE_OBJECT Pdo,
  28. IN OUT PIRP Irp
  29. );
  30. /**************************************************************************
  31. FDO ROUTINES
  32. **************************************************************************/
  33. NTSTATUS
  34. SdbusFdoWaitWake(
  35. IN PDEVICE_OBJECT Fdo,
  36. IN PIRP Irp
  37. )
  38. /*++
  39. Routine Description
  40. Handles WAIT_WAKE for the given sd controller
  41. Arguments
  42. Pdo - Pointer to the functional device object for the sd controller
  43. Irp - The IRP_MN_WAIT_WAKE Irp
  44. Return Value
  45. STATUS_PENDING - Wait wake is pending
  46. STATUS_SUCCESS - Wake is already asserted, wait wake IRP is completed
  47. in this case
  48. Any other status - Error
  49. --*/
  50. {
  51. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  52. WAKESTATE oldWakeState;
  53. //
  54. // Record the wait wake Irp..
  55. //
  56. fdoExtension->WaitWakeIrp = Irp;
  57. oldWakeState = InterlockedCompareExchange(&fdoExtension->WaitWakeState,
  58. WAKESTATE_ARMED, WAKESTATE_WAITING);
  59. DebugPrint((SDBUS_DEBUG_POWER, "fdo %x irp %x WaitWake: prevState %s\n",
  60. Fdo, Irp, WAKESTATE_STRING(oldWakeState)));
  61. if (oldWakeState == WAKESTATE_WAITING_CANCELLED) {
  62. fdoExtension->WaitWakeState = WAKESTATE_COMPLETING;
  63. Irp->IoStatus.Status = STATUS_CANCELLED;
  64. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  65. return STATUS_CANCELLED;
  66. }
  67. IoMarkIrpPending(Irp);
  68. IoCopyCurrentIrpStackLocationToNext (Irp);
  69. //
  70. // Set our completion routine in the Irp..
  71. //
  72. IoSetCompletionRoutine(Irp,
  73. SdbusFdoWaitWakeIoCompletion,
  74. Fdo,
  75. TRUE,
  76. TRUE,
  77. TRUE);
  78. //
  79. // now pass this down to the lower driver..
  80. //
  81. PoCallDriver(fdoExtension->LowerDevice, Irp);
  82. return STATUS_PENDING;
  83. }
  84. NTSTATUS
  85. SdbusFdoWaitWakeIoCompletion(
  86. IN PDEVICE_OBJECT Fdo,
  87. IN PIRP Irp,
  88. IN PVOID Context
  89. )
  90. /*++
  91. Routine Description:
  92. Completion routine for the IRP_MN_WAIT_WAKE request for this
  93. sd controller. This is called when the WAIT_WAKE IRP is
  94. completed by the lower driver (PCI/ACPI) indicating either that
  95. 1. SD bus controller asserted wake
  96. 2. WAIT_WAKE was cancelled
  97. 3. Lower driver returned an error for some reason
  98. Arguments:
  99. Fdo - Pointer to Functional device object for the sd controller
  100. Irp - Pointer to the IRP for the power request (IRP_MN_WAIT_WAKE)
  101. Context - Not used
  102. Return Value:
  103. STATUS_SUCCESS - WAIT_WAKE was completed with success
  104. Any other status - Wake could be not be accomplished.
  105. --*/
  106. {
  107. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  108. PPDO_EXTENSION pdoExtension;
  109. PDEVICE_OBJECT pdo;
  110. WAKESTATE oldWakeState;
  111. UNREFERENCED_PARAMETER(Context);
  112. oldWakeState = InterlockedExchange(&fdoExtension->WaitWakeState, WAKESTATE_COMPLETING);
  113. DebugPrint((SDBUS_DEBUG_POWER, "fdo %x irp %x WW IoComp: prev=%s\n",
  114. Fdo, Irp, WAKESTATE_STRING(oldWakeState)));
  115. if (oldWakeState != WAKESTATE_ARMED) {
  116. ASSERT(oldWakeState == WAKESTATE_ARMING_CANCELLED);
  117. return STATUS_MORE_PROCESSING_REQUIRED;
  118. }
  119. if (IsDeviceFlagSet(fdoExtension, SDBUS_FDO_WAKE_BY_CD)) {
  120. POWER_STATE powerState;
  121. ResetDeviceFlag(fdoExtension, SDBUS_FDO_WAKE_BY_CD);
  122. PoStartNextPowerIrp(Irp);
  123. powerState.DeviceState = PowerDeviceD0;
  124. PoRequestPowerIrp(fdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, NULL, NULL, NULL);
  125. } else {
  126. // NOTE:
  127. // At this point we do NOT know how to distinguish which function
  128. // in a multifunction device has asserted wake.
  129. // So we go through the entire list of PDOs hanging off this FDO
  130. // and complete all the outstanding WAIT_WAKE Irps for every PDO that
  131. // that's waiting. We leave it up to the FDO for the device to figure
  132. // if it asserted wake
  133. //
  134. for (pdo = fdoExtension->PdoList; pdo != NULL ; pdo = pdoExtension->NextPdoInFdoChain) {
  135. pdoExtension = pdo->DeviceExtension;
  136. if (IsDeviceLogicallyRemoved(pdoExtension) ||
  137. IsDevicePhysicallyRemoved(pdoExtension)) {
  138. //
  139. // This pdo is about to be removed ..
  140. // skip it
  141. //
  142. continue;
  143. }
  144. if (pdoExtension->WaitWakeIrp != NULL) {
  145. PIRP finishedIrp;
  146. //
  147. // Ah.. this is a possible candidate to have asserted the wake
  148. //
  149. //
  150. // Make sure this IRP will not be completed again or cancelled
  151. //
  152. finishedIrp = pdoExtension->WaitWakeIrp;
  153. DebugPrint((SDBUS_DEBUG_POWER, "fdo %x WW IoComp: irp %08x for pdo %08x\n",
  154. Fdo, finishedIrp, pdo));
  155. IoSetCancelRoutine(finishedIrp, NULL);
  156. //
  157. // Propagate parent's status to child
  158. //
  159. PoStartNextPowerIrp(finishedIrp);
  160. finishedIrp->IoStatus.Status = Irp->IoStatus.Status;
  161. //
  162. // Since we didn't pass this IRP down, call our own completion routine
  163. //
  164. // SdbusPdoWaitWakeCompletion(pdo, finishedIrp, pdoExtension);
  165. IoCompleteRequest(finishedIrp, IO_NO_INCREMENT);
  166. }
  167. }
  168. PoStartNextPowerIrp(Irp);
  169. }
  170. return Irp->IoStatus.Status;
  171. }
  172. VOID
  173. SdbusFdoWaitWakePoCompletion(
  174. IN PDEVICE_OBJECT Fdo,
  175. IN UCHAR MinorFunction,
  176. IN POWER_STATE PowerState,
  177. IN PVOID Context,
  178. IN PIO_STATUS_BLOCK IoStatus
  179. )
  180. /*++
  181. Routine Description
  182. This routine is called on completion of a D irp generated by an S irp.
  183. Parameters
  184. DeviceObject - Pointer to the Fdo for the SDBUS controller
  185. MinorFunction - Minor function of the IRP_MJ_POWER request
  186. PowerState - Power state requested
  187. Context - Context passed in to the completion routine
  188. IoStatus - Pointer to the status block which will contain
  189. the returned status
  190. Return Value
  191. Status
  192. --*/
  193. {
  194. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  195. DebugPrint((SDBUS_DEBUG_POWER, "fdo %x irp %x WaitWakePoCompletion: prevState %s\n",
  196. Fdo, fdoExtension->WaitWakeIrp,
  197. WAKESTATE_STRING(fdoExtension->WaitWakeState)));
  198. ASSERT (fdoExtension->WaitWakeIrp);
  199. fdoExtension->WaitWakeIrp = NULL;
  200. ASSERT (fdoExtension->WaitWakeState == WAKESTATE_COMPLETING);
  201. fdoExtension->WaitWakeState = WAKESTATE_DISARMED;
  202. }
  203. NTSTATUS
  204. SdbusFdoArmForWake(
  205. PFDO_EXTENSION FdoExtension
  206. )
  207. /*++
  208. Routine Description:
  209. This routine is called to enable the controller for wake. It is called by the Pdo
  210. wake routines when a wake-enabled controller gets a wait-wake irp, and also by
  211. the idle routine to arm for wake from D3 by card insertion.
  212. Arguments:
  213. FdoExtension - device extension of the controller
  214. Return Value:
  215. status
  216. --*/
  217. {
  218. NTSTATUS status = STATUS_PENDING;
  219. PIO_STACK_LOCATION irpStack;
  220. PIRP irp;
  221. LONG oldWakeState;
  222. POWER_STATE powerState;
  223. oldWakeState = InterlockedCompareExchange(&FdoExtension->WaitWakeState,
  224. WAKESTATE_WAITING, WAKESTATE_DISARMED);
  225. DebugPrint((SDBUS_DEBUG_POWER, "fdo %x ArmForWake: prevState %s\n",
  226. FdoExtension->DeviceObject, WAKESTATE_STRING(oldWakeState)));
  227. if ((oldWakeState == WAKESTATE_ARMED) || (oldWakeState == WAKESTATE_WAITING)) {
  228. return STATUS_SUCCESS;
  229. }
  230. if (oldWakeState != WAKESTATE_DISARMED) {
  231. return STATUS_UNSUCCESSFUL;
  232. }
  233. powerState.SystemState = FdoExtension->DeviceCapabilities.SystemWake;
  234. status = PoRequestPowerIrp(FdoExtension->DeviceObject,
  235. IRP_MN_WAIT_WAKE,
  236. powerState,
  237. SdbusFdoWaitWakePoCompletion,
  238. NULL,
  239. NULL);
  240. if (!NT_SUCCESS(status)) {
  241. FdoExtension->WaitWakeState = WAKESTATE_DISARMED;
  242. DebugPrint((SDBUS_DEBUG_POWER, "WaitWake to FDO, expecting STATUS_PENDING, got %08X\n", status));
  243. }
  244. return status;
  245. }
  246. NTSTATUS
  247. SdbusFdoDisarmWake(
  248. PFDO_EXTENSION FdoExtension
  249. )
  250. /*++
  251. Routine Description:
  252. This routine is called to disable the controller for wake.
  253. Arguments:
  254. FdoExtension - device extension of the controller
  255. Return Value:
  256. status
  257. --*/
  258. {
  259. WAKESTATE oldWakeState;
  260. oldWakeState = InterlockedCompareExchange(&FdoExtension->WaitWakeState,
  261. WAKESTATE_WAITING_CANCELLED, WAKESTATE_WAITING);
  262. DebugPrint((SDBUS_DEBUG_POWER, "fdo %x DisarmWake: prevState %s\n",
  263. FdoExtension->DeviceObject, WAKESTATE_STRING(oldWakeState)));
  264. if (oldWakeState != WAKESTATE_WAITING) {
  265. oldWakeState = InterlockedCompareExchange(&FdoExtension->WaitWakeState,
  266. WAKESTATE_ARMING_CANCELLED, WAKESTATE_ARMED);
  267. if (oldWakeState != WAKESTATE_ARMED) {
  268. return STATUS_UNSUCCESSFUL;
  269. }
  270. }
  271. if (oldWakeState == WAKESTATE_ARMED) {
  272. IoCancelIrp(FdoExtension->WaitWakeIrp);
  273. //
  274. // Now that we've cancelled the IRP, try to give back ownership
  275. // to the completion routine by restoring the WAKESTATE_ARMED state
  276. //
  277. oldWakeState = InterlockedCompareExchange(&FdoExtension->WaitWakeState,
  278. WAKESTATE_ARMED, WAKESTATE_ARMING_CANCELLED);
  279. if (oldWakeState == WAKESTATE_COMPLETING) {
  280. //
  281. // We didn't give control back of the IRP in time, we we own it now
  282. //
  283. IoCompleteRequest(FdoExtension->WaitWakeIrp, IO_NO_INCREMENT);
  284. }
  285. }
  286. return STATUS_SUCCESS;
  287. }
  288. NTSTATUS
  289. SdbusFdoCheckForIdle(
  290. IN PFDO_EXTENSION FdoExtension
  291. )
  292. {
  293. POWER_STATE powerState;
  294. NTSTATUS status;
  295. //
  296. // Make sure all sockets are empty
  297. //
  298. #if 0
  299. for (socket = FdoExtension->SocketList; socket != NULL; socket = socket->NextSocket) {
  300. if (IsCardInSocket(socket)) {
  301. return STATUS_UNSUCCESSFUL;
  302. }
  303. }
  304. #endif
  305. //
  306. // Arm for wakeup
  307. //
  308. status = SdbusFdoArmForWake(FdoExtension);
  309. if (!NT_SUCCESS(status)) {
  310. return status;
  311. }
  312. SetDeviceFlag(FdoExtension, SDBUS_FDO_WAKE_BY_CD);
  313. powerState.DeviceState = PowerDeviceD3;
  314. PoRequestPowerIrp(FdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, NULL, NULL, NULL);
  315. return STATUS_SUCCESS;
  316. }
  317. /**************************************************************************
  318. PDO ROUTINES
  319. **************************************************************************/
  320. NTSTATUS
  321. SdbusPdoWaitWake(
  322. IN PDEVICE_OBJECT Pdo,
  323. IN PIRP Irp,
  324. OUT BOOLEAN *CompleteIrp
  325. )
  326. /*++
  327. Routine Description
  328. Handles WAIT_WAKE for the given pc-card.
  329. Arguments
  330. Pdo - Pointer to the device object for the pc-card
  331. Irp - The IRP_MN_WAIT_WAKE Irp
  332. CompleteIrp - This routine will set this to TRUE if the IRP should be
  333. completed after this is called and FALSE if it should not be
  334. touched
  335. Return Value
  336. STATUS_PENDING - Wait wake is pending
  337. STATUS_SUCCESS - Wake is already asserted, wait wake IRP is completed
  338. in this case
  339. Any other status - Error
  340. --*/
  341. {
  342. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  343. PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension;
  344. NTSTATUS status;
  345. *CompleteIrp = FALSE;
  346. if ((pdoExtension->DeviceCapabilities.DeviceWake == PowerDeviceUnspecified) ||
  347. (pdoExtension->DeviceCapabilities.DeviceWake < pdoExtension->DevicePowerState)) {
  348. //
  349. // Either we don't support wake at all OR the current device power state
  350. // of the PC-Card doesn't support wake
  351. //
  352. return STATUS_INVALID_DEVICE_STATE;
  353. }
  354. if (pdoExtension->Flags & SDBUS_DEVICE_WAKE_PENDING) {
  355. //
  356. // A WAKE is already pending
  357. //
  358. return STATUS_DEVICE_BUSY;
  359. }
  360. status = SdbusFdoArmForWake(fdoExtension);
  361. if (!NT_SUCCESS(status)) {
  362. return status;
  363. }
  364. //for the time being, expect STATUS_PENDING from FdoArmForWake
  365. ASSERT(status == STATUS_PENDING);
  366. //
  367. // Parent has one (more) waiter..
  368. //
  369. InterlockedIncrement(&fdoExtension->ChildWaitWakeCount);
  370. //for testing, make sure there is only one waiter
  371. ASSERT (fdoExtension->ChildWaitWakeCount == 1);
  372. pdoExtension->WaitWakeIrp = Irp;
  373. pdoExtension->Flags |= SDBUS_DEVICE_WAKE_PENDING;
  374. //
  375. // Set Ring enable/cstschg for the card here..
  376. //
  377. // (*socket->SocketFnPtr->PCBEnableDisableWakeupEvent)(socket, pdoExtension, TRUE);
  378. //
  379. // PCI currently does not do anything with a WW irp for a cardbus PDO. So we hack around
  380. // this here by not passing the irp down. Instead it is held pending here, so we can
  381. // set a cancel routine just like the read PDO driver would. If PCI were to do something
  382. // with the irp, we could code something like the following:
  383. //
  384. // if (IsCardBusCard(pdoExtension)) {
  385. // IoSetCompletionRoutine(Irp, SdbusPdoWaitWakeCompletion, pdoExtension,TRUE,TRUE,TRUE);
  386. // IoCopyCurrentIrpStackLocationToNext(Irp);
  387. // status = IoCallDriver (pdoExtension->LowerDevice, Irp);
  388. // ASSERT (status == STATUS_PENDING);
  389. // return status;
  390. // }
  391. IoMarkIrpPending(Irp);
  392. //
  393. // Allow IRP to be cancelled..
  394. //
  395. IoSetCancelRoutine(Irp, SdbusPdoWaitWakeCancelRoutine);
  396. IoSetCompletionRoutine(Irp,
  397. SdbusPdoWaitWakeCompletion,
  398. pdoExtension,
  399. TRUE,
  400. TRUE,
  401. TRUE);
  402. return STATUS_PENDING;
  403. }
  404. NTSTATUS
  405. SdbusPdoWaitWakeCompletion(
  406. IN PDEVICE_OBJECT Pdo,
  407. IN PIRP Irp,
  408. IN PPDO_EXTENSION PdoExtension
  409. )
  410. /*++
  411. Routine Description
  412. Completion routine called when a pending IRP_MN_WAIT_WAKE Irp completes
  413. Arguments
  414. Pdo - Pointer to the physical device object for the pc-card
  415. Irp - Pointer to the wait wake IRP
  416. PdoExtension - Pointer to the device extension for the Pdo
  417. Return Value
  418. Status from the IRP
  419. --*/
  420. {
  421. PFDO_EXTENSION fdoExtension = PdoExtension->FdoExtension;
  422. DebugPrint((SDBUS_DEBUG_POWER, "pdo %08x irp %08x --> WaitWakeCompletion\n", Pdo, Irp));
  423. ASSERT (PdoExtension->Flags & SDBUS_DEVICE_WAKE_PENDING);
  424. PdoExtension->Flags &= ~SDBUS_DEVICE_WAKE_PENDING;
  425. PdoExtension->WaitWakeIrp = NULL;
  426. //
  427. // Reset ring enable/cstschg
  428. //
  429. // (*socket->SocketFnPtr->PCBEnableDisableWakeupEvent)(socket, PdoExtension, FALSE);
  430. ASSERT (fdoExtension->ChildWaitWakeCount > 0);
  431. InterlockedDecrement(&fdoExtension->ChildWaitWakeCount);
  432. //
  433. // Wake completed
  434. //
  435. InterlockedDecrement(&PdoExtension->DeletionLock);
  436. return Irp->IoStatus.Status;
  437. }
  438. VOID
  439. SdbusPdoWaitWakeCancelRoutine(
  440. IN PDEVICE_OBJECT Pdo,
  441. IN OUT PIRP Irp
  442. )
  443. /*++
  444. Routine Description:
  445. Cancel an outstanding (pending) WAIT_WAKE Irp.
  446. Note: The CancelSpinLock is held on entry
  447. Arguments:
  448. Pdo - Pointer to the physical device object for the pc-card
  449. on which the WAKE is pending
  450. Irp - Pointer to the WAIT_WAKE Irp to be cancelled
  451. Return Value
  452. None
  453. --*/
  454. {
  455. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  456. PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension;
  457. DebugPrint((SDBUS_DEBUG_POWER, "pdo %08x irp %08x --> WaitWakeCancelRoutine\n", Pdo, Irp));
  458. IoReleaseCancelSpinLock(Irp->CancelIrql);
  459. if (pdoExtension->WaitWakeIrp == NULL) {
  460. //
  461. // Wait wake already completed/cancelled
  462. //
  463. return;
  464. }
  465. pdoExtension->Flags &= ~SDBUS_DEVICE_WAKE_PENDING;
  466. pdoExtension->WaitWakeIrp = NULL;
  467. //
  468. // Reset ring enable, disabling wake..
  469. //
  470. // (*socket->SocketFnPtr->PCBEnableDisableWakeupEvent)(socket, pdoExtension, FALSE);
  471. //
  472. // Since this is cancelled, see if parent's wait wake
  473. // needs to be cancelled too.
  474. // First, decrement the number of child waiters..
  475. //
  476. ASSERT (fdoExtension->ChildWaitWakeCount > 0);
  477. if (InterlockedDecrement(&fdoExtension->ChildWaitWakeCount) == 0) {
  478. //
  479. // No more waiters.. cancel the parent's wake IRP
  480. //
  481. ASSERT(fdoExtension->WaitWakeIrp);
  482. if (fdoExtension->WaitWakeIrp) {
  483. IoCancelIrp(fdoExtension->WaitWakeIrp);
  484. }
  485. }
  486. InterlockedDecrement(&pdoExtension->DeletionLock);
  487. //
  488. // Complete the IRP
  489. //
  490. Irp->IoStatus.Information = 0;
  491. //
  492. // Is this necessary?
  493. //
  494. PoStartNextPowerIrp(Irp);
  495. Irp->IoStatus.Status = STATUS_CANCELLED;
  496. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  497. }