Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2989 lines
99 KiB

  1. /*++
  2. Copyright (c) 1990-1995 Microsoft Corporation
  3. Module Name:
  4. ndispwr.c
  5. Abstract:
  6. This module contains the code to process power managment IRPs that are
  7. sent under the IRP_MJ_POWER major code.
  8. Author:
  9. Kyle Brandon (KyleB)
  10. Alireza Dabagh (alid)
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. 02/11/97 KyleB Created
  15. --*/
  16. #include <precomp.h>
  17. #pragma hdrstop
  18. #define MODULE_NUMBER MODULE_POWER
  19. NTSTATUS
  20. FASTCALL
  21. ndisQueryPowerCapabilities(
  22. IN PNDIS_MINIPORT_BLOCK Miniport
  23. )
  24. /*++
  25. Routine Description:
  26. This routine will process the IRP_MN_QUERY_CAPABILITIES by querying the
  27. next device object and saving information from that request.
  28. Arguments:
  29. pIrp - Pointer to the IRP.
  30. pIrpSp - Pointer to the stack parameters for the IRP.
  31. pAdapter - Pointer to the device.
  32. Return Value:
  33. --*/
  34. {
  35. PIRP pirp;
  36. PIO_STACK_LOCATION pirpSpN;
  37. NTSTATUS Status = STATUS_SUCCESS;
  38. PDEVICE_CAPABILITIES pDeviceCaps;
  39. PNDIS_PM_WAKE_UP_CAPABILITIES pWakeUpCaps;
  40. DEVICE_CAPABILITIES deviceCaps;
  41. POWER_QUERY pQuery;
  42. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  43. ("==>ndisQueryPowerCapabilities: Miniport %p\n", Miniport));
  44. do
  45. {
  46. //
  47. // default = no PM support
  48. //
  49. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_PM_SUPPORTED);
  50. //
  51. // if the Next device object is NULL, Don't bother, just flag the Miniport
  52. // as not supporting PM.
  53. // this can happen for IM devices under Memphis
  54. //
  55. if (Miniport->NextDeviceObject == NULL)
  56. {
  57. break;
  58. }
  59. //
  60. // Send the IRP_MN_QUERY_CAPABILITIES to pdo.
  61. //
  62. pirp = IoAllocateIrp((CCHAR)(Miniport->NextDeviceObject->StackSize + 1),
  63. FALSE);
  64. if (NULL == pirp)
  65. {
  66. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  67. ("ndisQueryPowerCapabilities: Miniport %p, Failed to allocate an irp for IRP_MN_QUERY_CAPABILITIES\n", Miniport));
  68. NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
  69. NDIS_ERROR_CODE_OUT_OF_RESOURCES,
  70. 0);
  71. Status = STATUS_INSUFFICIENT_RESOURCES;
  72. break;
  73. }
  74. NdisZeroMemory(&deviceCaps, sizeof(deviceCaps));
  75. deviceCaps.Size = sizeof(DEVICE_CAPABILITIES);
  76. deviceCaps.Version = 1;
  77. //
  78. // should initalize deviceCaps.Address and deviceCaps.UINumber here as well
  79. //
  80. deviceCaps.Address = -1;
  81. deviceCaps.UINumber= -1;
  82. //
  83. // Get the stack pointer.
  84. //
  85. pirpSpN = IoGetNextIrpStackLocation(pirp);
  86. ASSERT(pirpSpN != NULL);
  87. NdisZeroMemory(pirpSpN, sizeof(IO_STACK_LOCATION ) );
  88. //
  89. // Set the default device state to full on.
  90. //
  91. pirpSpN->MajorFunction = IRP_MJ_PNP;
  92. pirpSpN->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  93. pirpSpN->Parameters.DeviceCapabilities.Capabilities = &deviceCaps;
  94. pirp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  95. //
  96. // Setup the I/O completion routine to be called.
  97. //
  98. INITIALIZE_EVENT(&pQuery.Event);
  99. IoSetCompletionRoutine(pirp,
  100. ndisCompletionRoutine,
  101. &pQuery,
  102. TRUE,
  103. TRUE,
  104. TRUE);
  105. //
  106. // Call the next driver.
  107. //
  108. Status = IoCallDriver(Miniport->NextDeviceObject, pirp);
  109. if (STATUS_PENDING == Status)
  110. {
  111. Status = WAIT_FOR_OBJECT(&pQuery.Event, NULL);
  112. ASSERT(NT_SUCCESS(Status));
  113. }
  114. //
  115. // If the lower device object successfully completed the request
  116. // then we save that information.
  117. //
  118. if (NT_SUCCESS(pQuery.Status))
  119. {
  120. //
  121. // Get the pointer to the device capabilities as returned by
  122. // the parent PDO.
  123. //
  124. pDeviceCaps = &deviceCaps;
  125. //
  126. // save the entire device caps received from bus driver/ACPI
  127. //
  128. NdisMoveMemory(
  129. &Miniport->DeviceCaps,
  130. pDeviceCaps,
  131. sizeof(DEVICE_CAPABILITIES));
  132. if ((pDeviceCaps->DeviceWake != PowerDeviceUnspecified) &&
  133. (pDeviceCaps->SystemWake != PowerSystemUnspecified))
  134. {
  135. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_PM_SUPPORTED);
  136. }
  137. IF_DBG(DBG_COMP_PM, DBG_LEVEL_INFO)
  138. {
  139. UINT i;
  140. DbgPrint("ndisQueryPowerCapabilities: Miniport %p, Bus PM capabilities\n", Miniport);
  141. DbgPrint("\tDeviceD1:\t\t%ld\n", (pDeviceCaps->DeviceD1 == 0) ? 0 : 1);
  142. DbgPrint("\tDeviceD2:\t\t%ld\n", (pDeviceCaps->DeviceD2 == 0) ? 0 : 1);
  143. DbgPrint("\tWakeFromD0:\t\t%ld\n", (pDeviceCaps->WakeFromD0 == 0) ? 0 : 1);
  144. DbgPrint("\tWakeFromD1:\t\t%ld\n", (pDeviceCaps->WakeFromD1 == 0) ? 0 : 1);
  145. DbgPrint("\tWakeFromD2:\t\t%ld\n", (pDeviceCaps->WakeFromD2 == 0) ? 0 : 1);
  146. DbgPrint("\tWakeFromD3:\t\t%ld\n\n", (pDeviceCaps->WakeFromD3 == 0) ? 0 : 1);
  147. DbgPrint("\tSystemState\t\tDeviceState\n");
  148. if (pDeviceCaps->DeviceState[0] == PowerDeviceUnspecified)
  149. DbgPrint("\tPowerSystemUnspecified\tPowerDeviceUnspecified\n");
  150. else
  151. DbgPrint("\tPowerSystemUnspecified\t\tD%ld\n", pDeviceCaps->DeviceState[0] - 1);
  152. for (i = 1; i < PowerSystemMaximum; i++)
  153. {
  154. if (pDeviceCaps->DeviceState[i]== PowerDeviceUnspecified)
  155. DbgPrint("\tS%ld\t\t\tPowerDeviceUnspecified\n",i-1);
  156. else
  157. DbgPrint("\tS%ld\t\t\tD%ld\n",i-1, pDeviceCaps->DeviceState[i] - 1);
  158. }
  159. if (pDeviceCaps->SystemWake == PowerSystemUnspecified)
  160. DbgPrint("\t\tSystemWake: PowerSystemUnspecified\n");
  161. else
  162. DbgPrint("\t\tSystemWake: S%ld\n", pDeviceCaps->SystemWake - 1);
  163. if (pDeviceCaps->DeviceWake == PowerDeviceUnspecified)
  164. DbgPrint("\t\tDeviceWake: PowerDeviceUnspecified\n");
  165. else
  166. DbgPrint("\t\tDeviceWake: D%ld\n", pDeviceCaps->DeviceWake - 1);
  167. }
  168. }
  169. else
  170. {
  171. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,("ndisQueryPowerCapabilities: Miniport %p, Bus driver failed IRP_MN_QUERY_CAPABILITIES\n", Miniport));
  172. }
  173. //
  174. // The irp is no longer needed.
  175. //
  176. IoFreeIrp(pirp);
  177. } while (FALSE);
  178. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  179. ("<==ndisQueryPowerCapabilities: Miniport %p, Status 0x%x\n", Miniport, Status));
  180. return(Status);
  181. }
  182. NTSTATUS
  183. ndisMediaDisconnectComplete(
  184. IN PDEVICE_OBJECT pdo,
  185. IN UCHAR MinorFunction,
  186. IN POWER_STATE PowerState,
  187. IN PVOID Context,
  188. IN PIO_STATUS_BLOCK IoStatus
  189. )
  190. /*++
  191. Routine Description:
  192. Arguments:
  193. pdo - Pointer to the DEVICE_OBJECT for the miniport.
  194. pirp - Pointer to the device set power state IRP that we created.
  195. Context - Pointer to the miniport block
  196. Return Value:
  197. --*/
  198. {
  199. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context;
  200. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  201. KIRQL OldIrql;
  202. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  203. ("==>ndisMediaDisconnectComplete: Miniport %p\n", Miniport));
  204. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  205. //
  206. // double check that we didn't get a link up while we were doing all this.
  207. //
  208. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED))
  209. {
  210. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  211. ("ndisMediaDisconnectComplete: Miniport %p, disconnect complete\n", Miniport));
  212. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  213. }
  214. else
  215. {
  216. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED);
  217. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  218. //
  219. // if system is not going to sleep, wake up the device
  220. //
  221. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING))
  222. {
  223. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  224. ("ndisMediaDisconnectComplete: Miniport %p, disconnect was cancelled. Power back up the miniport\n", Miniport));
  225. //
  226. // Wake it back up
  227. //
  228. PowerState.DeviceState = PowerDeviceD0;
  229. Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject,
  230. IRP_MN_SET_POWER,
  231. PowerState,
  232. NULL,
  233. NULL,
  234. NULL);
  235. }
  236. }
  237. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  238. ("<==ndisMediaDisconnectComplete: Miniport %p\n", Miniport));
  239. return(STATUS_MORE_PROCESSING_REQUIRED);
  240. }
  241. VOID
  242. ndisMediaDisconnectWorker(
  243. IN PPOWER_WORK_ITEM pWorkItem,
  244. IN PVOID Context
  245. )
  246. /*++
  247. Routine Description:
  248. Arguments:
  249. Return Value:
  250. --*/
  251. {
  252. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context;
  253. POWER_STATE PowerState;
  254. NTSTATUS Status;
  255. NDIS_STATUS NdisStatus;
  256. ULONG WakeEnable;
  257. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  258. ("==>ndisMediaDisconnectWorker: Miniport %p\n", Miniport));
  259. //
  260. // Determine the minimum device state we can go to and still get a link enabled.
  261. //
  262. if (Miniport->DeviceCaps.DeviceWake < Miniport->PMCapabilities.WakeUpCapabilities.MinLinkChangeWakeUp)
  263. {
  264. PowerState.DeviceState = Miniport->DeviceCaps.DeviceWake;
  265. }
  266. else
  267. {
  268. PowerState.DeviceState = Miniport->PMCapabilities.WakeUpCapabilities.MinLinkChangeWakeUp;
  269. }
  270. //
  271. // enable the appropriate wakeup method. this includes link change,
  272. // pattern match and/or magic packet.
  273. // if LINK_CHANGE method is disabled, we should not even get here
  274. //
  275. //
  276. // Miniport->WakeUpEnable is the wakeup methods enabled from protocol (and ndis point of view)
  277. // with this qfe, when the user turns wol off from UI, the methods going down are not
  278. // the methods set by protocol/ndis
  279. //
  280. WakeEnable = Miniport->WakeUpEnable;
  281. if (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_PATTERN_MATCH)
  282. {
  283. WakeEnable &= ~NDIS_PNP_WAKE_UP_PATTERN_MATCH;
  284. }
  285. if (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_MAGIC_PACKET)
  286. {
  287. WakeEnable &= ~NDIS_PNP_WAKE_UP_MAGIC_PACKET;
  288. }
  289. NdisStatus = ndisQuerySetMiniportDeviceState(Miniport,
  290. WakeEnable,
  291. OID_PNP_ENABLE_WAKE_UP,
  292. TRUE);
  293. if (NdisStatus == NDIS_STATUS_SUCCESS)
  294. {
  295. //
  296. // We need to request a device state irp.
  297. //
  298. Miniport->WaitWakeSystemState = Miniport->DeviceCaps.SystemWake;
  299. Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject,
  300. IRP_MN_SET_POWER,
  301. PowerState,
  302. ndisMediaDisconnectComplete,
  303. Miniport,
  304. NULL);
  305. }
  306. FREE_POOL(pWorkItem);
  307. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  308. ("<==ndisMediaDisconnectWorker: Miniport %p\n", Miniport));
  309. }
  310. VOID
  311. ndisMediaDisconnectTimeout(
  312. IN PVOID SystemSpecific1,
  313. IN PVOID Context,
  314. IN PVOID SystemSpecific2,
  315. IN PVOID SystemSpecific3
  316. )
  317. /*++
  318. Routine Description:
  319. Arguments:
  320. Return Value:
  321. --*/
  322. {
  323. //
  324. // Fire off a workitem to take care of this at passive level.
  325. //
  326. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context;
  327. PNDIS_OPEN_BLOCK MiniportOpen;
  328. PPOWER_WORK_ITEM pWorkItem;
  329. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  330. ("==>ndisMediaDisconnectTimeout: Miniport %p\n", Miniport));
  331. do
  332. {
  333. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  334. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT))
  335. {
  336. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  337. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  338. ("ndisMediaDisconnectTimeout: Miniport %p, media disconnect was cancelled\n", Miniport));
  339. break;
  340. }
  341. //
  342. // Clear the disconnect wait flag.
  343. //
  344. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT);
  345. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  346. pWorkItem = ALLOC_FROM_POOL(sizeof(POWER_WORK_ITEM), NDIS_TAG_WORK_ITEM);
  347. if (pWorkItem != NULL)
  348. {
  349. //
  350. // Initialize the ndis work item to power on.
  351. //
  352. NdisInitializeWorkItem(&pWorkItem->WorkItem,
  353. (NDIS_PROC)ndisMediaDisconnectWorker,
  354. Miniport);
  355. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE);
  356. //
  357. // Schedule the workitem to fire.
  358. //
  359. NdisScheduleWorkItem(&pWorkItem->WorkItem);
  360. }
  361. } while (FALSE);
  362. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  363. ("<==ndisMediaDisconnectTimeout: Miniport %p\n", Miniport));
  364. }
  365. NTSTATUS
  366. ndisWaitWakeComplete(
  367. IN PDEVICE_OBJECT pdo,
  368. IN UCHAR MinorFunction,
  369. IN POWER_STATE PowerState,
  370. IN PVOID Context,
  371. IN PIO_STATUS_BLOCK IoStatus
  372. )
  373. /*++
  374. Routine Description:
  375. Arguments:
  376. DeviceObject
  377. Irp
  378. Context
  379. Return Value:
  380. --*/
  381. {
  382. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context;
  383. PIRP pirp;
  384. NTSTATUS Status = IoStatus->Status;
  385. POWER_STATE DevicePowerState;
  386. KIRQL OldIrql;
  387. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  388. ("==>ndisWaitWakeComplete: Miniport %p, pIrp %p, Status %lx\n",
  389. Miniport, Miniport->pIrpWaitWake, Status));
  390. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  391. pirp = Miniport->pIrpWaitWake;
  392. Miniport->pIrpWaitWake = NULL;
  393. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  394. if (pirp != NULL)
  395. {
  396. //
  397. // If this completion routine was called because a wake-up occured at the device level
  398. // then we need to initiate a device irp to start up the nic. If it was completed
  399. // due to a cancellation then we skip this since it was cancelled due to a device irp
  400. // being sent to wake-up the device.
  401. //
  402. if (Status == STATUS_SUCCESS)
  403. {
  404. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  405. ("ndisWaitWakeComplete: Miniport %p, Wake irp was complete due to wake event\n", Miniport));
  406. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING))
  407. {
  408. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  409. ("ndisWaitWakeComplete: Miniport %p, Powering up the Miniport\n", Miniport));
  410. //
  411. // We need to request a set power to power up the device.
  412. //
  413. DevicePowerState.DeviceState = PowerDeviceD0;
  414. Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject,
  415. IRP_MN_SET_POWER,
  416. DevicePowerState,
  417. NULL,
  418. NULL,
  419. NULL);
  420. }
  421. else
  422. {
  423. //
  424. // it is also possible that the device woke up the whole system (WOL) in which case we
  425. // will get a system power IRP eventually and we don't need to request a power IRP.
  426. //
  427. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  428. ("ndisWaitWakeComplete: Miniport %p woke up the system.\n", Miniport));
  429. }
  430. }
  431. else
  432. {
  433. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  434. ("ndisWaitWakeComplete: Miniport %p, WAIT_WAKE irp failed or cancelled. Status %lx\n",
  435. Miniport, Status));
  436. }
  437. }
  438. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  439. ("<==ndisWaitWakeComplete: Miniport %p\n", Miniport));
  440. return(STATUS_MORE_PROCESSING_REQUIRED);
  441. }
  442. NTSTATUS
  443. ndisQueryPowerComplete(
  444. IN PDEVICE_OBJECT pdo,
  445. IN PIRP pirp,
  446. IN PVOID Context
  447. )
  448. /*++
  449. Routine Description:
  450. Arguments:
  451. pdo - Pointer to the device object
  452. pirp - Pointer to the query power irp
  453. Context - Pointer to the miniport.
  454. Return Value:
  455. --*/
  456. {
  457. NTSTATUS Status = pirp->IoStatus.Status;
  458. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  459. ("==>ndisQueryPowerComplete: Miniport %p, Bus driver returned %lx for QueryPower\n",
  460. Context, pirp->IoStatus.Status));
  461. #ifdef TRACE_PM_PROBLEMS
  462. if (!NT_SUCCESS(pirp->IoStatus.Status))
  463. {
  464. DbgPrint("ndisQueryPowerComplete: Miniport %p, Bus Driver returned %lx for QueryPower.\n",
  465. Context, pirp->IoStatus.Status);
  466. }
  467. #endif
  468. PoStartNextPowerIrp(pirp);
  469. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  470. ("<==ndisQueryPowerComplete: Miniport %p\n", Context));
  471. return(Status);
  472. }
  473. NTSTATUS
  474. ndisQueryPower(
  475. IN PIRP pirp,
  476. IN PIO_STACK_LOCATION pirpSp,
  477. IN PNDIS_MINIPORT_BLOCK Miniport
  478. )
  479. /*++
  480. Routine Description:
  481. This routine will process the IRP_MN_QUERY_POWER for a miniport driver.
  482. Arguments:
  483. pirp - Pointer to the IRP.
  484. pirpSp - Pointer to the IRPs current stack location.
  485. Adapter - Pointer to the adapter.
  486. Return Value:
  487. --*/
  488. {
  489. NTSTATUS Status = STATUS_SUCCESS;
  490. DEVICE_POWER_STATE DeviceState;
  491. NDIS_STATUS NdisStatus;
  492. PIO_STACK_LOCATION pirpSpN;
  493. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  494. ("==>ndisQueryPower: Miniport %p\n", Miniport));
  495. do
  496. {
  497. //
  498. // We only handle system power states sent as a query.
  499. //
  500. if (pirpSp->Parameters.Power.Type != SystemPowerState)
  501. {
  502. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  503. ("ndisQueryPower: Miniport %p, Not a system state! Type: 0x%x. State: 0x%x\n",
  504. Miniport, pirpSp->Parameters.Power.Type, pirpSp->Parameters.Power.State));
  505. Status = STATUS_INVALID_DEVICE_REQUEST;
  506. break;
  507. }
  508. //
  509. // Determine if the system state is appropriate and what device state we
  510. // should go to.
  511. //
  512. Status = ndisMPowerPolicy(Miniport,
  513. pirpSp->Parameters.Power.State.SystemState,
  514. &DeviceState,
  515. TRUE);
  516. if (!ndisIsMiniportStarted(Miniport) ||
  517. (Miniport->PnPDeviceState != NdisPnPDeviceStarted) ||
  518. (STATUS_DEVICE_POWERED_OFF == Status))
  519. {
  520. pirp->IoStatus.Status = STATUS_SUCCESS;
  521. PoStartNextPowerIrp(pirp);
  522. IoCompleteRequest(pirp, 0);
  523. return(STATUS_SUCCESS);
  524. }
  525. //
  526. // If we didn't succeed then fail the query power.
  527. //
  528. if (!NT_SUCCESS(Status))
  529. {
  530. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  531. ("ndisQueryPower: Miniport %p, Unable to go to system state 0x%x\n",
  532. Miniport, pirpSp->Parameters.Power.State.SystemState));
  533. break;
  534. }
  535. //
  536. // Notify the transports with the query power PnP event.
  537. //
  538. NdisStatus = ndisPnPNotifyAllTransports(Miniport,
  539. NetEventQueryPower,
  540. &DeviceState,
  541. sizeof(DeviceState));
  542. if (NDIS_STATUS_SUCCESS != NdisStatus)
  543. {
  544. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  545. ("ndisQueryPower: Miniport %p, ndisPnPNotifyAllTransports failed\n", Miniport));
  546. Status = NdisStatus;
  547. break;
  548. }
  549. //
  550. // Notify the miniport...
  551. //
  552. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE))
  553. {
  554. NdisStatus = ndisQuerySetMiniportDeviceState(Miniport,
  555. DeviceState,
  556. OID_PNP_QUERY_POWER,
  557. FALSE);
  558. if (NDIS_STATUS_SUCCESS != NdisStatus)
  559. {
  560. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  561. ("ndisQueryPower: Miniport %p, failed query power\n", Miniport));
  562. Status = STATUS_UNSUCCESSFUL;
  563. break;
  564. }
  565. }
  566. } while (FALSE);
  567. if (!NT_SUCCESS(Status))
  568. {
  569. pirp->IoStatus.Status = Status;
  570. PoStartNextPowerIrp(pirp);
  571. IoCompleteRequest(pirp, 0);
  572. }
  573. else
  574. {
  575. //
  576. // Pass this irp down the stack.
  577. //
  578. pirpSpN = IoGetNextIrpStackLocation(pirp);
  579. pirpSpN->MajorFunction = IRP_MJ_POWER;
  580. pirpSpN->MinorFunction = IRP_MN_QUERY_POWER;
  581. pirpSpN->Parameters.Power.SystemContext = pirpSp->Parameters.Power.SystemContext;
  582. pirpSpN->Parameters.Power.Type = DevicePowerState;
  583. pirpSpN->Parameters.Power.State.DeviceState = DeviceState;
  584. IoSetCompletionRoutine(
  585. pirp,
  586. ndisQueryPowerComplete,
  587. Miniport,
  588. TRUE,
  589. TRUE,
  590. TRUE);
  591. IoMarkIrpPending(pirp);
  592. PoStartNextPowerIrp(pirp);
  593. PoCallDriver(Miniport->NextDeviceObject, pirp);
  594. Status = STATUS_PENDING;
  595. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  596. ("ndisQueryPower: Miniport %p, PoCallDriver to NextDeviceObject returned %lx\n", Miniport, Status));
  597. }
  598. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  599. ("<==ndisQueryPower: Miniport %p\n", Miniport));
  600. return(Status);
  601. }
  602. VOID
  603. FASTCALL
  604. ndisPmHaltMiniport(
  605. IN PNDIS_MINIPORT_BLOCK Miniport
  606. )
  607. /*++
  608. Routine Description:
  609. This will stop the miniport from functioning...
  610. Arguments:
  611. Miniport - pointer to the mini-port to halt
  612. Return Value:
  613. None.
  614. --*/
  615. {
  616. KIRQL OldIrql;
  617. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  618. ("==>ndisPmHaltMiniport: Miniport \n", Miniport));
  619. PnPReferencePackage();
  620. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  621. NdisResetEvent(&Miniport->OpenReadyEvent);
  622. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_HALTED))
  623. {
  624. ASSERT(FALSE);
  625. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  626. return;
  627. }
  628. //
  629. // Mark this miniport as halting.
  630. //
  631. MINIPORT_SET_FLAG(Miniport, fMINIPORT_PM_HALTING);
  632. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_PM_HALTED);
  633. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
  634. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_NO_SHUTDOWN);
  635. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  636. ndisMCommonHaltMiniport(Miniport);
  637. NdisMDeregisterAdapterShutdownHandler(Miniport);
  638. Miniport->MiniportAdapterContext = NULL;
  639. PnPDereferencePackage();
  640. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  641. ("<==ndisPmHaltMiniport: Miniport %p\n", Miniport));
  642. }
  643. NDIS_STATUS
  644. ndisPmInitializeMiniport(
  645. IN PNDIS_MINIPORT_BLOCK Miniport
  646. )
  647. /*++
  648. Routine Description:
  649. This routine will re-initialize a miniport that has been halted due to
  650. a PM low power transition.
  651. Arguments:
  652. Miniport - Pointer to the miniport block to re-initialize.
  653. Return Value:
  654. --*/
  655. {
  656. PNDIS_M_DRIVER_BLOCK pMiniBlock = Miniport->DriverHandle;
  657. NDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle;
  658. NDIS_STATUS Status;
  659. NDIS_STATUS OpenErrorStatus;
  660. UINT SelectedMediumIndex;
  661. ULONG Flags;
  662. ULONG GenericUlong = 0;
  663. KIRQL OldIrql;
  664. UCHAR SendFlags;
  665. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  666. ("==>ndisPmInitializeMiniport: Miniport %p\n", Miniport));
  667. do
  668. {
  669. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PM_HALTING |
  670. fMINIPORT_DEREGISTERED_INTERRUPT |
  671. fMINIPORT_RESET_REQUESTED |
  672. fMINIPORT_RESET_IN_PROGRESS);
  673. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_REMOVE_IN_PROGRESS);
  674. Flags = Miniport->Flags;
  675. SendFlags = Miniport->SendFlags;
  676. //
  677. // Clean up any workitems that might have been queue'd
  678. //
  679. NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemMiniportCallback, NULL);
  680. NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL);
  681. NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL);
  682. NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL);
  683. NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetInProgress, NULL);
  684. InitializeListHead(&Miniport->PacketList);
  685. //
  686. // Initialize the configuration handle for use during the initialization.
  687. //
  688. ConfigurationHandle.DriverObject = Miniport->DriverHandle->NdisDriverInfo->DriverObject;
  689. ConfigurationHandle.DeviceObject = Miniport->DeviceObject;
  690. ConfigurationHandle.DriverBaseName = &Miniport->BaseName;
  691. ASSERT(KeGetCurrentIrql() == 0);
  692. Status = ndisInitializeConfiguration((PNDIS_WRAPPER_CONFIGURATION_HANDLE)&ConfigurationHandle,
  693. Miniport,
  694. NULL);
  695. ASSERT(KeGetCurrentIrql() == 0);
  696. if (NDIS_STATUS_SUCCESS != Status)
  697. {
  698. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  699. ("ndisPmInitializeMiniport: Miniport %p, ndisInitializeConfiguration failed, Status: 0x%x\n", Miniport, Status));
  700. break;
  701. }
  702. //
  703. // Call adapter callback. The current value for "Export"
  704. // is what we tell him to name this device.
  705. //
  706. MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
  707. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
  708. Miniport->CurrentDevicePowerState = PowerDeviceD0;
  709. Status = (pMiniBlock->MiniportCharacteristics.InitializeHandler)(
  710. &OpenErrorStatus,
  711. &SelectedMediumIndex,
  712. ndisMediumArray,
  713. ndisMediumArraySize / sizeof(NDIS_MEDIUM),
  714. (NDIS_HANDLE)Miniport,
  715. (NDIS_HANDLE)&ConfigurationHandle);
  716. ASSERT(KeGetCurrentIrql() == 0);
  717. if (NDIS_STATUS_SUCCESS != Status)
  718. {
  719. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  720. ("ndisPmInitializeMiniport: Miniport %p, MiniportInitialize handler failed, Status 0x%x\n", Miniport, Status));
  721. break;
  722. }
  723. ASSERT (Miniport->MediaType == ndisMediumArray[SelectedMediumIndex]);
  724. //
  725. // Restore saved settings
  726. //
  727. Miniport->Flags = Flags;
  728. Miniport->SendFlags = SendFlags;
  729. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_PM_HALTED | fMINIPORT_REJECT_REQUESTS);
  730. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
  731. CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
  732. //
  733. // Clear the flag preventing the miniport's shutdown handler from being
  734. // called if needed.
  735. //
  736. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_NO_SHUTDOWN);
  737. //
  738. // if device does not need polling for connect status then assume it is connected
  739. // as we always do when we intialize a miniport. if it does require media polling
  740. // leave the media status as it was before suspend. it will be updated on the very first
  741. // wakeup DPC.
  742. //
  743. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUIRES_MEDIA_POLLING))
  744. {
  745. MINIPORT_SET_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED);
  746. }
  747. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED))
  748. {
  749. //
  750. // set the ReceivePacket handler
  751. //
  752. ndisMSetIndicatePacketHandler(Miniport);
  753. }
  754. BLOCK_LOCK_MINIPORT_LOCKED(Miniport, OldIrql);
  755. //
  756. // Restore the filter information.
  757. //
  758. ndisMRestoreFilterSettings(Miniport, NULL, FALSE);
  759. //
  760. // Make sure the filter settings get updated.
  761. //
  762. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
  763. {
  764. ndisMDoRequests(Miniport);
  765. }
  766. else
  767. {
  768. NDISM_PROCESS_DEFERRED(Miniport);
  769. }
  770. UNLOCK_MINIPORT_L(Miniport);
  771. //
  772. // Start up the wake up timer.
  773. //
  774. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  775. ("ndisPmInitializeMiniport: Miniport %p, startup the wake-up DPC timer\n", Miniport));
  776. NdisMSetPeriodicTimer((PNDIS_MINIPORT_TIMER)(&Miniport->WakeUpDpcTimer),
  777. Miniport->CheckForHangSeconds*1000);
  778. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  779. ASSERT(KeGetCurrentIrql() == 0);
  780. if (Miniport->MediaType == NdisMedium802_3)
  781. {
  782. ndisMNotifyMachineName(Miniport, NULL);
  783. }
  784. //
  785. // Register with WMI.
  786. //
  787. Status = IoWMIRegistrationControl(Miniport->DeviceObject, WMIREG_ACTION_REGISTER);
  788. if (!NT_SUCCESS(Status))
  789. {
  790. //
  791. // This should NOT keep the adapter from initializing but we should log the error.
  792. //
  793. DBGPRINT_RAW((DBG_COMP_INIT | DBG_COMP_WMI), DBG_LEVEL_WARN,
  794. ("ndisPmInitializeMiniport: Miniport %p, Failed to register for WMI support\n", Miniport));
  795. }
  796. Status = NDIS_STATUS_SUCCESS;
  797. KeQueryTickCount(&Miniport->NdisStats.StartTicks);
  798. } while (FALSE);
  799. if (NDIS_STATUS_SUCCESS != Status)
  800. {
  801. NdisMDeregisterAdapterShutdownHandler(Miniport);
  802. ndisLastFailedInitErrorCode = Status;
  803. ASSERT(Miniport->Interrupt == NULL);
  804. ASSERT(Miniport->TimerQueue == NULL);
  805. ASSERT(Miniport->MapRegisters == NULL);
  806. if ((Miniport->TimerQueue != NULL) || (Miniport->Interrupt != NULL))
  807. {
  808. if (Miniport->Interrupt != NULL)
  809. {
  810. BAD_MINIPORT(Miniport, "Unloading without deregistering interrupt");
  811. }
  812. else
  813. {
  814. BAD_MINIPORT(Miniport, "Unloading without deregistering timer");
  815. }
  816. KeBugCheckEx(BUGCODE_ID_DRIVER,
  817. (ULONG_PTR)Miniport,
  818. (ULONG_PTR)Miniport->Interrupt,
  819. (ULONG_PTR)Miniport->TimerQueue,
  820. 1);
  821. }
  822. MINIPORT_SET_FLAG(Miniport, fMINIPORT_PM_HALTING);
  823. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_PM_HALTED);
  824. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
  825. }
  826. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  827. ("<==ndisPmInitializeMiniport: Miniport %p\n", Miniport));
  828. return(Status);
  829. }
  830. NDIS_STATUS
  831. ndisQuerySetMiniportDeviceState(
  832. IN PNDIS_MINIPORT_BLOCK Miniport,
  833. IN DEVICE_POWER_STATE DeviceState,
  834. IN NDIS_OID Oid,
  835. IN BOOLEAN fSet
  836. )
  837. /*++
  838. Routine Description:
  839. Arguments:
  840. Return Value:
  841. --*/
  842. {
  843. NDIS_STATUS NdisStatus;
  844. NDIS_REQUEST PowerReq;
  845. PNDIS_COREQ_RESERVED CoReqRsvd;
  846. ULONG State;
  847. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  848. ("==>ndisQuerySetMiniportDeviceState: Miniport %p\n", Miniport));
  849. //
  850. // Setup the miniport's internal request for a set power OID.
  851. //
  852. CoReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&PowerReq);
  853. INITIALIZE_EVENT(&CoReqRsvd->Event);
  854. PowerReq.DATA.SET_INFORMATION.InformationBuffer = &State;
  855. PowerReq.DATA.SET_INFORMATION.InformationBufferLength = sizeof(State);
  856. PowerReq.RequestType = fSet ? NdisRequestSetInformation : NdisRequestQueryInformation;
  857. PowerReq.DATA.SET_INFORMATION.Oid = Oid;
  858. PowerReq.DATA.SET_INFORMATION.InformationBuffer = &DeviceState;
  859. PowerReq.DATA.SET_INFORMATION.InformationBufferLength = sizeof(DeviceState);
  860. NdisStatus = ndisQuerySetMiniport(Miniport,
  861. NULL,
  862. fSet,
  863. &PowerReq,
  864. NULL);
  865. #ifdef TRACE_PM_PROBLEMS
  866. if (NdisStatus != NDIS_STATUS_SUCCESS)
  867. {
  868. DbgPrint("ndisQuerySetMiniportDeviceState: Miniport %p, (Name: %p) failed Oid %lx, Set = %lx with error %lx\n",
  869. Miniport,
  870. Miniport->pAdapterInstanceName,
  871. Oid,
  872. fSet,
  873. NdisStatus);
  874. }
  875. #endif
  876. //
  877. // Miniport can't fail the set power request.
  878. //
  879. if (fSet)
  880. {
  881. ASSERT(NDIS_STATUS_SUCCESS == NdisStatus);
  882. }
  883. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  884. ("<==ndisQuerySetMiniportDeviceState: Miniport %p, Status %lx\n", Miniport, NdisStatus));
  885. return(NdisStatus);
  886. }
  887. NTSTATUS
  888. ndisSetSystemPowerComplete(
  889. IN PDEVICE_OBJECT pdo,
  890. IN UCHAR MinorFunction,
  891. IN POWER_STATE PowerState,
  892. IN PVOID Context,
  893. IN PIO_STATUS_BLOCK IoStatus
  894. )
  895. /*++
  896. Routine Description:
  897. Arguments:
  898. pdo - Pointer to the DEVICE_OBJECT for the miniport.
  899. pirp - Pointer to the device set power state IRP that we created.
  900. Context - Pointer to the system set power state sent by the OS.
  901. Return Value:
  902. --*/
  903. {
  904. PIRP pirpSystem = Context;
  905. PIO_STACK_LOCATION pirpSp;
  906. PNDIS_MINIPORT_BLOCK Miniport;
  907. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  908. ("==>ndisSetSystemPowerComplete: DeviceObject %p\n", pdo));
  909. //
  910. // Save the status code with the original IRP.
  911. //
  912. pirpSystem->IoStatus = *IoStatus;
  913. //
  914. // did everything go well?
  915. //
  916. if (NT_SUCCESS(IoStatus->Status))
  917. {
  918. //
  919. // Get current stack pointer.
  920. //
  921. pirpSp = IoGetCurrentIrpStackLocation(pirpSystem);
  922. ASSERT(SystemPowerState == pirpSp->Parameters.Power.Type);
  923. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  924. ("ndisSetSystemPowerComplete: DeviceObject %p, Going to system power state %lx\n",
  925. pdo, pirpSp->Parameters.Power.State));
  926. //
  927. // Notify the system that we are in the appropriate power state.
  928. //
  929. PoSetPowerState(pirpSp->DeviceObject,SystemPowerState, pirpSp->Parameters.Power.State);
  930. Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)pirpSp->DeviceObject->DeviceExtension + 1);
  931. //
  932. // now send down the System power IRP
  933. //
  934. IoCopyCurrentIrpStackLocationToNext(pirpSystem);
  935. PoCallDriver(Miniport->NextDeviceObject, pirpSystem);
  936. }
  937. else
  938. {
  939. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  940. ("ndisSetSystemPowerComplete: DeviceObject %p, IRP_MN_SET_POWER failed!\n", pdo));
  941. IoCompleteRequest(pirpSystem, 0);
  942. }
  943. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  944. ("<==ndisSetSystemPowerComplete: DeviceObject %p\n", pdo));
  945. return(STATUS_MORE_PROCESSING_REQUIRED);
  946. }
  947. NTSTATUS
  948. ndisSetSystemPowerOnComplete(
  949. IN PDEVICE_OBJECT pdo,
  950. IN PIRP pirp,
  951. IN PVOID Context
  952. )
  953. /*++
  954. Routine Description:
  955. Completion routine for S0 irp completion. This routine requests a D0 irp to be sent down the stack.
  956. Arguments:
  957. pdo - Pointer to the DEVICE_OBJECT for the miniport.
  958. pirp - Pointer to the S0 irp sent by the power manager.
  959. Context - Pointer to the miniport context
  960. Return Value:
  961. --*/
  962. {
  963. PIO_STACK_LOCATION pirpSp = IoGetCurrentIrpStackLocation(pirp);
  964. PNDIS_MINIPORT_BLOCK Miniport = Context;
  965. POWER_STATE PowerState;
  966. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  967. ("==>ndisSetSystemPowerOnComplete: DeviceObject %p\n", pdo));
  968. //
  969. // did everything go well?
  970. //
  971. if (NT_SUCCESS(pirp->IoStatus.Status))
  972. {
  973. //
  974. // Request the D irp now.
  975. //
  976. PowerState.DeviceState = PowerDeviceD0;
  977. PoRequestPowerIrp(Miniport->PhysicalDeviceObject,
  978. IRP_MN_SET_POWER,
  979. PowerState,
  980. NULL,
  981. NULL,
  982. NULL);
  983. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  984. ("ndisSetSystemPowerOnComplete: DeviceObject %p, Going to system power state %lx\n",
  985. pdo, PowerState));
  986. //
  987. // Notify the system that we are in the appropriate power state.
  988. //
  989. PoSetPowerState(pdo ,SystemPowerState, pirpSp->Parameters.Power.State);
  990. }
  991. return(STATUS_SUCCESS);
  992. }
  993. VOID
  994. ndisDevicePowerOn(
  995. IN PPOWER_WORK_ITEM pWorkItem,
  996. IN PVOID pContext
  997. )
  998. /*++
  999. Routine Description:
  1000. Arguments:
  1001. Return Value:
  1002. --*/
  1003. {
  1004. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)pContext;
  1005. DEVICE_POWER_STATE DeviceState;
  1006. POWER_STATE PowerState;
  1007. NDIS_STATUS NdisStatus;
  1008. PIRP pirp;
  1009. PIO_STACK_LOCATION pirpSp;
  1010. NTSTATUS NtStatus;
  1011. NDIS_POWER_PROFILE PowerProfile;
  1012. BOOLEAN fNotifyProtocols = FALSE;
  1013. BOOLEAN fStartMediaDisconnectTimer = FALSE;
  1014. KIRQL OldIrql;
  1015. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1016. ("==>ndisDevicePowerOn: Miniport %p\n", Miniport));
  1017. PnPReferencePackage();
  1018. pirp = pWorkItem->pIrp;
  1019. pirpSp = IoGetCurrentIrpStackLocation(pirp);
  1020. DeviceState = pirpSp->Parameters.Power.State.DeviceState;
  1021. #ifdef TRACE_PM_PROBLEMS
  1022. if (!NT_SUCCESS(pirp->IoStatus.Status))
  1023. {
  1024. DbgPrint("ndisDevicePowerOn: Miniport %p, Bus Driver returned %lx for Powering up the Miniport.\n",
  1025. Miniport, pirp->IoStatus.Status);
  1026. }
  1027. #endif
  1028. if (NT_SUCCESS(pirp->IoStatus.Status))
  1029. {
  1030. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1031. ("ndisDevicePowerOn: Miniport %p, Bus driver succeeded power up\n", Miniport));
  1032. //
  1033. // If the device is not in D0 then we need to wake up the miniport and
  1034. // restore the handlers.
  1035. //
  1036. if (Miniport->CurrentDevicePowerState != PowerDeviceD0)
  1037. {
  1038. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1039. ("ndisDevicePowerOn: Miniport %p, Power up the Miniport\n", Miniport));
  1040. //
  1041. // What type of miniport was this?
  1042. //
  1043. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE))
  1044. {
  1045. //
  1046. // Set the miniport's device state.
  1047. //
  1048. NdisStatus = ndisQuerySetMiniportDeviceState(Miniport,
  1049. DeviceState,
  1050. OID_PNP_SET_POWER,
  1051. TRUE);
  1052. ASSERT(KeGetCurrentIrql() == 0);
  1053. if (NdisStatus == NDIS_STATUS_SUCCESS)
  1054. Miniport->CurrentDevicePowerState = DeviceState;
  1055. //
  1056. // Start wake up timer
  1057. //
  1058. NdisMSetPeriodicTimer((PNDIS_MINIPORT_TIMER)(&Miniport->WakeUpDpcTimer),
  1059. Miniport->CheckForHangSeconds*1000);
  1060. }
  1061. else
  1062. {
  1063. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  1064. if (((Miniport->DriverHandle->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER) == 0) &&
  1065. (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_HALTED)))
  1066. {
  1067. NdisStatus = ndisPmInitializeMiniport(Miniport);
  1068. ASSERT(KeGetCurrentIrql() == 0);
  1069. }
  1070. else
  1071. {
  1072. NdisStatus = NDIS_STATUS_SUCCESS;
  1073. }
  1074. }
  1075. if (NDIS_STATUS_SUCCESS == NdisStatus)
  1076. {
  1077. if (ndisIsMiniportStarted(Miniport))
  1078. {
  1079. NdisSetEvent(&Miniport->OpenReadyEvent);
  1080. //
  1081. // Restore the handlers.
  1082. //
  1083. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1084. ndisMRestoreOpenHandlers(Miniport, fMINIPORT_STATE_PM_STOPPED);
  1085. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1086. ASSERT(KeGetCurrentIrql() == 0);
  1087. ASSERT(Miniport->SymbolicLinkName.Buffer != NULL);
  1088. if (Miniport->SymbolicLinkName.Buffer != NULL)
  1089. {
  1090. NtStatus = IoSetDeviceInterfaceState(&Miniport->SymbolicLinkName, TRUE);
  1091. }
  1092. if (!NT_SUCCESS(NtStatus))
  1093. {
  1094. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_ERR,
  1095. ("ndisDevicePowerOn: IoRegisterDeviceClassAssociation failed: Miniport %p, Status %lx\n", Miniport, NtStatus));
  1096. }
  1097. fNotifyProtocols = TRUE;
  1098. fStartMediaDisconnectTimer = TRUE;
  1099. //
  1100. // let the adapter know about the current power source
  1101. //
  1102. PowerProfile = ((BOOLEAN)ndisAcOnLine == TRUE) ?
  1103. NdisPowerProfileAcOnLine :
  1104. NdisPowerProfileBattery;
  1105. ndisNotifyMiniports(Miniport,
  1106. NdisDevicePnPEventPowerProfileChanged,
  1107. &PowerProfile,
  1108. sizeof(NDIS_POWER_PROFILE));
  1109. }
  1110. //
  1111. // Save the new power state the device is in.
  1112. //
  1113. Miniport->CurrentDevicePowerState = DeviceState;
  1114. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1115. ("ndisDevicePowerOn: Miniport %p, Going to device state 0x%x\n", Miniport, DeviceState));
  1116. //
  1117. // Notify the system that we are in the new device state.
  1118. //
  1119. PowerState.DeviceState = DeviceState;
  1120. PoSetPowerState(Miniport->DeviceObject, DevicePowerState, PowerState);
  1121. }
  1122. else
  1123. {
  1124. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  1125. ("ndisDevicePowerOn: Miniport %p, Power on failed by device driver for the Miniport, Error %lx!\n",
  1126. Miniport, NdisStatus));
  1127. #ifdef TRACE_PM_PROBLEMS
  1128. DbgPrint("ndisDevicePowerOn: Miniport %p, Device Driver failed powering up Miniport with Error %lx.\n",
  1129. Miniport,
  1130. NdisStatus);
  1131. #endif
  1132. pirp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  1133. }
  1134. }
  1135. else
  1136. {
  1137. //
  1138. // device is already in D0. we are here because of a cancel of QueryPower
  1139. //
  1140. if (ndisIsMiniportStarted(Miniport) &&
  1141. (Miniport->PnPDeviceState == NdisPnPDeviceStarted))
  1142. {
  1143. //
  1144. // even if the current state of the device is D0, we
  1145. // need to notify the protocol. because we could be getting
  1146. // this IRP as a cancel to a query IRP -or- the device
  1147. // never lost its D0 state, but the sytem went to sleep
  1148. // and woke up!
  1149. //
  1150. NdisSetEvent(&Miniport->OpenReadyEvent);
  1151. //
  1152. // Restore the handlers.
  1153. //
  1154. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1155. ndisMRestoreOpenHandlers(Miniport, fMINIPORT_STATE_PM_STOPPED);
  1156. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1157. fNotifyProtocols = TRUE;
  1158. fStartMediaDisconnectTimer = FALSE;
  1159. }
  1160. }
  1161. }
  1162. NtStatus = pirp->IoStatus.Status;
  1163. PoStartNextPowerIrp(pirp);
  1164. IoCompleteRequest(pirp, 0);
  1165. //
  1166. // notify the protocols here after completing the power IRP
  1167. // to avoid deadlocks when protocols block on a request that can only
  1168. // complete when the other power IRPs go through
  1169. //
  1170. //
  1171. // Handle the case where the device was not able to power up.
  1172. //
  1173. if (!NT_SUCCESS(NtStatus))
  1174. {
  1175. #ifdef TRACE_PM_PROBLEMS
  1176. DbgPrint("ndisDevicePowerOn: Miniport %p, Bus or Device failed powering up the Miniport with Error %lx.\n",
  1177. Miniport,
  1178. NtStatus);
  1179. #endif
  1180. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  1181. ("ndisDevicePowerOn: Miniport %p, Power on failed by bus or device driver for Miniport with Error %lx!\n",
  1182. Miniport, NtStatus));
  1183. //
  1184. // Mark the miniport as having failed so that we remove it correctly.
  1185. //
  1186. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_DEVICE_FAILED);
  1187. //
  1188. // We need to tell pnp that the device state has changed.
  1189. //
  1190. IoInvalidateDeviceState(Miniport->PhysicalDeviceObject);
  1191. ASSERT(KeGetCurrentIrql() == 0);
  1192. }
  1193. if (fNotifyProtocols)
  1194. {
  1195. //
  1196. // for some protocols we may have closed the binding
  1197. //
  1198. ndisCheckAdapterBindings(Miniport, NULL);
  1199. //
  1200. // Notify the transports.
  1201. //
  1202. ndisPnPNotifyAllTransports(Miniport,
  1203. NetEventSetPower,
  1204. &DeviceState,
  1205. sizeof(DeviceState));
  1206. ndisNotifyDevicePowerStateChange(Miniport, DeviceState);
  1207. //
  1208. // if media state has changed from disconnect to connect
  1209. // and the last indicated status was disconnect,
  1210. // we should notify the protcols (and Ndis) that the media is
  1211. // connected
  1212. //
  1213. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_INDICATED) &&
  1214. MINIPORT_TEST_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED))
  1215. {
  1216. BLOCK_LOCK_MINIPORT_LOCKED(Miniport, OldIrql);
  1217. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  1218. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED);
  1219. NdisMIndicateStatus(Miniport,
  1220. NDIS_STATUS_MEDIA_CONNECT,
  1221. INTERNAL_INDICATION_BUFFER,
  1222. INTERNAL_INDICATION_SIZE);
  1223. NdisMIndicateStatusComplete(Miniport);
  1224. UNLOCK_MINIPORT_L(Miniport);
  1225. LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
  1226. }
  1227. //
  1228. // check the media status and if it is disconnected, start the timer
  1229. //
  1230. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED) &&
  1231. fStartMediaDisconnectTimer)
  1232. {
  1233. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE) &&
  1234. (Miniport->WakeUpEnable & NDIS_PNP_WAKE_UP_LINK_CHANGE) &&
  1235. (Miniport->MediaDisconnectTimeOut != (USHORT)(-1)))
  1236. {
  1237. //
  1238. // Are we already waiting for the disconnect timer to fire?
  1239. //
  1240. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT))
  1241. {
  1242. //
  1243. // Mark the miniport as disconnecting and fire off the
  1244. // timer.
  1245. //
  1246. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED);
  1247. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT);
  1248. NdisSetTimer(&Miniport->MediaDisconnectTimer, Miniport->MediaDisconnectTimeOut * 1000);
  1249. }
  1250. }
  1251. }
  1252. }
  1253. ASSERT(KeGetCurrentIrql() == 0);
  1254. MINIPORT_DECREMENT_REF(Miniport);
  1255. FREE_POOL(pWorkItem);
  1256. PnPDereferencePackage();
  1257. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1258. ("<==ndisDevicePowerOn: Miniport %p\n", Miniport));
  1259. }
  1260. NTSTATUS
  1261. ndisSetDevicePowerOnComplete(
  1262. IN PDEVICE_OBJECT pdo,
  1263. IN PIRP pirp,
  1264. IN PVOID pContext
  1265. )
  1266. /*++
  1267. Routine Description:
  1268. Arguments:
  1269. pdo - Pointer to the device object for the miniport.
  1270. pirp - Pointer to the device set power state IRP that was completed.
  1271. Context - Not used
  1272. Return Value:
  1273. --*/
  1274. {
  1275. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)pContext;
  1276. PPOWER_WORK_ITEM pWorkItem;
  1277. NDIS_STATUS NdisStatus;
  1278. DEVICE_POWER_STATE DeviceState;
  1279. POWER_STATE PowerState;
  1280. PIO_STACK_LOCATION pirpSp;
  1281. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1282. ("==>ndisSetDevicePowerOnComplete: Miniport %p, Irp %p, Status %lx\n",
  1283. Miniport, pirp, pirp->IoStatus.Status));
  1284. do
  1285. {
  1286. if (Miniport->PnPDeviceState != NdisPnPDeviceStarted)
  1287. {
  1288. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1289. ("ndisSetDevicePowerOnComplete: Miniport %p is not started yet.\n", Miniport));
  1290. pirpSp = IoGetCurrentIrpStackLocation(pirp);
  1291. DeviceState = pirpSp->Parameters.Power.State.DeviceState;
  1292. //
  1293. // Notify the system that we are in the new device state.
  1294. //
  1295. Miniport->CurrentDevicePowerState = DeviceState;
  1296. PowerState.DeviceState = DeviceState;
  1297. PoSetPowerState(Miniport->DeviceObject, DevicePowerState, PowerState);
  1298. PoStartNextPowerIrp(pirp);
  1299. IoCompleteRequest(pirp, 0);
  1300. break;
  1301. }
  1302. pWorkItem = ALLOC_FROM_POOL(sizeof(POWER_WORK_ITEM), NDIS_TAG_WORK_ITEM);
  1303. if (pWorkItem == NULL)
  1304. {
  1305. pirp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1306. PoStartNextPowerIrp(pirp);
  1307. IoCompleteRequest(pirp, 0);
  1308. break;
  1309. }
  1310. //
  1311. // Initialize the ndis work item to power on.
  1312. //
  1313. NdisInitializeWorkItem(&pWorkItem->WorkItem,
  1314. (NDIS_PROC)ndisDevicePowerOn,
  1315. Miniport);
  1316. pWorkItem->pIrp = pirp;
  1317. //
  1318. // this reference and corresponding dereference in ndisDevicePowerOn is done
  1319. // to ensure ndis does not return back from REMOVE IRP while we are waiting
  1320. // for ndisDevicePowerOn to fire.
  1321. //
  1322. MINIPORT_INCREMENT_REF(Miniport);
  1323. //
  1324. // Schedule the workitem to fire.
  1325. //
  1326. INITIALIZE_WORK_ITEM((PWORK_QUEUE_ITEM)(&pWorkItem->WorkItem.WrapperReserved),
  1327. ndisWorkItemHandler,
  1328. &pWorkItem->WorkItem);
  1329. XQUEUE_WORK_ITEM((PWORK_QUEUE_ITEM)(&pWorkItem->WorkItem.WrapperReserved), DelayedWorkQueue);
  1330. } while (FALSE);
  1331. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1332. ("<==ndisSetDevicePowerOnComplete: Miniport %p\n", Miniport));
  1333. return(STATUS_MORE_PROCESSING_REQUIRED);
  1334. }
  1335. VOID
  1336. ndisDevicePowerDown(
  1337. IN PPOWER_WORK_ITEM pWorkItem,
  1338. IN PVOID pContext
  1339. )
  1340. /*++
  1341. Routine Description:
  1342. Arguments:
  1343. Return Value:
  1344. --*/
  1345. {
  1346. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)pContext;
  1347. DEVICE_POWER_STATE DeviceState;
  1348. POWER_STATE PowerState;
  1349. NDIS_STATUS NdisStatus;
  1350. PIRP pirp;
  1351. PIO_STACK_LOCATION pirpSp;
  1352. KIRQL OldIrql;
  1353. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1354. ("==>ndisDevicePowerDown: Miniport %p\n", Miniport));
  1355. PnPReferencePackage();
  1356. pirp = pWorkItem->pIrp;
  1357. pirpSp = IoGetCurrentIrpStackLocation(pirp);
  1358. DeviceState = pirpSp->Parameters.Power.State.DeviceState;
  1359. //
  1360. // If the complete status is successful then we need to continue with
  1361. // wakeing the stack.
  1362. //
  1363. if (NT_SUCCESS(pirp->IoStatus.Status))
  1364. {
  1365. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1366. ("ndisDevicePowerDown: Miniport %p, going to device state 0x%x\n", Miniport, DeviceState));
  1367. //
  1368. // Build a power state.
  1369. //
  1370. PowerState.DeviceState = DeviceState;
  1371. //
  1372. // Save the current device state with the miniport block.
  1373. //
  1374. Miniport->CurrentDevicePowerState = DeviceState;
  1375. //
  1376. // Let the system know about the devices new power state.
  1377. //
  1378. PoSetPowerState(Miniport->DeviceObject, DevicePowerState, PowerState);
  1379. }
  1380. else if (ndisIsMiniportStarted(Miniport) &&
  1381. (Miniport->PnPDeviceState == NdisPnPDeviceStarted))
  1382. {
  1383. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  1384. ("ndisDevicePowerDown: Miniport %p, Bus driver failed to power down the Miniport\n", Miniport));
  1385. #ifdef TRACE_PM_PROBLEMS
  1386. DbgPrint("ndisDevicePowerDown: Miniport %p, Bus Driver returned %lx for Powering Down the Miniport\n",
  1387. Miniport, pirp->IoStatus.Status);
  1388. #endif
  1389. //
  1390. // We need to go back to the current device state.
  1391. //
  1392. PowerState.DeviceState = Miniport->CurrentDevicePowerState;
  1393. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1394. ("ndisDevicePowerDown: Miniport %p, going to device power state 0x%x\n", Miniport, Miniport->CurrentDevicePowerState));
  1395. //
  1396. // What type of miniport was this?
  1397. //
  1398. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE))
  1399. {
  1400. //
  1401. // Set the miniport's device state.
  1402. //
  1403. NdisStatus = ndisQuerySetMiniportDeviceState(Miniport,
  1404. PowerState.DeviceState,
  1405. OID_PNP_SET_POWER,
  1406. TRUE);
  1407. }
  1408. else
  1409. {
  1410. NdisStatus = ndisPmInitializeMiniport(Miniport);
  1411. }
  1412. //
  1413. // Is the miniport initialized?
  1414. //
  1415. if (NDIS_STATUS_SUCCESS != NdisStatus)
  1416. {
  1417. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1418. ("ndisDevicePowerDown: Miniport %p, failed to power down but we are not able to reinitialize it.\n", Miniport));
  1419. //
  1420. // Mark the miniport as having failed so that we remove it correctly.
  1421. //
  1422. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_DEVICE_FAILED);
  1423. //
  1424. // The bus driver failed the power off and we can't power the miniport back on.
  1425. // we invalidate the device state so that it will get removed.
  1426. //
  1427. IoInvalidateDeviceState(Miniport->PhysicalDeviceObject);
  1428. pirp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  1429. }
  1430. else
  1431. {
  1432. //
  1433. // Restore the handlers.
  1434. //
  1435. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1436. ndisMRestoreOpenHandlers(Miniport, fMINIPORT_STATE_PM_STOPPED);
  1437. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1438. IoSetDeviceInterfaceState(&Miniport->SymbolicLinkName, TRUE);
  1439. ndisNotifyDevicePowerStateChange(Miniport, PowerState.DeviceState);
  1440. //
  1441. // Notify the transports.
  1442. //
  1443. NdisStatus = ndisPnPNotifyAllTransports(Miniport,
  1444. NetEventSetPower,
  1445. &PowerState.DeviceState,
  1446. sizeof(PowerState.DeviceState));
  1447. ASSERT(NDIS_STATUS_SUCCESS == NdisStatus);
  1448. }
  1449. }
  1450. PoStartNextPowerIrp(pirp);
  1451. IoCompleteRequest(pirp, 0);
  1452. FREE_POOL(pWorkItem);
  1453. ASSERT(KeGetCurrentIrql() == 0);
  1454. PnPDereferencePackage();
  1455. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1456. ("<==ndisDevicePowerDown: Miniport %p\n", Miniport));
  1457. }
  1458. NTSTATUS
  1459. ndisSetDevicePowerDownComplete(
  1460. IN PDEVICE_OBJECT pdo,
  1461. IN PIRP pirp,
  1462. IN PVOID pContext
  1463. )
  1464. /*++
  1465. Routine Description:
  1466. Arguments:
  1467. pdo - Pointer to the device object for the miniport.
  1468. pirp - Pointer to the device set power state IRP that was completed.
  1469. Context - Not used
  1470. Return Value:
  1471. --*/
  1472. {
  1473. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)pContext;
  1474. NTSTATUS Status;
  1475. PPOWER_WORK_ITEM pWorkItem;
  1476. NDIS_STATUS NdisStatus;
  1477. BOOLEAN fTimerCancelled;
  1478. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1479. ("==>ndisSetDevicePowerDownComplete: Miniport %p, Irp %p, Status %lx\n",
  1480. Miniport, pirp, pirp->IoStatus.Status));
  1481. //
  1482. // cancel any pending media disconnect timers
  1483. //
  1484. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT))
  1485. {
  1486. //
  1487. // Clear the disconnect wait bit and cancel the timer.
  1488. // IF the timer routine hasn't grabed the lock then we are ok.
  1489. //
  1490. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1491. ("ndisSetDevicePowerDownComplete: Miniport %p, cancelling media disconnect timer\n",Miniport));
  1492. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT);
  1493. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED);
  1494. NdisCancelTimer(&Miniport->MediaDisconnectTimer, &fTimerCancelled);
  1495. }
  1496. do
  1497. {
  1498. pWorkItem = ALLOC_FROM_POOL(sizeof(POWER_WORK_ITEM), NDIS_TAG_WORK_ITEM);
  1499. if (pWorkItem == NULL)
  1500. {
  1501. pirp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1502. PoStartNextPowerIrp(pirp);
  1503. IoCompleteRequest(pirp, 0);
  1504. break;
  1505. }
  1506. NdisInitializeWorkItem(&pWorkItem->WorkItem,
  1507. (NDIS_PROC)ndisDevicePowerDown,
  1508. Miniport);
  1509. pWorkItem->pIrp = pirp;
  1510. //
  1511. // Schedule the workitem to fire.
  1512. //
  1513. NdisScheduleWorkItem(&pWorkItem->WorkItem);
  1514. } while (FALSE);
  1515. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1516. ("<==ndisSetDevicePowerDownComplete: Miniport %p\n", Miniport));
  1517. return(STATUS_MORE_PROCESSING_REQUIRED);
  1518. }
  1519. NTSTATUS
  1520. ndisSetPower(
  1521. IN PIRP pirp,
  1522. IN PIO_STACK_LOCATION pirpSp,
  1523. IN PNDIS_MINIPORT_BLOCK Miniport
  1524. )
  1525. /*++
  1526. Routine Description:
  1527. This routine will process the IRP_MN_SET_POWER for a miniport driver.
  1528. Arguments:
  1529. pirp - Pointer to the IRP.
  1530. pirpSp - Pointer to the IRPs current stack location.
  1531. Miniport - Pointer to the Miniport
  1532. Return Value:
  1533. --*/
  1534. {
  1535. POWER_STATE PowerState;
  1536. DEVICE_POWER_STATE DeviceState;
  1537. SYSTEM_POWER_STATE SystemState;
  1538. NDIS_DEVICE_POWER_STATE NdisDeviceState;
  1539. NTSTATUS Status;
  1540. PIO_STACK_LOCATION pirpSpN;
  1541. IO_STATUS_BLOCK IoStatus;
  1542. PIRP pirpWake;
  1543. NDIS_STATUS NdisStatus;
  1544. KEVENT Event;
  1545. ULONG WakeEnable = 0;
  1546. PIRP pIrpWaitWake;
  1547. KIRQL OldIrql;
  1548. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1549. ("==>ndisSetPower: Miniport %p, Irp %p\n", Miniport, pirp));
  1550. PnPReferencePackage();
  1551. switch (pirpSp->Parameters.Power.Type)
  1552. {
  1553. case SystemPowerState:
  1554. SystemState = pirpSp->Parameters.Power.State.SystemState;
  1555. Miniport->WaitWakeSystemState = SystemState;
  1556. //
  1557. // if system is shutting down, call the shutdown handler
  1558. // for miniport and be done with it
  1559. //
  1560. if (SystemState >= PowerSystemShutdown)
  1561. {
  1562. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1563. ("ndisSetPower: Miniport %p, SystemState %lx\n", Miniport, SystemState));
  1564. if ((Miniport->DriverHandle->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER) == 0)
  1565. {
  1566. ndisMShutdownMiniport(Miniport);
  1567. }
  1568. pirp->IoStatus.Status = STATUS_SUCCESS;
  1569. PoStartNextPowerIrp(pirp);
  1570. IoSkipCurrentIrpStackLocation(pirp);
  1571. Status = PoCallDriver(Miniport->NextDeviceObject, pirp);
  1572. break;
  1573. }
  1574. else
  1575. {
  1576. //
  1577. // Get the device state for the system state. Note that this will
  1578. // set the fMINIPORT_SYSTEM_SLEEPING flag if we are going to
  1579. // SystemState > PowerSystemWorking
  1580. //
  1581. Status = ndisMPowerPolicy(Miniport, SystemState, &DeviceState, FALSE);
  1582. //
  1583. // Is the device already powered off?
  1584. //
  1585. if (STATUS_DEVICE_POWERED_OFF == Status)
  1586. {
  1587. pirp->IoStatus.Status = STATUS_SUCCESS;
  1588. PoStartNextPowerIrp(pirp);
  1589. IoCompleteRequest(pirp, 0);
  1590. Status = STATUS_SUCCESS;
  1591. break;
  1592. }
  1593. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1594. ("ndisSetPower: Miniport %p, SystemPowerState[0x%x] DevicePowerState[0x%x]\n",
  1595. Miniport, SystemState, DeviceState));
  1596. PowerState.DeviceState = DeviceState;
  1597. if (SystemState > PowerSystemWorking)
  1598. {
  1599. NdisResetEvent(&Miniport->OpenReadyEvent);
  1600. //
  1601. // if system is going to sleep mode, then notify protocols and
  1602. // request a WAIT_WAKE IRP
  1603. //
  1604. //
  1605. // Notify the transports of the impending state transition.
  1606. // There is nothing we can do if transports fail this
  1607. // Note: for all practical purposes there is no need to map
  1608. // SytemState to device state here
  1609. //
  1610. if (SystemState > PowerSystemSleeping3)
  1611. NdisDeviceState = PowerSystemSleeping3;
  1612. else
  1613. NdisDeviceState = SystemState;
  1614. ndisNotifyDevicePowerStateChange(Miniport, NdisDeviceState);
  1615. NdisStatus = ndisPnPNotifyAllTransports(Miniport,
  1616. NetEventSetPower,
  1617. &NdisDeviceState,
  1618. sizeof(SystemState));
  1619. //
  1620. // protocols can't fail going to a sleeping state
  1621. //
  1622. ASSERT(NDIS_STATUS_SUCCESS == NdisStatus);
  1623. MiniportReferencePackage();
  1624. //
  1625. // Swap the handlers.
  1626. //
  1627. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1628. ndisMSwapOpenHandlers(Miniport,
  1629. NDIS_STATUS_ADAPTER_NOT_READY,
  1630. fMINIPORT_STATE_PM_STOPPED);
  1631. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1632. MiniportDereferencePackage();
  1633. //
  1634. // What type of miniport was this?
  1635. //
  1636. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE))
  1637. {
  1638. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1639. if (Miniport->pIrpWaitWake != NULL)
  1640. {
  1641. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE);
  1642. }
  1643. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1644. //
  1645. // Is wake-up enabled?
  1646. //
  1647. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE))
  1648. {
  1649. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE);
  1650. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1651. ("ndisSetPower: Miniport %p, Creating a wake irp for the device\n", Miniport));
  1652. //
  1653. // reuquest a power irp for wake notification
  1654. //
  1655. PowerState.SystemState = Miniport->WaitWakeSystemState;
  1656. Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject,
  1657. IRP_MN_WAIT_WAKE,
  1658. PowerState,
  1659. ndisWaitWakeComplete,
  1660. Miniport,
  1661. &Miniport->pIrpWaitWake);
  1662. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1663. ("ndisSetPower: Miniport %p, WaiteWakeIrp %p\n",
  1664. Miniport, Miniport->pIrpWaitWake));
  1665. }
  1666. }
  1667. }
  1668. else
  1669. {
  1670. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1671. pIrpWaitWake = Miniport->pIrpWaitWake;
  1672. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1673. //
  1674. // if we are transitioning to PowerSystemWorking or just asserting
  1675. // it to cancel a query power, we will notify the protocols when
  1676. // we get the device power IRP
  1677. //
  1678. //
  1679. // If there is a wait-wake irp outstanding then we need to cancel it.
  1680. //
  1681. if (pIrpWaitWake)
  1682. {
  1683. if (IoCancelIrp(pIrpWaitWake))
  1684. {
  1685. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1686. ("ndisSetPower: Miniport %p, Successfully canceled wake irp\n", Miniport));
  1687. }
  1688. }
  1689. //
  1690. // Send the S0 irp down the stack first. When it completes, send the D0 irp. This
  1691. // allows the power manager to resume faster while the slow network initialization
  1692. // takes place in the background.
  1693. //
  1694. IoCopyCurrentIrpStackLocationToNext(pirp);
  1695. IoSetCompletionRoutine(pirp,
  1696. ndisSetSystemPowerOnComplete,
  1697. Miniport,
  1698. TRUE,
  1699. TRUE,
  1700. TRUE);
  1701. IoMarkIrpPending(pirp);
  1702. PoStartNextPowerIrp(pirp);
  1703. PoCallDriver(Miniport->NextDeviceObject, pirp);
  1704. Status = STATUS_PENDING;
  1705. break;
  1706. }
  1707. }
  1708. //
  1709. // no matter what was the outcome of trying to set a WAIT_WAKE IRP
  1710. // we still have to set the device state appropiately
  1711. //
  1712. PowerState.DeviceState = DeviceState;
  1713. //
  1714. // Save the device object with the system irp to use in the
  1715. // completion routine.
  1716. //
  1717. pirpSpN = IoGetNextIrpStackLocation(pirp);
  1718. pirpSpN->DeviceObject = Miniport->DeviceObject;
  1719. IoMarkIrpPending(pirp);
  1720. PoStartNextPowerIrp(pirp);
  1721. //
  1722. // Let the completion routine take care of everything.
  1723. //
  1724. Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject,
  1725. IRP_MN_SET_POWER,
  1726. PowerState,
  1727. ndisSetSystemPowerComplete,
  1728. pirp,
  1729. NULL);
  1730. if (STATUS_PENDING != Status)
  1731. {
  1732. IoStatus.Status = Status;
  1733. IoStatus.Information = 0;
  1734. ndisSetSystemPowerComplete(Miniport->PhysicalDeviceObject,
  1735. IRP_MN_SET_POWER,
  1736. PowerState,
  1737. pirp,
  1738. &IoStatus);
  1739. }
  1740. Status = STATUS_PENDING;
  1741. break;
  1742. case DevicePowerState:
  1743. //
  1744. // Get the device state.
  1745. //
  1746. DeviceState = pirpSp->Parameters.Power.State.DeviceState;
  1747. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1748. ("ndisSetPower: Miniport %p, DeviceState[0x%x]\n", Miniport, DeviceState));
  1749. //
  1750. // What state is the device going to?
  1751. //
  1752. switch (DeviceState)
  1753. {
  1754. case PowerDeviceD0:
  1755. //
  1756. // We need to pass this IRP down to the pdo so that
  1757. // it can power on.
  1758. //
  1759. IoCopyCurrentIrpStackLocationToNext(pirp);
  1760. IoSetCompletionRoutine(pirp,
  1761. ndisSetDevicePowerOnComplete,
  1762. Miniport,
  1763. TRUE,
  1764. TRUE,
  1765. TRUE);
  1766. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1767. ("ndisSetPower: Miniport %p, Power up the bus driver.\n", Miniport));
  1768. //
  1769. // Mark the IRP as pending and send it down the stack.
  1770. //
  1771. IoMarkIrpPending(pirp);
  1772. PoStartNextPowerIrp(pirp);
  1773. PoCallDriver(Miniport->NextDeviceObject, pirp);
  1774. Status = STATUS_PENDING;
  1775. break;
  1776. case PowerDeviceD1:
  1777. case PowerDeviceD2:
  1778. case PowerDeviceD3:
  1779. if (ndisIsMiniportStarted(Miniport) &&
  1780. (Miniport->PnPDeviceState == NdisPnPDeviceStarted))
  1781. {
  1782. //
  1783. // if the device state setting is not the result of going to
  1784. // a sleeping system state, (such as media disconnect case)
  1785. // then notify protocols, etc.
  1786. //
  1787. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING))
  1788. {
  1789. NdisResetEvent(&Miniport->OpenReadyEvent);
  1790. ndisNotifyDevicePowerStateChange(Miniport, DeviceState);
  1791. //
  1792. // Notify the transports of the impending state transition.
  1793. //
  1794. NdisStatus = ndisPnPNotifyAllTransports(Miniport,
  1795. NetEventSetPower,
  1796. &DeviceState,
  1797. sizeof(DeviceState));
  1798. ASSERT(NDIS_STATUS_SUCCESS == NdisStatus);
  1799. //
  1800. // Swap the handlers.
  1801. //
  1802. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1803. ndisMSwapOpenHandlers(Miniport,
  1804. NDIS_STATUS_ADAPTER_NOT_READY,
  1805. fMINIPORT_STATE_PM_STOPPED);
  1806. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1807. }
  1808. //
  1809. // What type of miniport was this?
  1810. //
  1811. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE))
  1812. {
  1813. BOOLEAN Canceled;
  1814. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING))
  1815. {
  1816. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1817. if (Miniport->pIrpWaitWake != NULL)
  1818. {
  1819. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE);
  1820. }
  1821. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1822. //
  1823. // Is wake-up enabled?
  1824. //
  1825. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE))
  1826. {
  1827. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE);
  1828. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1829. ("ndisSetPower: Miniport %p, Creating a wake irp for the device\n", Miniport));
  1830. //
  1831. // reuquest a power irp for wake notification
  1832. //
  1833. PowerState.SystemState = Miniport->WaitWakeSystemState;
  1834. Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject,
  1835. IRP_MN_WAIT_WAKE,
  1836. PowerState,
  1837. ndisWaitWakeComplete,
  1838. Miniport,
  1839. &Miniport->pIrpWaitWake);
  1840. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1841. ("ndisSetPower: Miniport %p, WaiteWakeIrp %p\n",
  1842. Miniport, Miniport->pIrpWaitWake));
  1843. }
  1844. }
  1845. //
  1846. // disable the interface
  1847. //
  1848. if (Miniport->SymbolicLinkName.Buffer != NULL)
  1849. {
  1850. IoSetDeviceInterfaceState(&Miniport->SymbolicLinkName, FALSE);
  1851. }
  1852. //
  1853. // Set the miniport device state.
  1854. //
  1855. NdisStatus = ndisQuerySetMiniportDeviceState(Miniport,
  1856. DeviceState,
  1857. OID_PNP_SET_POWER,
  1858. TRUE);
  1859. if (NDIS_STATUS_SUCCESS != NdisStatus)
  1860. {
  1861. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  1862. ("ndisSetPower: Miniport %p, Failed to power the device down\n", Miniport));
  1863. if (Miniport->SymbolicLinkName.Buffer != NULL)
  1864. {
  1865. IoSetDeviceInterfaceState(&Miniport->SymbolicLinkName, TRUE);
  1866. }
  1867. pirp->IoStatus.Status = NdisStatus;
  1868. PoStartNextPowerIrp(pirp);
  1869. IoCompleteRequest(pirp, 0);
  1870. Status = NdisStatus;
  1871. break;
  1872. }
  1873. //
  1874. // Cancel the wake-up timer.
  1875. //
  1876. NdisCancelTimer(&Miniport->WakeUpDpcTimer, &Canceled);
  1877. if (!Canceled)
  1878. {
  1879. NdisStallExecution(NDIS_MINIPORT_WAKEUP_TIMEOUT * 1000);
  1880. }
  1881. }
  1882. else
  1883. {
  1884. if ((Miniport->DriverHandle->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER) == 0)
  1885. {
  1886. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1887. ("ndisSetPower: Miniport %p, Halt the miniport\n", Miniport));
  1888. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_FAILED))
  1889. {
  1890. //
  1891. // Halt the legacy miniport.
  1892. //
  1893. ndisPmHaltMiniport(Miniport);
  1894. }
  1895. }
  1896. }
  1897. }
  1898. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1899. ("ndisSetPower: Miniport %p, Notify the bus driver of the low power state\n", Miniport));
  1900. //
  1901. // We need to pass this IRP down to the pdo so that
  1902. // it can power down.
  1903. //
  1904. IoCopyCurrentIrpStackLocationToNext(pirp);
  1905. IoSetCompletionRoutine(pirp,
  1906. ndisSetDevicePowerDownComplete,
  1907. Miniport,
  1908. TRUE,
  1909. TRUE,
  1910. TRUE);
  1911. IoMarkIrpPending(pirp);
  1912. PoStartNextPowerIrp(pirp);
  1913. PoCallDriver(Miniport->NextDeviceObject, pirp);
  1914. Status = STATUS_PENDING;
  1915. break;
  1916. }
  1917. //
  1918. // Done with processing the device set power state.
  1919. //
  1920. break;
  1921. }
  1922. PnPDereferencePackage();
  1923. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1924. ("<==ndisSetPower: Miniport %p, Status %lx\n", Miniport, Status));
  1925. return(Status);
  1926. }
  1927. NTSTATUS
  1928. ndisPowerDispatch(
  1929. IN PDEVICE_OBJECT pDeviceObject,
  1930. IN PIRP pirp
  1931. )
  1932. /*++
  1933. Routine Description:
  1934. Arguments:
  1935. Return Value:
  1936. --*/
  1937. {
  1938. PIO_STACK_LOCATION pirpSp;
  1939. NTSTATUS Status;
  1940. PNDIS_MINIPORT_BLOCK Miniport;
  1941. PDEVICE_OBJECT NextDeviceObject;
  1942. PIO_STACK_LOCATION pirpSpN;
  1943. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1944. ("==>ndisPowerDispatch: DeviceObject %p, Irp %p\n", pDeviceObject, pirp));
  1945. PnPReferencePackage();
  1946. //
  1947. // Get a pointer to the adapter block and miniport block then determine
  1948. // which one we should use.
  1949. //
  1950. Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)pDeviceObject->DeviceExtension + 1);
  1951. if (Miniport->Signature != (PVOID)MINIPORT_DEVICE_MAGIC_VALUE)
  1952. {
  1953. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1954. ("ndisPowerDispatch: DeviceObject %p, Irp %p, Device extension is not a miniport.\n", pDeviceObject, pirp));
  1955. //
  1956. // Fail the invalid request.
  1957. //
  1958. pirp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST;
  1959. PoStartNextPowerIrp(pirp);
  1960. IoCompleteRequest(pirp, 0);
  1961. goto Done;
  1962. }
  1963. //
  1964. // Get a pointer to the next DeviceObject.
  1965. //
  1966. NextDeviceObject = Miniport->NextDeviceObject;
  1967. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1968. ("ndisPowerDispatch: Miniport %p\n", Miniport));
  1969. //
  1970. // Get the stack parameters for this IRP.
  1971. //
  1972. pirpSp = IoGetCurrentIrpStackLocation(pirp);
  1973. switch (pirpSp->MinorFunction)
  1974. {
  1975. //
  1976. // power management stuff
  1977. //
  1978. case IRP_MN_POWER_SEQUENCE:
  1979. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1980. ("ndisPowerDispatch: Miniport %p, Processing IRP_MN_POWER_SEQUENCE\n", Miniport));
  1981. PoStartNextPowerIrp(pirp);
  1982. //
  1983. // Generic routine that will pass the IRP to the next device
  1984. // object in the layer that wants to process it.
  1985. //
  1986. IoCopyCurrentIrpStackLocationToNext(pirp);
  1987. Status = ndisPassIrpDownTheStack(pirp, NextDeviceObject);
  1988. pirp->IoStatus.Status = Status;
  1989. IoCompleteRequest(pirp, 0);
  1990. break;
  1991. case IRP_MN_WAIT_WAKE:
  1992. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  1993. ("ndisPowerDispatch: Miniport %p, Processing IRP_MN_WAIT_WAKE\n", Miniport));
  1994. //
  1995. // Fill in the wake information.
  1996. //
  1997. pirpSp->Parameters.WaitWake.PowerState = Miniport->WaitWakeSystemState;
  1998. IoCopyCurrentIrpStackLocationToNext(pirp);
  1999. PoStartNextPowerIrp(pirp);
  2000. Status = PoCallDriver(NextDeviceObject, pirp);
  2001. break;
  2002. case IRP_MN_QUERY_POWER:
  2003. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2004. ("ndisPowerDispatch: Miniport %p, Processing IRP_MN_QUERY_POWER\n", Miniport));
  2005. Status = ndisQueryPower(pirp, pirpSp, Miniport);
  2006. break;
  2007. case IRP_MN_SET_POWER:
  2008. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2009. ("ndisPowerDispatch: Miniport %p, Processing IRP_MN_SET_POWER\n", Miniport));
  2010. Status = ndisSetPower(pirp, pirpSp, Miniport);
  2011. break;
  2012. default:
  2013. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2014. ("ndisPowerDispatch: Miniport %p, Processing minor function: %lx\n",
  2015. Miniport, pirpSp->MinorFunction));
  2016. //
  2017. // send the IRP down
  2018. //
  2019. PoStartNextPowerIrp(pirp);
  2020. IoSkipCurrentIrpStackLocation(pirp);
  2021. Status = PoCallDriver(NextDeviceObject, pirp);
  2022. break;
  2023. }
  2024. Done:
  2025. PnPDereferencePackage();
  2026. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2027. ("<==ndisPowerDispatch: Miniport %p, Status 0x%x\n", Miniport, Status));
  2028. return(Status);
  2029. }
  2030. NTSTATUS
  2031. FASTCALL
  2032. ndisMShutdownMiniport(
  2033. IN PNDIS_MINIPORT_BLOCK Miniport
  2034. )
  2035. /*++
  2036. Routine Description:
  2037. The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis
  2038. shutdown routine, if one is registered.
  2039. Arguments:
  2040. DeviceObject - The adapter's device object.
  2041. Irp - The IRP.
  2042. Return Value:
  2043. Always STATUS_SUCCESS.
  2044. --*/
  2045. {
  2046. PDEVICE_OBJECT DeviceObject = Miniport->DeviceObject;
  2047. PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension;
  2048. KIRQL OldIrql;
  2049. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  2050. ("==>ndisMShutdownMiniport: Miniport %p\n", Miniport));
  2051. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  2052. //
  2053. // Mark the miniport as halting and NOT using normal interrupts.
  2054. //
  2055. MINIPORT_SET_FLAG(Miniport, fMINIPORT_PM_HALTING);
  2056. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SHUTTING_DOWN);
  2057. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
  2058. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  2059. if ((WrapperContext->ShutdownHandler != NULL) &&
  2060. (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_NO_SHUTDOWN) == 0))
  2061. {
  2062. //
  2063. // Call the shutdown routine.
  2064. //
  2065. if (WrapperContext->ShutdownHandler != NULL)
  2066. {
  2067. WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
  2068. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SHUT_DOWN);
  2069. }
  2070. }
  2071. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  2072. ("<==ndisMShutdownMiniport: Miniport %p\n", Miniport));
  2073. return STATUS_SUCCESS;
  2074. }
  2075. NTSTATUS
  2076. ndisMPowerPolicy(
  2077. IN PNDIS_MINIPORT_BLOCK Miniport,
  2078. IN SYSTEM_POWER_STATE SystemState,
  2079. IN PDEVICE_POWER_STATE pDeviceState,
  2080. IN BOOLEAN fIsQuery
  2081. )
  2082. /*++
  2083. Routine Description:
  2084. This routine will determine if the miniport should go to the given device state.
  2085. Arguments:
  2086. Miniport - Pointer to the miniport block
  2087. SystemState - State the system wants to go to.
  2088. Return Value:
  2089. --*/
  2090. {
  2091. DEVICE_POWER_STATE DeviceStateForSystemState, MinDeviceWakeup = PowerDeviceUnspecified;
  2092. NTSTATUS Status = STATUS_SUCCESS;
  2093. DEVICE_POWER_STATE NewDeviceState = PowerDeviceD3;
  2094. PNDIS_PM_WAKE_UP_CAPABILITIES pWakeCaps;
  2095. NDIS_STATUS NdisStatus;
  2096. ULONG WakeEnable;
  2097. PIRP pIrpWaitWake;
  2098. KIRQL OldIrql;
  2099. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2100. ("==>ndisMPowerPolicy: Miniport %p, SystemState %lx\n", Miniport, SystemState));
  2101. if (SystemState >= PowerSystemShutdown)
  2102. {
  2103. //
  2104. // if this is a shutdown request, set device to D3 and return
  2105. //
  2106. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2107. ("ndisMPowerPolicy: Miniport %p, shutting down\n", Miniport));
  2108. *pDeviceState = PowerDeviceD3;
  2109. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2110. ("<==ndisMPowerPolicy: Miniport %p\n", Miniport));
  2111. return(STATUS_SUCCESS);
  2112. }
  2113. //
  2114. // If the system wants to transition to working then we are going to D0.
  2115. //
  2116. if (SystemState == PowerSystemWorking)
  2117. {
  2118. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2119. ("ndisMPowerPolicy: Miniport %p, Wakeing up the device\n", Miniport));
  2120. if (!fIsQuery)
  2121. {
  2122. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING);
  2123. }
  2124. *pDeviceState = PowerDeviceD0;
  2125. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2126. ("<==ndisMPowerPolicy: Miniport %p\n", Miniport));
  2127. return(STATUS_SUCCESS);
  2128. }
  2129. if (!fIsQuery)
  2130. {
  2131. //
  2132. // tag the miniport so when we get the device power IRP, we
  2133. // know we have already been here, taken care of protocols, etc.
  2134. //
  2135. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING);
  2136. }
  2137. //
  2138. // if this is a legacy miniport or power-disabled miniport then throw it in D3
  2139. // do the same thing for IM miniports that have not been initialized yet
  2140. //
  2141. if ((!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE)) ||
  2142. (!(ndisIsMiniportStarted(Miniport) && (Miniport->PnPDeviceState == NdisPnPDeviceStarted))))
  2143. {
  2144. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2145. ("ndisMPowerPolicy: Miniport %p, Place legacy or PM disabled device in D3\n", Miniport));
  2146. *pDeviceState = PowerDeviceD3;
  2147. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2148. ("<==ndisMPowerPolicy: Miniport %p\n", Miniport));
  2149. return(STATUS_SUCCESS);
  2150. }
  2151. //
  2152. // First check for the case where the netcard is already asleep due to a
  2153. // media disconnect.
  2154. //
  2155. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  2156. pIrpWaitWake = Miniport->pIrpWaitWake;
  2157. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  2158. if ((Miniport->CurrentDevicePowerState > PowerDeviceD0) &&
  2159. (pIrpWaitWake != NULL))
  2160. {
  2161. ///
  2162. // Miniport is in a lower power state than D0 and there is a wake irp pending in
  2163. // the bus driver. This is a pretty good indication that the cable was pulled.
  2164. // We are not going to enable any wake-up method seeing as the cable has been disconnect.
  2165. // but if the user does not want to wakeup the machine as a result of a cable
  2166. // reconnect, cancel any pending wait-wake IRP
  2167. ///
  2168. if (!fIsQuery && ((!MINIPORT_PNP_TEST_FLAG (Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE)) ||
  2169. (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_RECONNECT)))
  2170. {
  2171. if (IoCancelIrp(pIrpWaitWake))
  2172. {
  2173. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2174. ("ndisMPowerPolicy: Miniport %p, Successfully canceled media connect wake irp\n", Miniport));
  2175. }
  2176. }
  2177. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2178. ("<==ndisMPowerPolicy: Miniport %p\n", Miniport));
  2179. return(STATUS_DEVICE_POWERED_OFF);
  2180. }
  2181. do
  2182. {
  2183. //
  2184. // Is system wake-up enabled in the policy?
  2185. // if wake-up is not enabled then we simply power off.
  2186. //
  2187. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE))
  2188. {
  2189. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2190. ("ndisMPowerPolicy: Miniport %p, Device power wake is not enabled (%u)\n",
  2191. Miniport, MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE)));
  2192. break;
  2193. }
  2194. //
  2195. // This is the -lightest- state the device can go to for the requested
  2196. // system state.
  2197. //
  2198. DeviceStateForSystemState = Miniport->DeviceCaps.DeviceState[SystemState];
  2199. //
  2200. // Check to see if we are going below SystemSleeping3
  2201. //
  2202. //
  2203. //
  2204. // if we are going to S4 or deeper and device can not wake up the system from that state
  2205. // just do it
  2206. //
  2207. if ((SystemState >= PowerSystemHibernate) &&
  2208. ((SystemState > Miniport->DeviceCaps.SystemWake) || (DeviceStateForSystemState > Miniport->DeviceCaps.DeviceWake)))
  2209. {
  2210. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2211. ("ndisMPowerPolicy: Miniport %p, System is either entering hibernate or shutting down.\n", Miniport));
  2212. //
  2213. // We succeed this call.
  2214. //
  2215. break;
  2216. }
  2217. //
  2218. // Get a nice pointer to the wake-up capabilities.
  2219. //
  2220. pWakeCaps = &Miniport->PMCapabilities.WakeUpCapabilities;
  2221. if ((NDIS_PNP_WAKE_UP_MAGIC_PACKET == (Miniport->WakeUpEnable & NDIS_PNP_WAKE_UP_MAGIC_PACKET)) &&
  2222. (PowerDeviceUnspecified != pWakeCaps->MinMagicPacketWakeUp))
  2223. {
  2224. MinDeviceWakeup = pWakeCaps->MinMagicPacketWakeUp;
  2225. }
  2226. if ((NDIS_PNP_WAKE_UP_PATTERN_MATCH == (Miniport->WakeUpEnable & NDIS_PNP_WAKE_UP_PATTERN_MATCH)) &&
  2227. (PowerDeviceUnspecified != pWakeCaps->MinPatternWakeUp))
  2228. {
  2229. if ((MinDeviceWakeup == PowerDeviceUnspecified) ||
  2230. (MinDeviceWakeup > pWakeCaps->MinPatternWakeUp))
  2231. {
  2232. MinDeviceWakeup = pWakeCaps->MinPatternWakeUp;
  2233. }
  2234. }
  2235. //
  2236. // if both MagicPacket and pattern match are NOT enabled (or the system can't do either)
  2237. // then we may as well go to D3.
  2238. //
  2239. if (MinDeviceWakeup == PowerDeviceUnspecified)
  2240. {
  2241. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2242. ("ndisMPowerPolicy: Miniport %p, MagicPacket and pattern match are not enabled.\n", Miniport));
  2243. break;
  2244. }
  2245. //
  2246. // from this point on, we try to go to power state that we can wake up the system from
  2247. //
  2248. //
  2249. // make sure we don't go too deep
  2250. //
  2251. if (MinDeviceWakeup > Miniport->DeviceCaps.DeviceWake)
  2252. {
  2253. MinDeviceWakeup = Miniport->DeviceCaps.DeviceWake;
  2254. }
  2255. //
  2256. // If the system state requested is lower than the minimum required to wake up the system
  2257. // or the corresponding device state is deeper than the lowest device state to wake
  2258. // up the system then we
  2259. // fail this call. Note that we also set the device state to D3. Since
  2260. // we are not going to be able to support wake-up then we power off.
  2261. // The query power will look at the failure code and return that to the
  2262. // system. The set power will ignore the failure code and set the device
  2263. // into D3.
  2264. //
  2265. if ((SystemState > Miniport->DeviceCaps.SystemWake) ||
  2266. (DeviceStateForSystemState > MinDeviceWakeup) ||
  2267. (DeviceStateForSystemState == PowerDeviceUnspecified))
  2268. {
  2269. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  2270. ("ndisMPowerPolicy: Miniport %p, Requested system state is lower than the minimum wake-up system state\n", Miniport));
  2271. Status = STATUS_UNSUCCESSFUL;
  2272. break;
  2273. }
  2274. //
  2275. // starting from DeviceWake and up to DeviceState[SystemState], find a
  2276. // suitable device state
  2277. //
  2278. switch (MinDeviceWakeup)
  2279. {
  2280. case PowerDeviceD3:
  2281. if (Miniport->DeviceCaps.WakeFromD3)
  2282. {
  2283. NewDeviceState = PowerDeviceD3;
  2284. break;
  2285. }
  2286. case PowerDeviceD2:
  2287. if (Miniport->DeviceCaps.DeviceD2 && Miniport->DeviceCaps.WakeFromD2)
  2288. {
  2289. NewDeviceState = PowerDeviceD2;
  2290. break;
  2291. }
  2292. case PowerDeviceD1:
  2293. if (Miniport->DeviceCaps.DeviceD1 && Miniport->DeviceCaps.WakeFromD1)
  2294. {
  2295. NewDeviceState = PowerDeviceD1;
  2296. break;
  2297. }
  2298. case PowerDeviceD0:
  2299. if (Miniport->DeviceCaps.WakeFromD0)
  2300. {
  2301. NewDeviceState = PowerDeviceD0;
  2302. break;
  2303. }
  2304. default:
  2305. Status = STATUS_UNSUCCESSFUL;
  2306. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  2307. ("ndisMPowerPolicy: Miniport %p, couldn't find any wake-able DeviceState 0x%x\n", Miniport));
  2308. break;
  2309. }
  2310. //
  2311. // ok, we started with deepest state (based on what device said can do)
  2312. // and went up. make sure we didn't go too far up. i.e. the statem state
  2313. // we are going to can maintain the device in desired power state
  2314. //
  2315. if ((Status == NDIS_STATUS_SUCCESS) &&
  2316. (DeviceStateForSystemState > NewDeviceState))
  2317. {
  2318. Status = STATUS_UNSUCCESSFUL;
  2319. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  2320. ("ndisMPowerPolicy: Miniport %p, couldn't find any wake-able DeviceState 0x%x\n", Miniport));
  2321. }
  2322. //
  2323. // If this is for the set power then we need to enable wake-up on the miniport.
  2324. //
  2325. if (!fIsQuery)
  2326. {
  2327. //
  2328. // We need to send a request to the miniport to enable the correct wake-up types NOT
  2329. // including the link change.
  2330. //
  2331. WakeEnable = Miniport->WakeUpEnable & ~NDIS_PNP_WAKE_UP_LINK_CHANGE;
  2332. if (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_PATTERN_MATCH)
  2333. {
  2334. WakeEnable &= ~NDIS_PNP_WAKE_UP_PATTERN_MATCH;
  2335. }
  2336. if (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_MAGIC_PACKET)
  2337. {
  2338. WakeEnable &= ~NDIS_PNP_WAKE_UP_MAGIC_PACKET;
  2339. }
  2340. NdisStatus = ndisQuerySetMiniportDeviceState(Miniport,
  2341. WakeEnable,
  2342. OID_PNP_ENABLE_WAKE_UP,
  2343. TRUE);
  2344. if (NDIS_STATUS_SUCCESS == NdisStatus)
  2345. {
  2346. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE);
  2347. }
  2348. else
  2349. {
  2350. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR,
  2351. ("ndisMPowerPolicy: Miniport %p, Unable to enable the following wake-up methods 0x%x\n", Miniport, WakeEnable));
  2352. //
  2353. // Since we can't enable the wake methods we may as well go to D3.
  2354. //
  2355. NewDeviceState = PowerDeviceD3;
  2356. break;
  2357. }
  2358. }
  2359. //
  2360. // Save the device state that we should go to.
  2361. //
  2362. *pDeviceState = NewDeviceState;
  2363. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2364. ("ndisMPowerPolicy: Miniport %p, SystemState 0x%x, DeviceState 0x%x\n", Miniport, SystemState, *pDeviceState));
  2365. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2366. ("<==ndisMPowerPolicy: Miniport %p\n", Miniport));
  2367. return(Status);
  2368. } while (FALSE);
  2369. //
  2370. // If this is not a query then we need to cancel wake-up on the miniport.
  2371. //
  2372. if (!fIsQuery && MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE))
  2373. {
  2374. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2375. ("ndisMPowerPolicy: Miniport %p, Disabling wake-up on the miniport\n", Miniport));
  2376. WakeEnable = 0;
  2377. ndisQuerySetMiniportDeviceState(Miniport,
  2378. WakeEnable,
  2379. OID_PNP_ENABLE_WAKE_UP,
  2380. TRUE);
  2381. }
  2382. //
  2383. // Save the device state that we should go to.
  2384. //
  2385. *pDeviceState = NewDeviceState;
  2386. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2387. ("ndisMPowerPolicy: Miniport %p, SystemState 0x%x, DeviceState 0x%x\n", Miniport, SystemState, *pDeviceState));
  2388. DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
  2389. ("<==ndisMPowerPolicy: Miniport %p\n", Miniport));
  2390. return(Status);
  2391. }