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.

1133 lines
40 KiB

  1. /*****************************************************************************
  2. * power.cpp - WDM Streaming port class driver
  3. *****************************************************************************
  4. * Copyright (c) 1996-2000 Microsoft Corporation. All rights reserved.
  5. *
  6. * This file contains code related to ACPI / power management
  7. * for the audio adpaters/miniports
  8. */
  9. #include "private.h"
  10. #ifndef DEBUGLVL_POWER
  11. #define DEBUGLVL_POWER DEBUGLVL_VERBOSE
  12. #endif
  13. NTSTATUS
  14. ProcessPowerIrp
  15. (
  16. IN PIRP pIrp,
  17. IN PIO_STACK_LOCATION pIrpStack,
  18. IN PDEVICE_OBJECT pDeviceObject
  19. );
  20. #pragma code_seg("PAGE")
  21. /*****************************************************************************
  22. * GetDeviceACPIInfo()
  23. *****************************************************************************
  24. * Called in response to a PnP - IRP_MN_QUERY_CAPABILITIES
  25. * Call the bus driver to fill out the inital info,
  26. * Then overwrite with our own...
  27. *
  28. */
  29. NTSTATUS
  30. GetDeviceACPIInfo
  31. (
  32. IN PIRP pIrp,
  33. IN PDEVICE_OBJECT pDeviceObject
  34. )
  35. {
  36. PAGED_CODE();
  37. _DbgPrintF(DEBUGLVL_POWER,("GetDeviceACPIInfo"));
  38. ASSERT( pDeviceObject );
  39. PDEVICE_CONTEXT pDeviceContext
  40. = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  41. ASSERT( pDeviceContext );
  42. // Gotta call down to the PDO (bus driver)
  43. // and let it fill out the default for this bus
  44. NTSTATUS ntStatus = ForwardIrpSynchronous( pDeviceContext, pIrp );
  45. if( NT_SUCCESS(ntStatus) )
  46. {
  47. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(pIrp);
  48. PDEVICE_CAPABILITIES pDeviceCaps = irpSp->Parameters.DeviceCapabilities.Capabilities;
  49. ASSERT( pDeviceCaps );
  50. ASSERT( pDeviceCaps->Size >= sizeof( DEVICE_CAPABILITIES ) );
  51. if( pDeviceCaps && ( pDeviceCaps->Size >= sizeof( DEVICE_CAPABILITIES ) ) )
  52. {
  53. // pass the structure on down to the adapter
  54. if( pDeviceContext )
  55. {
  56. if( pDeviceContext->pAdapterPower )
  57. {
  58. ntStatus = pDeviceContext->pAdapterPower->QueryDeviceCapabilities( pDeviceCaps );
  59. ASSERT(ntStatus != STATUS_PENDING);
  60. }
  61. }
  62. // make sure that we have sensible settings for the system sleep states
  63. pDeviceCaps->DeviceState[PowerSystemWorking] = PowerDeviceD0;
  64. for(ULONG i=ULONG(PowerSystemSleeping1); i <= ULONG(PowerSystemShutdown); i++ )
  65. {
  66. // and we want some sleeping in the sleep modes.
  67. //
  68. // DEADISSUE-00/11/11-MartinP
  69. // We go ahead and include this code, even though it is possible that
  70. // there are devices that exist that can maintain state in the device
  71. // while sleeping.
  72. //
  73. if(pDeviceCaps->DeviceState[i] == PowerDeviceD0)
  74. {
  75. pDeviceCaps->DeviceState[i] = PowerDeviceD3;
  76. }
  77. }
  78. // save in our device extension the stuff we're interested in
  79. for( i=ULONG(PowerSystemUnspecified); i < ULONG(PowerSystemMaximum); i++)
  80. {
  81. pDeviceContext->DeviceStateMap[ i ] = pDeviceCaps->DeviceState[ i ];
  82. }
  83. _DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemUnspecified = D%d", pDeviceCaps->DeviceState[PowerSystemUnspecified] - 1));
  84. _DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemWorking = D%d", pDeviceCaps->DeviceState[PowerSystemWorking] - 1));
  85. _DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemSleeping1 = D%d", pDeviceCaps->DeviceState[PowerSystemSleeping1] - 1));
  86. _DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemSleeping2 = D%d", pDeviceCaps->DeviceState[PowerSystemSleeping2] - 1));
  87. _DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemSleeping3 = D%d", pDeviceCaps->DeviceState[PowerSystemSleeping3] - 1));
  88. _DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemHibernate = D%d", pDeviceCaps->DeviceState[PowerSystemHibernate] - 1));
  89. _DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: PowerSystemShutdown = D%d", pDeviceCaps->DeviceState[PowerSystemShutdown] - 1));
  90. _DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: SystemWake = %d", pDeviceCaps->SystemWake ));
  91. _DbgPrintF( DEBUGLVL_POWER, ( "DeviceCaps: DeviceWake = %d", pDeviceCaps->DeviceWake ));
  92. }
  93. }
  94. // complete the irp
  95. CompleteIrp( pDeviceContext, pIrp, ntStatus );
  96. // set the current power states
  97. pDeviceContext->CurrentDeviceState = PowerDeviceD0;
  98. pDeviceContext->CurrentSystemState = PowerSystemWorking;
  99. // attempt to get the idle info from the registry
  100. if( NT_SUCCESS(ntStatus) )
  101. {
  102. ULONG ConservationIdleTime;
  103. ULONG PerformanceIdleTime;
  104. DEVICE_POWER_STATE IdleDeviceState;
  105. NTSTATUS ntStatus2 = GetIdleInfoFromRegistry( pDeviceContext,
  106. &ConservationIdleTime,
  107. &PerformanceIdleTime,
  108. &IdleDeviceState );
  109. if(NT_SUCCESS(ntStatus2))
  110. {
  111. pDeviceContext->ConservationIdleTime = ConservationIdleTime;
  112. pDeviceContext->PerformanceIdleTime = PerformanceIdleTime;
  113. pDeviceContext->IdleDeviceState = IdleDeviceState;
  114. }
  115. // register for idle detection
  116. pDeviceContext->IdleTimer = PoRegisterDeviceForIdleDetection( pDeviceContext->PhysicalDeviceObject,
  117. pDeviceContext->ConservationIdleTime,
  118. pDeviceContext->PerformanceIdleTime,
  119. pDeviceContext->IdleDeviceState );
  120. _DbgPrintF(DEBUGLVL_POWER,("Idle Detection Enabled (%d %d %d) %s", pDeviceContext->ConservationIdleTime,
  121. pDeviceContext->PerformanceIdleTime,
  122. ULONG(pDeviceContext->IdleDeviceState),
  123. pDeviceContext->IdleTimer ? "" : "FAILED!"));
  124. }
  125. return ntStatus;
  126. }
  127. #pragma code_seg()
  128. VOID
  129. DevicePowerRequestRoutine(
  130. IN PKDPC Dpc,
  131. IN PVOID Context,
  132. IN PVOID SystemContext1,
  133. IN PVOID SystemContext2
  134. )
  135. {
  136. PDEVICE_CONTEXT pDeviceContext = (PDEVICE_CONTEXT) Context;
  137. POWER_STATE newPowerState;
  138. newPowerState.DeviceState = PowerDeviceD0;
  139. PoRequestPowerIrp(pDeviceContext->PhysicalDeviceObject,
  140. IRP_MN_SET_POWER,
  141. newPowerState,
  142. NULL,
  143. NULL,
  144. NULL
  145. );
  146. }
  147. /*****************************************************************************
  148. * PowerIrpCompletionRoutine()
  149. *****************************************************************************
  150. * Used when requested a new power irp.
  151. * Just signal an event and return.
  152. *
  153. */
  154. VOID
  155. PowerIrpCompletionRoutine
  156. (
  157. IN PDEVICE_OBJECT DeviceObject,
  158. IN UCHAR MinorFunction,
  159. IN POWER_STATE PowerState,
  160. IN PVOID Context,
  161. IN PIO_STATUS_BLOCK IoStatus
  162. )
  163. {
  164. ASSERT(Context);
  165. _DbgPrintF( DEBUGLVL_POWER, ("PowerIrpCompletionRoutine"));
  166. PPOWER_IRP_CONTEXT pPowerIrpContext = PPOWER_IRP_CONTEXT(Context);
  167. // set the return status
  168. pPowerIrpContext->Status = IoStatus->Status;
  169. // complete any pending system power irp
  170. if( pPowerIrpContext->PendingSystemPowerIrp )
  171. {
  172. _DbgPrintF(DEBUGLVL_POWER,("Device Set/Query Power Irp completed, Completing Associated System Power Irp"));
  173. if (NT_SUCCESS(IoStatus->Status))
  174. {
  175. // Forward the system set power irp to the PDO
  176. ForwardIrpSynchronous( pPowerIrpContext->DeviceContext,
  177. pPowerIrpContext->PendingSystemPowerIrp );
  178. } else
  179. {
  180. pPowerIrpContext->PendingSystemPowerIrp->IoStatus.Status = IoStatus->Status;
  181. }
  182. // start the next power irp
  183. PoStartNextPowerIrp( pPowerIrpContext->PendingSystemPowerIrp );
  184. // complete the system set power irp
  185. CompleteIrp( pPowerIrpContext->DeviceContext,
  186. pPowerIrpContext->PendingSystemPowerIrp,
  187. pPowerIrpContext->PendingSystemPowerIrp->IoStatus.Status );
  188. // free the context (only when completing a pending system power irp)
  189. ExFreePool( pPowerIrpContext );
  190. } else
  191. {
  192. // set the sync event (not used in conjunction with pending system power irps)
  193. if( pPowerIrpContext->PowerSyncEvent )
  194. {
  195. KeSetEvent( pPowerIrpContext->PowerSyncEvent,
  196. 0,
  197. FALSE );
  198. }
  199. }
  200. }
  201. #pragma code_seg("PAGE")
  202. /*****************************************************************************
  203. * DispatchPower()
  204. *****************************************************************************
  205. * Deals with all the power/ACPI messages from the OS.
  206. * yay.
  207. *
  208. */
  209. NTSTATUS
  210. DispatchPower
  211. (
  212. IN PDEVICE_OBJECT pDeviceObject,
  213. IN PIRP pIrp
  214. )
  215. {
  216. PAGED_CODE();
  217. ASSERT(pDeviceObject);
  218. ASSERT(pIrp);
  219. NTSTATUS ntStatus = STATUS_SUCCESS;
  220. PIO_STACK_LOCATION pIrpStack =
  221. IoGetCurrentIrpStackLocation(pIrp);
  222. PDEVICE_CONTEXT pDeviceContext =
  223. PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  224. ntStatus = PcValidateDeviceContext(pDeviceContext, pIrp);
  225. if (!NT_SUCCESS(ntStatus))
  226. {
  227. // Don't know what to do, but this is probably a PDO.
  228. // We'll try to make this right by completing the IRP
  229. // untouched (per PnP, WMI, and Power rules). Note
  230. // that if this isn't a PDO, and isn't a portcls FDO, then
  231. // the driver messed up by using Portcls as a filter (huh?)
  232. // In this case the verifier will fail us, WHQL will catch
  233. // them, and the driver will be fixed. We'd be very surprised
  234. // to see such a case.
  235. PoStartNextPowerIrp( pIrp );
  236. ntStatus = pIrp->IoStatus.Status;
  237. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  238. return ntStatus;
  239. }
  240. IncrementPendingIrpCount( pDeviceContext );
  241. #if (DBG)
  242. static PCHAR aszMnNames[] =
  243. {
  244. "IRP_MN_WAIT_WAKE",
  245. "IRP_MN_POWER_SEQUENCE",
  246. "IRP_MN_SET_POWER",
  247. "IRP_MN_QUERY_POWER"
  248. };
  249. if (pIrpStack->MinorFunction >= SIZEOF_ARRAY(aszMnNames))
  250. {
  251. _DbgPrintF( DEBUGLVL_POWER,("DispatchPower function 0x%02x",pIrpStack->MinorFunction));
  252. }
  253. else
  254. {
  255. _DbgPrintF( DEBUGLVL_POWER,("DispatchPower function %s",aszMnNames[pIrpStack->MinorFunction]));
  256. }
  257. #endif
  258. // Assume we won't deal with the irp.
  259. BOOL IrpHandled = FALSE;
  260. switch (pIrpStack->MinorFunction)
  261. {
  262. case IRP_MN_QUERY_POWER:
  263. case IRP_MN_SET_POWER:
  264. // Is this a device state change?
  265. if( DevicePowerState == pIrpStack->Parameters.Power.Type )
  266. {
  267. // yeah. Deal with it
  268. ntStatus = ProcessPowerIrp( pIrp,
  269. pIrpStack,
  270. pDeviceObject );
  271. IrpHandled = TRUE;
  272. // And quit.
  273. } else
  274. {
  275. // A system state change
  276. if( IRP_MN_QUERY_POWER == pIrpStack->MinorFunction )
  277. {
  278. _DbgPrintF(DEBUGLVL_POWER,(" IRP_MN_QUERY_POWER: ->S%d",
  279. pIrpStack->Parameters.Power.State.SystemState-1));
  280. } else
  281. {
  282. _DbgPrintF(DEBUGLVL_POWER,(" IRP_MN_SET_POWER: ->S%d",
  283. pIrpStack->Parameters.Power.State.SystemState-1));
  284. }
  285. POWER_STATE newPowerState;
  286. // determine appropriate device state
  287. newPowerState.DeviceState = pDeviceContext->DeviceStateMap[ pIrpStack->Parameters.Power.State.SystemState ];
  288. //
  289. // do a sanity check on the device state
  290. if ((newPowerState.DeviceState < PowerDeviceD0) ||
  291. (newPowerState.DeviceState > PowerDeviceD3) )
  292. {
  293. if (pIrpStack->Parameters.Power.State.SystemState == PowerSystemWorking)
  294. {
  295. newPowerState.DeviceState = PowerDeviceD0;
  296. } else
  297. {
  298. newPowerState.DeviceState = PowerDeviceD3;
  299. }
  300. }
  301. _DbgPrintF(DEBUGLVL_POWER,(" ...Requesting Device Power IRP -> D%d",newPowerState.DeviceState-1));
  302. if ((pIrpStack->MinorFunction == IRP_MN_SET_POWER) &&
  303. (newPowerState.DeviceState == PowerDeviceD0)) {
  304. //
  305. // doing a resume, request the D irp, but complete S-irp immediately
  306. //
  307. KeInsertQueueDpc(&pDeviceContext->DevicePowerRequestDpc, NULL, NULL);
  308. break;
  309. } else {
  310. // allocate a completion context (can't be on the stack because we're not going to block)
  311. PPOWER_IRP_CONTEXT PowerIrpContext =
  312. PPOWER_IRP_CONTEXT(ExAllocatePoolWithTag(NonPagedPool,
  313. sizeof(POWER_IRP_CONTEXT),
  314. 'oPcP' ) ); // 'PcPo'
  315. if (PowerIrpContext)
  316. {
  317. _DbgPrintF(DEBUGLVL_POWER,("...Pending System Power Irp until Device Power Irp completes"));
  318. // set up device power irp completion context
  319. PowerIrpContext->PowerSyncEvent = NULL;
  320. #if DBG
  321. PowerIrpContext->Status = STATUS_PENDING;
  322. #endif
  323. PowerIrpContext->PendingSystemPowerIrp = pIrp;
  324. PowerIrpContext->DeviceContext = pDeviceContext;
  325. // pend the system set power irp
  326. //
  327. #if DBG
  328. pIrp->IoStatus.Status = STATUS_PENDING;
  329. #endif
  330. IoMarkIrpPending( pIrp );
  331. // set our tracking of system power state
  332. if (pIrpStack->MinorFunction == IRP_MN_SET_POWER) {
  333. pDeviceContext->CurrentSystemState = pIrpStack->Parameters.Power.State.SystemState;
  334. }
  335. // request the new device state
  336. //
  337. ntStatus = PoRequestPowerIrp(
  338. pDeviceContext->PhysicalDeviceObject,
  339. pIrpStack->MinorFunction,
  340. newPowerState,
  341. PowerIrpCompletionRoutine,
  342. PowerIrpContext,
  343. NULL
  344. );
  345. if (!NT_SUCCESS(ntStatus))
  346. {
  347. _DbgPrintF(DEBUGLVL_TERSE,("PoRequestPowerIrp failed (%08x)", ntStatus));
  348. CompleteIrp( pDeviceContext, pIrp, ntStatus );
  349. }
  350. IrpHandled = TRUE;
  351. // set up return status
  352. ntStatus = STATUS_PENDING;
  353. } else
  354. {
  355. // couldn't allocate completion context
  356. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  357. PoStartNextPowerIrp( pIrp );
  358. CompleteIrp( pDeviceContext, pIrp, ntStatus);
  359. return ntStatus;
  360. }
  361. }
  362. }
  363. break;
  364. }
  365. // If we didn't cope with the irp
  366. if( !IrpHandled )
  367. {
  368. // Send it on it's way.
  369. ntStatus = ForwardIrpSynchronous( pDeviceContext, pIrp );
  370. // and complete it.
  371. PoStartNextPowerIrp( pIrp );
  372. CompleteIrp( pDeviceContext, pIrp, ntStatus );
  373. }
  374. return ntStatus;
  375. }
  376. /*****************************************************************************
  377. * PcRegisterAdapterPowerManagement()
  378. *****************************************************************************
  379. * Register the adapter's power management interface
  380. * with portcls. This routine also does a QI for a shutdown notification
  381. * interface.
  382. */
  383. PORTCLASSAPI
  384. NTSTATUS
  385. NTAPI
  386. PcRegisterAdapterPowerManagement
  387. (
  388. IN PUNKNOWN Unknown,
  389. IN PVOID pvContext1
  390. )
  391. {
  392. PAGED_CODE();
  393. ASSERT(pvContext1);
  394. ASSERT(Unknown);
  395. _DbgPrintF(DEBUGLVL_POWER,("PcRegisterAdapterPowerManagement"));
  396. //
  397. // Validate Parameters.
  398. //
  399. if (NULL == pvContext1 ||
  400. NULL == Unknown)
  401. {
  402. _DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterAdapterPowerManagement : Invalid Parameter"));
  403. return STATUS_INVALID_PARAMETER;
  404. }
  405. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  406. PDEVICE_OBJECT pDeviceObject = PDEVICE_OBJECT(pvContext1);
  407. PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  408. ASSERT( pDeviceContext );
  409. //
  410. // Validate DeviceContext.
  411. //
  412. if (NULL == pDeviceContext)
  413. {
  414. _DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterAdapterPowerManagement : Invalid DeviceContext"));
  415. return STATUS_INVALID_PARAMETER;
  416. }
  417. #if (DBG)
  418. if( pDeviceContext->pAdapterPower )
  419. {
  420. _DbgPrintF( DEBUGLVL_POWER, ("Adapter overwriting PowerManagement interface"));
  421. }
  422. #endif
  423. // Make sure this is really the right
  424. // interface (Note: We have to release
  425. // it when the device is closed/stoped )
  426. PVOID pResult;
  427. ntStatus = Unknown->QueryInterface
  428. (
  429. IID_IAdapterPowerManagement,
  430. &pResult
  431. );
  432. if( NT_SUCCESS(ntStatus) )
  433. {
  434. // Store the interface for later use.
  435. pDeviceContext->pAdapterPower = PADAPTERPOWERMANAGEMENT( pResult );
  436. } else
  437. {
  438. pDeviceContext->pAdapterPower = 0;
  439. }
  440. return ntStatus;
  441. }
  442. /*****************************************************************************
  443. * PowerNotifySubdevices()
  444. *****************************************************************************
  445. * Called by ProcessPowerIrp to notify the device's subdevices of a power
  446. * state change.
  447. *
  448. */
  449. void
  450. PowerNotifySubdevices
  451. (
  452. IN PDEVICE_CONTEXT pDeviceContext,
  453. IN POWER_STATE PowerState
  454. )
  455. {
  456. PAGED_CODE();
  457. ASSERT(pDeviceContext);
  458. _DbgPrintF(DEBUGLVL_POWER,("PowerNotifySubdevices"));
  459. // only notify the subdevices if we're started and if there are subdevices
  460. if (pDeviceContext->DeviceStopState == DeviceStarted)
  461. {
  462. PKSOBJECT_CREATE_ITEM createItem = pDeviceContext->CreateItems;
  463. // iterate through the subdevices
  464. for( ULONG index=0; index < pDeviceContext->MaxObjects; index++,createItem++)
  465. {
  466. if( createItem && (createItem->Create) )
  467. {
  468. PSUBDEVICE subDevice = PSUBDEVICE( createItem->Context );
  469. if( subDevice )
  470. {
  471. // notify the subdevice
  472. subDevice->PowerChangeNotify( PowerState );
  473. }
  474. }
  475. }
  476. }
  477. }
  478. /*****************************************************************************
  479. * DevicePowerWorker()
  480. *****************************************************************************
  481. * Called by ProcessPowerIrp in order to notify the device of the state change.
  482. * This is done in a work item so that the processing for the D0 irp doesn't
  483. * block the rest of the system from processing D0 irps.
  484. */
  485. QUEUED_CALLBACK_RETURN
  486. DevicePowerWorker
  487. (
  488. IN PDEVICE_OBJECT pDeviceObject,
  489. IN PVOID PowerState
  490. )
  491. {
  492. PDEVICE_CONTEXT pDeviceContext =
  493. PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  494. BOOL ProcessPendedIrps = FALSE;
  495. POWER_STATE NewPowerState;
  496. NewPowerState.DeviceState = (DEVICE_POWER_STATE)(ULONG_PTR)PowerState;
  497. // acquire the device so we're sync'ed with creates
  498. AcquireDevice(pDeviceContext);
  499. // change the driver state if it has a registered POWER interface
  500. if( pDeviceContext->pAdapterPower )
  501. {
  502. // notify the adapter
  503. pDeviceContext->pAdapterPower->PowerChangeState( NewPowerState );
  504. }
  505. // keep track of new state
  506. pDeviceContext->CurrentDeviceState = NewPowerState.DeviceState;
  507. // notify everyone we're now in our lighter D-state
  508. PoSetPowerState( pDeviceObject,
  509. DevicePowerState,
  510. NewPowerState );
  511. PowerNotifySubdevices( pDeviceContext, NewPowerState );
  512. // set PendCreates appropriately
  513. if( pDeviceContext->DeviceStopState == DeviceStarted )
  514. {
  515. // start allowing creates
  516. pDeviceContext->PendCreates = FALSE;
  517. // we have to process the pended irps after we release the device
  518. ProcessPendedIrps = TRUE;
  519. }
  520. ReleaseDevice(pDeviceContext);
  521. // complete if necessary any pended IRPs
  522. if ( ProcessPendedIrps )
  523. {
  524. CompletePendedIrps( pDeviceObject,
  525. pDeviceContext,
  526. EMPTY_QUEUE_AND_PROCESS );
  527. }
  528. return QUEUED_CALLBACK_FREE;
  529. }
  530. /*****************************************************************************
  531. * ProcessPowerIrp()
  532. *****************************************************************************
  533. * Called by DispatchPower to call the Adapter driver and all other work
  534. * related to a request. Note that this routine MUST return STATUS_SUCCESS
  535. * for IRP_MN_SET_POWER requests.
  536. *
  537. */
  538. NTSTATUS
  539. ProcessPowerIrp
  540. (
  541. IN PIRP pIrp,
  542. IN PIO_STACK_LOCATION pIrpStack,
  543. IN PDEVICE_OBJECT pDeviceObject
  544. )
  545. {
  546. PAGED_CODE();
  547. ASSERT(pIrp);
  548. ASSERT(pIrpStack);
  549. ASSERT(pDeviceObject);
  550. _DbgPrintF(DEBUGLVL_POWER,("ProcessPowerIrp"));
  551. // Assume the worst
  552. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  553. PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  554. POWER_STATE NewPowerState = pIrpStack->Parameters.Power.State;
  555. // Get the current count of open
  556. // objects for this device (pins, streams, whatever).
  557. // NOTE: This count is maintained by KSO.CPP
  558. ULONG objectCount = pDeviceContext->ExistingObjectCount;
  559. // get the active pin count
  560. // NOTE: This count is maintained by IRPSTRM.CPP
  561. ULONG activePinCount = pDeviceContext->ActivePinCount;
  562. BOOL MovingToALighterState = (pDeviceContext->CurrentDeviceState > NewPowerState.DeviceState);
  563. if (pDeviceContext->CurrentDeviceState != NewPowerState.DeviceState) {
  564. // Deal with the particular IRP_MN
  565. switch( pIrpStack->MinorFunction )
  566. {
  567. case IRP_MN_QUERY_POWER:
  568. // simply query the driver if it has registered an interface
  569. if( pDeviceContext->pAdapterPower )
  570. {
  571. ntStatus = pDeviceContext->pAdapterPower->QueryPowerChangeState( NewPowerState );
  572. } else
  573. {
  574. // succeed the query
  575. ntStatus = STATUS_SUCCESS;
  576. }
  577. _DbgPrintF(DEBUGLVL_POWER,(" IRP_MN_QUERY_POWER: D%d->D%d %s",
  578. pDeviceContext->CurrentDeviceState-1,
  579. NewPowerState.DeviceState-1,
  580. NT_SUCCESS(ntStatus) ? "OKAY" : "FAIL"));
  581. break;
  582. case IRP_MN_SET_POWER:
  583. _DbgPrintF(DEBUGLVL_POWER,(" IRP_MN_SET_POWER: D%d->D%d",
  584. pDeviceContext->CurrentDeviceState-1,
  585. NewPowerState.DeviceState-1));
  586. // acquire the device so we're sync'ed with creates
  587. AcquireDevice(pDeviceContext);
  588. // if we're moving from a low power state to a higher power state
  589. if( MovingToALighterState )
  590. {
  591. ASSERT(pDeviceContext->CurrentDeviceState != PowerDeviceD0);
  592. ASSERT(NewPowerState.DeviceState == PowerDeviceD0);
  593. // Then we need to forward to the PDO BEFORE doing our work.
  594. ForwardIrpSynchronous( pDeviceContext, pIrp );
  595. ReleaseDevice(pDeviceContext);
  596. // Do the rest of the work in a work item in order to complete the D0 Irp
  597. // as soon as possible
  598. ntStatus = CallbackEnqueue(
  599. &pDeviceContext->pWorkQueueItemStart,
  600. DevicePowerWorker,
  601. pDeviceObject,
  602. (PVOID)(ULONG_PTR)NewPowerState.DeviceState,
  603. PASSIVE_LEVEL,
  604. EQCF_DIFFERENT_THREAD_REQUIRED
  605. );
  606. // If we fail to enqueue the callback, do this the slow way
  607. if ( !NT_SUCCESS(ntStatus) )
  608. {
  609. DevicePowerWorker( pDeviceObject,
  610. (PVOID)(ULONG_PTR)NewPowerState.DeviceState );
  611. }
  612. } else {
  613. // warn everyone we're about to enter a deeper D-state
  614. PoSetPowerState( pDeviceObject,
  615. DevicePowerState,
  616. NewPowerState );
  617. // moving to a lower state, notify the subdevices
  618. PowerNotifySubdevices( pDeviceContext, NewPowerState );
  619. // keep track of suspends for debugging only
  620. pDeviceContext->SuspendCount++;
  621. // change the driver state if it has a registered POWER interface
  622. if( pDeviceContext->pAdapterPower )
  623. {
  624. // notify the adapter
  625. pDeviceContext->pAdapterPower->PowerChangeState( NewPowerState );
  626. }
  627. // keep track of new state
  628. pDeviceContext->CurrentDeviceState = NewPowerState.DeviceState;
  629. ReleaseDevice(pDeviceContext);
  630. }
  631. // this irp is non-failable
  632. ntStatus = STATUS_SUCCESS;
  633. break;
  634. default:
  635. ASSERT(!"Called with unknown PM IRP ");
  636. break;
  637. }
  638. } else {
  639. //
  640. // We're already there...
  641. //
  642. ntStatus = STATUS_SUCCESS;
  643. ASSERT(!MovingToALighterState);
  644. }
  645. // set the return status
  646. pIrp->IoStatus.Status = ntStatus;
  647. // if not moving to a higher state, forward to the PDO.
  648. if( !MovingToALighterState )
  649. {
  650. ForwardIrpSynchronous( pDeviceContext, pIrp );
  651. }
  652. // start the next power irp
  653. PoStartNextPowerIrp( pIrp );
  654. // complete this irp
  655. CompleteIrp( pDeviceContext, pIrp, ntStatus );
  656. return ntStatus;
  657. }
  658. /*****************************************************************************
  659. * UpdateActivePinCount()
  660. *****************************************************************************
  661. *
  662. */
  663. NTSTATUS
  664. UpdateActivePinCount
  665. (
  666. IN PDEVICE_CONTEXT DeviceContext,
  667. IN BOOL Increment
  668. )
  669. {
  670. PAGED_CODE();
  671. ASSERT(DeviceContext);
  672. ULONG ActivePinCount;
  673. NTSTATUS ntStatus = STATUS_SUCCESS;
  674. BOOL DoSystemStateRegistration;
  675. //
  676. // PoRegisterSystemState and PoUnregisterSystemState are not available on WDM 1.0 (Win98 and Win98SE)
  677. DoSystemStateRegistration = IoIsWdmVersionAvailable( 0x01, 0x10 );
  678. // adjust the active pin count
  679. if( Increment )
  680. {
  681. ActivePinCount = InterlockedIncrement( PLONG(&DeviceContext->ActivePinCount) );
  682. //#if COMPILED_FOR_WDM110
  683. if ( 1 == ActivePinCount )
  684. {
  685. // register the system state as busy
  686. DeviceContext->SystemStateHandle = PoRegisterSystemState( DeviceContext->SystemStateHandle,
  687. ES_SYSTEM_REQUIRED | ES_CONTINUOUS );
  688. }
  689. //#endif // COMPILED_FOR_WDM110
  690. } else
  691. {
  692. ActivePinCount = InterlockedDecrement( PLONG(&DeviceContext->ActivePinCount) );
  693. //#if COMPILED_FOR_WDM110
  694. if( 0 == ActivePinCount )
  695. {
  696. PoUnregisterSystemState( DeviceContext->SystemStateHandle );
  697. DeviceContext->SystemStateHandle = NULL;
  698. }
  699. //#endif // COMPILED_FOR_WDM110
  700. }
  701. _DbgPrintF(DEBUGLVL_VERBOSE,("UpdateActivePinCount (%d)",ActivePinCount));
  702. // _DbgPrintF(DEBUGLVL_POWER,("UpdateActivePinCount (%d)",ActivePinCount));
  703. return ntStatus;
  704. }
  705. /*****************************************************************************
  706. * GetIdleInfoFromRegistry()
  707. *****************************************************************************
  708. *
  709. */
  710. NTSTATUS
  711. GetIdleInfoFromRegistry
  712. (
  713. IN PDEVICE_CONTEXT DeviceContext,
  714. OUT PULONG ConservationIdleTime,
  715. OUT PULONG PerformanceIdleTime,
  716. OUT PDEVICE_POWER_STATE IdleDeviceState
  717. )
  718. {
  719. PAGED_CODE();
  720. ASSERT(DeviceContext);
  721. ASSERT(ConservationIdleTime);
  722. ASSERT(PerformanceIdleTime);
  723. ASSERT(IdleDeviceState);
  724. NTSTATUS ntStatus;
  725. HANDLE DriverRegistryKey;
  726. HANDLE PowerSettingsKey;
  727. // store default values in return parms
  728. *ConservationIdleTime = DEFAULT_CONSERVATION_IDLE_TIME;
  729. *PerformanceIdleTime = DEFAULT_PERFORMANCE_IDLE_TIME;
  730. *IdleDeviceState = DEFAULT_IDLE_DEVICE_POWER_STATE;
  731. // open the driver registry key
  732. ntStatus = IoOpenDeviceRegistryKey( DeviceContext->PhysicalDeviceObject,
  733. PLUGPLAY_REGKEY_DRIVER,
  734. KEY_READ,
  735. &DriverRegistryKey );
  736. if(NT_SUCCESS(ntStatus))
  737. {
  738. OBJECT_ATTRIBUTES PowerSettingsAttributes;
  739. UNICODE_STRING PowerSettingsKeyName;
  740. // init the power settings key name
  741. RtlInitUnicodeString( &PowerSettingsKeyName, L"PowerSettings" );
  742. // init the power settings key object attributes
  743. InitializeObjectAttributes( &PowerSettingsAttributes,
  744. &PowerSettingsKeyName,
  745. OBJ_CASE_INSENSITIVE,
  746. DriverRegistryKey,
  747. NULL );
  748. // open the power settings key
  749. ntStatus = ZwOpenKey( &PowerSettingsKey,
  750. KEY_READ,
  751. &PowerSettingsAttributes );
  752. if(NT_SUCCESS(ntStatus))
  753. {
  754. UNICODE_STRING ConservationKey,PerformanceKey,IdleStateKey;
  755. ULONG BytesReturned;
  756. // init the key names
  757. RtlInitUnicodeString( &ConservationKey, L"ConservationIdleTime" );
  758. RtlInitUnicodeString( &PerformanceKey, L"PerformanceIdleTime" );
  759. RtlInitUnicodeString( &IdleStateKey, L"IdlePowerState" );
  760. // allocate a buffer to hold the query
  761. PVOID KeyData = ExAllocatePoolWithTag(PagedPool,
  762. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD),
  763. 'dKcP' ); // 'PcKd'
  764. if( NULL != KeyData )
  765. {
  766. // get the conservation idle time
  767. ntStatus = ZwQueryValueKey( PowerSettingsKey,
  768. &ConservationKey,
  769. KeyValuePartialInformation,
  770. KeyData,
  771. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD),
  772. &BytesReturned );
  773. if(NT_SUCCESS(ntStatus))
  774. {
  775. PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = PKEY_VALUE_PARTIAL_INFORMATION(KeyData);
  776. if(PartialInfo->DataLength == sizeof(DWORD))
  777. {
  778. // set the return value
  779. *ConservationIdleTime = *(PDWORD(PartialInfo->Data));
  780. }
  781. }
  782. // get the performance idle time
  783. ntStatus = ZwQueryValueKey( PowerSettingsKey,
  784. &PerformanceKey,
  785. KeyValuePartialInformation,
  786. KeyData,
  787. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD),
  788. &BytesReturned );
  789. if(NT_SUCCESS(ntStatus))
  790. {
  791. PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = PKEY_VALUE_PARTIAL_INFORMATION(KeyData);
  792. if(PartialInfo->DataLength == sizeof(DWORD))
  793. {
  794. // set the return value
  795. *PerformanceIdleTime = *(PDWORD(PartialInfo->Data));
  796. }
  797. }
  798. // get the device idle state
  799. ntStatus = ZwQueryValueKey( PowerSettingsKey,
  800. &IdleStateKey,
  801. KeyValuePartialInformation,
  802. KeyData,
  803. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD),
  804. &BytesReturned );
  805. if(NT_SUCCESS(ntStatus))
  806. {
  807. PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = PKEY_VALUE_PARTIAL_INFORMATION(KeyData);
  808. if(PartialInfo->DataLength == sizeof(DWORD))
  809. {
  810. // determine the return value
  811. switch( *(PDWORD(PartialInfo->Data)) )
  812. {
  813. case 3:
  814. *IdleDeviceState = PowerDeviceD3;
  815. break;
  816. case 2:
  817. *IdleDeviceState = PowerDeviceD2;
  818. break;
  819. case 1:
  820. *IdleDeviceState = PowerDeviceD1;
  821. break;
  822. default:
  823. *IdleDeviceState = PowerDeviceD0;
  824. break;
  825. }
  826. }
  827. }
  828. // free the key info buffer
  829. ExFreePool( KeyData );
  830. }
  831. // close the power settings key
  832. ZwClose( PowerSettingsKey );
  833. }
  834. // close the driver registry key
  835. ZwClose( DriverRegistryKey );
  836. }
  837. // always succeed since we return either the registry value(s) or the defaults
  838. return STATUS_SUCCESS;
  839. }
  840. /*****************************************************************************
  841. * PcRequestNewPowerState()
  842. *****************************************************************************
  843. * This routine is used to request a new power state for the device. It is
  844. * normally used internally by portcls but is also exported to adapters so
  845. * that the adapters can also request power state changes.
  846. */
  847. PORTCLASSAPI
  848. NTSTATUS
  849. NTAPI
  850. PcRequestNewPowerState
  851. (
  852. IN PDEVICE_OBJECT pDeviceObject,
  853. IN DEVICE_POWER_STATE RequestedNewState
  854. )
  855. {
  856. PAGED_CODE();
  857. ASSERT(pDeviceObject);
  858. _DbgPrintF(DEBUGLVL_POWER,("PcRequestNewPowerState"));
  859. //
  860. // Validate Parameters.
  861. //
  862. if (NULL == pDeviceObject)
  863. {
  864. _DbgPrintF(DEBUGLVL_TERSE, ("PcRequestNewPowerState : Invalid Parameter"));
  865. return STATUS_INVALID_PARAMETER;
  866. }
  867. PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  868. ASSERT(pDeviceContext);
  869. NTSTATUS ntStatus = STATUS_SUCCESS;
  870. //
  871. // Validate DeviceContext.
  872. //
  873. if (NULL == pDeviceContext)
  874. {
  875. _DbgPrintF(DEBUGLVL_TERSE, ("PcRequestNewPowerState : Invalid DeviceContext"));
  876. return STATUS_INVALID_PARAMETER;
  877. }
  878. // check if this is actually a state change
  879. if( RequestedNewState != pDeviceContext->CurrentDeviceState )
  880. {
  881. POWER_STATE newPowerState;
  882. POWER_IRP_CONTEXT PowerIrpContext;
  883. KEVENT SyncEvent;
  884. // prepare the requested state
  885. newPowerState.DeviceState = RequestedNewState;
  886. // setup the sync event and the completion routine context
  887. KeInitializeEvent( &SyncEvent,
  888. SynchronizationEvent,
  889. FALSE );
  890. PowerIrpContext.PowerSyncEvent = &SyncEvent;
  891. #if DBG
  892. PowerIrpContext.Status = STATUS_PENDING;
  893. #endif // DBG
  894. PowerIrpContext.PendingSystemPowerIrp = NULL;
  895. PowerIrpContext.DeviceContext = NULL;
  896. // Set the new power state
  897. ntStatus = PoRequestPowerIrp( pDeviceContext->PhysicalDeviceObject,
  898. IRP_MN_SET_POWER,
  899. newPowerState,
  900. PowerIrpCompletionRoutine,
  901. &PowerIrpContext,
  902. NULL );
  903. // Did this get allocated and sent??
  904. //
  905. if( NT_SUCCESS(ntStatus) )
  906. {
  907. // Wait for the completion event
  908. KeWaitForSingleObject( &SyncEvent,
  909. Suspended,
  910. KernelMode,
  911. FALSE,
  912. NULL );
  913. ntStatus = PowerIrpContext.Status;
  914. }
  915. }
  916. return ntStatus;
  917. }
  918. /*****************************************************************************
  919. * CheckCurrentPowerState()
  920. *****************************************************************************
  921. * This routine resets the idle timer and checks to see if the device is
  922. * current in the D0 (full power) state. If it isn't, it requests that the
  923. * device power up to D0.
  924. */
  925. NTSTATUS
  926. CheckCurrentPowerState
  927. (
  928. IN PDEVICE_OBJECT pDeviceObject
  929. )
  930. {
  931. PAGED_CODE();
  932. ASSERT(pDeviceObject);
  933. PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  934. NTSTATUS ntStatus = STATUS_SUCCESS;
  935. // reset the idle timer
  936. if( pDeviceContext->IdleTimer )
  937. {
  938. PoSetDeviceBusy( pDeviceContext->IdleTimer );
  939. }
  940. // check if we're in PowerDeviceD0
  941. if( pDeviceContext->CurrentDeviceState != PowerDeviceD0 )
  942. {
  943. ntStatus = STATUS_DEVICE_NOT_READY;
  944. }
  945. return ntStatus;
  946. }
  947. #pragma code_seg()