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.

2937 lines
83 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. power.c
  5. Abstract:
  6. the power code
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. 6-20-99 : created
  12. --*/
  13. #include "common.h"
  14. // paged functions
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, USBPORT_ComputeRootHubDeviceCaps)
  17. #pragma alloc_text(PAGE, USBPORT_ComputeHcPowerStates)
  18. #endif
  19. // non paged functions
  20. //USBPORT_PdoPowerIrp
  21. //USBPORT_FdoPowerIrp
  22. //USBPORT_SystemPowerState
  23. //USBPORT_DevicePowerState
  24. //USBPORT_PoRequestCompletion
  25. //USBPORT_CancelPendingWakeIrp
  26. #if DBG
  27. PUCHAR
  28. S_State(
  29. SYSTEM_POWER_STATE S
  30. )
  31. {
  32. switch (S) {
  33. case PowerSystemUnspecified:
  34. return "SystemUnspecified S?";
  35. case PowerSystemWorking:
  36. return "SystemWorking S0";
  37. case PowerSystemSleeping1:
  38. return "SystemSleeping1 S1";
  39. case PowerSystemSleeping2:
  40. return "SystemSleeping2 S2";
  41. case PowerSystemSleeping3:
  42. return "SystemSleeping3 S3";
  43. case PowerSystemHibernate:
  44. return "SystemHibernate";
  45. case PowerSystemShutdown:
  46. return "SystemShutdown";
  47. case PowerSystemMaximum:
  48. return "SystemMaximum";
  49. }
  50. return "???";
  51. }
  52. PUCHAR
  53. D_State(
  54. DEVICE_POWER_STATE D
  55. )
  56. {
  57. switch (D) {
  58. case PowerDeviceUnspecified:
  59. return "D?";
  60. case PowerDeviceD0:
  61. return "D0";
  62. case PowerDeviceD1:
  63. return "D1";
  64. case PowerDeviceD2:
  65. return "D2";
  66. case PowerDeviceD3:
  67. return "D3";
  68. case PowerDeviceMaximum:
  69. return "DX";
  70. }
  71. return "??";
  72. }
  73. #endif
  74. PHC_POWER_STATE
  75. USBPORT_GetHcPowerState(
  76. PDEVICE_OBJECT FdoDeviceObject,
  77. PHC_POWER_STATE_TABLE HcPowerStateTbl,
  78. SYSTEM_POWER_STATE SystemState
  79. )
  80. /*++
  81. Routine Description:
  82. For a given system power state return a pointer to
  83. the hc power state stored in the device extension.
  84. Arguments:
  85. Return Value:
  86. NTSTATUS
  87. --*/
  88. {
  89. PDEVICE_EXTENSION devExt;
  90. PHC_POWER_STATE powerState;
  91. ULONG i;
  92. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  93. ASSERT_FDOEXT(devExt);
  94. powerState = NULL;
  95. for (i=0; i<USBPORT_MAPPED_SLEEP_STATES; i++) {
  96. if (HcPowerStateTbl->PowerState[i].SystemState ==
  97. SystemState) {
  98. powerState = &HcPowerStateTbl->PowerState[i];
  99. break;
  100. }
  101. }
  102. USBPORT_ASSERT(powerState != NULL);
  103. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'ghcP', 0, powerState, 0);
  104. return powerState;
  105. }
  106. VOID
  107. USBPORT_ComputeHcPowerStates(
  108. PDEVICE_OBJECT FdoDeviceObject,
  109. PDEVICE_CAPABILITIES HcDeviceCaps,
  110. PHC_POWER_STATE_TABLE HcPowerStateTbl
  111. )
  112. /*++
  113. Routine Description:
  114. Using the HC capabilities reported by the parent bus compute
  115. the host controllers power attributes.
  116. Power attributes are defined as follows:
  117. { attributes }
  118. | SystemState | DeviceState | Powered? | Wake? |
  119. +-------------+---------------+------------+--------+
  120. S1-S4 D0-D3 Y/N Y/N
  121. The table includes entries for every possible system sleep state
  122. the OS may ask us to enter.
  123. (S1) PowerSystemSleeping1
  124. (S2) PowerSystemSleeping2
  125. (S3) PowerSystemSleeping3
  126. (S4) PowerSystemHibernate
  127. We have four possible cases for each sleep state:
  128. Powered? Wake?
  129. case 1 Y Y
  130. case 2 N N
  131. case 3 Y N
  132. *case 4 N Y
  133. currently we only support cases 1 & 2 but we recognize all 4
  134. in the event we need to support them all.
  135. In reality there exists a lot of case 3 but we currently have
  136. no way to detect it.
  137. Arguments:
  138. Return Value:
  139. none
  140. --*/
  141. {
  142. SYSTEM_POWER_STATE s;
  143. ULONG i;
  144. SYSTEM_POWER_STATE systemWake;
  145. DEVICE_POWER_STATE deviceWake;
  146. PAGED_CODE();
  147. systemWake = HcDeviceCaps->SystemWake;
  148. deviceWake = HcDeviceCaps->DeviceWake;
  149. // The HC can wake the system for any sleep state lighter (<=)
  150. // systemWake
  151. // iniialize the table
  152. s = PowerSystemSleeping1;
  153. for (i=0; i<USBPORT_MAPPED_SLEEP_STATES; i++) {
  154. HcPowerStateTbl->PowerState[i].SystemState = s;
  155. HcPowerStateTbl->PowerState[i].DeviceState =
  156. HcDeviceCaps->DeviceState[s];
  157. // it follows that if the map indicates that the DeviceState
  158. // is D3 but the system state is still <= SystemWake then the
  159. // hc is still powered
  160. if (s <= systemWake) {
  161. if (HcDeviceCaps->DeviceState[s] == PowerDeviceUnspecified) {
  162. // for unspecified we go with case 2, ie no power
  163. // case 2
  164. HcPowerStateTbl->PowerState[i].Attributes =
  165. HcPower_N_Wakeup_N;
  166. } else {
  167. // case 1
  168. HcPowerStateTbl->PowerState[i].Attributes =
  169. HcPower_Y_Wakeup_Y;
  170. }
  171. } else {
  172. if (HcDeviceCaps->DeviceState[s] == PowerDeviceD3 ||
  173. HcDeviceCaps->DeviceState[s] == PowerDeviceUnspecified) {
  174. // case 2
  175. HcPowerStateTbl->PowerState[i].Attributes =
  176. HcPower_N_Wakeup_N;
  177. } else {
  178. //
  179. // case 3
  180. HcPowerStateTbl->PowerState[i].Attributes =
  181. HcPower_Y_Wakeup_N;
  182. }
  183. }
  184. // 330157
  185. // disable wake from s4 since we do not support it yet
  186. //if (s == PowerSystemHibernate) {
  187. // HcPowerStateTbl->PowerState[i].Attributes =
  188. // HcPower_N_Wakeup_N;
  189. //}
  190. s++;
  191. }
  192. USBPORT_ASSERT(s == PowerSystemShutdown);
  193. }
  194. VOID
  195. USBPORT_ComputeRootHubDeviceCaps(
  196. PDEVICE_OBJECT FdoDeviceObject,
  197. PDEVICE_OBJECT PdoDeviceObject
  198. )
  199. /*++
  200. Routine Description:
  201. Attempt to create the root hub
  202. Power Summary:
  203. <Gloassary>
  204. Lightest - PowerDeviceD0, PowerSystemWorking
  205. Deepest - PowerDeviceD3, PowerSystemHibernate
  206. SystemWake - this is defined to be the 'deepest' System state in which
  207. the hardware can wake the system.
  208. DeviceWake -
  209. DeviceState[] - map of system states and the corresponding D states
  210. these are the states the HW is in for any given
  211. System Sleep state.
  212. HostControllerPowerAttributes - we define our own structure to describe
  213. the attributes of a host comtroller -- this allows us to
  214. map all possible controller scenarios on to the messed
  215. up WDM power rules.
  216. Arguments:
  217. Return Value:
  218. NTSTATUS
  219. --*/
  220. {
  221. PDEVICE_CAPABILITIES hcDeviceCaps, rhDeviceCaps;
  222. PDEVICE_EXTENSION rhDevExt, devExt;
  223. BOOLEAN wakeupSupport;
  224. SYSTEM_POWER_STATE s;
  225. PAGED_CODE();
  226. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  227. ASSERT_FDOEXT(devExt);
  228. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  229. ASSERT_PDOEXT(rhDevExt);
  230. hcDeviceCaps = &devExt->DeviceCapabilities;
  231. rhDeviceCaps = &rhDevExt->DeviceCapabilities;
  232. // do we wish to support wakeup?
  233. // if the USBPORT_FDOFLAG_ENABLE_SYSTEM_WAKE flag NOT is set
  234. // then wakeup is disabled and the HC power attributes have been
  235. // modified to reflect this.
  236. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_ENABLE_SYSTEM_WAKE)) {
  237. wakeupSupport = TRUE;
  238. } else {
  239. // wakeup is disabled
  240. USBPORT_KdPrint((1, " USB SYSTEM WAKEUP is Disabled\n"));
  241. wakeupSupport = FALSE;
  242. }
  243. #if DBG
  244. if (wakeupSupport) {
  245. USBPORT_KdPrint((1, " USB SYSTEM WAKEUP is Supported\n"));
  246. } else {
  247. USBPORT_KdPrint((1, " USB SYSTEM WAKEUP is NOT Supported\n"));
  248. }
  249. #endif
  250. // clone capabilities from the HC
  251. RtlCopyMemory(rhDeviceCaps,
  252. hcDeviceCaps,
  253. sizeof(DEVICE_CAPABILITIES));
  254. // construct the root hub device capabilities
  255. // root hub is not removable
  256. rhDeviceCaps->Removable=FALSE;
  257. rhDeviceCaps->UniqueID=FALSE;
  258. rhDeviceCaps->Address = 0;
  259. rhDeviceCaps->UINumber = 0;
  260. // for the root hub D2 translates to 'USB suspend'
  261. // so we always indicate we can wake from D2
  262. rhDeviceCaps->DeviceWake = PowerDeviceD2;
  263. rhDeviceCaps->WakeFromD0 = TRUE;
  264. rhDeviceCaps->WakeFromD1 = FALSE;
  265. rhDeviceCaps->WakeFromD2 = TRUE;
  266. rhDeviceCaps->WakeFromD3 = FALSE;
  267. rhDeviceCaps->DeviceD2 = TRUE;
  268. rhDeviceCaps->DeviceD1 = FALSE;
  269. // generate the root hub power capabilities from the
  270. // HC Power Attributes plus a little magic
  271. USBPORT_ASSERT(rhDeviceCaps->SystemWake >= PowerSystemUnspecified &&
  272. rhDeviceCaps->SystemWake <= PowerSystemMaximum);
  273. rhDeviceCaps->SystemWake =
  274. (PowerSystemUnspecified == rhDeviceCaps->SystemWake) ?
  275. PowerSystemWorking :
  276. rhDeviceCaps->SystemWake;
  277. for (s=PowerSystemSleeping1; s<=PowerSystemHibernate; s++) {
  278. PHC_POWER_STATE hcPowerState;
  279. hcPowerState = USBPORT_GetHcPowerState(FdoDeviceObject,
  280. &devExt->Fdo.HcPowerStateTbl,
  281. s);
  282. if (hcPowerState != NULL) {
  283. switch (hcPowerState->Attributes) {
  284. case HcPower_Y_Wakeup_Y:
  285. rhDeviceCaps->DeviceState[s] = PowerDeviceD2;
  286. break;
  287. case HcPower_N_Wakeup_N:
  288. case HcPower_Y_Wakeup_N:
  289. case HcPower_N_Wakeup_Y:
  290. rhDeviceCaps->DeviceState[s] = PowerDeviceD3;
  291. break;
  292. }
  293. }
  294. }
  295. }
  296. NTSTATUS
  297. USBPORT_PoRequestCompletion(
  298. PDEVICE_OBJECT DeviceObject,
  299. UCHAR MinorFunction,
  300. POWER_STATE PowerState,
  301. PVOID Context,
  302. PIO_STATUS_BLOCK IoStatus
  303. )
  304. /*++
  305. Routine Description:
  306. Called when the Device Power State Irp we requested is completed.
  307. this is where we Call down the systemPowerIrp
  308. Arguments:
  309. DeviceObject - Pointer to the device object for the class device.
  310. DevicePowerState - The Dx that we are in/tagetted.
  311. Context - Driver defined context.
  312. IoStatus - The status of the IRP.
  313. Return Value:
  314. The function value is the final status from the operation.
  315. --*/
  316. {
  317. PIRP irp;
  318. PDEVICE_EXTENSION devExt;
  319. PDEVICE_OBJECT fdoDeviceObject = Context;
  320. NTSTATUS ntStatus = IoStatus->Status;
  321. // a call to this function basically tells us
  322. // that we are now in the requested D-state
  323. // we now finish the whole process by calling
  324. // down the original SysPower request to our
  325. // PDO
  326. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  327. ASSERT_FDOEXT(devExt);
  328. USBPORT_KdPrint((1,
  329. "PoRequestComplete fdo(%x) MN_SET_POWER DEV(%s)\n",
  330. fdoDeviceObject, D_State(PowerState.DeviceState)));
  331. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'PwCp', ntStatus,
  332. devExt->CurrentDevicePowerState, PowerState.DeviceState);
  333. // note that if the SetD0 has failed we do not attempt
  334. // to re-start the controller
  335. if (NT_SUCCESS(ntStatus)) {
  336. if (PowerState.DeviceState == PowerDeviceD0) {
  337. #ifdef XPSE
  338. {
  339. LARGE_INTEGER t, dt;
  340. // compute time to D0
  341. KeQuerySystemTime(&t);
  342. dt.QuadPart = t.QuadPart - devExt->Fdo.D0ResumeTimeStart.QuadPart;
  343. devExt->Fdo.D0ResumeTime = (ULONG) (dt.QuadPart/10000);
  344. KeQuerySystemTime(&devExt->Fdo.ThreadResumeTimeStart);
  345. USBPORT_KdPrint((1, " D0ResumeTime %d ms %x %x\n",
  346. devExt->Fdo.D0ResumeTime,
  347. t.HighPart, t.LowPart));
  348. }
  349. #endif
  350. // defer start to our worker thread or workitem
  351. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_NEED_SET_POWER_D0);
  352. MP_FlushInterrupts(devExt);
  353. if (USBPORT_IS_USB20(devExt)) {
  354. MP_TakePortControl(devExt);
  355. }
  356. USBPORT_SignalWorker(fdoDeviceObject);
  357. // enable sligthtly faster completion of S irps
  358. USBPORT_QueuePowerWorkItem(fdoDeviceObject);
  359. // on completion of this function the controller is
  360. // in D0, we may not have powered up yet though.
  361. devExt->CurrentDevicePowerState = PowerDeviceD0;
  362. } else {
  363. // we should not receive another power irp until
  364. // we make a call to PoStartNextPowerIrp so there
  365. // is no protection here.
  366. irp = devExt->SystemPowerIrp;
  367. devExt->SystemPowerIrp = NULL;
  368. USBPORT_ASSERT(irp != NULL);
  369. IoCopyCurrentIrpStackLocationToNext(irp);
  370. PoStartNextPowerIrp(irp);
  371. DECREMENT_PENDING_REQUEST_COUNT(fdoDeviceObject, irp);
  372. PoCallDriver(devExt->Fdo.TopOfStackDeviceObject,
  373. irp);
  374. devExt->CurrentDevicePowerState = PowerState.DeviceState;
  375. }
  376. } else {
  377. // try to complete the irp with an error but don't attempt
  378. // to power the bus
  379. irp = devExt->SystemPowerIrp;
  380. devExt->SystemPowerIrp = NULL;
  381. USBPORT_ASSERT(irp != NULL);
  382. IoCopyCurrentIrpStackLocationToNext(irp);
  383. PoStartNextPowerIrp(irp);
  384. DECREMENT_PENDING_REQUEST_COUNT(fdoDeviceObject, irp);
  385. // According to adriano 'S IRP should be immediately completed with
  386. // the same status as the D IRP in the failure case'
  387. // Since the method of handling this is not documented anywhere we will
  388. // go with what Adrian says.
  389. //
  390. // The fact that this request has failed will probably cause other
  391. // complaints
  392. irp->IoStatus.Status = ntStatus;
  393. IoCompleteRequest(irp,
  394. IO_NO_INCREMENT);
  395. //PoCallDriver(devExt->Fdo.TopOfStackDeviceObject,
  396. // irp);
  397. // set the system irp status
  398. // note that the current power state is now undefined
  399. }
  400. // Note that the status returned here does not matter, this routine
  401. // is called by the kernel (PopCompleteRequestIrp) when the irp
  402. // completes to PDO and this function ignores the returned status.
  403. // PopCompleteRequestIrp also immediatly frees the irp so we need
  404. // take care not to reference it after this routine has run.
  405. return ntStatus;
  406. }
  407. NTSTATUS
  408. USBPORT_FdoSystemPowerState(
  409. PDEVICE_OBJECT FdoDeviceObject,
  410. PIRP Irp
  411. )
  412. /*++
  413. Routine Description:
  414. Handle SystemPowerState Messages for the HC FDO
  415. Arguments:
  416. DeviceObject - pointer to a hcd device object (FDO)
  417. Irp - pointer to an I/O Request Packet
  418. Return Value:
  419. NT status code
  420. --*/
  421. {
  422. PIO_STACK_LOCATION irpStack;
  423. NTSTATUS ntStatus;
  424. PDEVICE_EXTENSION devExt;
  425. POWER_STATE powerState;
  426. SYSTEM_POWER_STATE requestedSystemState;
  427. PHC_POWER_STATE hcPowerState;
  428. irpStack = IoGetCurrentIrpStackLocation(Irp);
  429. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  430. ASSERT_FDOEXT(devExt);
  431. USBPORT_ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
  432. USBPORT_ASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
  433. USBPORT_ASSERT(irpStack->Parameters.Power.Type == SystemPowerState);
  434. requestedSystemState = irpStack->Parameters.Power.State.SystemState;
  435. USBPORT_KdPrint((1,
  436. "MJ_POWER HC fdo(%x) MN_SET_POWER SYS(%s)\n",
  437. FdoDeviceObject, S_State(requestedSystemState)));
  438. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'RspS', 0,
  439. FdoDeviceObject, requestedSystemState);
  440. // ** begin special case
  441. // OS may send us a power irps even if we are not 'started'. In this
  442. // case we just pass them on with 'STATUS_SUCCESS' since we don't
  443. // really need to do anything.
  444. if (!TEST_FLAG(devExt->PnpStateFlags, USBPORT_PNP_STARTED)) {
  445. // we should probably be in an 'Unspecified' power state.
  446. ntStatus = STATUS_SUCCESS;
  447. goto USBPORT_FdoSystemPowerState_Done;
  448. }
  449. // ** end special case
  450. // compute the appropriate D-state
  451. // remember the last 'sleep' system state we entered
  452. // for debugging
  453. if (requestedSystemState != PowerSystemWorking) {
  454. devExt->Fdo.LastSystemSleepState = requestedSystemState;
  455. }
  456. switch (requestedSystemState) {
  457. case PowerSystemWorking:
  458. //
  459. // go to 'ON'
  460. //
  461. powerState.DeviceState = PowerDeviceD0;
  462. #ifdef XPSE
  463. KeQuerySystemTime(&devExt->Fdo.S0ResumeTimeStart);
  464. #endif
  465. break;
  466. case PowerSystemShutdown:
  467. USBPORT_KdPrint((1, " >Shutdown HC Detected\n"));
  468. // For this driver this will always map to D3.
  469. //
  470. // this driver will only run on Win98gold or Win98se
  471. // to support USB2 controllers that don't have Legacy
  472. // BIOS.
  473. //
  474. // For Win98 Millenium or Win2k it doesn't matter if
  475. // the controllers have a BIOS since we never hand
  476. // control back to DOS.
  477. // not sure yet if it is legitimate to 'Wake' from shutdown
  478. // or how we are supposed to handle this. Some BIOSes Falsely
  479. // report that they can do this.
  480. powerState.DeviceState = PowerDeviceD3;
  481. USBPORT_TurnControllerOff(FdoDeviceObject);
  482. break;
  483. case PowerSystemHibernate:
  484. USBPORT_KdPrint((1, " >Hibernate HC Detected\n"));
  485. // powerState.DeviceState = PowerDeviceD3;
  486. //
  487. // USBPORT_TurnControllerOff(FdoDeviceObject);
  488. // break;
  489. case PowerSystemSleeping1:
  490. case PowerSystemSleeping2:
  491. case PowerSystemSleeping3:
  492. {
  493. PDEVICE_EXTENSION rhDevExt;
  494. USBPORT_ASSERT(devExt->Fdo.RootHubPdo != NULL);
  495. GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
  496. ASSERT_PDOEXT(rhDevExt);
  497. USBPORT_KdPrint((1, " >Sleeping Detected\n"));
  498. //
  499. // Take action based on what happens to the controller
  500. // in the requested S state. This minimizes the chance
  501. // of confusing the Hub driver or other USB devices/drivers.
  502. // It also speeds up the resume process.
  503. // get our power info summary
  504. hcPowerState = USBPORT_GetHcPowerState(FdoDeviceObject,
  505. &devExt->Fdo.HcPowerStateTbl,
  506. requestedSystemState);
  507. // keep lint tools happy.
  508. if (hcPowerState == NULL) {
  509. return STATUS_UNSUCCESSFUL;
  510. }
  511. // get the current power state of the root hub
  512. if (rhDevExt->CurrentDevicePowerState == PowerDeviceD2 ||
  513. rhDevExt->CurrentDevicePowerState == PowerDeviceD1) {
  514. USBPORT_ASSERT(hcPowerState->Attributes == HcPower_Y_Wakeup_Y ||
  515. hcPowerState->Attributes == HcPower_Y_Wakeup_N);
  516. // take action on the controller
  517. USBPORT_SuspendController(FdoDeviceObject);
  518. // it is 'impure' for the controller to interrupt while in a
  519. // low power state so if we suspended it we disable interrupts now.
  520. // The presence of a wake IRP should enable the PME that wakes
  521. // the system.
  522. // **We disable here so that we don't take a resume interrupt from
  523. // the controller while going into suspend
  524. if (hcPowerState->DeviceState != PowerDeviceD0) {
  525. MP_DisableInterrupts(FdoDeviceObject, devExt);
  526. }
  527. // select the D state for the HC
  528. powerState.DeviceState = hcPowerState->DeviceState;
  529. // if the root hub is enabled for wakeup and this this
  530. // system state supports it then mark the controller as
  531. // 'enabled' for wake.
  532. if (USBPORT_RootHubEnabledForWake(FdoDeviceObject) &&
  533. hcPowerState->Attributes == HcPower_Y_Wakeup_Y) {
  534. DEBUG_BREAK();
  535. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_WAKE_ENABLED);
  536. if (hcPowerState->DeviceState == PowerDeviceD0) {
  537. USBPORT_ArmHcForWake(FdoDeviceObject);
  538. USBPORT_Wait(FdoDeviceObject, 100);
  539. }
  540. }
  541. } else {
  542. // if the controller remains powered then it is optimal
  543. // to 'suspend' otherwise we must turn it off
  544. // always 'suspend' the USB 2 controller, this will hopefuly
  545. // keep us from restting the CC in the case where a device
  546. // on the CC is enabled for wake for a the 20 controller is
  547. // not
  548. if ((hcPowerState->Attributes == HcPower_Y_Wakeup_Y ||
  549. hcPowerState->Attributes == HcPower_Y_Wakeup_N ||
  550. USBPORT_IS_USB20(devExt)) &&
  551. !TEST_FLAG(rhDevExt->PnpStateFlags, USBPORT_PNP_REMOVED)) {
  552. USBPORT_SuspendController(FdoDeviceObject);
  553. powerState.DeviceState = hcPowerState->DeviceState;
  554. if (USBPORT_IS_USB20(devExt) &&
  555. powerState.DeviceState == PowerDeviceUnspecified) {
  556. // if no state specified go to D3
  557. powerState.DeviceState = PowerDeviceD3;
  558. }
  559. // clear the IRQ enabled flag since it is invalid for
  560. // the hardware to interrupt in any state but D0
  561. // it is 'impure' for the controller to interrupt while in a
  562. // low power state so if we suspended it we disable interrupts now.
  563. // The presence of a wake IRP should enable the PME that wakes
  564. // the system.
  565. // **We disable here so that we don't take a resume interrupt from
  566. // the controller while going into suspend
  567. MP_DisableInterrupts(FdoDeviceObject, devExt);
  568. } else {
  569. USBPORT_TurnControllerOff(FdoDeviceObject);
  570. powerState.DeviceState = PowerDeviceD3;
  571. }
  572. }
  573. } // PowerSystemSleepingX
  574. break;
  575. default:
  576. // This is the case where the requested system state is unkown
  577. // to us. It not clear what to do here.
  578. // Vince sez try to ignore it so we will
  579. powerState.DeviceState = devExt->CurrentDevicePowerState;
  580. //powerState.DeviceState = PowerDeviceD3;
  581. //USBPORT_TurnControllerOff(FdoDeviceObject);
  582. DEBUG_BREAK();
  583. }
  584. //
  585. // now based on the D state request a Power irp
  586. // if necessary
  587. //
  588. //
  589. // are we already in this state?
  590. //
  591. // Note: if we get a D3 request before we are started
  592. // we don't need to pass the irp down to turn us off
  593. // we consider the controller initially off until we
  594. // get start.
  595. //
  596. if (devExt->CurrentDevicePowerState != powerState.DeviceState) {
  597. // No,
  598. // now allocate another irp and use PoCallDriver
  599. // to send it to ourselves
  600. IoMarkIrpPending(Irp);
  601. // remember the system power irp, we should
  602. // not receive another power irp until we
  603. // make a call to PoStartNextPowerIrp so there
  604. // is no protection here.
  605. USBPORT_ASSERT(devExt->SystemPowerIrp == NULL);
  606. devExt->SystemPowerIrp = Irp;
  607. USBPORT_KdPrint((1, " >Requesting HC D-State - %s\n",
  608. D_State(powerState.DeviceState)));
  609. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'RqPw', FdoDeviceObject,
  610. devExt->CurrentDevicePowerState, powerState.DeviceState);
  611. #ifdef XPSE
  612. KeQuerySystemTime(&devExt->Fdo.D0ResumeTimeStart);
  613. #endif
  614. ntStatus =
  615. PoRequestPowerIrp(devExt->Fdo.PhysicalDeviceObject,
  616. IRP_MN_SET_POWER,
  617. powerState,
  618. USBPORT_PoRequestCompletion,
  619. FdoDeviceObject,
  620. NULL);
  621. // hardcode STATUS_PENDING so that it is is returned
  622. // by the Dispatch routine
  623. // can we rely on what PoRequestPowerIrp returns?
  624. ntStatus = STATUS_PENDING;
  625. } else {
  626. // Yes,
  627. // We are already in the requested D state
  628. // just pass this irp along
  629. if (powerState.DeviceState == PowerDeviceD0) {
  630. MP_EnableInterrupts(devExt);
  631. }
  632. ntStatus = STATUS_SUCCESS;
  633. }
  634. USBPORT_FdoSystemPowerState_Done:
  635. return ntStatus;
  636. }
  637. NTSTATUS
  638. USBPORT_FdoDevicePowerState(
  639. PDEVICE_OBJECT FdoDeviceObject,
  640. PIRP Irp
  641. )
  642. /*++
  643. Routine Description:
  644. Handle DevicePowerState Messages for the HC FDO
  645. Arguments:
  646. DeviceObject - pointer to a hcd device object (FDO)
  647. Irp - pointer to an I/O Request Packet
  648. Return Value:
  649. NT status code
  650. returning STATUS_PENDING indicates that the Irp should
  651. not be called down to the PDO yet.
  652. --*/
  653. {
  654. PIO_STACK_LOCATION irpStack;
  655. NTSTATUS ntStatus;
  656. PDEVICE_EXTENSION devExt;
  657. POWER_STATE powerState;
  658. DEVICE_POWER_STATE requestedDeviceState;
  659. irpStack = IoGetCurrentIrpStackLocation(Irp);
  660. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  661. ASSERT_FDOEXT(devExt);
  662. USBPORT_ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
  663. USBPORT_ASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
  664. USBPORT_ASSERT(irpStack->Parameters.Power.Type == DevicePowerState);
  665. requestedDeviceState = irpStack->Parameters.Power.State.SystemState;
  666. USBPORT_KdPrint((1,
  667. "MJ_POWER HC fdo(%x) MN_SET_POWER DEV(%s)\n",
  668. FdoDeviceObject, D_State(requestedDeviceState)));
  669. switch (requestedDeviceState) {
  670. case PowerDeviceD0:
  671. // we cannot enter D0 until we pass the power irp
  672. // down to our parent BUS. return success here - we
  673. // will turn the controller on from the completion
  674. // routine of the original request for this power
  675. // irp
  676. ntStatus = STATUS_SUCCESS;
  677. break;
  678. case PowerDeviceD1:
  679. case PowerDeviceD2:
  680. case PowerDeviceD3:
  681. // we took action when we received the SystemPowerMessage
  682. // because thats when we know what the state of the HW will be.
  683. // it is 'impure' for the controller to interrupt while in a
  684. // low power state so if we suspended it we disable interrupts now.
  685. // The presence of a wake IRP should enable the PME that wakes
  686. // the system.
  687. MP_DisableInterrupts(FdoDeviceObject, devExt);
  688. //
  689. if (USBPORT_IS_USB20(devExt)) {
  690. PDEVICE_RELATIONS devR;
  691. // set magic count to number of CCs plus usb2 controller
  692. devR = USBPORT_FindCompanionControllers(FdoDeviceObject,
  693. FALSE,
  694. FALSE);
  695. devExt->Fdo.DependentControllers = 0;
  696. if (devR) {
  697. devExt->Fdo.DependentControllers = devR->Count + 1;
  698. FREE_POOL(FdoDeviceObject, devR);
  699. }
  700. }
  701. // if wakeup is enabled (on the root hub PDO) then we will
  702. // enable on the platform before entering the low
  703. // power state.
  704. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_WAKE_ENABLED)) {
  705. USBPORT_ArmHcForWake(FdoDeviceObject);
  706. }
  707. ntStatus = STATUS_SUCCESS;
  708. break;
  709. case PowerDeviceUnspecified:
  710. // for unspecified we will turn the HW off -- I'm not sure we
  711. // will ever see this since the D messages originate from us.
  712. USBPORT_TurnControllerOff(FdoDeviceObject);
  713. ntStatus = STATUS_SUCCESS;
  714. break;
  715. default:
  716. ntStatus = STATUS_UNSUCCESSFUL;
  717. }
  718. return ntStatus;
  719. }
  720. NTSTATUS
  721. USBPORT_FdoPowerIrp(
  722. PDEVICE_OBJECT FdoDeviceObject,
  723. PIRP Irp
  724. )
  725. /*++
  726. Routine Description:
  727. Process the Power IRPs sent to the FDO for the host
  728. controller.
  729. Arguments:
  730. DeviceObject - pointer to a hcd device object (FDO)
  731. Irp - pointer to an I/O Request Packet
  732. Return Value:
  733. NT status code
  734. --*/
  735. {
  736. PIO_STACK_LOCATION irpStack;
  737. NTSTATUS ntStatus;
  738. PDEVICE_EXTENSION devExt;
  739. irpStack = IoGetCurrentIrpStackLocation(Irp);
  740. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  741. ASSERT_FDOEXT(devExt);
  742. USBPORT_ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
  743. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'fPow', irpStack->MinorFunction,
  744. FdoDeviceObject, devExt->CurrentDevicePowerState);
  745. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'fpow',
  746. irpStack->Parameters.Others.Argument1, // WAIT_WAKE: PowerState
  747. irpStack->Parameters.Others.Argument2, // SET_POWER: Type
  748. irpStack->Parameters.Others.Argument3); // SET_POWER: State
  749. // map system state to D state
  750. switch (irpStack->MinorFunction) {
  751. case IRP_MN_WAIT_WAKE:
  752. USBPORT_KdPrint((1,
  753. "MJ_POWER HC fdo(%x) MN_WAIT_WAKE\n",
  754. FdoDeviceObject));
  755. ntStatus = USBPORT_ProcessHcWakeIrp(FdoDeviceObject, Irp);
  756. goto USBPORT_FdoPowerIrp_Done;
  757. break;
  758. case IRP_MN_SET_POWER:
  759. if (irpStack->Parameters.Power.Type == SystemPowerState) {
  760. ntStatus = USBPORT_FdoSystemPowerState(FdoDeviceObject, Irp);
  761. } else {
  762. ntStatus = USBPORT_FdoDevicePowerState(FdoDeviceObject, Irp);
  763. }
  764. if (ntStatus == STATUS_PENDING) {
  765. // we deferred to a completion routine
  766. // returned STATUS_PENDING and bail.
  767. goto USBPORT_FdoPowerIrp_Done;
  768. }
  769. break;
  770. case IRP_MN_QUERY_POWER:
  771. // we succeed all requests to enter low power
  772. // states for the HC fdo
  773. Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS;
  774. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'QpFD', 0, 0, ntStatus);
  775. USBPORT_KdPrint((1,
  776. "MJ_POWER HC fdo(%x) MN_QUERY_POWER\n",
  777. FdoDeviceObject));
  778. break;
  779. default:
  780. USBPORT_KdPrint((1,
  781. "MJ_POWER HC fdo(%x) MN_%d not handled\n",
  782. FdoDeviceObject,
  783. irpStack->MinorFunction));
  784. } /* irpStack->MinorFunction */
  785. IoCopyCurrentIrpStackLocationToNext(Irp);
  786. //
  787. // All PNP_POWER POWER messages get passed to the
  788. // top of the PDO stack we attached to when loaded
  789. //
  790. // In some cases we finish processing in a completion
  791. // routine
  792. //
  793. // pass on to our PDO
  794. DECREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, Irp);
  795. PoStartNextPowerIrp(Irp);
  796. ntStatus =
  797. PoCallDriver(devExt->Fdo.TopOfStackDeviceObject,
  798. Irp);
  799. USBPORT_FdoPowerIrp_Done:
  800. return ntStatus;
  801. }
  802. NTSTATUS
  803. USBPORT_PdoPowerIrp(
  804. PDEVICE_OBJECT PdoDeviceObject,
  805. PIRP Irp
  806. )
  807. /*++
  808. Routine Description:
  809. Disptach routine for Power Irps sent to the PDO for the root hub.
  810. NOTE:
  811. irps sent to the PDO are always completed by the bus driver
  812. Arguments:
  813. DeviceObject - Pdo for the root hub
  814. Return Value:
  815. NTSTATUS
  816. --*/
  817. {
  818. PIO_STACK_LOCATION irpStack;
  819. NTSTATUS ntStatus;
  820. PDEVICE_EXTENSION rhDevExt, devExt;
  821. PDEVICE_OBJECT fdoDeviceObject;
  822. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  823. ASSERT_PDOEXT(rhDevExt);
  824. fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
  825. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  826. ASSERT_FDOEXT(devExt);
  827. irpStack = IoGetCurrentIrpStackLocation (Irp);
  828. USBPORT_ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
  829. // use whatever status is in the IRP by default
  830. ntStatus = Irp->IoStatus.Status;
  831. // PNP messages for the PDO created for the root hub
  832. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'pPow',
  833. irpStack->MinorFunction, PdoDeviceObject, ntStatus);
  834. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'ppow',
  835. irpStack->Parameters.Others.Argument1, // WAIT_WAKE: PowerState
  836. irpStack->Parameters.Others.Argument2, // SET_POWER: Type
  837. irpStack->Parameters.Others.Argument3); // SET_POWER: State
  838. switch (irpStack->MinorFunction) {
  839. case IRP_MN_WAIT_WAKE:
  840. USBPORT_KdPrint((1,
  841. "MJ_POWER RH pdo(%x) MN_WAIT_WAKE\n",
  842. PdoDeviceObject));
  843. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_ENABLE_SYSTEM_WAKE)) {
  844. KIRQL irql;
  845. PDRIVER_CANCEL cr;
  846. // we only support one wait_wake irp pending
  847. // in the root hub -- basically we have a pending
  848. // irp table with one entry
  849. ACQUIRE_WAKEIRP_LOCK(fdoDeviceObject, irql);
  850. cr = IoSetCancelRoutine(Irp, USBPORT_CancelPendingWakeIrp);
  851. USBPORT_ASSERT(cr == NULL);
  852. if (Irp->Cancel &&
  853. IoSetCancelRoutine(Irp, NULL)) {
  854. // irp was canceled and our cancel routine
  855. // did not run
  856. RELEASE_WAKEIRP_LOCK(fdoDeviceObject, irql);
  857. ntStatus = STATUS_CANCELLED;
  858. // no postartnextpowerIrp for waitwake
  859. goto USBPORT_PdoPowerIrp_Complete;
  860. } else {
  861. // cancel routine is set, if irp is canceled
  862. // the cancel routine will stall on the
  863. // WAKE_IRP_LOCK
  864. if (rhDevExt->Pdo.PendingWaitWakeIrp == NULL) {
  865. // keep the irp in our table, we take no
  866. // other action until we actully enter a
  867. // low power state.
  868. IoMarkIrpPending(Irp);
  869. rhDevExt->Pdo.PendingWaitWakeIrp = Irp;
  870. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'pWWi',
  871. Irp, 0, 0);
  872. ntStatus = STATUS_PENDING;
  873. RELEASE_WAKEIRP_LOCK(fdoDeviceObject, irql);
  874. goto USBPORT_PdoPowerIrp_Done;
  875. } else {
  876. // we already have a wake irp, complete this
  877. // one with STATUS_BUSY.
  878. // note that since it is not in our table if
  879. // the cancel routine is running (ie stalled
  880. // on the WAKEIRP_LOCK it will ignore the irp
  881. // when we release the lock.
  882. if (IoSetCancelRoutine(Irp, NULL) != NULL) {
  883. ntStatus = STATUS_DEVICE_BUSY;
  884. } else {
  885. // let the cancel routine complete it.
  886. RELEASE_WAKEIRP_LOCK(fdoDeviceObject, irql);
  887. goto USBPORT_PdoPowerIrp_Done;
  888. }
  889. }
  890. RELEASE_WAKEIRP_LOCK(fdoDeviceObject, irql);
  891. }
  892. } else {
  893. ntStatus = STATUS_NOT_SUPPORTED;
  894. // no postartnextpowerIrp for waitwake
  895. goto USBPORT_PdoPowerIrp_Complete;
  896. }
  897. break;
  898. case IRP_MN_QUERY_POWER:
  899. ntStatus = STATUS_SUCCESS;
  900. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'RqrP', 0, 0, ntStatus);
  901. USBPORT_KdPrint((1,
  902. "MJ_POWER RH pdo(%x) MN_QUERY_POWER\n",
  903. PdoDeviceObject));
  904. break;
  905. case IRP_MN_SET_POWER:
  906. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'RspP', 0, 0,
  907. irpStack->Parameters.Power.Type);
  908. switch (irpStack->Parameters.Power.Type) {
  909. case SystemPowerState:
  910. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'RspS', 0, 0,
  911. irpStack->Parameters.Power.Type);
  912. //
  913. // since the fdo driver for the root hub pdo is our own
  914. // hub driver and it is well behaved, we don't expect to see
  915. // a system message where the power state is still undefined
  916. //
  917. // we just complete this with success
  918. //
  919. ntStatus = STATUS_SUCCESS;
  920. USBPORT_KdPrint((1,
  921. "MJ_POWER RH pdo(%x) MN_SET_POWER SYS(%s))\n",
  922. PdoDeviceObject,
  923. S_State(irpStack->Parameters.Power.State.SystemState)));
  924. break;
  925. case DevicePowerState:
  926. {
  927. DEVICE_POWER_STATE deviceState =
  928. irpStack->Parameters.Power.State.DeviceState;
  929. USBPORT_KdPrint((1,
  930. "MJ_POWER RH pdo(%x) MN_SET_POWER DEV(%s)\n",
  931. PdoDeviceObject,
  932. D_State(deviceState)));
  933. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'RspD', deviceState, 0,
  934. irpStack->Parameters.Power.Type);
  935. // Handle D states for the ROOT HUB Pdo:
  936. //
  937. // NOTE:
  938. // if the root hub is placed in D3 then it is considered OFF.
  939. //
  940. // if the root hub is placed in D2 or D1 then it is 'suspended',
  941. // the hub driver should not do this unless all the ports have
  942. // been selectively suspended first
  943. //
  944. // if the root hub is placed in D0 it is on
  945. //
  946. // We are not required to take any action here, however
  947. // this is where 'selective suspend' of the bus is handled
  948. //
  949. // For D1 - D3 we can tweak the host controller, ie stop
  950. // the schedule disable ints, etc. since it won't be in use
  951. // while the root hub PDO is suspended.
  952. //
  953. // Whatever we do to the controller here we need to be able to
  954. // recognize resume signalling.
  955. // assume success
  956. ntStatus = STATUS_SUCCESS;
  957. switch (deviceState) {
  958. case PowerDeviceD0:
  959. // re-activate controller if idle
  960. if (devExt->CurrentDevicePowerState != PowerDeviceD0) {
  961. // trap the condition in case this is our bug
  962. USBPORT_PowerFault(fdoDeviceObject,
  963. "controller not powered");
  964. // fail the request
  965. ntStatus = STATUS_UNSUCCESSFUL;
  966. } else {
  967. while (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_NEED_SET_POWER_D0)) {
  968. // wait for the driver thread to finsih
  969. // D0 processing
  970. USBPORT_Wait(fdoDeviceObject, 10);
  971. }
  972. USBPORT_ResumeController(fdoDeviceObject);
  973. rhDevExt->CurrentDevicePowerState = deviceState;
  974. //662596
  975. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_CC_LOCK) &&
  976. USBPORT_IS_USB20(devExt)) {
  977. USBPORT_KdPrint((1, " power 20 (release)\n"));
  978. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_CC_LOCK);
  979. KeReleaseSemaphore(&devExt->Fdo.CcLock,
  980. LOW_REALTIME_PRIORITY,
  981. 1,
  982. FALSE);
  983. }
  984. //662596
  985. USBPORT_CompletePdoWaitWake(fdoDeviceObject);
  986. // if we have an idle irp, complete it now
  987. USBPORT_CompletePendingIdleIrp(PdoDeviceObject);
  988. }
  989. break;
  990. case PowerDeviceD1:
  991. case PowerDeviceD2:
  992. case PowerDeviceD3:
  993. // suspend/idle the controller
  994. // The controller is only turned off and on by power
  995. // action to the FDO, suspend and resume are tied
  996. // to the root hub PDO.
  997. USBPORT_SuspendController(fdoDeviceObject);
  998. rhDevExt->CurrentDevicePowerState = deviceState;
  999. break;
  1000. case PowerDeviceUnspecified:
  1001. // do nothing
  1002. break;
  1003. }
  1004. }
  1005. break;
  1006. }
  1007. break;
  1008. default:
  1009. //
  1010. // default behavior for an unhandled Power irp is to return the
  1011. // status currently in the irp
  1012. // is this true for power?
  1013. USBPORT_KdPrint((1,
  1014. "MJ_POWER RH pdo(%x) MN_%d not handled\n",
  1015. PdoDeviceObject,
  1016. irpStack->MinorFunction));
  1017. } /* switch, POWER minor function */
  1018. // NOTE: for some reason we don't call PoStartnextPowerIrp for
  1019. // WaitWake Irps -- I guess they are not power irps
  1020. PoStartNextPowerIrp(Irp);
  1021. USBPORT_PdoPowerIrp_Complete:
  1022. USBPORT_CompleteIrp(PdoDeviceObject,
  1023. Irp,
  1024. ntStatus,
  1025. 0);
  1026. USBPORT_PdoPowerIrp_Done:
  1027. return ntStatus;
  1028. }
  1029. BOOLEAN
  1030. USBPORT_RootHubEnabledForWake(
  1031. PDEVICE_OBJECT FdoDeviceObject
  1032. )
  1033. /*++
  1034. Routine Description:
  1035. Arguments:
  1036. Return Value:
  1037. True if the root hub has been enabled for wake via
  1038. a waitwake irp.
  1039. --*/
  1040. {
  1041. BOOLEAN wakeEnabled;
  1042. PDEVICE_EXTENSION rhDevExt, devExt;
  1043. KIRQL irql;
  1044. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1045. ASSERT_FDOEXT(devExt);
  1046. GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
  1047. ASSERT_PDOEXT(rhDevExt);
  1048. ACQUIRE_WAKEIRP_LOCK(FdoDeviceObject, irql);
  1049. wakeEnabled = rhDevExt->Pdo.PendingWaitWakeIrp != NULL ? TRUE: FALSE;
  1050. RELEASE_WAKEIRP_LOCK(FdoDeviceObject, irql);
  1051. return wakeEnabled;
  1052. }
  1053. VOID
  1054. USBPORT_CancelPendingWakeIrp(
  1055. PDEVICE_OBJECT PdoDeviceObject,
  1056. PIRP CancelIrp
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. Handle Cancel for the root hub wake irp
  1061. Arguments:
  1062. Return Value:
  1063. none.
  1064. --*/
  1065. {
  1066. PDEVICE_EXTENSION rhDevExt, devExt;
  1067. PDEVICE_OBJECT fdoDeviceObject;
  1068. KIRQL irql;
  1069. // release cancel spinlock immediatly,
  1070. // we are protected by the WAKEIRP_LOCK
  1071. IoReleaseCancelSpinLock(CancelIrp->CancelIrql);
  1072. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  1073. ASSERT_PDOEXT(rhDevExt);
  1074. fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
  1075. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  1076. ASSERT_FDOEXT(devExt);
  1077. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'cnWW', fdoDeviceObject, CancelIrp, 0);
  1078. ACQUIRE_WAKEIRP_LOCK(fdoDeviceObject, irql);
  1079. USBPORT_ASSERT(rhDevExt->Pdo.PendingWaitWakeIrp == CancelIrp);
  1080. rhDevExt->Pdo.PendingWaitWakeIrp = NULL;
  1081. RELEASE_WAKEIRP_LOCK(fdoDeviceObject, irql);
  1082. USBPORT_CompleteIrp(PdoDeviceObject,
  1083. CancelIrp,
  1084. STATUS_CANCELLED,
  1085. 0);
  1086. }
  1087. VOID
  1088. USBPORT_CancelPendingIdleIrp(
  1089. PDEVICE_OBJECT PdoDeviceObject,
  1090. PIRP CancelIrp
  1091. )
  1092. /*++
  1093. Routine Description:
  1094. Handle Cancel for the root hub wake irp
  1095. Arguments:
  1096. Return Value:
  1097. --*/
  1098. {
  1099. PDEVICE_EXTENSION rhDevExt, devExt;
  1100. PDEVICE_OBJECT fdoDeviceObject;
  1101. KIRQL irql;
  1102. // release cancel spinlock immediatly,
  1103. // we are protected by the IDLEIRP_LOCK
  1104. IoReleaseCancelSpinLock(CancelIrp->CancelIrql);
  1105. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  1106. ASSERT_PDOEXT(rhDevExt);
  1107. fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
  1108. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  1109. ASSERT_FDOEXT(devExt);
  1110. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'cnIR', fdoDeviceObject, CancelIrp, 0);
  1111. ACQUIRE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1112. USBPORT_ASSERT(rhDevExt->Pdo.PendingIdleNotificationIrp == CancelIrp);
  1113. rhDevExt->Pdo.PendingIdleNotificationIrp = NULL;
  1114. CLEAR_PDO_FLAG(rhDevExt, USBPORT_PDOFLAG_HAVE_IDLE_IRP);
  1115. RELEASE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1116. USBPORT_CompleteIrp(PdoDeviceObject,
  1117. CancelIrp,
  1118. STATUS_CANCELLED,
  1119. 0);
  1120. }
  1121. VOID
  1122. USBPORT_TurnControllerOff(
  1123. PDEVICE_OBJECT FdoDeviceObject
  1124. )
  1125. /*++
  1126. Routine Description:
  1127. When we say OFF we mean OFF.
  1128. This is similar to a stop -- the mniport does not
  1129. know the difference. The port however does and
  1130. does not free the miniports resources
  1131. This function may be called multiple times ie even
  1132. if controller is already off with no ill effects.
  1133. Arguments:
  1134. DeviceObject - DeviceObject of the controller to turn off
  1135. Return Value:
  1136. this is NON FAILABLE.
  1137. --*/
  1138. {
  1139. PDEVICE_EXTENSION devExt;
  1140. KIRQL irql;
  1141. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1142. ASSERT_FDOEXT(devExt);
  1143. if (!TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_OFF)) {
  1144. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'Coff', 0, 0, 0);
  1145. USBPORT_KdPrint((1, " >Turning Controller OFF\n"));
  1146. DEBUG_BREAK();
  1147. // tell the DM tiner not to poll the controller
  1148. USBPORT_ACQUIRE_DM_LOCK(devExt, irql);
  1149. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_SKIP_TIMER_WORK);
  1150. USBPORT_RELEASE_DM_LOCK(devExt, irql);
  1151. if (TEST_FLAG(devExt->Fdo.MpStateFlags, MP_STATE_STARTED)) {
  1152. MP_DisableInterrupts(FdoDeviceObject, devExt);
  1153. CLEAR_FLAG(devExt->Fdo.MpStateFlags, MP_STATE_STARTED);
  1154. MP_StopController(devExt, TRUE);
  1155. }
  1156. USBPORT_NukeAllEndpoints(FdoDeviceObject);
  1157. // Off overrides suspended
  1158. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_SUSPENDED);
  1159. CLEAR_FLAG(devExt->Fdo.MpStateFlags, MP_STATE_SUSPENDED);
  1160. USBPORT_AcquireSpinLock(FdoDeviceObject,
  1161. &devExt->Fdo.CoreFunctionSpin, &irql);
  1162. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_OFF);
  1163. USBPORT_ReleaseSpinLock(FdoDeviceObject,
  1164. &devExt->Fdo.CoreFunctionSpin, irql);
  1165. }
  1166. }
  1167. VOID
  1168. USBPORT_RestoreController(
  1169. PDEVICE_OBJECT FdoDeviceObject
  1170. )
  1171. /*++
  1172. Routine Description:
  1173. Turns the controller back on to the 'suspended' state after a
  1174. power event.
  1175. Arguments:
  1176. DeviceObject - DeviceObject of the controller to turn off
  1177. Return Value:
  1178. none.
  1179. --*/
  1180. {
  1181. PDEVICE_EXTENSION devExt;
  1182. USB_MINIPORT_STATUS mpStatus;
  1183. PIRP irp;
  1184. KIRQL irql;
  1185. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1186. ASSERT_FDOEXT(devExt);
  1187. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'REST', devExt->SystemPowerIrp, 0, 0);
  1188. // call down the orginal system Power request
  1189. // no protection since we haven't
  1190. // called PoStartNextPowerIrp
  1191. irp = devExt->SystemPowerIrp;
  1192. devExt->SystemPowerIrp = NULL;
  1193. // we are now in D0, we must set the flag here
  1194. // because the PoCallDriver will initiate the
  1195. // power up for the root hub which checks the
  1196. // power state of the controller.
  1197. devExt->CurrentDevicePowerState = PowerDeviceD0;
  1198. MP_EnableInterrupts(devExt);
  1199. // we may not have a system power irp if the power
  1200. // up requested originated from wake completion so
  1201. // in this case we don't need to cal it down.
  1202. if (irp != NULL) {
  1203. IoCopyCurrentIrpStackLocationToNext(irp);
  1204. PoStartNextPowerIrp(irp);
  1205. DECREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, irp);
  1206. PoCallDriver(devExt->Fdo.TopOfStackDeviceObject,
  1207. irp);
  1208. }
  1209. }
  1210. VOID
  1211. USBPORT_TurnControllerOn(
  1212. PDEVICE_OBJECT FdoDeviceObject
  1213. )
  1214. /*++
  1215. Routine Description:
  1216. Similar to start -- but we already have our resources.
  1217. NOTE that the miniport activates as if it the system
  1218. was booted normally.
  1219. We only get here after the Set D0 request has been passed
  1220. to the parent bus.
  1221. Arguments:
  1222. DeviceObject - DeviceObject of the controller to turn off
  1223. Return Value:
  1224. NT status code.
  1225. --*/
  1226. {
  1227. PDEVICE_EXTENSION devExt;
  1228. PHC_RESOURCES hcResources;
  1229. USB_MINIPORT_STATUS mpStatus;
  1230. PIRP irp;
  1231. KIRQL irql;
  1232. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1233. ASSERT_FDOEXT(devExt);
  1234. hcResources = &devExt->Fdo.HcResources;
  1235. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'C_on', 0, 0, 0);
  1236. DEBUG_BREAK();
  1237. // zero the controller extension
  1238. RtlZeroMemory(devExt->Fdo.MiniportDeviceData,
  1239. devExt->Fdo.MiniportDriver->RegistrationPacket.DeviceDataSize);
  1240. // zero miniport common buffer
  1241. RtlZeroMemory(hcResources->CommonBufferVa,
  1242. REGISTRATION_PACKET(devExt).CommonBufferBytes);
  1243. // attempt to re-start the miniport
  1244. MP_StartController(devExt, hcResources, mpStatus);
  1245. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'mpRS', mpStatus, 0, 0);
  1246. if (mpStatus == USBMP_STATUS_SUCCESS) {
  1247. // controller started, set flag and begin passing
  1248. // interrupts to the miniport
  1249. SET_FLAG(devExt->Fdo.MpStateFlags, MP_STATE_STARTED);
  1250. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'rIRQ', mpStatus, 0, 0);
  1251. MP_EnableInterrupts(devExt);
  1252. USBPORT_ACQUIRE_DM_LOCK(devExt, irql);
  1253. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_SKIP_TIMER_WORK);
  1254. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_FAIL_URBS);
  1255. USBPORT_RELEASE_DM_LOCK(devExt, irql);
  1256. } else {
  1257. // failure on re-start?
  1258. TEST_TRAP();
  1259. }
  1260. // we are now in D0,
  1261. //
  1262. // since we don't hook the completion of the
  1263. // system power irp we will consider ourselves
  1264. // on at this point since we have already received
  1265. // the D0 completion.
  1266. devExt->CurrentDevicePowerState = PowerDeviceD0;
  1267. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_OFF);
  1268. // call down the orginal system Power request
  1269. // no protection since we haven't
  1270. // called PoStartNextPowerIrp
  1271. irp = devExt->SystemPowerIrp;
  1272. devExt->SystemPowerIrp = NULL;
  1273. // we may not have a system power irp if the power
  1274. // up requested originated from wake completion so
  1275. // in this case we don't need to cal it down.
  1276. if (irp != NULL) {
  1277. IoCopyCurrentIrpStackLocationToNext(irp);
  1278. PoStartNextPowerIrp(irp);
  1279. DECREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, irp);
  1280. PoCallDriver(devExt->Fdo.TopOfStackDeviceObject,
  1281. irp);
  1282. }
  1283. }
  1284. VOID
  1285. USBPORT_SuspendController(
  1286. PDEVICE_OBJECT FdoDeviceObject
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. Suspends the USB Host controller
  1291. Arguments:
  1292. DeviceObject - DeviceObject of the controller to turn off
  1293. Return Value:
  1294. this is NON FAILABLE.
  1295. --*/
  1296. {
  1297. PDEVICE_EXTENSION devExt;
  1298. KIRQL irql;
  1299. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1300. ASSERT_FDOEXT(devExt);
  1301. // There should be no transfers on the HW at time of suspend.
  1302. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_FAIL_URBS);
  1303. USBPORT_FlushController(FdoDeviceObject);
  1304. // Our job here is to 'idle' controller and twiddle the
  1305. // appropriate bits to allow it to recognize resume signalling
  1306. USBPORT_ASSERT(!TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_OFF));
  1307. if (!TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_SUSPENDED)) {
  1308. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'Csus', 0, 0, 0);
  1309. USBPORT_KdPrint((1, " >SUSPEND controller\n"));
  1310. DEBUG_BREAK();
  1311. // tell the DM timer not to poll the controller
  1312. USBPORT_ACQUIRE_DM_LOCK(devExt, irql);
  1313. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_SKIP_TIMER_WORK);
  1314. USBPORT_RELEASE_DM_LOCK(devExt, irql);
  1315. if (TEST_FLAG(devExt->Fdo.MpStateFlags, MP_STATE_STARTED)) {
  1316. SET_FLAG(devExt->Fdo.MpStateFlags, MP_STATE_SUSPENDED);
  1317. // introduce a 10ms wait here to allow any
  1318. // port suspends to finish
  1319. USBPORT_Wait(FdoDeviceObject, 10);
  1320. // BUGBUG HP ia64 fix
  1321. // we cannot suspend until we finish notifying the companions
  1322. // that it is OK to start
  1323. if (USBPORT_IS_USB20(devExt)) {
  1324. // we cannot suspend until we finish notifying the companions
  1325. // that it is OK to start
  1326. InterlockedDecrement(&devExt->Fdo.PendingRhCallback);
  1327. while (devExt->Fdo.PendingRhCallback) {
  1328. USBPORT_Wait(FdoDeviceObject, 10);
  1329. }
  1330. // reset the counter for the next time through
  1331. devExt->Fdo.PendingRhCallback = 1;
  1332. KeWaitForSingleObject(&devExt->Fdo.CcLock,
  1333. Executive,
  1334. KernelMode,
  1335. FALSE,
  1336. NULL);
  1337. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_CC_LOCK);
  1338. }
  1339. MP_SuspendController(devExt);
  1340. if (USBPORT_IS_USB20(devExt)) {
  1341. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_CC_LOCK);
  1342. KeReleaseSemaphore(&devExt->Fdo.CcLock,
  1343. LOW_REALTIME_PRIORITY,
  1344. 1,
  1345. FALSE);
  1346. }
  1347. }
  1348. USBPORT_AcquireSpinLock(FdoDeviceObject,
  1349. &devExt->Fdo.CoreFunctionSpin, &irql);
  1350. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_SUSPENDED);
  1351. USBPORT_ReleaseSpinLock(FdoDeviceObject,
  1352. &devExt->Fdo.CoreFunctionSpin, irql);
  1353. }
  1354. }
  1355. VOID
  1356. USBPORT_ResumeController(
  1357. PDEVICE_OBJECT FdoDeviceObject
  1358. )
  1359. /*++
  1360. Routine Description:
  1361. Suspends the USB Host controller
  1362. Arguments:
  1363. DeviceObject - DeviceObject of the controller to turn off
  1364. Return Value:
  1365. this is NON FAILABLE.
  1366. --*/
  1367. {
  1368. PDEVICE_EXTENSION devExt;
  1369. KIRQL irql;
  1370. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1371. ASSERT_FDOEXT(devExt);
  1372. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_SUSPENDED)) {
  1373. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'Cres', 0, 0, 0);
  1374. USBPORT_KdPrint((1, " >RESUME controller\n"));
  1375. DEBUG_BREAK();
  1376. USBPORT_ACQUIRE_DM_LOCK(devExt, irql);
  1377. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_SKIP_TIMER_WORK);
  1378. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_FAIL_URBS);
  1379. USBPORT_RELEASE_DM_LOCK(devExt, irql);
  1380. USBPORT_ASSERT(!TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_OFF));
  1381. if (TEST_FLAG(devExt->Fdo.MpStateFlags, MP_STATE_SUSPENDED)) {
  1382. USB_MINIPORT_STATUS mpStatus;
  1383. CLEAR_FLAG(devExt->Fdo.MpStateFlags, MP_STATE_SUSPENDED);
  1384. MP_ResumeController(devExt, mpStatus);
  1385. if (mpStatus != USBMP_STATUS_SUCCESS) {
  1386. USBPORT_KdPrint((1, " >controller failed resume, re-start\n"));
  1387. USBPORT_ACQUIRE_DM_LOCK(devExt, irql);
  1388. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_SKIP_TIMER_WORK);
  1389. USBPORT_RELEASE_DM_LOCK(devExt, irql);
  1390. MP_DisableInterrupts(FdoDeviceObject, devExt);
  1391. MP_StopController(devExt, TRUE);
  1392. USBPORT_NukeAllEndpoints(FdoDeviceObject);
  1393. // zero the controller extension
  1394. RtlZeroMemory(devExt->Fdo.MiniportDeviceData,
  1395. devExt->Fdo.MiniportDriver->RegistrationPacket.DeviceDataSize);
  1396. // zero miniport common buffer
  1397. RtlZeroMemory(devExt->Fdo.HcResources.CommonBufferVa,
  1398. REGISTRATION_PACKET(devExt).CommonBufferBytes);
  1399. devExt->Fdo.HcResources.Restart = TRUE;
  1400. MP_StartController(devExt, &devExt->Fdo.HcResources, mpStatus);
  1401. devExt->Fdo.HcResources.Restart = FALSE;
  1402. if (mpStatus == USBMP_STATUS_SUCCESS) {
  1403. // don't need to enable interrupts if start failed
  1404. MP_EnableInterrupts(devExt);
  1405. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC)) {
  1406. // if this is a CC then power the ports here
  1407. USBPORT_KdPrint((1, " >power CC ports\n"));
  1408. USBPORT_RootHub_PowerAndChirpAllCcPorts(
  1409. FdoDeviceObject);
  1410. }
  1411. }
  1412. USBPORT_ACQUIRE_DM_LOCK(devExt, irql);
  1413. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_SKIP_TIMER_WORK);
  1414. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_FAIL_URBS);
  1415. USBPORT_RELEASE_DM_LOCK(devExt, irql);
  1416. }
  1417. // wait 100 after bus resume before allowing drivers to talk
  1418. // to the device. Unfortuantely many USB devices are busted
  1419. // and will not respond if accessed immediately after resume.
  1420. USBPORT_Wait(FdoDeviceObject, 100);
  1421. }
  1422. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_SUSPENDED);
  1423. }
  1424. }
  1425. VOID
  1426. USBPORT_DoIdleNotificationCallback(
  1427. PDEVICE_OBJECT PdoDeviceObject
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. Our mission here is to do the 'IdleNotification' callback if we have
  1432. an irp. The trick is to synchronize the callback with the cancel
  1433. routine ie we don't want the hub driver to cancel the irp and unload
  1434. while we are calling it back.
  1435. Arguments:
  1436. Return Value:
  1437. NTSTATUS
  1438. --*/
  1439. {
  1440. PIRP irp;
  1441. PDEVICE_EXTENSION rhDevExt, devExt;
  1442. PDEVICE_OBJECT fdoDeviceObject;
  1443. PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
  1444. KIRQL irql;
  1445. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  1446. ASSERT_PDOEXT(rhDevExt);
  1447. fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
  1448. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  1449. ASSERT_FDOEXT(devExt);
  1450. // cancel routine will stall here,
  1451. // if cancel is running we will stall here
  1452. ACQUIRE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1453. // remove the irp from the table so that the
  1454. // cancel routine cannot find it
  1455. irp = rhDevExt->Pdo.PendingIdleNotificationIrp;
  1456. rhDevExt->Pdo.PendingIdleNotificationIrp = NULL;
  1457. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'idCB', irp, 0, 0);
  1458. RELEASE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1459. // do the callback if we have an irp
  1460. if (irp != NULL) {
  1461. idleCallbackInfo = (PUSB_IDLE_CALLBACK_INFO)
  1462. IoGetCurrentIrpStackLocation(irp)->\
  1463. Parameters.DeviceIoControl.Type3InputBuffer;
  1464. USBPORT_ASSERT(idleCallbackInfo && idleCallbackInfo->IdleCallback);
  1465. if (idleCallbackInfo && idleCallbackInfo->IdleCallback) {
  1466. USBPORT_KdPrint((1, "-do idle callback\n"));
  1467. // the hub driver expects this to happen at passive level
  1468. ASSERT_PASSIVE();
  1469. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'doCB', irp, 0, 0);
  1470. idleCallbackInfo->IdleCallback(idleCallbackInfo->IdleContext);
  1471. }
  1472. // put the irp back in the table, if the cancel routine
  1473. // has run the IRP will be marked canceled
  1474. ACQUIRE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1475. if (irp->Cancel) {
  1476. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'caCB', irp, 0, 0);
  1477. CLEAR_PDO_FLAG(rhDevExt, USBPORT_PDOFLAG_HAVE_IDLE_IRP);
  1478. RELEASE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1479. USBPORT_CompleteIrp(PdoDeviceObject,
  1480. irp,
  1481. STATUS_CANCELLED,
  1482. 0);
  1483. } else {
  1484. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'rsCB', irp, 0, 0);
  1485. rhDevExt->Pdo.PendingIdleNotificationIrp = irp;
  1486. RELEASE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1487. }
  1488. }
  1489. }
  1490. NTSTATUS
  1491. USBPORT_IdleNotificationRequest(
  1492. PDEVICE_OBJECT PdoDeviceObject,
  1493. PIRP Irp
  1494. )
  1495. /*++
  1496. Routine Description:
  1497. Request by the hub driver to go 'idle' is suspend.
  1498. If we call the callback the hub will request a D2 power irp.
  1499. If we do not call the callback, now poer irp will be sent and
  1500. the bus will noy enter UsbSuspend.
  1501. We are required to sit on the Irp until canceled. We permit only
  1502. one 'selective suspend' IRP in the driver at a time.
  1503. NOTE: a possible optimization is to have the hub driver simply
  1504. not issue this IOCTL since it doesn't actualy do anything.
  1505. Arguments:
  1506. Return Value:
  1507. NTSTATUS
  1508. --*/
  1509. {
  1510. PIO_STACK_LOCATION irpStack;
  1511. NTSTATUS ntStatus = STATUS_BOGUS;
  1512. PDEVICE_EXTENSION rhDevExt, devExt;
  1513. PDEVICE_OBJECT fdoDeviceObject;
  1514. KIRQL irql;
  1515. PDRIVER_CANCEL cr;
  1516. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  1517. ASSERT_PDOEXT(rhDevExt);
  1518. fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
  1519. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  1520. ASSERT_FDOEXT(devExt);
  1521. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'iNOT', PdoDeviceObject, Irp, 0);
  1522. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1523. USBPORT_ASSERT(irpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
  1524. if (!TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_RH_CAN_SUSPEND)) {
  1525. // NOTE: This is where we override selective suspend
  1526. // ifthe HW (controller)
  1527. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'noSS', PdoDeviceObject, Irp, 0);
  1528. ntStatus = STATUS_NOT_SUPPORTED;
  1529. goto USBPORT_IdleNotificationRequest_Complete;
  1530. }
  1531. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_CONTROLLER_GONE)) {
  1532. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'gone', PdoDeviceObject, Irp, 0);
  1533. ntStatus = STATUS_DEVICE_NOT_CONNECTED;
  1534. goto USBPORT_IdleNotificationRequest_Complete;
  1535. }
  1536. // we only support one idle irp pending
  1537. // in the root hub -- basically we have a pending
  1538. // irp table with one entry
  1539. ACQUIRE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1540. cr = IoSetCancelRoutine(Irp, USBPORT_CancelPendingIdleIrp);
  1541. USBPORT_ASSERT(cr == NULL);
  1542. if (Irp->Cancel &&
  1543. IoSetCancelRoutine(Irp, NULL)) {
  1544. // irp was canceled and our cancel routine
  1545. // did not run
  1546. RELEASE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1547. ntStatus = STATUS_CANCELLED;
  1548. goto USBPORT_IdleNotificationRequest_Complete;
  1549. } else {
  1550. // cancel routine is set, if irp is canceled
  1551. // the cancel routine will stall on the
  1552. // IDLE_IRP_LOCK which we are holding
  1553. if (!TEST_PDO_FLAG(rhDevExt, USBPORT_PDOFLAG_HAVE_IDLE_IRP)) {
  1554. // keep the irp in our table
  1555. IoMarkIrpPending(Irp);
  1556. rhDevExt->Pdo.PendingIdleNotificationIrp = Irp;
  1557. SET_PDO_FLAG(rhDevExt, USBPORT_PDOFLAG_HAVE_IDLE_IRP);
  1558. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'pNOT', PdoDeviceObject, Irp, 0);
  1559. ntStatus = STATUS_PENDING;
  1560. RELEASE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1561. goto USBPORT_IdleNotificationRequest_Done;
  1562. } else {
  1563. // we already have a wake irp, complete this
  1564. // one with STATUS_BUSY.
  1565. // note that since it is not in our table if
  1566. // the cancel routine is running (ie stalled
  1567. // on the IDLEIRP_LOCK it will ignore the irp
  1568. // when we release the lock.
  1569. if (IoSetCancelRoutine(Irp, NULL) != NULL) {
  1570. // cancel routine did not run
  1571. ntStatus = STATUS_DEVICE_BUSY;
  1572. } else {
  1573. // let the cancel routine complete it.
  1574. IoMarkIrpPending(Irp);
  1575. ntStatus = STATUS_PENDING;
  1576. RELEASE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1577. goto USBPORT_IdleNotificationRequest_Done_NoCB;
  1578. }
  1579. }
  1580. RELEASE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1581. }
  1582. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'cpNT', PdoDeviceObject, Irp, ntStatus);
  1583. USBPORT_IdleNotificationRequest_Complete:
  1584. USBPORT_CompleteIrp(PdoDeviceObject,
  1585. Irp,
  1586. ntStatus,
  1587. 0);
  1588. USBPORT_IdleNotificationRequest_Done:
  1589. // now issue the callback immediatly if we have an irp
  1590. USBPORT_DoIdleNotificationCallback(PdoDeviceObject);
  1591. USBPORT_IdleNotificationRequest_Done_NoCB:
  1592. return ntStatus;
  1593. }
  1594. VOID
  1595. USBPORT_CompletePdoWaitWake(
  1596. PDEVICE_OBJECT FdoDeviceObject
  1597. )
  1598. /*++
  1599. Routine Description:
  1600. called when the root hub pdo has 'woke up'
  1601. Arguments:
  1602. Return Value:
  1603. none
  1604. --*/
  1605. {
  1606. PIRP irp;
  1607. PDEVICE_EXTENSION rhDevExt, devExt;
  1608. KIRQL irql;
  1609. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1610. ASSERT_FDOEXT(devExt);
  1611. GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
  1612. ASSERT_PDOEXT(rhDevExt);
  1613. ACQUIRE_WAKEIRP_LOCK(FdoDeviceObject, irql);
  1614. irp = rhDevExt->Pdo.PendingWaitWakeIrp;
  1615. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'WAKi', FdoDeviceObject, irp, 0);
  1616. if (irp != NULL &&
  1617. IoSetCancelRoutine(irp, NULL)) {
  1618. // we have an irp and the cancel routine has not
  1619. // run, complete the irp.
  1620. rhDevExt->Pdo.PendingWaitWakeIrp = NULL;
  1621. RELEASE_WAKEIRP_LOCK(FdoDeviceObject, irql);
  1622. // since this irp was sent to the PDO we
  1623. // complete it to the PDO
  1624. USBPORT_KdPrint((1, " Complete PDO Wake Irp %x\n", irp));
  1625. DEBUG_BREAK();
  1626. USBPORT_CompleteIrp(devExt->Fdo.RootHubPdo,
  1627. irp,
  1628. STATUS_SUCCESS,
  1629. 0);
  1630. } else {
  1631. RELEASE_WAKEIRP_LOCK(FdoDeviceObject, irql);
  1632. }
  1633. }
  1634. VOID
  1635. USBPORT_CompletePendingIdleIrp(
  1636. PDEVICE_OBJECT PdoDeviceObject
  1637. )
  1638. /*++
  1639. Routine Description:
  1640. If we have one complete the idle notification request
  1641. irp
  1642. Arguments:
  1643. Return Value:
  1644. --*/
  1645. {
  1646. PIRP irp;
  1647. PDEVICE_EXTENSION rhDevExt, devExt;
  1648. PDEVICE_OBJECT fdoDeviceObject;
  1649. KIRQL irql;
  1650. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  1651. ASSERT_PDOEXT(rhDevExt);
  1652. fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
  1653. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  1654. ASSERT_FDOEXT(devExt);
  1655. // cancel routine will stall here,
  1656. // if cancel is running we will stall here
  1657. ACQUIRE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1658. // remove the irp from the table so that the
  1659. // cancel routine cannot find it
  1660. irp = rhDevExt->Pdo.PendingIdleNotificationIrp;
  1661. LOGENTRY(NULL, fdoDeviceObject, LOG_POWER, 'idCP', irp, 0, 0);
  1662. rhDevExt->Pdo.PendingIdleNotificationIrp = NULL;
  1663. if (irp != NULL) {
  1664. CLEAR_PDO_FLAG(rhDevExt, USBPORT_PDOFLAG_HAVE_IDLE_IRP);
  1665. }
  1666. RELEASE_IDLEIRP_LOCK(fdoDeviceObject, irql);
  1667. // do the callback if we have an irp
  1668. if (irp != NULL) {
  1669. // we need to complete this Irp
  1670. IoSetCancelRoutine(irp, NULL);
  1671. USBPORT_KdPrint((1, "-complete idle irp\n"));
  1672. USBPORT_CompleteIrp(PdoDeviceObject,
  1673. irp,
  1674. STATUS_SUCCESS,
  1675. 0);
  1676. }
  1677. }
  1678. NTSTATUS
  1679. USBPORT_ProcessHcWakeIrp(
  1680. PDEVICE_OBJECT FdoDeviceObject,
  1681. PIRP Irp
  1682. )
  1683. /*++
  1684. Routine Description:
  1685. Process the HC wake irp
  1686. Arguments:
  1687. Return Value:
  1688. --*/
  1689. {
  1690. PDEVICE_EXTENSION devExt;
  1691. USBHC_WAKE_STATE oldWakeState;
  1692. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1693. ASSERT_FDOEXT(devExt);
  1694. devExt->Fdo.HcPendingWakeIrp = Irp;
  1695. // Advance the state if the armed if we are to proceed
  1696. oldWakeState = InterlockedCompareExchange( (PULONG) &devExt->Fdo.HcWakeState,
  1697. HCWAKESTATE_ARMED,
  1698. HCWAKESTATE_WAITING );
  1699. if (oldWakeState == HCWAKESTATE_WAITING_CANCELLED) {
  1700. // We got disarmed, finish up and complete the IRP
  1701. devExt->Fdo.HcWakeState = HCWAKESTATE_COMPLETING;
  1702. DECREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, Irp);
  1703. Irp->IoStatus.Status = STATUS_CANCELLED;
  1704. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1705. return STATUS_CANCELLED;
  1706. }
  1707. // We went from WAITING to ARMED. Set a completion routine and forward
  1708. // the IRP. Note that our completion routine might complete the IRP
  1709. // asynchronously, so we mark the IRP pending
  1710. IoMarkIrpPending(Irp);
  1711. IoCopyCurrentIrpStackLocationToNext( Irp );
  1712. IoSetCompletionRoutine( Irp,
  1713. USBPORT_HcWakeIrp_Io_Completion,
  1714. NULL,
  1715. TRUE,
  1716. TRUE,
  1717. TRUE);
  1718. DECREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, Irp);
  1719. PoCallDriver(devExt->Fdo.TopOfStackDeviceObject,
  1720. Irp);
  1721. return STATUS_PENDING;
  1722. }
  1723. NTSTATUS
  1724. USBPORT_HcWakeIrp_Io_Completion(
  1725. PDEVICE_OBJECT DeviceObject,
  1726. PIRP Irp,
  1727. PVOID Context
  1728. )
  1729. /*++
  1730. Routine Description:
  1731. Called when the HC wake irp completes we use this to hook completion
  1732. so we can handle the cancel
  1733. This routine runs before the USBPORT_USBPORT_HcWakeIrp_Po_Completion
  1734. Arguments:
  1735. Return Value:
  1736. The function value is the final status from the operation.
  1737. --*/
  1738. {
  1739. PIRP irp;
  1740. PDEVICE_EXTENSION devExt;
  1741. USBHC_WAKE_STATE oldWakeState;
  1742. GET_DEVICE_EXT(devExt, DeviceObject);
  1743. ASSERT_FDOEXT(devExt);
  1744. // Advance the state to completing
  1745. oldWakeState = InterlockedExchange( (PULONG) &devExt->Fdo.HcWakeState,
  1746. HCWAKESTATE_COMPLETING );
  1747. if (oldWakeState == HCWAKESTATE_ARMED) {
  1748. // Normal case, IoCancelIrp isn�t being called. Note that we already
  1749. // marked the IRP pending in our dispatch routine
  1750. return STATUS_SUCCESS;
  1751. } else {
  1752. ASSERT(oldWakeState == HCWAKESTATE_ARMING_CANCELLED);
  1753. // IoCancelIrp is being called RIGHT NOW. The disarm code will try
  1754. // to put back the WAKESTATE_ARMED state. It will then see our
  1755. // WAKESTATE_COMPLETED value, and complete the IRP itself!
  1756. return STATUS_MORE_PROCESSING_REQUIRED;
  1757. }
  1758. }
  1759. NTSTATUS
  1760. USBPORT_HcWakeIrp_Po_Completion(
  1761. PDEVICE_OBJECT DeviceObject,
  1762. UCHAR MinorFunction,
  1763. POWER_STATE DeviceState,
  1764. PVOID Context,
  1765. PIO_STATUS_BLOCK IoStatus
  1766. )
  1767. /*++
  1768. Routine Description:
  1769. Called when a wake irp completes for the controller
  1770. Arguments:
  1771. DeviceObject - Pointer to the device object for the class device.
  1772. Irp - Irp completed.
  1773. Context - Driver defined context.
  1774. Return Value:
  1775. STATUS_MORE_PROCESSING_REQUIRED - stalls completion of the irp.
  1776. --*/
  1777. {
  1778. NTSTATUS poNtStatus;
  1779. PDEVICE_EXTENSION devExt = Context;
  1780. KIRQL irql;
  1781. POWER_STATE powerState;
  1782. USBPORT_KdPrint((1,
  1783. "HcWakeIrpCompletion (%x)\n", IoStatus->Status));
  1784. LOGENTRY(NULL, devExt->HcFdoDeviceObject, LOG_POWER, 'WAKc',
  1785. devExt, IoStatus->Status, 0);
  1786. //
  1787. // Zero already freed IRP pointer (not necessary, but nice when debugging)
  1788. //
  1789. devExt->Fdo.HcPendingWakeIrp = NULL;
  1790. //
  1791. // Restore state (old state will have been completing)
  1792. //
  1793. devExt->Fdo.HcWakeState = HCWAKESTATE_DISARMED;
  1794. if (IoStatus->Status == STATUS_SUCCESS) {
  1795. LOGENTRY(NULL, devExt->HcFdoDeviceObject, LOG_POWER, 'WAK0', 0, 0, 0);
  1796. // a successful completion of the wake Irp means something
  1797. // generated resume signalling
  1798. // The idea here is that we won't have a wake irp down
  1799. // unless we are in some D state other than D0. Remember
  1800. // this is the controller FDO not the root hub.
  1801. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_RESUME_SIGNALLING);
  1802. // we canceled the wake irp when entering D0 so we should
  1803. // not see any completions unless we are in a low power
  1804. // state
  1805. //USBPORT_ASSERT(devExt->CurrentDevicePowerState != PowerDeviceD0);
  1806. // we must now attempt to put the controller in D0
  1807. powerState.DeviceState = PowerDeviceD0;
  1808. USBPORT_KdPrint((1, " >Wakeup Requesting HC D-State - %s\n",
  1809. D_State(powerState.DeviceState)));
  1810. poNtStatus =
  1811. PoRequestPowerIrp(devExt->Fdo.PhysicalDeviceObject,
  1812. IRP_MN_SET_POWER,
  1813. powerState,
  1814. USBPORT_PoRequestCompletion,
  1815. devExt->HcFdoDeviceObject,
  1816. NULL);
  1817. } else {
  1818. // some other error, means we f'up probably with the
  1819. // help of the ACPI BIOS
  1820. if (IoStatus->Status == STATUS_CANCELLED) {
  1821. LOGENTRY(NULL, devExt->HcFdoDeviceObject, LOG_POWER, 'WAK1',
  1822. 0, 0, 0);
  1823. USBPORT_KdPrint((1, " >Wakeup Irp Completed with cancel %x\n",
  1824. IoStatus->Status));
  1825. } else {
  1826. LOGENTRY(NULL, devExt->HcFdoDeviceObject, LOG_POWER, 'WAK2',
  1827. 0, 0, 0);
  1828. USBPORT_KdPrint((0, " >Wakeup Irp Completed with error %x\n",
  1829. IoStatus->Status));
  1830. // if status is STATUS_INVALID_DEVICE_STATE then you need
  1831. // to complain to the ACPI guys about your system not waking
  1832. // from USB. This is likely due to a bad Device Capability
  1833. // structure.
  1834. if (IoStatus->Status == STATUS_INVALID_DEVICE_STATE) {
  1835. BUG_TRAP();
  1836. }
  1837. }
  1838. }
  1839. DECREMENT_PENDING_REQUEST_COUNT(devExt->HcFdoDeviceObject, NULL);
  1840. // Note that the status returned here does not matter, this routine
  1841. // is called by the kernel (PopCompleteRequestIrp) when the irp
  1842. // completes to PDO and this function ignores the returned status.
  1843. // PopCompleteRequestIrp also immediatly frees the irp so we need
  1844. // take care not to reference it after this routine has run.
  1845. KeSetEvent(&devExt->Fdo.HcPendingWakeIrpEvent,
  1846. 1,
  1847. FALSE);
  1848. return IoStatus->Status;
  1849. }
  1850. VOID
  1851. USBPORT_ArmHcForWake(
  1852. PDEVICE_OBJECT FdoDeviceObject
  1853. )
  1854. /*++
  1855. Routine Description:
  1856. ArmHcforWake
  1857. Allocate and submit a 'WaitWake' Irp to the host controllers PDO
  1858. (usually owned by PCI). This will enable the PME event needed to
  1859. wake the system.
  1860. Note: We only post the wake irp if the root hub PDO is 'enabled'
  1861. for wakeup AND the host controller supports it.
  1862. Arguments:
  1863. Return Value:
  1864. none.
  1865. --*/
  1866. {
  1867. PIRP irp;
  1868. PDEVICE_EXTENSION devExt;
  1869. KIRQL irql;
  1870. BOOLEAN post = FALSE;
  1871. POWER_STATE powerState;
  1872. NTSTATUS ntStatus, waitStatus;
  1873. USBHC_WAKE_STATE oldWakeState;
  1874. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1875. ASSERT_FDOEXT(devExt);
  1876. USBPORT_ASSERT(TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_WAKE_ENABLED));
  1877. // this check just prevents us from posting a wake irp when we
  1878. // already have one pending, although I'm not sure how we might
  1879. // get into this situation.
  1880. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'hWW>',
  1881. 0, 0, 0);
  1882. while (1) {
  1883. oldWakeState = InterlockedCompareExchange((PULONG)&devExt->Fdo.HcWakeState,
  1884. HCWAKESTATE_WAITING,
  1885. HCWAKESTATE_DISARMED);
  1886. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'hWWx', oldWakeState, 0, 0);
  1887. if (oldWakeState == HCWAKESTATE_DISARMED) {
  1888. break;
  1889. }
  1890. if ((oldWakeState == HCWAKESTATE_ARMED) ||
  1891. (oldWakeState == HCWAKESTATE_WAITING)) {
  1892. // The device is already arming
  1893. return;
  1894. }
  1895. // wait for previous wake irp to finish
  1896. USBPORT_DisarmHcForWake(FdoDeviceObject);
  1897. }
  1898. // current state is HCWAKESTATE_WAITING
  1899. // set flag for tracking purposes only
  1900. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_HCPENDING_WAKE_IRP);
  1901. // wait for wake irp to finish
  1902. waitStatus = KeWaitForSingleObject(
  1903. &devExt->Fdo.HcPendingWakeIrpEvent,
  1904. Suspended,
  1905. KernelMode,
  1906. FALSE,
  1907. NULL);
  1908. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'hWWp',
  1909. 0, 0, 0);
  1910. // According to the NTDDK this should be systemwake
  1911. powerState.DeviceState = devExt->DeviceCapabilities.SystemWake;
  1912. // send the wake irp to our PDO, since it is not our
  1913. // responsibility to free the irp we don't keep track
  1914. // of it
  1915. ntStatus = PoRequestPowerIrp(devExt->Fdo.PhysicalDeviceObject,
  1916. IRP_MN_WAIT_WAKE,
  1917. powerState,
  1918. USBPORT_HcWakeIrp_Po_Completion,
  1919. devExt,
  1920. NULL);
  1921. INCREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, NULL);
  1922. if (ntStatus != STATUS_PENDING) {
  1923. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'WAKp',
  1924. FdoDeviceObject, 0, ntStatus);
  1925. devExt->Fdo.HcWakeState = HCWAKESTATE_DISARMED;
  1926. KeSetEvent(&devExt->Fdo.HcPendingWakeIrpEvent,
  1927. 1,
  1928. FALSE);
  1929. DECREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, NULL);
  1930. } else {
  1931. USBPORT_KdPrint((1, ">HC enabled for wakeup (%x) \n", ntStatus));
  1932. DEBUG_BREAK();
  1933. }
  1934. }
  1935. #ifdef IA64
  1936. __forceinline
  1937. LONG
  1938. InterlockedOr (
  1939. IN OUT LONG volatile *Target,
  1940. IN LONG Set
  1941. )
  1942. {
  1943. LONG i;
  1944. LONG j;
  1945. j = *Target;
  1946. do {
  1947. i = j;
  1948. j = InterlockedCompareExchange(Target,
  1949. i | Set,
  1950. i);
  1951. } while (i != j);
  1952. return j;
  1953. }
  1954. #else
  1955. #define InterlockedOr _InterlockedOr
  1956. #endif
  1957. VOID
  1958. USBPORT_DisarmHcForWake(
  1959. PDEVICE_OBJECT FdoDeviceObject
  1960. )
  1961. /*++
  1962. Routine Description:
  1963. DisarmForWake
  1964. cancels and frees the Pending wake irp for the host controller
  1965. Arguments:
  1966. Return Value:
  1967. none.
  1968. --*/
  1969. {
  1970. PIRP irp;
  1971. KIRQL irql;
  1972. PDEVICE_EXTENSION devExt;
  1973. USBHC_WAKE_STATE oldWakeState;
  1974. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1975. ASSERT_FDOEXT(devExt);
  1976. // no longer enabled for wake
  1977. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_WAKE_ENABLED);
  1978. // Go from HCWAKESTATE_WAITING to HCWAKESTATE_WAITING_CANCELLED, or
  1979. // HCWAKESTATE_ARMED to HCWAKESTATE_ARMING_CANCELLED, or
  1980. // stay in HCWAKESTATE_DISARMED or HCWAKESTATE_COMPLETING
  1981. oldWakeState = InterlockedOr( (PULONG)&devExt->Fdo.HcWakeState, 1 );
  1982. //oldWakeState = RtlInterlockedSetBits((PULONG)&devExt->Fdo.HcWakeState, 1 );
  1983. if (oldWakeState == HCWAKESTATE_ARMED) {
  1984. IoCancelIrp(devExt->Fdo.HcPendingWakeIrp);
  1985. //
  1986. // Now that we�ve cancelled the IRP, try to give back ownership
  1987. // to the completion routine by restoring the HCWAKESTATE_ARMED state
  1988. //
  1989. oldWakeState = InterlockedCompareExchange( (PULONG) &devExt->Fdo.HcWakeState,
  1990. HCWAKESTATE_ARMED,
  1991. HCWAKESTATE_ARMING_CANCELLED );
  1992. if (oldWakeState == HCWAKESTATE_COMPLETING) {
  1993. //
  1994. // We didn�t give back control of IRP in time, so we own it now.
  1995. //
  1996. // this will cause tp PoCompletion routine to run
  1997. IoCompleteRequest( devExt->Fdo.HcPendingWakeIrp, IO_NO_INCREMENT);
  1998. }
  1999. }
  2000. }
  2001. #if 0
  2002. VOID
  2003. USBPORT_SubmitHcWakeIrp(
  2004. PDEVICE_OBJECT FdoDeviceObject
  2005. )
  2006. /*++
  2007. Routine Description:
  2008. Allocate and submit a 'WaitWake' Irp to the host controllers PDO
  2009. (usually owned by PCI). This will enable the PME event needed to
  2010. wake the system.
  2011. Note: We only post the wake irp if the root hub PDO is 'enabled'
  2012. for wakeup AND the host controller supports it.
  2013. Arguments:
  2014. Return Value:
  2015. none.
  2016. --*/
  2017. {
  2018. PIRP irp;
  2019. PDEVICE_EXTENSION devExt;
  2020. KIRQL irql;
  2021. BOOLEAN post = FALSE;
  2022. POWER_STATE powerState;
  2023. NTSTATUS ntStatus;
  2024. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2025. ASSERT_FDOEXT(devExt);
  2026. USBPORT_ASSERT(TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_WAKE_ENABLED));
  2027. // this check just prevents us from posting a wake irp when we
  2028. // already have one pending, although I'm not sure how we might
  2029. // get into this situation.
  2030. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'hWW>',
  2031. 0, 0, 0);
  2032. // if USBPORT_FDOFLAG_PENDING_WAKE_IRP is set then we have an irp
  2033. // pending, or are about to have one otherwise we set the field and
  2034. // post an irp
  2035. KeAcquireSpinLock(&devExt->Fdo.HcPendingWakeIrpSpin.sl, &irql);
  2036. if (!TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_HCPENDING_WAKE_IRP)) {
  2037. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'hWW0',
  2038. 0, 0, 0);
  2039. // no wake irp pending, indicate that we
  2040. // are about to post one
  2041. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_HCPENDING_WAKE_IRP);
  2042. USBPORT_ASSERT(devExt->Fdo.HcPendingWakeIrp == NULL);
  2043. post = TRUE;
  2044. // this event will be signalled when the irp completes
  2045. KeInitializeEvent(&devExt->Fdo.HcPendingWakeIrpEvent,
  2046. NotificationEvent, FALSE);
  2047. KeInitializeEvent(&devExt->Fdo.HcPendingWakeIrpPostedEvent,
  2048. NotificationEvent, FALSE);
  2049. }
  2050. KeReleaseSpinLock(&devExt->Fdo.HcPendingWakeIrpSpin.sl, irql);
  2051. if (post) {
  2052. // no wake irp, post one
  2053. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'hWWp',
  2054. 0, 0, 0);
  2055. // According to the NTDDK this should be systemwake
  2056. powerState.DeviceState = devExt->DeviceCapabilities.SystemWake;
  2057. // send the wake irp to our PDO, since it is not our
  2058. // responsibility to free the irp we don't keep track
  2059. // of it
  2060. ntStatus = PoRequestPowerIrp(devExt->Fdo.PhysicalDeviceObject,
  2061. IRP_MN_WAIT_WAKE,
  2062. powerState,
  2063. USBPORT_HcWakeIrpCompletion,
  2064. devExt,
  2065. &irp);
  2066. // serialize the cancel code so that we don't free
  2067. // the irp until we know the address
  2068. // track the pending request since we have the completion
  2069. // routine hooked
  2070. INCREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, NULL);
  2071. if (ntStatus == STATUS_PENDING) {
  2072. devExt->Fdo.HcPendingWakeIrp = irp;
  2073. LOGENTRY(NULL, FdoDeviceObject, LOG_POWER, 'WAKp',
  2074. FdoDeviceObject, irp, ntStatus);
  2075. KeSetEvent(&devExt->Fdo.HcPendingWakeIrpPostedEvent,
  2076. 1,
  2077. FALSE);
  2078. } else {
  2079. TEST_TRAP();
  2080. }
  2081. USBPORT_KdPrint((1, ">HC enabled for wakeup (%x) (irp = %x)\n",
  2082. ntStatus, irp));
  2083. DEBUG_BREAK();
  2084. }
  2085. }
  2086. #endif
  2087. VOID
  2088. USBPORT_HcQueueWakeDpc(
  2089. PDEVICE_OBJECT FdoDeviceObject
  2090. )
  2091. {
  2092. PDEVICE_EXTENSION devExt;
  2093. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2094. ASSERT_FDOEXT(devExt);
  2095. if (KeInsertQueueDpc(&devExt->Fdo.HcWakeDpc, 0, 0)) {
  2096. INCREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, NULL);
  2097. }
  2098. }
  2099. VOID
  2100. USBPORT_HcWakeDpc(
  2101. PKDPC Dpc,
  2102. PVOID DeferredContext,
  2103. PVOID SystemArgument1,
  2104. PVOID SystemArgument2
  2105. )
  2106. /*++
  2107. Routine Description:
  2108. This routine runs at DISPATCH_LEVEL IRQL.
  2109. Arguments:
  2110. Dpc - Pointer to the DPC object.
  2111. DeferredContext - supplies FdoDeviceObject.
  2112. SystemArgument1 - not used.
  2113. SystemArgument2 - not used.
  2114. Return Value:
  2115. None.
  2116. --*/
  2117. {
  2118. PDEVICE_OBJECT fdoDeviceObject = DeferredContext;
  2119. PDEVICE_EXTENSION devExt;
  2120. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  2121. ASSERT_FDOEXT(devExt);
  2122. USBPORT_CompletePdoWaitWake(fdoDeviceObject);
  2123. DECREMENT_PENDING_REQUEST_COUNT(fdoDeviceObject, NULL);
  2124. }