|
|
/*++
Copyright (c) 1990-1995 Microsoft Corporation
Module Name:
ndispwr.c
Abstract:
This module contains the code to process power managment IRPs that are sent under the IRP_MJ_POWER major code.
Author:
Kyle Brandon (KyleB) Alireza Dabagh (alid)
Environment:
Kernel mode
Revision History:
02/11/97 KyleB Created
--*/
#include <precomp.h>
#pragma hdrstop
#define MODULE_NUMBER MODULE_POWER
NTSTATUS FASTCALL ndisQueryPowerCapabilities( IN PNDIS_MINIPORT_BLOCK Miniport ) /*++
Routine Description:
This routine will process the IRP_MN_QUERY_CAPABILITIES by querying the next device object and saving information from that request.
Arguments:
pIrp - Pointer to the IRP. pIrpSp - Pointer to the stack parameters for the IRP. pAdapter - Pointer to the device.
Return Value:
--*/ { PIRP pirp; PIO_STACK_LOCATION pirpSpN; NTSTATUS Status = STATUS_SUCCESS; PDEVICE_CAPABILITIES pDeviceCaps; PNDIS_PM_WAKE_UP_CAPABILITIES pWakeUpCaps; DEVICE_CAPABILITIES deviceCaps; POWER_QUERY pQuery;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisQueryPowerCapabilities: Miniport %p\n", Miniport));
do { //
// default = no PM support
//
MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_PM_SUPPORTED);
//
// if the Next device object is NULL, Don't bother, just flag the Miniport
// as not supporting PM.
// this can happen for IM devices under Memphis
//
if (Miniport->NextDeviceObject == NULL) { break; } //
// Send the IRP_MN_QUERY_CAPABILITIES to pdo.
//
pirp = IoAllocateIrp((CCHAR)(Miniport->NextDeviceObject->StackSize + 1), FALSE); if (NULL == pirp) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisQueryPowerCapabilities: Miniport %p, Failed to allocate an irp for IRP_MN_QUERY_CAPABILITIES\n", Miniport));
NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport, NDIS_ERROR_CODE_OUT_OF_RESOURCES, 0); Status = STATUS_INSUFFICIENT_RESOURCES; break; } NdisZeroMemory(&deviceCaps, sizeof(deviceCaps)); deviceCaps.Size = sizeof(DEVICE_CAPABILITIES); deviceCaps.Version = 1;
//
// should initalize deviceCaps.Address and deviceCaps.UINumber here as well
//
deviceCaps.Address = -1; deviceCaps.UINumber= -1; //
// Get the stack pointer.
//
pirpSpN = IoGetNextIrpStackLocation(pirp); ASSERT(pirpSpN != NULL); NdisZeroMemory(pirpSpN, sizeof(IO_STACK_LOCATION ) ); //
// Set the default device state to full on.
//
pirpSpN->MajorFunction = IRP_MJ_PNP; pirpSpN->MinorFunction = IRP_MN_QUERY_CAPABILITIES; pirpSpN->Parameters.DeviceCapabilities.Capabilities = &deviceCaps; pirp->IoStatus.Status = STATUS_NOT_SUPPORTED; //
// Setup the I/O completion routine to be called.
//
INITIALIZE_EVENT(&pQuery.Event); IoSetCompletionRoutine(pirp, ndisCompletionRoutine, &pQuery, TRUE, TRUE, TRUE);
//
// Call the next driver.
//
Status = IoCallDriver(Miniport->NextDeviceObject, pirp); if (STATUS_PENDING == Status) { Status = WAIT_FOR_OBJECT(&pQuery.Event, NULL); ASSERT(NT_SUCCESS(Status)); }
//
// If the lower device object successfully completed the request
// then we save that information.
//
if (NT_SUCCESS(pQuery.Status)) { //
// Get the pointer to the device capabilities as returned by
// the parent PDO.
//
pDeviceCaps = &deviceCaps; //
// save the entire device caps received from bus driver/ACPI
//
NdisMoveMemory( &Miniport->DeviceCaps, pDeviceCaps, sizeof(DEVICE_CAPABILITIES));
if ((pDeviceCaps->DeviceWake != PowerDeviceUnspecified) && (pDeviceCaps->SystemWake != PowerSystemUnspecified)) { MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_PM_SUPPORTED); }
IF_DBG(DBG_COMP_PM, DBG_LEVEL_INFO) { UINT i; DbgPrint("ndisQueryPowerCapabilities: Miniport %p, Bus PM capabilities\n", Miniport); DbgPrint("\tDeviceD1:\t\t%ld\n", (pDeviceCaps->DeviceD1 == 0) ? 0 : 1); DbgPrint("\tDeviceD2:\t\t%ld\n", (pDeviceCaps->DeviceD2 == 0) ? 0 : 1); DbgPrint("\tWakeFromD0:\t\t%ld\n", (pDeviceCaps->WakeFromD0 == 0) ? 0 : 1); DbgPrint("\tWakeFromD1:\t\t%ld\n", (pDeviceCaps->WakeFromD1 == 0) ? 0 : 1); DbgPrint("\tWakeFromD2:\t\t%ld\n", (pDeviceCaps->WakeFromD2 == 0) ? 0 : 1); DbgPrint("\tWakeFromD3:\t\t%ld\n\n", (pDeviceCaps->WakeFromD3 == 0) ? 0 : 1); DbgPrint("\tSystemState\t\tDeviceState\n");
if (pDeviceCaps->DeviceState[0] == PowerDeviceUnspecified) DbgPrint("\tPowerSystemUnspecified\tPowerDeviceUnspecified\n"); else DbgPrint("\tPowerSystemUnspecified\t\tD%ld\n", pDeviceCaps->DeviceState[0] - 1);
for (i = 1; i < PowerSystemMaximum; i++) { if (pDeviceCaps->DeviceState[i]== PowerDeviceUnspecified) DbgPrint("\tS%ld\t\t\tPowerDeviceUnspecified\n",i-1); else DbgPrint("\tS%ld\t\t\tD%ld\n",i-1, pDeviceCaps->DeviceState[i] - 1);
}
if (pDeviceCaps->SystemWake == PowerSystemUnspecified) DbgPrint("\t\tSystemWake: PowerSystemUnspecified\n"); else DbgPrint("\t\tSystemWake: S%ld\n", pDeviceCaps->SystemWake - 1);
if (pDeviceCaps->DeviceWake == PowerDeviceUnspecified) DbgPrint("\t\tDeviceWake: PowerDeviceUnspecified\n"); else DbgPrint("\t\tDeviceWake: D%ld\n", pDeviceCaps->DeviceWake - 1);
} } else { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,("ndisQueryPowerCapabilities: Miniport %p, Bus driver failed IRP_MN_QUERY_CAPABILITIES\n", Miniport)); }
//
// The irp is no longer needed.
//
IoFreeIrp(pirp); } while (FALSE); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisQueryPowerCapabilities: Miniport %p, Status 0x%x\n", Miniport, Status));
return(Status); }
NTSTATUS ndisMediaDisconnectComplete( IN PDEVICE_OBJECT pdo, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) /*++
Routine Description:
Arguments:
pdo - Pointer to the DEVICE_OBJECT for the miniport. pirp - Pointer to the device set power state IRP that we created. Context - Pointer to the miniport block
Return Value:
--*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context; NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED; KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisMediaDisconnectComplete: Miniport %p\n", Miniport));
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
//
// double check that we didn't get a link up while we were doing all this.
//
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMediaDisconnectComplete: Miniport %p, disconnect complete\n", Miniport));
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); } else {
MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
//
// if system is not going to sleep, wake up the device
//
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMediaDisconnectComplete: Miniport %p, disconnect was cancelled. Power back up the miniport\n", Miniport));
//
// Wake it back up
//
PowerState.DeviceState = PowerDeviceD0; Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject, IRP_MN_SET_POWER, PowerState, NULL, NULL, NULL); } } DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisMediaDisconnectComplete: Miniport %p\n", Miniport));
return(STATUS_MORE_PROCESSING_REQUIRED); }
VOID ndisMediaDisconnectWorker( IN PPOWER_WORK_ITEM pWorkItem, IN PVOID Context ) /*++
Routine Description:
Arguments:
Return Value:
--*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context; POWER_STATE PowerState; NTSTATUS Status; NDIS_STATUS NdisStatus; ULONG WakeEnable;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisMediaDisconnectWorker: Miniport %p\n", Miniport));
//
// Determine the minimum device state we can go to and still get a link enabled.
//
if (Miniport->DeviceCaps.DeviceWake < Miniport->PMCapabilities.WakeUpCapabilities.MinLinkChangeWakeUp) { PowerState.DeviceState = Miniport->DeviceCaps.DeviceWake; } else { PowerState.DeviceState = Miniport->PMCapabilities.WakeUpCapabilities.MinLinkChangeWakeUp; }
//
// enable the appropriate wakeup method. this includes link change,
// pattern match and/or magic packet.
// if LINK_CHANGE method is disabled, we should not even get here
//
//
// Miniport->WakeUpEnable is the wakeup methods enabled from protocol (and ndis point of view)
// with this qfe, when the user turns wol off from UI, the methods going down are not
// the methods set by protocol/ndis
//
WakeEnable = Miniport->WakeUpEnable;
if (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_PATTERN_MATCH) { WakeEnable &= ~NDIS_PNP_WAKE_UP_PATTERN_MATCH; }
if (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_MAGIC_PACKET) { WakeEnable &= ~NDIS_PNP_WAKE_UP_MAGIC_PACKET; } NdisStatus = ndisQuerySetMiniportDeviceState(Miniport, WakeEnable, OID_PNP_ENABLE_WAKE_UP, TRUE);
if (NdisStatus == NDIS_STATUS_SUCCESS) { //
// We need to request a device state irp.
//
Miniport->WaitWakeSystemState = Miniport->DeviceCaps.SystemWake; Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject, IRP_MN_SET_POWER, PowerState, ndisMediaDisconnectComplete, Miniport, NULL);
} FREE_POOL(pWorkItem);
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisMediaDisconnectWorker: Miniport %p\n", Miniport)); }
VOID ndisMediaDisconnectTimeout( IN PVOID SystemSpecific1, IN PVOID Context, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3 ) /*++
Routine Description:
Arguments:
Return Value:
--*/ { //
// Fire off a workitem to take care of this at passive level.
//
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context; PNDIS_OPEN_BLOCK MiniportOpen; PPOWER_WORK_ITEM pWorkItem;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisMediaDisconnectTimeout: Miniport %p\n", Miniport));
do { NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport); if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT)) { NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMediaDisconnectTimeout: Miniport %p, media disconnect was cancelled\n", Miniport)); break; } //
// Clear the disconnect wait flag.
//
MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT); NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
pWorkItem = ALLOC_FROM_POOL(sizeof(POWER_WORK_ITEM), NDIS_TAG_WORK_ITEM); if (pWorkItem != NULL) { //
// Initialize the ndis work item to power on.
//
NdisInitializeWorkItem(&pWorkItem->WorkItem, (NDIS_PROC)ndisMediaDisconnectWorker, Miniport); MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE); //
// Schedule the workitem to fire.
//
NdisScheduleWorkItem(&pWorkItem->WorkItem); } } while (FALSE); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisMediaDisconnectTimeout: Miniport %p\n", Miniport)); }
NTSTATUS ndisWaitWakeComplete( IN PDEVICE_OBJECT pdo, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) /*++
Routine Description:
Arguments:
DeviceObject Irp Context
Return Value:
--*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context; PIRP pirp; NTSTATUS Status = IoStatus->Status; POWER_STATE DevicePowerState; KIRQL OldIrql; DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisWaitWakeComplete: Miniport %p, pIrp %p, Status %lx\n", Miniport, Miniport->pIrpWaitWake, Status));
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); pirp = Miniport->pIrpWaitWake; Miniport->pIrpWaitWake = NULL; NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); if (pirp != NULL) {
//
// If this completion routine was called because a wake-up occured at the device level
// then we need to initiate a device irp to start up the nic. If it was completed
// due to a cancellation then we skip this since it was cancelled due to a device irp
// being sent to wake-up the device.
//
if (Status == STATUS_SUCCESS) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisWaitWakeComplete: Miniport %p, Wake irp was complete due to wake event\n", Miniport));
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisWaitWakeComplete: Miniport %p, Powering up the Miniport\n", Miniport)); //
// We need to request a set power to power up the device.
//
DevicePowerState.DeviceState = PowerDeviceD0; Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject, IRP_MN_SET_POWER, DevicePowerState, NULL, NULL, NULL); } else { //
// it is also possible that the device woke up the whole system (WOL) in which case we
// will get a system power IRP eventually and we don't need to request a power IRP.
//
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisWaitWakeComplete: Miniport %p woke up the system.\n", Miniport)); } } else { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisWaitWakeComplete: Miniport %p, WAIT_WAKE irp failed or cancelled. Status %lx\n", Miniport, Status));
}
} DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisWaitWakeComplete: Miniport %p\n", Miniport)); return(STATUS_MORE_PROCESSING_REQUIRED); }
NTSTATUS ndisQueryPowerComplete( IN PDEVICE_OBJECT pdo, IN PIRP pirp, IN PVOID Context ) /*++
Routine Description:
Arguments:
pdo - Pointer to the device object pirp - Pointer to the query power irp Context - Pointer to the miniport.
Return Value:
--*/ { NTSTATUS Status = pirp->IoStatus.Status;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisQueryPowerComplete: Miniport %p, Bus driver returned %lx for QueryPower\n", Context, pirp->IoStatus.Status)); #ifdef TRACE_PM_PROBLEMS
if (!NT_SUCCESS(pirp->IoStatus.Status)) { DbgPrint("ndisQueryPowerComplete: Miniport %p, Bus Driver returned %lx for QueryPower.\n", Context, pirp->IoStatus.Status); } #endif
PoStartNextPowerIrp(pirp);
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisQueryPowerComplete: Miniport %p\n", Context));
return(Status); }
NTSTATUS ndisQueryPower( IN PIRP pirp, IN PIO_STACK_LOCATION pirpSp, IN PNDIS_MINIPORT_BLOCK Miniport ) /*++
Routine Description:
This routine will process the IRP_MN_QUERY_POWER for a miniport driver.
Arguments:
pirp - Pointer to the IRP. pirpSp - Pointer to the IRPs current stack location. Adapter - Pointer to the adapter.
Return Value:
--*/ { NTSTATUS Status = STATUS_SUCCESS; DEVICE_POWER_STATE DeviceState; NDIS_STATUS NdisStatus; PIO_STACK_LOCATION pirpSpN;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisQueryPower: Miniport %p\n", Miniport));
do { //
// We only handle system power states sent as a query.
//
if (pirpSp->Parameters.Power.Type != SystemPowerState) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisQueryPower: Miniport %p, Not a system state! Type: 0x%x. State: 0x%x\n", Miniport, pirpSp->Parameters.Power.Type, pirpSp->Parameters.Power.State)); Status = STATUS_INVALID_DEVICE_REQUEST;
break; }
//
// Determine if the system state is appropriate and what device state we
// should go to.
//
Status = ndisMPowerPolicy(Miniport, pirpSp->Parameters.Power.State.SystemState, &DeviceState, TRUE);
if (!ndisIsMiniportStarted(Miniport) || (Miniport->PnPDeviceState != NdisPnPDeviceStarted) || (STATUS_DEVICE_POWERED_OFF == Status)) { pirp->IoStatus.Status = STATUS_SUCCESS; PoStartNextPowerIrp(pirp); IoCompleteRequest(pirp, 0); return(STATUS_SUCCESS); }
//
// If we didn't succeed then fail the query power.
//
if (!NT_SUCCESS(Status)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisQueryPower: Miniport %p, Unable to go to system state 0x%x\n", Miniport, pirpSp->Parameters.Power.State.SystemState));
break; }
//
// Notify the transports with the query power PnP event.
//
NdisStatus = ndisPnPNotifyAllTransports(Miniport, NetEventQueryPower, &DeviceState, sizeof(DeviceState)); if (NDIS_STATUS_SUCCESS != NdisStatus) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisQueryPower: Miniport %p, ndisPnPNotifyAllTransports failed\n", Miniport));
Status = NdisStatus; break; }
//
// Notify the miniport...
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE)) { NdisStatus = ndisQuerySetMiniportDeviceState(Miniport, DeviceState, OID_PNP_QUERY_POWER, FALSE);
if (NDIS_STATUS_SUCCESS != NdisStatus) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisQueryPower: Miniport %p, failed query power\n", Miniport)); Status = STATUS_UNSUCCESSFUL; break; } }
} while (FALSE);
if (!NT_SUCCESS(Status)) { pirp->IoStatus.Status = Status; PoStartNextPowerIrp(pirp); IoCompleteRequest(pirp, 0); } else { //
// Pass this irp down the stack.
//
pirpSpN = IoGetNextIrpStackLocation(pirp); pirpSpN->MajorFunction = IRP_MJ_POWER; pirpSpN->MinorFunction = IRP_MN_QUERY_POWER;
pirpSpN->Parameters.Power.SystemContext = pirpSp->Parameters.Power.SystemContext; pirpSpN->Parameters.Power.Type = DevicePowerState; pirpSpN->Parameters.Power.State.DeviceState = DeviceState;
IoSetCompletionRoutine( pirp, ndisQueryPowerComplete, Miniport, TRUE, TRUE, TRUE);
IoMarkIrpPending(pirp); PoStartNextPowerIrp(pirp); PoCallDriver(Miniport->NextDeviceObject, pirp); Status = STATUS_PENDING;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisQueryPower: Miniport %p, PoCallDriver to NextDeviceObject returned %lx\n", Miniport, Status));
}
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisQueryPower: Miniport %p\n", Miniport));
return(Status); }
VOID FASTCALL ndisPmHaltMiniport( IN PNDIS_MINIPORT_BLOCK Miniport ) /*++
Routine Description:
This will stop the miniport from functioning...
Arguments:
Miniport - pointer to the mini-port to halt
Return Value:
None.
--*/
{ KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisPmHaltMiniport: Miniport \n", Miniport));
PnPReferencePackage();
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
NdisResetEvent(&Miniport->OpenReadyEvent);
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_HALTED)) { ASSERT(FALSE); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); return; } //
// Mark this miniport as halting.
//
MINIPORT_SET_FLAG(Miniport, fMINIPORT_PM_HALTING); MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_PM_HALTED);
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS); MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_NO_SHUTDOWN);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
ndisMCommonHaltMiniport(Miniport);
NdisMDeregisterAdapterShutdownHandler(Miniport);
Miniport->MiniportAdapterContext = NULL;
PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisPmHaltMiniport: Miniport %p\n", Miniport)); }
NDIS_STATUS ndisPmInitializeMiniport( IN PNDIS_MINIPORT_BLOCK Miniport ) /*++
Routine Description:
This routine will re-initialize a miniport that has been halted due to a PM low power transition.
Arguments:
Miniport - Pointer to the miniport block to re-initialize.
Return Value:
--*/ { PNDIS_M_DRIVER_BLOCK pMiniBlock = Miniport->DriverHandle; NDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle; NDIS_STATUS Status; NDIS_STATUS OpenErrorStatus; UINT SelectedMediumIndex; ULONG Flags; ULONG GenericUlong = 0; KIRQL OldIrql; UCHAR SendFlags;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisPmInitializeMiniport: Miniport %p\n", Miniport)); do { MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PM_HALTING | fMINIPORT_DEREGISTERED_INTERRUPT | fMINIPORT_RESET_REQUESTED | fMINIPORT_RESET_IN_PROGRESS); MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_REMOVE_IN_PROGRESS);
Flags = Miniport->Flags; SendFlags = Miniport->SendFlags;
//
// Clean up any workitems that might have been queue'd
//
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemMiniportCallback, NULL); NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL); NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL); NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL); NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetInProgress, NULL); InitializeListHead(&Miniport->PacketList);
//
// Initialize the configuration handle for use during the initialization.
//
ConfigurationHandle.DriverObject = Miniport->DriverHandle->NdisDriverInfo->DriverObject; ConfigurationHandle.DeviceObject = Miniport->DeviceObject; ConfigurationHandle.DriverBaseName = &Miniport->BaseName;
ASSERT(KeGetCurrentIrql() == 0); Status = ndisInitializeConfiguration((PNDIS_WRAPPER_CONFIGURATION_HANDLE)&ConfigurationHandle, Miniport, NULL); ASSERT(KeGetCurrentIrql() == 0);
if (NDIS_STATUS_SUCCESS != Status) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisPmInitializeMiniport: Miniport %p, ndisInitializeConfiguration failed, Status: 0x%x\n", Miniport, Status)); break; } //
// Call adapter callback. The current value for "Export"
// is what we tell him to name this device.
//
MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE); MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS); Miniport->CurrentDevicePowerState = PowerDeviceD0; Status = (pMiniBlock->MiniportCharacteristics.InitializeHandler)( &OpenErrorStatus, &SelectedMediumIndex, ndisMediumArray, ndisMediumArraySize / sizeof(NDIS_MEDIUM), (NDIS_HANDLE)Miniport, (NDIS_HANDLE)&ConfigurationHandle); ASSERT(KeGetCurrentIrql() == 0);
if (NDIS_STATUS_SUCCESS != Status) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisPmInitializeMiniport: Miniport %p, MiniportInitialize handler failed, Status 0x%x\n", Miniport, Status)); break; } ASSERT (Miniport->MediaType == ndisMediumArray[SelectedMediumIndex]); //
// Restore saved settings
//
Miniport->Flags = Flags; Miniport->SendFlags = SendFlags; MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_PM_HALTED | fMINIPORT_REJECT_REQUESTS); MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE); CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
//
// Clear the flag preventing the miniport's shutdown handler from being
// called if needed.
//
MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_NO_SHUTDOWN);
//
// if device does not need polling for connect status then assume it is connected
// as we always do when we intialize a miniport. if it does require media polling
// leave the media status as it was before suspend. it will be updated on the very first
// wakeup DPC.
//
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUIRES_MEDIA_POLLING)) { MINIPORT_SET_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED); }
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED)) { //
// set the ReceivePacket handler
//
ndisMSetIndicatePacketHandler(Miniport); }
BLOCK_LOCK_MINIPORT_LOCKED(Miniport, OldIrql);
//
// Restore the filter information.
//
ndisMRestoreFilterSettings(Miniport, NULL, FALSE);
//
// Make sure the filter settings get updated.
//
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE)) { ndisMDoRequests(Miniport); } else { NDISM_PROCESS_DEFERRED(Miniport); }
UNLOCK_MINIPORT_L(Miniport);
//
// Start up the wake up timer.
//
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisPmInitializeMiniport: Miniport %p, startup the wake-up DPC timer\n", Miniport)); NdisMSetPeriodicTimer((PNDIS_MINIPORT_TIMER)(&Miniport->WakeUpDpcTimer), Miniport->CheckForHangSeconds*1000);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
ASSERT(KeGetCurrentIrql() == 0);
if (Miniport->MediaType == NdisMedium802_3) { ndisMNotifyMachineName(Miniport, NULL); }
//
// Register with WMI.
//
Status = IoWMIRegistrationControl(Miniport->DeviceObject, WMIREG_ACTION_REGISTER);
if (!NT_SUCCESS(Status)) { //
// This should NOT keep the adapter from initializing but we should log the error.
//
DBGPRINT_RAW((DBG_COMP_INIT | DBG_COMP_WMI), DBG_LEVEL_WARN, ("ndisPmInitializeMiniport: Miniport %p, Failed to register for WMI support\n", Miniport)); }
Status = NDIS_STATUS_SUCCESS; KeQueryTickCount(&Miniport->NdisStats.StartTicks); } while (FALSE);
if (NDIS_STATUS_SUCCESS != Status) { NdisMDeregisterAdapterShutdownHandler(Miniport); ndisLastFailedInitErrorCode = Status; ASSERT(Miniport->Interrupt == NULL); ASSERT(Miniport->TimerQueue == NULL); ASSERT(Miniport->MapRegisters == NULL);
if ((Miniport->TimerQueue != NULL) || (Miniport->Interrupt != NULL)) { if (Miniport->Interrupt != NULL) { BAD_MINIPORT(Miniport, "Unloading without deregistering interrupt"); } else { BAD_MINIPORT(Miniport, "Unloading without deregistering timer"); } KeBugCheckEx(BUGCODE_ID_DRIVER, (ULONG_PTR)Miniport, (ULONG_PTR)Miniport->Interrupt, (ULONG_PTR)Miniport->TimerQueue, 1); } MINIPORT_SET_FLAG(Miniport, fMINIPORT_PM_HALTING); MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_PM_HALTED); MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS); }
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisPmInitializeMiniport: Miniport %p\n", Miniport));
return(Status); }
NDIS_STATUS ndisQuerySetMiniportDeviceState( IN PNDIS_MINIPORT_BLOCK Miniport, IN DEVICE_POWER_STATE DeviceState, IN NDIS_OID Oid, IN BOOLEAN fSet ) /*++
Routine Description:
Arguments:
Return Value:
--*/ { NDIS_STATUS NdisStatus; NDIS_REQUEST PowerReq; PNDIS_COREQ_RESERVED CoReqRsvd; ULONG State;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisQuerySetMiniportDeviceState: Miniport %p\n", Miniport));
//
// Setup the miniport's internal request for a set power OID.
//
CoReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&PowerReq); INITIALIZE_EVENT(&CoReqRsvd->Event);
PowerReq.DATA.SET_INFORMATION.InformationBuffer = &State; PowerReq.DATA.SET_INFORMATION.InformationBufferLength = sizeof(State);
PowerReq.RequestType = fSet ? NdisRequestSetInformation : NdisRequestQueryInformation;
PowerReq.DATA.SET_INFORMATION.Oid = Oid; PowerReq.DATA.SET_INFORMATION.InformationBuffer = &DeviceState; PowerReq.DATA.SET_INFORMATION.InformationBufferLength = sizeof(DeviceState);
NdisStatus = ndisQuerySetMiniport(Miniport, NULL, fSet, &PowerReq, NULL);
#ifdef TRACE_PM_PROBLEMS
if (NdisStatus != NDIS_STATUS_SUCCESS) { DbgPrint("ndisQuerySetMiniportDeviceState: Miniport %p, (Name: %p) failed Oid %lx, Set = %lx with error %lx\n", Miniport, Miniport->pAdapterInstanceName, Oid, fSet, NdisStatus); } #endif
//
// Miniport can't fail the set power request.
//
if (fSet) { ASSERT(NDIS_STATUS_SUCCESS == NdisStatus); } DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisQuerySetMiniportDeviceState: Miniport %p, Status %lx\n", Miniport, NdisStatus));
return(NdisStatus); }
NTSTATUS ndisSetSystemPowerComplete( IN PDEVICE_OBJECT pdo, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) /*++
Routine Description:
Arguments:
pdo - Pointer to the DEVICE_OBJECT for the miniport. pirp - Pointer to the device set power state IRP that we created. Context - Pointer to the system set power state sent by the OS.
Return Value:
--*/ { PIRP pirpSystem = Context; PIO_STACK_LOCATION pirpSp; PNDIS_MINIPORT_BLOCK Miniport;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisSetSystemPowerComplete: DeviceObject %p\n", pdo));
//
// Save the status code with the original IRP.
//
pirpSystem->IoStatus = *IoStatus;
//
// did everything go well?
//
if (NT_SUCCESS(IoStatus->Status)) { //
// Get current stack pointer.
//
pirpSp = IoGetCurrentIrpStackLocation(pirpSystem);
ASSERT(SystemPowerState == pirpSp->Parameters.Power.Type); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetSystemPowerComplete: DeviceObject %p, Going to system power state %lx\n", pdo, pirpSp->Parameters.Power.State));
//
// Notify the system that we are in the appropriate power state.
//
PoSetPowerState(pirpSp->DeviceObject,SystemPowerState, pirpSp->Parameters.Power.State); Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)pirpSp->DeviceObject->DeviceExtension + 1);
//
// now send down the System power IRP
//
IoCopyCurrentIrpStackLocationToNext(pirpSystem); PoCallDriver(Miniport->NextDeviceObject, pirpSystem); } else { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisSetSystemPowerComplete: DeviceObject %p, IRP_MN_SET_POWER failed!\n", pdo)); IoCompleteRequest(pirpSystem, 0);
}
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisSetSystemPowerComplete: DeviceObject %p\n", pdo));
return(STATUS_MORE_PROCESSING_REQUIRED); }
NTSTATUS ndisSetSystemPowerOnComplete( IN PDEVICE_OBJECT pdo, IN PIRP pirp, IN PVOID Context ) /*++
Routine Description:
Completion routine for S0 irp completion. This routine requests a D0 irp to be sent down the stack.
Arguments:
pdo - Pointer to the DEVICE_OBJECT for the miniport. pirp - Pointer to the S0 irp sent by the power manager. Context - Pointer to the miniport context
Return Value:
--*/ { PIO_STACK_LOCATION pirpSp = IoGetCurrentIrpStackLocation(pirp); PNDIS_MINIPORT_BLOCK Miniport = Context; POWER_STATE PowerState;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisSetSystemPowerOnComplete: DeviceObject %p\n", pdo));
//
// did everything go well?
//
if (NT_SUCCESS(pirp->IoStatus.Status)) { //
// Request the D irp now.
//
PowerState.DeviceState = PowerDeviceD0; PoRequestPowerIrp(Miniport->PhysicalDeviceObject, IRP_MN_SET_POWER, PowerState, NULL, NULL, NULL); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetSystemPowerOnComplete: DeviceObject %p, Going to system power state %lx\n", pdo, PowerState));
//
// Notify the system that we are in the appropriate power state.
//
PoSetPowerState(pdo ,SystemPowerState, pirpSp->Parameters.Power.State); } return(STATUS_SUCCESS); }
VOID ndisDevicePowerOn( IN PPOWER_WORK_ITEM pWorkItem, IN PVOID pContext ) /*++
Routine Description:
Arguments:
Return Value:
--*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)pContext; DEVICE_POWER_STATE DeviceState; POWER_STATE PowerState; NDIS_STATUS NdisStatus; PIRP pirp; PIO_STACK_LOCATION pirpSp; NTSTATUS NtStatus; NDIS_POWER_PROFILE PowerProfile; BOOLEAN fNotifyProtocols = FALSE; BOOLEAN fStartMediaDisconnectTimer = FALSE; KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisDevicePowerOn: Miniport %p\n", Miniport)); PnPReferencePackage(); pirp = pWorkItem->pIrp; pirpSp = IoGetCurrentIrpStackLocation(pirp); DeviceState = pirpSp->Parameters.Power.State.DeviceState;
#ifdef TRACE_PM_PROBLEMS
if (!NT_SUCCESS(pirp->IoStatus.Status)) { DbgPrint("ndisDevicePowerOn: Miniport %p, Bus Driver returned %lx for Powering up the Miniport.\n", Miniport, pirp->IoStatus.Status); } #endif
if (NT_SUCCESS(pirp->IoStatus.Status)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisDevicePowerOn: Miniport %p, Bus driver succeeded power up\n", Miniport));
//
// If the device is not in D0 then we need to wake up the miniport and
// restore the handlers.
//
if (Miniport->CurrentDevicePowerState != PowerDeviceD0) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisDevicePowerOn: Miniport %p, Power up the Miniport\n", Miniport));
//
// What type of miniport was this?
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE)) { //
// Set the miniport's device state.
//
NdisStatus = ndisQuerySetMiniportDeviceState(Miniport, DeviceState, OID_PNP_SET_POWER, TRUE); ASSERT(KeGetCurrentIrql() == 0);
if (NdisStatus == NDIS_STATUS_SUCCESS) Miniport->CurrentDevicePowerState = DeviceState;
//
// Start wake up timer
//
NdisMSetPeriodicTimer((PNDIS_MINIPORT_TIMER)(&Miniport->WakeUpDpcTimer), Miniport->CheckForHangSeconds*1000); } else { ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
if (((Miniport->DriverHandle->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER) == 0) && (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_HALTED))) { NdisStatus = ndisPmInitializeMiniport(Miniport); ASSERT(KeGetCurrentIrql() == 0); } else { NdisStatus = NDIS_STATUS_SUCCESS; } }
if (NDIS_STATUS_SUCCESS == NdisStatus) { if (ndisIsMiniportStarted(Miniport)) { NdisSetEvent(&Miniport->OpenReadyEvent); //
// Restore the handlers.
//
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); ndisMRestoreOpenHandlers(Miniport, fMINIPORT_STATE_PM_STOPPED); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); ASSERT(KeGetCurrentIrql() == 0);
ASSERT(Miniport->SymbolicLinkName.Buffer != NULL); if (Miniport->SymbolicLinkName.Buffer != NULL) { NtStatus = IoSetDeviceInterfaceState(&Miniport->SymbolicLinkName, TRUE); } if (!NT_SUCCESS(NtStatus)) { DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_ERR, ("ndisDevicePowerOn: IoRegisterDeviceClassAssociation failed: Miniport %p, Status %lx\n", Miniport, NtStatus)); }
fNotifyProtocols = TRUE; fStartMediaDisconnectTimer = TRUE;
//
// let the adapter know about the current power source
//
PowerProfile = ((BOOLEAN)ndisAcOnLine == TRUE) ? NdisPowerProfileAcOnLine : NdisPowerProfileBattery;
ndisNotifyMiniports(Miniport, NdisDevicePnPEventPowerProfileChanged, &PowerProfile, sizeof(NDIS_POWER_PROFILE));
} //
// Save the new power state the device is in.
//
Miniport->CurrentDevicePowerState = DeviceState; DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisDevicePowerOn: Miniport %p, Going to device state 0x%x\n", Miniport, DeviceState)); //
// Notify the system that we are in the new device state.
//
PowerState.DeviceState = DeviceState; PoSetPowerState(Miniport->DeviceObject, DevicePowerState, PowerState); } else { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisDevicePowerOn: Miniport %p, Power on failed by device driver for the Miniport, Error %lx!\n", Miniport, NdisStatus)); #ifdef TRACE_PM_PROBLEMS
DbgPrint("ndisDevicePowerOn: Miniport %p, Device Driver failed powering up Miniport with Error %lx.\n", Miniport, NdisStatus); #endif
pirp->IoStatus.Status = STATUS_UNSUCCESSFUL; } } else { //
// device is already in D0. we are here because of a cancel of QueryPower
//
if (ndisIsMiniportStarted(Miniport) && (Miniport->PnPDeviceState == NdisPnPDeviceStarted)) { //
// even if the current state of the device is D0, we
// need to notify the protocol. because we could be getting
// this IRP as a cancel to a query IRP -or- the device
// never lost its D0 state, but the sytem went to sleep
// and woke up!
//
NdisSetEvent(&Miniport->OpenReadyEvent);
//
// Restore the handlers.
//
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); ndisMRestoreOpenHandlers(Miniport, fMINIPORT_STATE_PM_STOPPED); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
fNotifyProtocols = TRUE; fStartMediaDisconnectTimer = FALSE;
} } }
NtStatus = pirp->IoStatus.Status; PoStartNextPowerIrp(pirp); IoCompleteRequest(pirp, 0);
//
// notify the protocols here after completing the power IRP
// to avoid deadlocks when protocols block on a request that can only
// complete when the other power IRPs go through
//
//
// Handle the case where the device was not able to power up.
//
if (!NT_SUCCESS(NtStatus)) { #ifdef TRACE_PM_PROBLEMS
DbgPrint("ndisDevicePowerOn: Miniport %p, Bus or Device failed powering up the Miniport with Error %lx.\n", Miniport, NtStatus); #endif
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisDevicePowerOn: Miniport %p, Power on failed by bus or device driver for Miniport with Error %lx!\n", Miniport, NtStatus));
//
// Mark the miniport as having failed so that we remove it correctly.
//
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_DEVICE_FAILED); //
// We need to tell pnp that the device state has changed.
//
IoInvalidateDeviceState(Miniport->PhysicalDeviceObject); ASSERT(KeGetCurrentIrql() == 0); }
if (fNotifyProtocols) { //
// for some protocols we may have closed the binding
//
ndisCheckAdapterBindings(Miniport, NULL); //
// Notify the transports.
//
ndisPnPNotifyAllTransports(Miniport, NetEventSetPower, &DeviceState, sizeof(DeviceState));
ndisNotifyDevicePowerStateChange(Miniport, DeviceState); //
// if media state has changed from disconnect to connect
// and the last indicated status was disconnect,
// we should notify the protcols (and Ndis) that the media is
// connected
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_INDICATED) && MINIPORT_TEST_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED)) { BLOCK_LOCK_MINIPORT_LOCKED(Miniport, OldIrql); NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport); MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED); NdisMIndicateStatus(Miniport, NDIS_STATUS_MEDIA_CONNECT, INTERNAL_INDICATION_BUFFER, INTERNAL_INDICATION_SIZE); NdisMIndicateStatusComplete(Miniport);
UNLOCK_MINIPORT_L(Miniport); LOWER_IRQL(OldIrql, DISPATCH_LEVEL); }
//
// check the media status and if it is disconnected, start the timer
//
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED) && fStartMediaDisconnectTimer) { if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE) && (Miniport->WakeUpEnable & NDIS_PNP_WAKE_UP_LINK_CHANGE) && (Miniport->MediaDisconnectTimeOut != (USHORT)(-1))) { //
// Are we already waiting for the disconnect timer to fire?
//
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT)) { //
// Mark the miniport as disconnecting and fire off the
// timer.
//
MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED); MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT);
NdisSetTimer(&Miniport->MediaDisconnectTimer, Miniport->MediaDisconnectTimeOut * 1000); } } } }
ASSERT(KeGetCurrentIrql() == 0);
MINIPORT_DECREMENT_REF(Miniport);
FREE_POOL(pWorkItem); PnPDereferencePackage(); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisDevicePowerOn: Miniport %p\n", Miniport)); }
NTSTATUS ndisSetDevicePowerOnComplete( IN PDEVICE_OBJECT pdo, IN PIRP pirp, IN PVOID pContext ) /*++
Routine Description:
Arguments:
pdo - Pointer to the device object for the miniport. pirp - Pointer to the device set power state IRP that was completed. Context - Not used
Return Value:
--*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)pContext; PPOWER_WORK_ITEM pWorkItem; NDIS_STATUS NdisStatus; DEVICE_POWER_STATE DeviceState; POWER_STATE PowerState; PIO_STACK_LOCATION pirpSp;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisSetDevicePowerOnComplete: Miniport %p, Irp %p, Status %lx\n", Miniport, pirp, pirp->IoStatus.Status));
do { if (Miniport->PnPDeviceState != NdisPnPDeviceStarted) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetDevicePowerOnComplete: Miniport %p is not started yet.\n", Miniport)); pirpSp = IoGetCurrentIrpStackLocation(pirp); DeviceState = pirpSp->Parameters.Power.State.DeviceState; //
// Notify the system that we are in the new device state.
//
Miniport->CurrentDevicePowerState = DeviceState; PowerState.DeviceState = DeviceState; PoSetPowerState(Miniport->DeviceObject, DevicePowerState, PowerState); PoStartNextPowerIrp(pirp); IoCompleteRequest(pirp, 0); break; } pWorkItem = ALLOC_FROM_POOL(sizeof(POWER_WORK_ITEM), NDIS_TAG_WORK_ITEM); if (pWorkItem == NULL) { pirp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
PoStartNextPowerIrp(pirp); IoCompleteRequest(pirp, 0); break; }
//
// Initialize the ndis work item to power on.
//
NdisInitializeWorkItem(&pWorkItem->WorkItem, (NDIS_PROC)ndisDevicePowerOn, Miniport); pWorkItem->pIrp = pirp;
//
// this reference and corresponding dereference in ndisDevicePowerOn is done
// to ensure ndis does not return back from REMOVE IRP while we are waiting
// for ndisDevicePowerOn to fire.
//
MINIPORT_INCREMENT_REF(Miniport);
//
// Schedule the workitem to fire.
//
INITIALIZE_WORK_ITEM((PWORK_QUEUE_ITEM)(&pWorkItem->WorkItem.WrapperReserved), ndisWorkItemHandler, &pWorkItem->WorkItem); XQUEUE_WORK_ITEM((PWORK_QUEUE_ITEM)(&pWorkItem->WorkItem.WrapperReserved), DelayedWorkQueue); } while (FALSE); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisSetDevicePowerOnComplete: Miniport %p\n", Miniport));
return(STATUS_MORE_PROCESSING_REQUIRED); }
VOID ndisDevicePowerDown( IN PPOWER_WORK_ITEM pWorkItem, IN PVOID pContext ) /*++
Routine Description:
Arguments:
Return Value:
--*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)pContext; DEVICE_POWER_STATE DeviceState; POWER_STATE PowerState; NDIS_STATUS NdisStatus; PIRP pirp; PIO_STACK_LOCATION pirpSp; KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisDevicePowerDown: Miniport %p\n", Miniport));
PnPReferencePackage();
pirp = pWorkItem->pIrp; pirpSp = IoGetCurrentIrpStackLocation(pirp); DeviceState = pirpSp->Parameters.Power.State.DeviceState;
//
// If the complete status is successful then we need to continue with
// wakeing the stack.
//
if (NT_SUCCESS(pirp->IoStatus.Status)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisDevicePowerDown: Miniport %p, going to device state 0x%x\n", Miniport, DeviceState));
//
// Build a power state.
//
PowerState.DeviceState = DeviceState;
//
// Save the current device state with the miniport block.
//
Miniport->CurrentDevicePowerState = DeviceState;
//
// Let the system know about the devices new power state.
//
PoSetPowerState(Miniport->DeviceObject, DevicePowerState, PowerState); } else if (ndisIsMiniportStarted(Miniport) && (Miniport->PnPDeviceState == NdisPnPDeviceStarted)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisDevicePowerDown: Miniport %p, Bus driver failed to power down the Miniport\n", Miniport)); #ifdef TRACE_PM_PROBLEMS
DbgPrint("ndisDevicePowerDown: Miniport %p, Bus Driver returned %lx for Powering Down the Miniport\n", Miniport, pirp->IoStatus.Status); #endif
//
// We need to go back to the current device state.
//
PowerState.DeviceState = Miniport->CurrentDevicePowerState;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisDevicePowerDown: Miniport %p, going to device power state 0x%x\n", Miniport, Miniport->CurrentDevicePowerState));
//
// What type of miniport was this?
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE)) { //
// Set the miniport's device state.
//
NdisStatus = ndisQuerySetMiniportDeviceState(Miniport, PowerState.DeviceState, OID_PNP_SET_POWER, TRUE); } else { NdisStatus = ndisPmInitializeMiniport(Miniport); }
//
// Is the miniport initialized?
//
if (NDIS_STATUS_SUCCESS != NdisStatus) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisDevicePowerDown: Miniport %p, failed to power down but we are not able to reinitialize it.\n", Miniport));
//
// Mark the miniport as having failed so that we remove it correctly.
//
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_DEVICE_FAILED);
//
// The bus driver failed the power off and we can't power the miniport back on.
// we invalidate the device state so that it will get removed.
//
IoInvalidateDeviceState(Miniport->PhysicalDeviceObject);
pirp->IoStatus.Status = STATUS_UNSUCCESSFUL; } else { //
// Restore the handlers.
//
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); ndisMRestoreOpenHandlers(Miniport, fMINIPORT_STATE_PM_STOPPED); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
IoSetDeviceInterfaceState(&Miniport->SymbolicLinkName, TRUE);
ndisNotifyDevicePowerStateChange(Miniport, PowerState.DeviceState); //
// Notify the transports.
//
NdisStatus = ndisPnPNotifyAllTransports(Miniport, NetEventSetPower, &PowerState.DeviceState, sizeof(PowerState.DeviceState)); ASSERT(NDIS_STATUS_SUCCESS == NdisStatus); } }
PoStartNextPowerIrp(pirp); IoCompleteRequest(pirp, 0);
FREE_POOL(pWorkItem);
ASSERT(KeGetCurrentIrql() == 0);
PnPDereferencePackage(); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisDevicePowerDown: Miniport %p\n", Miniport)); }
NTSTATUS ndisSetDevicePowerDownComplete( IN PDEVICE_OBJECT pdo, IN PIRP pirp, IN PVOID pContext ) /*++
Routine Description:
Arguments:
pdo - Pointer to the device object for the miniport. pirp - Pointer to the device set power state IRP that was completed. Context - Not used
Return Value:
--*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)pContext; NTSTATUS Status; PPOWER_WORK_ITEM pWorkItem; NDIS_STATUS NdisStatus; BOOLEAN fTimerCancelled;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisSetDevicePowerDownComplete: Miniport %p, Irp %p, Status %lx\n", Miniport, pirp, pirp->IoStatus.Status));
//
// cancel any pending media disconnect timers
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT)) { //
// Clear the disconnect wait bit and cancel the timer.
// IF the timer routine hasn't grabed the lock then we are ok.
//
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetDevicePowerDownComplete: Miniport %p, cancelling media disconnect timer\n",Miniport)); MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT); MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED);
NdisCancelTimer(&Miniport->MediaDisconnectTimer, &fTimerCancelled); }
do { pWorkItem = ALLOC_FROM_POOL(sizeof(POWER_WORK_ITEM), NDIS_TAG_WORK_ITEM); if (pWorkItem == NULL) { pirp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
PoStartNextPowerIrp(pirp); IoCompleteRequest(pirp, 0); break; }
NdisInitializeWorkItem(&pWorkItem->WorkItem, (NDIS_PROC)ndisDevicePowerDown, Miniport); pWorkItem->pIrp = pirp;
//
// Schedule the workitem to fire.
//
NdisScheduleWorkItem(&pWorkItem->WorkItem); } while (FALSE); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisSetDevicePowerDownComplete: Miniport %p\n", Miniport));
return(STATUS_MORE_PROCESSING_REQUIRED); }
NTSTATUS ndisSetPower( IN PIRP pirp, IN PIO_STACK_LOCATION pirpSp, IN PNDIS_MINIPORT_BLOCK Miniport ) /*++
Routine Description:
This routine will process the IRP_MN_SET_POWER for a miniport driver.
Arguments:
pirp - Pointer to the IRP. pirpSp - Pointer to the IRPs current stack location. Miniport - Pointer to the Miniport
Return Value:
--*/ { POWER_STATE PowerState; DEVICE_POWER_STATE DeviceState; SYSTEM_POWER_STATE SystemState; NDIS_DEVICE_POWER_STATE NdisDeviceState; NTSTATUS Status; PIO_STACK_LOCATION pirpSpN; IO_STATUS_BLOCK IoStatus; PIRP pirpWake; NDIS_STATUS NdisStatus; KEVENT Event; ULONG WakeEnable = 0; PIRP pIrpWaitWake; KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisSetPower: Miniport %p, Irp %p\n", Miniport, pirp));
PnPReferencePackage(); switch (pirpSp->Parameters.Power.Type) { case SystemPowerState:
SystemState = pirpSp->Parameters.Power.State.SystemState; Miniport->WaitWakeSystemState = SystemState; //
// if system is shutting down, call the shutdown handler
// for miniport and be done with it
//
if (SystemState >= PowerSystemShutdown) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, SystemState %lx\n", Miniport, SystemState));
if ((Miniport->DriverHandle->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER) == 0) { ndisMShutdownMiniport(Miniport); }
pirp->IoStatus.Status = STATUS_SUCCESS; PoStartNextPowerIrp(pirp); IoSkipCurrentIrpStackLocation(pirp); Status = PoCallDriver(Miniport->NextDeviceObject, pirp); break; } else { //
// Get the device state for the system state. Note that this will
// set the fMINIPORT_SYSTEM_SLEEPING flag if we are going to
// SystemState > PowerSystemWorking
//
Status = ndisMPowerPolicy(Miniport, SystemState, &DeviceState, FALSE);
//
// Is the device already powered off?
//
if (STATUS_DEVICE_POWERED_OFF == Status) { pirp->IoStatus.Status = STATUS_SUCCESS; PoStartNextPowerIrp(pirp); IoCompleteRequest(pirp, 0); Status = STATUS_SUCCESS; break; }
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, SystemPowerState[0x%x] DevicePowerState[0x%x]\n", Miniport, SystemState, DeviceState));
PowerState.DeviceState = DeviceState;
if (SystemState > PowerSystemWorking) { NdisResetEvent(&Miniport->OpenReadyEvent);
//
// if system is going to sleep mode, then notify protocols and
// request a WAIT_WAKE IRP
//
//
// Notify the transports of the impending state transition.
// There is nothing we can do if transports fail this
// Note: for all practical purposes there is no need to map
// SytemState to device state here
//
if (SystemState > PowerSystemSleeping3) NdisDeviceState = PowerSystemSleeping3; else NdisDeviceState = SystemState;
ndisNotifyDevicePowerStateChange(Miniport, NdisDeviceState); NdisStatus = ndisPnPNotifyAllTransports(Miniport, NetEventSetPower, &NdisDeviceState, sizeof(SystemState));
//
// protocols can't fail going to a sleeping state
//
ASSERT(NDIS_STATUS_SUCCESS == NdisStatus);
MiniportReferencePackage(); //
// Swap the handlers.
//
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); ndisMSwapOpenHandlers(Miniport, NDIS_STATUS_ADAPTER_NOT_READY, fMINIPORT_STATE_PM_STOPPED); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); MiniportDereferencePackage();
//
// What type of miniport was this?
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE)) {
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); if (Miniport->pIrpWaitWake != NULL) { MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE); } NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
//
// Is wake-up enabled?
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE)) { MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, Creating a wake irp for the device\n", Miniport));
//
// reuquest a power irp for wake notification
//
PowerState.SystemState = Miniport->WaitWakeSystemState; Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject, IRP_MN_WAIT_WAKE, PowerState, ndisWaitWakeComplete, Miniport, &Miniport->pIrpWaitWake); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, WaiteWakeIrp %p\n", Miniport, Miniport->pIrpWaitWake)); } } } else { NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); pIrpWaitWake = Miniport->pIrpWaitWake; NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); //
// if we are transitioning to PowerSystemWorking or just asserting
// it to cancel a query power, we will notify the protocols when
// we get the device power IRP
//
//
// If there is a wait-wake irp outstanding then we need to cancel it.
//
if (pIrpWaitWake) { if (IoCancelIrp(pIrpWaitWake)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, Successfully canceled wake irp\n", Miniport)); } }
//
// Send the S0 irp down the stack first. When it completes, send the D0 irp. This
// allows the power manager to resume faster while the slow network initialization
// takes place in the background.
//
IoCopyCurrentIrpStackLocationToNext(pirp); IoSetCompletionRoutine(pirp, ndisSetSystemPowerOnComplete, Miniport, TRUE, TRUE, TRUE); IoMarkIrpPending(pirp); PoStartNextPowerIrp(pirp); PoCallDriver(Miniport->NextDeviceObject, pirp); Status = STATUS_PENDING; break; } } //
// no matter what was the outcome of trying to set a WAIT_WAKE IRP
// we still have to set the device state appropiately
//
PowerState.DeviceState = DeviceState; //
// Save the device object with the system irp to use in the
// completion routine.
//
pirpSpN = IoGetNextIrpStackLocation(pirp); pirpSpN->DeviceObject = Miniport->DeviceObject; IoMarkIrpPending(pirp); PoStartNextPowerIrp(pirp);
//
// Let the completion routine take care of everything.
//
Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject, IRP_MN_SET_POWER, PowerState, ndisSetSystemPowerComplete, pirp, NULL); if (STATUS_PENDING != Status) { IoStatus.Status = Status; IoStatus.Information = 0;
ndisSetSystemPowerComplete(Miniport->PhysicalDeviceObject, IRP_MN_SET_POWER, PowerState, pirp, &IoStatus); } Status = STATUS_PENDING; break;
case DevicePowerState:
//
// Get the device state.
//
DeviceState = pirpSp->Parameters.Power.State.DeviceState;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, DeviceState[0x%x]\n", Miniport, DeviceState));
//
// What state is the device going to?
//
switch (DeviceState) { case PowerDeviceD0: //
// We need to pass this IRP down to the pdo so that
// it can power on.
//
IoCopyCurrentIrpStackLocationToNext(pirp);
IoSetCompletionRoutine(pirp, ndisSetDevicePowerOnComplete, Miniport, TRUE, TRUE, TRUE);
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, Power up the bus driver.\n", Miniport));
//
// Mark the IRP as pending and send it down the stack.
//
IoMarkIrpPending(pirp); PoStartNextPowerIrp(pirp); PoCallDriver(Miniport->NextDeviceObject, pirp); Status = STATUS_PENDING; break;
case PowerDeviceD1: case PowerDeviceD2: case PowerDeviceD3:
if (ndisIsMiniportStarted(Miniport) && (Miniport->PnPDeviceState == NdisPnPDeviceStarted)) { //
// if the device state setting is not the result of going to
// a sleeping system state, (such as media disconnect case)
// then notify protocols, etc.
//
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING)) { NdisResetEvent(&Miniport->OpenReadyEvent); ndisNotifyDevicePowerStateChange(Miniport, DeviceState); //
// Notify the transports of the impending state transition.
//
NdisStatus = ndisPnPNotifyAllTransports(Miniport, NetEventSetPower, &DeviceState, sizeof(DeviceState)); ASSERT(NDIS_STATUS_SUCCESS == NdisStatus);
//
// Swap the handlers.
//
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); ndisMSwapOpenHandlers(Miniport, NDIS_STATUS_ADAPTER_NOT_READY, fMINIPORT_STATE_PM_STOPPED); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); } //
// What type of miniport was this?
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE)) { BOOLEAN Canceled; if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING)) { NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); if (Miniport->pIrpWaitWake != NULL) { MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE); } NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
//
// Is wake-up enabled?
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE)) { MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, Creating a wake irp for the device\n", Miniport));
//
// reuquest a power irp for wake notification
//
PowerState.SystemState = Miniport->WaitWakeSystemState; Status = PoRequestPowerIrp(Miniport->PhysicalDeviceObject, IRP_MN_WAIT_WAKE, PowerState, ndisWaitWakeComplete, Miniport, &Miniport->pIrpWaitWake); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, WaiteWakeIrp %p\n", Miniport, Miniport->pIrpWaitWake)); } }
//
// disable the interface
//
if (Miniport->SymbolicLinkName.Buffer != NULL) { IoSetDeviceInterfaceState(&Miniport->SymbolicLinkName, FALSE); } //
// Set the miniport device state.
//
NdisStatus = ndisQuerySetMiniportDeviceState(Miniport, DeviceState, OID_PNP_SET_POWER, TRUE); if (NDIS_STATUS_SUCCESS != NdisStatus) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisSetPower: Miniport %p, Failed to power the device down\n", Miniport)); if (Miniport->SymbolicLinkName.Buffer != NULL) { IoSetDeviceInterfaceState(&Miniport->SymbolicLinkName, TRUE); } pirp->IoStatus.Status = NdisStatus; PoStartNextPowerIrp(pirp); IoCompleteRequest(pirp, 0); Status = NdisStatus; break; }
//
// Cancel the wake-up timer.
//
NdisCancelTimer(&Miniport->WakeUpDpcTimer, &Canceled); if (!Canceled) { NdisStallExecution(NDIS_MINIPORT_WAKEUP_TIMEOUT * 1000); } } else { if ((Miniport->DriverHandle->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER) == 0) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, Halt the miniport\n", Miniport));
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_FAILED)) { //
// Halt the legacy miniport.
//
ndisPmHaltMiniport(Miniport); } } } } DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisSetPower: Miniport %p, Notify the bus driver of the low power state\n", Miniport));
//
// We need to pass this IRP down to the pdo so that
// it can power down.
//
IoCopyCurrentIrpStackLocationToNext(pirp);
IoSetCompletionRoutine(pirp, ndisSetDevicePowerDownComplete, Miniport, TRUE, TRUE, TRUE);
IoMarkIrpPending(pirp); PoStartNextPowerIrp(pirp); PoCallDriver(Miniport->NextDeviceObject, pirp); Status = STATUS_PENDING; break; }
//
// Done with processing the device set power state.
//
break; } PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisSetPower: Miniport %p, Status %lx\n", Miniport, Status));
return(Status); }
NTSTATUS ndisPowerDispatch( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pirp ) /*++
Routine Description:
Arguments:
Return Value:
--*/ { PIO_STACK_LOCATION pirpSp; NTSTATUS Status; PNDIS_MINIPORT_BLOCK Miniport; PDEVICE_OBJECT NextDeviceObject; PIO_STACK_LOCATION pirpSpN;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisPowerDispatch: DeviceObject %p, Irp %p\n", pDeviceObject, pirp));
PnPReferencePackage();
//
// Get a pointer to the adapter block and miniport block then determine
// which one we should use.
//
Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)pDeviceObject->DeviceExtension + 1); if (Miniport->Signature != (PVOID)MINIPORT_DEVICE_MAGIC_VALUE) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisPowerDispatch: DeviceObject %p, Irp %p, Device extension is not a miniport.\n", pDeviceObject, pirp)); //
// Fail the invalid request.
//
pirp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST; PoStartNextPowerIrp(pirp); IoCompleteRequest(pirp, 0); goto Done; } //
// Get a pointer to the next DeviceObject.
//
NextDeviceObject = Miniport->NextDeviceObject;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisPowerDispatch: Miniport %p\n", Miniport));
//
// Get the stack parameters for this IRP.
//
pirpSp = IoGetCurrentIrpStackLocation(pirp);
switch (pirpSp->MinorFunction) { //
// power management stuff
//
case IRP_MN_POWER_SEQUENCE:
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisPowerDispatch: Miniport %p, Processing IRP_MN_POWER_SEQUENCE\n", Miniport)); PoStartNextPowerIrp(pirp); //
// Generic routine that will pass the IRP to the next device
// object in the layer that wants to process it.
//
IoCopyCurrentIrpStackLocationToNext(pirp); Status = ndisPassIrpDownTheStack(pirp, NextDeviceObject); pirp->IoStatus.Status = Status; IoCompleteRequest(pirp, 0); break;
case IRP_MN_WAIT_WAKE:
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisPowerDispatch: Miniport %p, Processing IRP_MN_WAIT_WAKE\n", Miniport));
//
// Fill in the wake information.
//
pirpSp->Parameters.WaitWake.PowerState = Miniport->WaitWakeSystemState; IoCopyCurrentIrpStackLocationToNext(pirp); PoStartNextPowerIrp(pirp); Status = PoCallDriver(NextDeviceObject, pirp); break;
case IRP_MN_QUERY_POWER:
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisPowerDispatch: Miniport %p, Processing IRP_MN_QUERY_POWER\n", Miniport));
Status = ndisQueryPower(pirp, pirpSp, Miniport); break;
case IRP_MN_SET_POWER:
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisPowerDispatch: Miniport %p, Processing IRP_MN_SET_POWER\n", Miniport));
Status = ndisSetPower(pirp, pirpSp, Miniport); break;
default: DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisPowerDispatch: Miniport %p, Processing minor function: %lx\n", Miniport, pirpSp->MinorFunction));
//
// send the IRP down
//
PoStartNextPowerIrp(pirp); IoSkipCurrentIrpStackLocation(pirp); Status = PoCallDriver(NextDeviceObject, pirp); break; }
Done: PnPDereferencePackage(); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisPowerDispatch: Miniport %p, Status 0x%x\n", Miniport, Status));
return(Status); }
NTSTATUS FASTCALL ndisMShutdownMiniport( IN PNDIS_MINIPORT_BLOCK Miniport )
/*++
Routine Description:
The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis shutdown routine, if one is registered.
Arguments:
DeviceObject - The adapter's device object. Irp - The IRP.
Return Value:
Always STATUS_SUCCESS.
--*/
{ PDEVICE_OBJECT DeviceObject = Miniport->DeviceObject; PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension; KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("==>ndisMShutdownMiniport: Miniport %p\n", Miniport));
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
//
// Mark the miniport as halting and NOT using normal interrupts.
//
MINIPORT_SET_FLAG(Miniport, fMINIPORT_PM_HALTING); MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SHUTTING_DOWN); MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
if ((WrapperContext->ShutdownHandler != NULL) && (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_NO_SHUTDOWN) == 0)) { //
// Call the shutdown routine.
//
if (WrapperContext->ShutdownHandler != NULL) { WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext); MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SHUT_DOWN); } }
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("<==ndisMShutdownMiniport: Miniport %p\n", Miniport));
return STATUS_SUCCESS; }
NTSTATUS ndisMPowerPolicy( IN PNDIS_MINIPORT_BLOCK Miniport, IN SYSTEM_POWER_STATE SystemState, IN PDEVICE_POWER_STATE pDeviceState, IN BOOLEAN fIsQuery ) /*++
Routine Description:
This routine will determine if the miniport should go to the given device state.
Arguments:
Miniport - Pointer to the miniport block SystemState - State the system wants to go to.
Return Value:
--*/ { DEVICE_POWER_STATE DeviceStateForSystemState, MinDeviceWakeup = PowerDeviceUnspecified; NTSTATUS Status = STATUS_SUCCESS; DEVICE_POWER_STATE NewDeviceState = PowerDeviceD3; PNDIS_PM_WAKE_UP_CAPABILITIES pWakeCaps; NDIS_STATUS NdisStatus; ULONG WakeEnable; PIRP pIrpWaitWake; KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("==>ndisMPowerPolicy: Miniport %p, SystemState %lx\n", Miniport, SystemState));
if (SystemState >= PowerSystemShutdown) { //
// if this is a shutdown request, set device to D3 and return
//
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMPowerPolicy: Miniport %p, shutting down\n", Miniport));
*pDeviceState = PowerDeviceD3; DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisMPowerPolicy: Miniport %p\n", Miniport)); return(STATUS_SUCCESS); } //
// If the system wants to transition to working then we are going to D0.
//
if (SystemState == PowerSystemWorking) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMPowerPolicy: Miniport %p, Wakeing up the device\n", Miniport)); if (!fIsQuery) { MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING); }
*pDeviceState = PowerDeviceD0; DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisMPowerPolicy: Miniport %p\n", Miniport)); return(STATUS_SUCCESS); } if (!fIsQuery) { //
// tag the miniport so when we get the device power IRP, we
// know we have already been here, taken care of protocols, etc.
//
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING); } //
// if this is a legacy miniport or power-disabled miniport then throw it in D3
// do the same thing for IM miniports that have not been initialized yet
//
if ((!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE)) || (!(ndisIsMiniportStarted(Miniport) && (Miniport->PnPDeviceState == NdisPnPDeviceStarted)))) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMPowerPolicy: Miniport %p, Place legacy or PM disabled device in D3\n", Miniport));
*pDeviceState = PowerDeviceD3; DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisMPowerPolicy: Miniport %p\n", Miniport)); return(STATUS_SUCCESS); }
//
// First check for the case where the netcard is already asleep due to a
// media disconnect.
//
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); pIrpWaitWake = Miniport->pIrpWaitWake; NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
if ((Miniport->CurrentDevicePowerState > PowerDeviceD0) && (pIrpWaitWake != NULL)) { ///
// Miniport is in a lower power state than D0 and there is a wake irp pending in
// the bus driver. This is a pretty good indication that the cable was pulled.
// We are not going to enable any wake-up method seeing as the cable has been disconnect.
// but if the user does not want to wakeup the machine as a result of a cable
// reconnect, cancel any pending wait-wake IRP
///
if (!fIsQuery && ((!MINIPORT_PNP_TEST_FLAG (Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE)) || (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_RECONNECT))) { if (IoCancelIrp(pIrpWaitWake)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMPowerPolicy: Miniport %p, Successfully canceled media connect wake irp\n", Miniport)); } } DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisMPowerPolicy: Miniport %p\n", Miniport)); return(STATUS_DEVICE_POWERED_OFF); }
do { //
// Is system wake-up enabled in the policy?
// if wake-up is not enabled then we simply power off.
//
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMPowerPolicy: Miniport %p, Device power wake is not enabled (%u)\n", Miniport, MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE)));
break; }
//
// This is the -lightest- state the device can go to for the requested
// system state.
//
DeviceStateForSystemState = Miniport->DeviceCaps.DeviceState[SystemState];
//
// Check to see if we are going below SystemSleeping3
//
//
//
// if we are going to S4 or deeper and device can not wake up the system from that state
// just do it
//
if ((SystemState >= PowerSystemHibernate) && ((SystemState > Miniport->DeviceCaps.SystemWake) || (DeviceStateForSystemState > Miniport->DeviceCaps.DeviceWake))) {
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMPowerPolicy: Miniport %p, System is either entering hibernate or shutting down.\n", Miniport));
//
// We succeed this call.
//
break; }
//
// Get a nice pointer to the wake-up capabilities.
//
pWakeCaps = &Miniport->PMCapabilities.WakeUpCapabilities;
if ((NDIS_PNP_WAKE_UP_MAGIC_PACKET == (Miniport->WakeUpEnable & NDIS_PNP_WAKE_UP_MAGIC_PACKET)) && (PowerDeviceUnspecified != pWakeCaps->MinMagicPacketWakeUp)) { MinDeviceWakeup = pWakeCaps->MinMagicPacketWakeUp; }
if ((NDIS_PNP_WAKE_UP_PATTERN_MATCH == (Miniport->WakeUpEnable & NDIS_PNP_WAKE_UP_PATTERN_MATCH)) && (PowerDeviceUnspecified != pWakeCaps->MinPatternWakeUp)) { if ((MinDeviceWakeup == PowerDeviceUnspecified) || (MinDeviceWakeup > pWakeCaps->MinPatternWakeUp)) { MinDeviceWakeup = pWakeCaps->MinPatternWakeUp; } }
//
// if both MagicPacket and pattern match are NOT enabled (or the system can't do either)
// then we may as well go to D3.
//
if (MinDeviceWakeup == PowerDeviceUnspecified) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMPowerPolicy: Miniport %p, MagicPacket and pattern match are not enabled.\n", Miniport));
break; }
//
// from this point on, we try to go to power state that we can wake up the system from
//
//
// make sure we don't go too deep
//
if (MinDeviceWakeup > Miniport->DeviceCaps.DeviceWake) { MinDeviceWakeup = Miniport->DeviceCaps.DeviceWake; } //
// If the system state requested is lower than the minimum required to wake up the system
// or the corresponding device state is deeper than the lowest device state to wake
// up the system then we
// fail this call. Note that we also set the device state to D3. Since
// we are not going to be able to support wake-up then we power off.
// The query power will look at the failure code and return that to the
// system. The set power will ignore the failure code and set the device
// into D3.
//
if ((SystemState > Miniport->DeviceCaps.SystemWake) || (DeviceStateForSystemState > MinDeviceWakeup) || (DeviceStateForSystemState == PowerDeviceUnspecified)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisMPowerPolicy: Miniport %p, Requested system state is lower than the minimum wake-up system state\n", Miniport));
Status = STATUS_UNSUCCESSFUL; break; }
//
// starting from DeviceWake and up to DeviceState[SystemState], find a
// suitable device state
//
switch (MinDeviceWakeup) { case PowerDeviceD3: if (Miniport->DeviceCaps.WakeFromD3) { NewDeviceState = PowerDeviceD3; break; } case PowerDeviceD2: if (Miniport->DeviceCaps.DeviceD2 && Miniport->DeviceCaps.WakeFromD2) { NewDeviceState = PowerDeviceD2; break; } case PowerDeviceD1: if (Miniport->DeviceCaps.DeviceD1 && Miniport->DeviceCaps.WakeFromD1) { NewDeviceState = PowerDeviceD1; break; } case PowerDeviceD0: if (Miniport->DeviceCaps.WakeFromD0) { NewDeviceState = PowerDeviceD0; break; } default: Status = STATUS_UNSUCCESSFUL; DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisMPowerPolicy: Miniport %p, couldn't find any wake-able DeviceState 0x%x\n", Miniport)); break;
}
//
// ok, we started with deepest state (based on what device said can do)
// and went up. make sure we didn't go too far up. i.e. the statem state
// we are going to can maintain the device in desired power state
//
if ((Status == NDIS_STATUS_SUCCESS) && (DeviceStateForSystemState > NewDeviceState)) { Status = STATUS_UNSUCCESSFUL; DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisMPowerPolicy: Miniport %p, couldn't find any wake-able DeviceState 0x%x\n", Miniport)); }
//
// If this is for the set power then we need to enable wake-up on the miniport.
//
if (!fIsQuery) { //
// We need to send a request to the miniport to enable the correct wake-up types NOT
// including the link change.
//
WakeEnable = Miniport->WakeUpEnable & ~NDIS_PNP_WAKE_UP_LINK_CHANGE; if (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_PATTERN_MATCH) { WakeEnable &= ~NDIS_PNP_WAKE_UP_PATTERN_MATCH; }
if (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_MAGIC_PACKET) { WakeEnable &= ~NDIS_PNP_WAKE_UP_MAGIC_PACKET; } NdisStatus = ndisQuerySetMiniportDeviceState(Miniport, WakeEnable, OID_PNP_ENABLE_WAKE_UP, TRUE);
if (NDIS_STATUS_SUCCESS == NdisStatus) { MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SEND_WAIT_WAKE); } else { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_ERR, ("ndisMPowerPolicy: Miniport %p, Unable to enable the following wake-up methods 0x%x\n", Miniport, WakeEnable)); //
// Since we can't enable the wake methods we may as well go to D3.
//
NewDeviceState = PowerDeviceD3; break; } }
//
// Save the device state that we should go to.
//
*pDeviceState = NewDeviceState; DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMPowerPolicy: Miniport %p, SystemState 0x%x, DeviceState 0x%x\n", Miniport, SystemState, *pDeviceState)); DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisMPowerPolicy: Miniport %p\n", Miniport)); return(Status);
} while (FALSE);
//
// If this is not a query then we need to cancel wake-up on the miniport.
//
if (!fIsQuery && MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMPowerPolicy: Miniport %p, Disabling wake-up on the miniport\n", Miniport));
WakeEnable = 0; ndisQuerySetMiniportDeviceState(Miniport, WakeEnable, OID_PNP_ENABLE_WAKE_UP, TRUE); }
//
// Save the device state that we should go to.
//
*pDeviceState = NewDeviceState;
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisMPowerPolicy: Miniport %p, SystemState 0x%x, DeviceState 0x%x\n", Miniport, SystemState, *pDeviceState));
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("<==ndisMPowerPolicy: Miniport %p\n", Miniport));
return(Status); }
|