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.

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