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.

745 lines
19 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. fdopower.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. SdbusFdoSetSystemPowerState(
  21. IN PDEVICE_OBJECT Fdo,
  22. IN OUT PIRP Irp
  23. );
  24. VOID
  25. SdbusFdoSetSystemPowerStateCompletion(
  26. IN PDEVICE_OBJECT Fdo,
  27. IN PVOID Context
  28. );
  29. NTSTATUS
  30. SdbusFdoRequestDevicePowerState(
  31. IN PDEVICE_OBJECT Fdo,
  32. IN DEVICE_POWER_STATE DevicePowerState,
  33. IN PSDBUS_COMPLETION_ROUTINE CompletionRoutine,
  34. IN PVOID Context,
  35. IN BOOLEAN WaitForRequestComplete
  36. );
  37. VOID
  38. SdbusFdoSystemPowerDeviceIrpComplete(
  39. IN PDEVICE_OBJECT Fdo,
  40. IN UCHAR MinorFunction,
  41. IN POWER_STATE PowerState,
  42. IN PVOID Context,
  43. IN PIO_STATUS_BLOCK IoStatus
  44. );
  45. NTSTATUS
  46. SdbusFdoSetDevicePowerState(
  47. IN PDEVICE_OBJECT Fdo,
  48. IN OUT PIRP Irp
  49. );
  50. NTSTATUS
  51. SdbusFdoSetDevicePowerStateCompletion(
  52. IN PDEVICE_OBJECT Fdo,
  53. IN PIRP Irp,
  54. IN PVOID Context
  55. );
  56. VOID
  57. SdbusFdoSetDevicePowerStateActivateComplete(
  58. IN PDEVICE_OBJECT Fdo,
  59. IN PVOID Context,
  60. IN NTSTATUS status
  61. );
  62. NTSTATUS
  63. SdbusSetPdoDevicePowerState(
  64. IN PDEVICE_OBJECT Pdo,
  65. IN OUT PIRP Irp
  66. );
  67. VOID
  68. SdbusPdoInitializeFunctionComplete(
  69. IN PSD_WORK_PACKET WorkPacket,
  70. IN NTSTATUS status
  71. );
  72. NTSTATUS
  73. SdbusPdoCompletePowerIrp(
  74. IN PPDO_EXTENSION pdoExtension,
  75. IN PIRP Irp,
  76. IN NTSTATUS status
  77. );
  78. //************************************************
  79. //
  80. // FDO Routines
  81. //
  82. //************************************************
  83. NTSTATUS
  84. SdbusSetFdoPowerState(
  85. IN PDEVICE_OBJECT Fdo,
  86. IN OUT PIRP Irp
  87. )
  88. /*++
  89. Routine Description
  90. Dispatches the IRP based on whether a system power state
  91. or device power state transition is requested
  92. Arguments
  93. DeviceObject - Pointer to the functional device object for the sd controller
  94. Irp - Pointer to the Irp for the power dispatch
  95. Return value
  96. status
  97. --*/
  98. {
  99. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  100. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  101. NTSTATUS status;
  102. if (irpStack->Parameters.Power.Type == DevicePowerState) {
  103. status = SdbusFdoSetDevicePowerState(Fdo, Irp);
  104. } else if (irpStack->Parameters.Power.Type == SystemPowerState) {
  105. status = SdbusFdoSetSystemPowerState(Fdo, Irp);
  106. } else {
  107. status = Irp->IoStatus.Status;
  108. PoStartNextPowerIrp (Irp);
  109. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  110. }
  111. return status;
  112. }
  113. NTSTATUS
  114. SdbusFdoSetSystemPowerState(
  115. IN PDEVICE_OBJECT Fdo,
  116. IN OUT PIRP Irp
  117. )
  118. /*++
  119. Routine Description
  120. Handles system power state IRPs for the host controller.
  121. Arguments
  122. DeviceObject - Pointer to the functional device object for the sd controller
  123. Irp - Pointer to the Irp for the power dispatch
  124. Return value
  125. status
  126. --*/
  127. {
  128. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  129. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  130. SYSTEM_POWER_STATE newSystemState = irpStack->Parameters.Power.State.SystemState;
  131. DEVICE_POWER_STATE devicePowerState;
  132. NTSTATUS status = STATUS_SUCCESS;
  133. BOOLEAN waitForCompletion = TRUE;
  134. try{
  135. //
  136. // Validate new system state
  137. //
  138. if (newSystemState >= POWER_SYSTEM_MAXIMUM) {
  139. status = STATUS_UNSUCCESSFUL;
  140. leave;
  141. }
  142. //
  143. // Switch to the appropriate device power state
  144. //
  145. devicePowerState = fdoExtension->DeviceCapabilities.DeviceState[newSystemState];
  146. if (devicePowerState == PowerDeviceUnspecified) {
  147. status = STATUS_UNSUCCESSFUL;
  148. leave;
  149. }
  150. //
  151. // Transitioned to system state
  152. //
  153. DebugPrint((SDBUS_DEBUG_POWER, "fdo %08x irp %08x transition S state %d => %d, sending D%d\n",
  154. Fdo, Irp, fdoExtension->SystemPowerState-1, newSystemState-1, devicePowerState-1));
  155. fdoExtension->SystemPowerState = newSystemState;
  156. //
  157. // Don't wait for completion if we are coming out of standby/hibernate
  158. //
  159. waitForCompletion = (newSystemState != PowerSystemWorking);
  160. if (!waitForCompletion) {
  161. IoMarkIrpPending(Irp);
  162. }
  163. status = SdbusFdoRequestDevicePowerState(fdoExtension->DeviceObject,
  164. devicePowerState,
  165. SdbusFdoSetSystemPowerStateCompletion,
  166. Irp,
  167. waitForCompletion);
  168. } finally {
  169. if (!NT_SUCCESS(status)) {
  170. PoStartNextPowerIrp (Irp);
  171. Irp->IoStatus.Status = status;
  172. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  173. }
  174. if (!waitForCompletion && (status != STATUS_PENDING)) {
  175. //
  176. // We've already marked the IRP pending, so we must return STATUS_PENDING
  177. // (ie fail it asynchronously)
  178. //
  179. status = STATUS_PENDING;
  180. }
  181. }
  182. DebugPrint((SDBUS_DEBUG_POWER, "fdo %08x irp %08x <-- %08x\n", Fdo, Irp, status));
  183. return status;
  184. }
  185. VOID
  186. SdbusFdoSetSystemPowerStateCompletion(
  187. IN PDEVICE_OBJECT Fdo,
  188. IN PVOID Context
  189. )
  190. /*++
  191. Routine Description
  192. Handles system power state IRPs for the host controller.
  193. Arguments
  194. DeviceObject - Pointer to the functional device object for the sd controller
  195. Irp - Pointer to the Irp for the power dispatch
  196. Return value
  197. status
  198. --*/
  199. {
  200. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  201. PIRP Irp = Context;
  202. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  203. PoSetPowerState (Fdo, SystemPowerState, irpStack->Parameters.Power.State);
  204. PoStartNextPowerIrp (Irp);
  205. IoSkipCurrentIrpStackLocation(Irp);
  206. PoCallDriver(fdoExtension->LowerDevice, Irp);
  207. }
  208. NTSTATUS
  209. SdbusFdoRequestDevicePowerState(
  210. IN PDEVICE_OBJECT Fdo,
  211. IN DEVICE_POWER_STATE DevicePowerState,
  212. IN PSDBUS_COMPLETION_ROUTINE CompletionRoutine,
  213. IN PVOID Context,
  214. IN BOOLEAN WaitForRequestComplete
  215. )
  216. /*++
  217. Routine Description
  218. This routine is called to request a new device power state for the FDO
  219. Parameters
  220. DeviceObject - Pointer to the Fdo for the SDBUS controller
  221. PowerState - Power state requested
  222. CompletionRoutine - Routine to be called when finished
  223. Context - Context passed in to the completion routine
  224. Return Value
  225. Status
  226. --*/
  227. {
  228. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  229. POWER_STATE powerState;
  230. NTSTATUS status;
  231. powerState.DeviceState = DevicePowerState;
  232. if (!WaitForRequestComplete) {
  233. //
  234. // Call the completion routine immediately
  235. //
  236. (*CompletionRoutine)(Fdo, Context);
  237. //
  238. // Request the device power irp to be completed later
  239. //
  240. PoRequestPowerIrp(fdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, NULL, NULL, NULL);
  241. status = STATUS_SUCCESS;
  242. } else {
  243. PSD_POWER_CONTEXT powerContext;
  244. powerContext = ExAllocatePool(NonPagedPool, sizeof(SD_POWER_CONTEXT));
  245. if (!powerContext) {
  246. return STATUS_INSUFFICIENT_RESOURCES;
  247. }
  248. powerContext->CompletionRoutine = CompletionRoutine;
  249. powerContext->Context = Context;
  250. status = PoRequestPowerIrp(fdoExtension->DeviceObject,
  251. IRP_MN_SET_POWER,
  252. powerState,
  253. SdbusFdoSystemPowerDeviceIrpComplete,
  254. powerContext,
  255. NULL
  256. );
  257. }
  258. return status;
  259. }
  260. VOID
  261. SdbusFdoSystemPowerDeviceIrpComplete(
  262. IN PDEVICE_OBJECT Fdo,
  263. IN UCHAR MinorFunction,
  264. IN POWER_STATE PowerState,
  265. IN PVOID Context,
  266. IN PIO_STATUS_BLOCK IoStatus
  267. )
  268. /*++
  269. Routine Description
  270. This routine is called on completion of a D irp generated by an S irp.
  271. Parameters
  272. DeviceObject - Pointer to the Fdo for the SDBUS controller
  273. MinorFunction - Minor function of the IRP_MJ_POWER request
  274. PowerState - Power state requested
  275. Context - Context passed in to the completion routine
  276. IoStatus - Pointer to the status block which will contain
  277. the returned status
  278. Return Value
  279. Status
  280. --*/
  281. {
  282. PSD_POWER_CONTEXT powerContext = Context;
  283. // DebugPrint((SDBUS_DEBUG_POWER, "fdo %08x irp %08x request for D%d complete, passing S irp down\n",
  284. // Fdo, Irp, PowerState.DeviceState-1));
  285. (*powerContext->CompletionRoutine)(Fdo, powerContext->Context);
  286. ExFreePool(powerContext);
  287. }
  288. NTSTATUS
  289. SdbusFdoSetDevicePowerState(
  290. IN PDEVICE_OBJECT Fdo,
  291. IN OUT PIRP Irp
  292. )
  293. /*++
  294. Routine Description
  295. Handles device power state IRPs for the pccard controller.
  296. Arguments
  297. DeviceObject - Pointer to the functional device object for the sd controller
  298. Irp - Pointer to the Irp for the power dispatch
  299. Return value
  300. status
  301. --*/
  302. {
  303. NTSTATUS status;
  304. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  305. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  306. DEVICE_POWER_STATE devicePowerState = irpStack->Parameters.Power.State.DeviceState;
  307. status = IoAcquireRemoveLock(&fdoExtension->RemoveLock, "Sdbu");
  308. if (!NT_SUCCESS(status)) {
  309. PoStartNextPowerIrp (Irp);
  310. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  311. return status;
  312. }
  313. if (devicePowerState != PowerDeviceD0) {
  314. (*(fdoExtension->FunctionBlock->DisableEvent))(fdoExtension, SDBUS_EVENT_ALL);
  315. //
  316. // Turn card off
  317. //
  318. (*(fdoExtension->FunctionBlock->SetPower))(fdoExtension, FALSE, NULL);
  319. }
  320. // anything to do here?
  321. // Perform any device-specific tasks that must be done before device power is removed,
  322. // such as closing the device, completing or flushing any pending I/O, disabling interrupts,
  323. // queuing subsequent incoming IRPs, and saving device context from which to restore or
  324. // reinitialize the device.
  325. // The driver should not cause a long delay (for example, a delay that a user might find
  326. // unreasonable for this type of device) while handling the IRP.
  327. // The driver should queue any incoming I/O requests until the device has returned to the working state.
  328. IoMarkIrpPending(Irp);
  329. IoCopyCurrentIrpStackLocationToNext (Irp);
  330. //
  331. // Set our completion routine in the Irp..
  332. //
  333. IoSetCompletionRoutine(Irp,
  334. SdbusFdoSetDevicePowerStateCompletion,
  335. Fdo,
  336. TRUE,
  337. TRUE,
  338. TRUE);
  339. PoCallDriver(fdoExtension->LowerDevice, Irp);
  340. return STATUS_PENDING;
  341. }
  342. NTSTATUS
  343. SdbusFdoSetDevicePowerStateCompletion(
  344. IN PDEVICE_OBJECT Fdo,
  345. IN PIRP Irp,
  346. IN PVOID Context
  347. )
  348. {
  349. NTSTATUS status;
  350. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  351. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  352. DEVICE_POWER_STATE devicePowerState = irpStack->Parameters.Power.State.DeviceState;
  353. PSD_WORK_PACKET workPacket;
  354. BOOLEAN cardInSlot;
  355. BOOLEAN completeDeviceIrp;
  356. try{
  357. if (devicePowerState != PowerDeviceD0) {
  358. completeDeviceIrp = TRUE;
  359. status = Irp->IoStatus.Status;
  360. leave;
  361. }
  362. //
  363. // powering up
  364. //
  365. (*(fdoExtension->FunctionBlock->InitController))(fdoExtension);
  366. (*(fdoExtension->FunctionBlock->EnableEvent))(fdoExtension, (SDBUS_EVENT_INSERTION | SDBUS_EVENT_REMOVAL));
  367. SdbusActivateSocket(Fdo, SdbusFdoSetDevicePowerStateActivateComplete, Irp);
  368. completeDeviceIrp = FALSE;
  369. status = STATUS_MORE_PROCESSING_REQUIRED;
  370. } finally {
  371. if (completeDeviceIrp) {
  372. PoSetPowerState(Fdo, DevicePowerState, irpStack->Parameters.Power.State);
  373. PoStartNextPowerIrp (Irp);
  374. IoReleaseRemoveLock(&fdoExtension->RemoveLock, "Sdbu");
  375. }
  376. }
  377. return status;
  378. }
  379. VOID
  380. SdbusFdoSetDevicePowerStateActivateComplete(
  381. IN PDEVICE_OBJECT Fdo,
  382. IN PVOID Context,
  383. IN NTSTATUS status
  384. )
  385. {
  386. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  387. PIRP Irp = Context;
  388. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  389. PoSetPowerState(Fdo, DevicePowerState, irpStack->Parameters.Power.State);
  390. PoStartNextPowerIrp(Irp);
  391. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  392. }
  393. //************************************************
  394. //
  395. // PDO Routines
  396. //
  397. //************************************************
  398. NTSTATUS
  399. SdbusSetPdoPowerState(
  400. IN PDEVICE_OBJECT Pdo,
  401. IN OUT PIRP Irp
  402. )
  403. /*++
  404. Routine Description
  405. Dispatches the IRP based on whether a system power state
  406. or device power state transition is requested
  407. Arguments
  408. Pdo - Pointer to the physical device object for the pc-card
  409. Irp - Pointer to the Irp for the power dispatch
  410. Return value
  411. status
  412. --*/
  413. {
  414. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  415. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  416. PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension;
  417. NTSTATUS status;
  418. switch (irpStack->Parameters.Power.Type) {
  419. case DevicePowerState:
  420. status = SdbusSetPdoDevicePowerState(Pdo, Irp);
  421. break;
  422. case SystemPowerState:
  423. pdoExtension->SystemPowerState = irpStack->Parameters.Power.State.SystemState;
  424. status = SdbusPdoCompletePowerIrp(pdoExtension, Irp, STATUS_SUCCESS);
  425. break;
  426. default:
  427. status = SdbusPdoCompletePowerIrp(pdoExtension, Irp, Irp->IoStatus.Status);
  428. }
  429. return status;
  430. }
  431. NTSTATUS
  432. SdbusSetPdoDevicePowerState(
  433. IN PDEVICE_OBJECT Pdo,
  434. IN OUT PIRP Irp
  435. )
  436. /*++
  437. Routine Description
  438. Handles the device power state transition for the given SD function.
  439. Arguments
  440. Pdo - Pointer to the physical device object for the SD function
  441. Irp - Irp for the system state transition
  442. Return value
  443. status
  444. --*/
  445. {
  446. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  447. PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension;
  448. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  449. DEVICE_POWER_STATE newDevicePowerState;
  450. POWER_STATE newPowerState;
  451. NTSTATUS status;
  452. newDevicePowerState = irpStack->Parameters.Power.State.DeviceState;
  453. DebugPrint((SDBUS_DEBUG_POWER, "pdo %08x transitioning D state %d => %d\n",
  454. Pdo, pdoExtension->DevicePowerState, newDevicePowerState));
  455. if (newDevicePowerState == pdoExtension->DevicePowerState) {
  456. status = SdbusPdoCompletePowerIrp(pdoExtension, Irp, STATUS_SUCCESS);
  457. return status;
  458. }
  459. if (newDevicePowerState == PowerDeviceD0) {
  460. PSD_WORK_PACKET workPacket;
  461. //
  462. // Power up, initialize function
  463. //
  464. status = SdbusBuildWorkPacket(fdoExtension,
  465. SDWP_INITIALIZE_FUNCTION,
  466. SdbusPdoInitializeFunctionComplete,
  467. Irp,
  468. &workPacket);
  469. if (!NT_SUCCESS(status)) {
  470. status = SdbusPdoCompletePowerIrp(pdoExtension, Irp, status);
  471. } else {
  472. IoMarkIrpPending(Irp);
  473. workPacket->PdoExtension = pdoExtension;
  474. SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_SYSTEM);
  475. status = STATUS_PENDING;
  476. }
  477. } else {
  478. //
  479. // moving to a low power state
  480. //
  481. newPowerState.DeviceState = newDevicePowerState;
  482. PoSetPowerState(Pdo, DevicePowerState, newPowerState);
  483. pdoExtension->DevicePowerState = newDevicePowerState;
  484. status = SdbusPdoCompletePowerIrp(pdoExtension, Irp, STATUS_SUCCESS);
  485. }
  486. return status;
  487. }
  488. VOID
  489. SdbusPdoInitializeFunctionComplete(
  490. IN PSD_WORK_PACKET WorkPacket,
  491. IN NTSTATUS status
  492. )
  493. /*++
  494. Routine Description:
  495. Arguments:
  496. Return Value:
  497. --*/
  498. {
  499. PPDO_EXTENSION pdoExtension = WorkPacket->PdoExtension;
  500. PIRP Irp = WorkPacket->CompletionContext;
  501. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  502. DEVICE_POWER_STATE newDevicePowerState;
  503. POWER_STATE newPowerState;
  504. newDevicePowerState = irpStack->Parameters.Power.State.DeviceState;
  505. newPowerState.DeviceState = newDevicePowerState;
  506. PoSetPowerState(pdoExtension->DeviceObject, DevicePowerState, newPowerState);
  507. pdoExtension->DevicePowerState = newDevicePowerState;
  508. SdbusPdoCompletePowerIrp(pdoExtension, Irp, status);
  509. }
  510. NTSTATUS
  511. SdbusPdoCompletePowerIrp(
  512. IN PPDO_EXTENSION pdoExtension,
  513. IN PIRP Irp,
  514. IN NTSTATUS status
  515. )
  516. /*++
  517. Routine Description
  518. Completion routine for the Power Irp directed to the PDO of the
  519. SD function.
  520. Arguments
  521. DeviceObject - Pointer to the PDO for the SD function
  522. Irp - Irp that needs to be completed
  523. Return Value
  524. status
  525. --*/
  526. {
  527. InterlockedDecrement(&pdoExtension->DeletionLock);
  528. Irp->IoStatus.Status = status;
  529. PoStartNextPowerIrp(Irp);
  530. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  531. return status;
  532. }