📄 nic_pm.c
字号:
}
// Lets move to the next DWORD. Init variables
pCurrentByte += 4 ;
NumBytesWritten = 4;
pCurrentUlong = (PULONG)pCurrentByte;
// We Copy in the Mask over here
{
// The Mask is at the end of the pattern
PUCHAR pMask = (PUCHAR)pNdisPattern + sizeof(*pNdisPattern);
//Dump (pMask,pNdisPattern->MaskSize, 0,1);
RtlMoveMemory (pCurrentByte, pMask, pNdisPattern->MaskSize);
NumBytesWritten += pNdisPattern->MaskSize;
}
// Update the output value
{
ULONG NumUlongs = (NumBytesWritten /4);
if ((NumBytesWritten %4) != 0)
{
NumUlongs ++;
}
ASSERT (NumUlongs == LengthOfFilter);
*pNext = *pNext + NumUlongs;
}
DebugPrint(TRACE, DBG_POWER, "<-- MPCreateProgrammableFilter\n");
return;
}
NTSTATUS
MPSetPowerD0(
PFDO_DATA FdoData
)
/*++
Routine Description:
This routine is called when the adapter receives a SetPower
to D0.
Arguments:
Adapter Pointer to the adapter structure
PowerState NewPowerState
Return Value:
--*/
{
NTSTATUS status;
KIRQL oldIrql;
LARGE_INTEGER DueTime;
//
// MPSetPowerD0Private Initializes the adapte, issues a selective reset.
//
MPSetPowerD0Private (FdoData);
ASSERT(FdoData->DevicePowerState == PowerDeviceD0);
//
// Set up the packet filter
//
KeAcquireSpinLock(&FdoData->Lock, &oldIrql);
status = NICSetPacketFilter(
FdoData,
FdoData->OldPacketFilter);
//
// If Set Packet Filter succeeds, restore the old packet filter
//
if (status == STATUS_SUCCESS)
{
FdoData->PacketFilter = FdoData->OldPacketFilter;
}
KeReleaseSpinLock(&FdoData->Lock, oldIrql);
//
// Set up the multicast list address
//
//
// We need to raise the IRQL before acquiring the lock
// because the functions called inside the guarded
// region assume that they are called at Dpc level and release
// and reacquire the lock using DpcLevel spinlock functions.
//
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock);
status = NICSetMulticastList(FdoData);
NICStartRecv(FdoData);
KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
KeLowerIrql(oldIrql);
//
// Restart the watchdog timer.
//
KeClearEvent(&FdoData->WatchDogTimerEvent);
DueTime.QuadPart = NIC_CHECK_FOR_HANG_DELAY;
KeSetTimer( &FdoData->WatchDogTimer, // Timer
DueTime, // DueTime
&FdoData->WatchDogTimerDpc // Dpc
);
//
// Register the interrupt if it's not done already
//
if(!MP_TEST_FLAG(FdoData, fMP_ADAPTER_INTERRUPT_IN_USE)) {
status = IoConnectInterrupt(&FdoData->Interrupt,
NICInterruptHandler,
FdoData, // ISR Context
NULL,
FdoData->InterruptVector,
FdoData->InterruptLevel,
FdoData->InterruptLevel,
FdoData->InterruptMode,
TRUE, // shared interrupt
FdoData->InterruptAffinity,
FALSE);
if (!NT_SUCCESS(status)) {
DebugPrint(ERROR, DBG_INIT, "IoConnectInterrupt failed %x\n", status);
}
else {
MP_SET_FLAG(FdoData, fMP_ADAPTER_INTERRUPT_IN_USE);
//
// Enable the interrupt, so the driver can send/receive packets
//
NICEnableInterrupt(FdoData);
}
} else {
NICEnableInterrupt(FdoData);
}
return status;
}
NTSTATUS
MPSetPowerLow(
PFDO_DATA FdoData,
DEVICE_POWER_STATE PowerState
)
/*++
Routine Description:
This routine is called when the FdoData receives a SetPower
to a PowerState > D0
Arguments:
FdoData Pointer to the FdoData structure
PowerState NewPowerState
Return Value:
NT Status code
--*/
{
NTSTATUS status = STATUS_SUCCESS;
do
{
//FdoData->DevicePowerState = PowerState;
//
// Stop sending packets. Create a new flag and make it part
// of the Send Fail Mask
//
//
// Stop hardware from receiving packets - Set the RU to idle
//
//
// Check the current status of the receive unit
//
if ((FdoData->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE)
{
//
// Issue an RU abort. Since an interrupt will be issued, the
// RU will be started by the DPC.
//
status = D100IssueScbCommand(FdoData, SCB_RUC_ABORT, TRUE);
}
if (status != STATUS_SUCCESS)
{
break;
}
//
// MPSetPowerLowPrivate first disables the interrupt, acknowledges all the pending
// interrupts and sets FdoData->DevicePowerState to the given low power state
// then starts Hardware specific part of the transition to low power state
// Setting up wake-up patterns, filters, wake-up events etc
//
KeSynchronizeExecution(
FdoData->Interrupt,
(PKSYNCHRONIZE_ROUTINE)MPSetPowerLowPrivate,
FdoData);
//
// Disconnect the interrupt when the device is in low power state.
// This is to avoid being in the ISR calling chain in case our interrupt
// line is shared by other devices, which is pretty normal for PCI
// devices. We will register our ISR when we resume from sleep.
//
IoDisconnectInterrupt(FdoData->Interrupt);
FdoData->Interrupt = NULL;
MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_INTERRUPT_IN_USE);
status = STATUS_SUCCESS;
} while (FALSE);
return status;
}
BOOLEAN
MPAreTwoPatternsEqual(
IN PNDIS_PM_PACKET_PATTERN pNdisPattern1,
IN PNDIS_PM_PACKET_PATTERN pNdisPattern2
)
/*++
Routine Description:
This routine will compare two wake up patterns to see if they are equal
Arguments:
pNdisPattern1 - Pattern1
pNdisPattern2 - Pattern 2
Return Value:
True - if patterns are equal
False - Otherwise
--*/
{
BOOLEAN bEqual = FALSE;
// Local variables used later in the compare section of this function
PUCHAR pMask1, pMask2;
PUCHAR pPattern1, pPattern2;
UINT MaskSize, PatternSize;
do
{
bEqual = (BOOLEAN)(pNdisPattern1->Priority == pNdisPattern2->Priority);
if (bEqual == FALSE)
{
break;
}
bEqual = (BOOLEAN)(pNdisPattern1->MaskSize == pNdisPattern2->MaskSize);
if (bEqual == FALSE)
{
break;
}
//
// Verify the Mask
//
MaskSize = pNdisPattern1->MaskSize ;
pMask1 = (PUCHAR) pNdisPattern1 + sizeof (NDIS_PM_PACKET_PATTERN);
pMask2 = (PUCHAR) pNdisPattern2 + sizeof (NDIS_PM_PACKET_PATTERN);
bEqual = (BOOLEAN)RtlEqualMemory (pMask1, pMask2, MaskSize);
if (bEqual == FALSE)
{
break;
}
//
// Verify the Pattern
//
bEqual = (BOOLEAN)(pNdisPattern1->PatternSize == pNdisPattern2->PatternSize);
if (bEqual == FALSE)
{
break;
}
PatternSize = pNdisPattern2->PatternSize;
pPattern1 = (PUCHAR) pNdisPattern1 + pNdisPattern1->PatternOffset;
pPattern2 = (PUCHAR) pNdisPattern2 + pNdisPattern2->PatternOffset;
bEqual = (BOOLEAN)RtlEqualMemory (pPattern1, pPattern2, PatternSize );
if (bEqual == FALSE)
{
break;
}
} while (FALSE);
return bEqual;
}
VOID
NICExtractPMInfoFromPciSpace(
PFDO_DATA FdoData,
PUCHAR pPciConfig
)
/*++
Routine Description:
Looks at the PM information in the
device specific section of the PCI Config space.
Interprets the register values and stores it
in the adapter structure
Definitions from Table 4.2 & 4.3, Pg 4-9 & 4-10
of the 10/100 Mbit Ethernet Family Software Technical
Reference Manual
Arguments:
Adapter Pointer to our adapter
pPciConfig Pointer to Common Pci Space
Return Value:
--*/
{
PMP_PM_PCI_SPACE pPmPciConfig = (PMP_PM_PCI_SPACE )pPciConfig;
MP_PMCSR PMCSR;
//
// First interpret the PM Capabities register
//
{
MP_PM_CAP_REG PmCaps;
PmCaps = pPmPciConfig->PMCaps;
if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D0)
{
FdoData->PoMgmt.bWakeFromD0 = TRUE;
}
if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D1)
{
FdoData->PoMgmt.bWakeFromD1 = TRUE;
}
if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D2)
{
FdoData->PoMgmt.bWakeFromD2 = TRUE;
}
if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D3HOT)
{
FdoData->PoMgmt.bWakeFromD3Hot = TRUE;
}
if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D3_AUX)
{
FdoData->PoMgmt.bWakeFromD3Aux = TRUE;
}
}
//
// Interpret the PM Control/Status Register
//
{
PMCSR = pPmPciConfig->PMCSR;
if (PMCSR.PME_En == 1)
{
//
// PME is enabled. Clear the PME_En bit.
// So that it is not asserted
//
MpClearPME_En (FdoData,PMCSR);
}
}
}
NTSTATUS
NICSetPower(
PFDO_DATA FdoData ,
DEVICE_POWER_STATE PowerState
)
/*++
Routine Description:
This routine is called when the FdoData receives a SetPower
request. It redirects the call to an appropriate routine to
Set the New PowerState
Arguments:
FdoData Pointer to the FdoData structure
PowerState NewPowerState
Return Value:
NTSTATUS Code
--*/
{
NTSTATUS status = STATUS_SUCCESS;
if (PowerState == PowerDeviceD0)
{
DebugPrint(TRACE, DBG_POWER, "Entering fully on state\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -