📄 e100bexadap.cpp
字号:
{
TRACE("E100bexAdapter::CheckForHang\n");
m_Lock.Lock();
// We need to dump our statistics if we are implementing the "periodic multicast
// command workaround"
if ( m_pCard->GetMcTimeoutFlag() )
{
// Dump the current stats
m_pCard->UpdateStats();
m_pCard->GetUpdatedStats(m_Stats);
// If we haven't received any frames recently, and we are implementing
// the "periodic multicast command workaround", then we'll chain in
// a multicast command to the transmit chain here.
if ( m_Stats->RcvGoodFrames && m_AiRevID < D101_A_STEP )
{
DoBogusMulticast();
}
}
// this is the implementation of the NDIS 4 feature for detecting
// link status change. It effectively checks every two seconds
// for link.
if (m_LinkIsActive != m_pCard->GetConnectionStatus())
{
// if status has changed
TRACE("E100bexAdapter::CheckForHang: media state changed to %s\n",
((m_LinkIsActive == NdisMediaStateConnected)? "Disconnected": "Connected"));
switch ( m_LinkIsActive )
{
case NdisMediaStateConnected:
// changing from connected
m_LinkIsActive = NdisMediaStateDisconnected;
m_Lock.Unlock();
IndicateStatus(NDIS_STATUS_MEDIA_DISCONNECT,NULL,0);
// NOTE: have to indicate status complete every time you indicate status
IndicateStatusComplete();
// NdisMIndicateStatusComplete(*this);
m_Lock.Lock();
break;
case NdisMediaStateDisconnected:
// changing from disconnected
m_LinkIsActive = NdisMediaStateConnected;
m_Lock.Unlock();
IndicateStatus(NDIS_STATUS_MEDIA_CONNECT,NULL,0);
// NOTE: have to indicate status complete every time you indicate status
IndicateStatusComplete();
// NdisMIndicateStatusComplete(*this);
m_Lock.Lock();
break;
}
}
m_Lock.Unlock();
// return FALSE to indicate that the adapter is not hung, and that
// Reset does NOT need to be called by the wrapper
return FALSE;
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::DoBogusMulticast
// Issues a multicast command to the NIC. If the
// receive unit is "locked-up", a multicast command will
// will reset and "un-lock" the receive unit. The multicast
// command that is issued here will be chained into the transmit
// list.
// Parameters:
// none
// IRQL:
// IRQL DISPATCH_LEVEL
// Return Mode:
// Synchronous
// NOTE:
//
VOID E100bexAdapter::DoBogusMulticast()
{
TRACE("E100bexAdapter::DoBogusMulticast() Entered\n");
// Attempt to acquire a Software TCB for the packet
PD100SwTcb pSwTcb = m_TxCBList.RemoveHead();
if (pSwTcb)
{
// Setup the pointer to the first MC Address
PUCHAR pMcAddress = (PUCHAR) &pSwTcb->Tcb->TxCbTbdPointer;
pMcAddress += 2;
// Setup the pointer to the first MC Address
PUSHORT pMcCount = (PUSHORT) &pSwTcb->Tcb->TxCbTbdPointer;
// Setup the multicast address count
*pMcCount = (USHORT) (m_NumberOfMcAddresses * ETH_LENGTH_OF_ADDRESS);
// Copy the current multicast addresses to the command block
for (UINT i = 0; (i < m_NumberOfMcAddresses) && (i < MAX_MULTICAST_ADDRESSES); i++)
{
for (UINT j = 0; j < ETH_LENGTH_OF_ADDRESS; j++)
{
*(pMcAddress++) = m_PrivateMulticastBuffer[i][j];
}
}
// Setup the command and status words of the command block
pSwTcb->Tcb->TxCbHeader.CbStatus = 0;
pSwTcb->Tcb->TxCbHeader.CbCommand = CB_S_BIT | CB_MULTICAST;
// If CU is idle (very first command) then we must
// setup the general pointer and issue a full CU-start
if (m_TransmitIdle)
{
TRACE2(("CU is idle -- First MC added to Active List\n"));
m_ActiveChainList.InsertHead(pSwTcb);
m_pCard->StartTransmitUnit(pSwTcb->TcbPhys);
m_TransmitIdle = FALSE;
m_ResumeWait = TRUE;
}
else
{
// If the CU has already been started, then append this
// TCB onto the end of the transmit chain, and issue a CU-Resume.
TRACE2(("adding MCB to Active chain\n"));
m_ActiveChainList.InsertTail(pSwTcb);
// Clear the suspend bit on the previous packet.
pSwTcb->PreviousTcb->TxCbHeader.CbCommand &= ~CB_S_BIT;
// We need to wait for the SCB to clear when inserting a non-
// transmit command dynamically into the CBL (command block list).
m_ResumeWait = TRUE;
// Issue a CU-Resume command to the device -- and wait for the
// SCB command word to clear first.
m_pCard->ResumeCommandUnit();
}
}
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::DisableInterrupt
// Optional function, supplied by drivers of NICs that support dynamic
// enabling and disabling of interrupts but do not share an IRQ
// Parameters:
// none
// IRQL:
// DIRQL
// Return Mode:
// Synchronous
// NOTE:
// MiniportDisableInterrupt typically disables interrupts by
// writing a mask to the NIC. If a driver does not have this function,
// typically its MiniportISR disables interrupts on the NIC.
VOID E100bexAdapter::DisableInterrupt(void)
{
TRACE("E100bexAdapter::DisableInterrupt() Entered\n");
// Disable interrupts on our PCI board by setting the mask bit
m_pCard->DisableInterrupt();
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::EnableInterrupt
// Optional function, supplied by some drivers of NICs that support
// dynamic enabling and disabling of interrupts but do not share an IRQ
// Parameters:
// none
// IRQL:
// IRQL DISPATCH_LEVEL
// Return Mode:
// Synchronous
// NOTE:
// A NIC driver that exports a MiniportDisableInterrupt function
// need not have a reciprocal MiniportEnableInterrupt function.
// Such a driver's MiniportHandleInterrupt function is responsible
// for re-enabling interrupts on the NIC.
VOID E100bexAdapter::EnableInterrupt(void)
{
TRACE("E100bexAdapter::EnableInterrupt() Entered\n");
// Enable interrupts on our PCI board by clearing the mask bit
m_pCard->EnableInterrupt();
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::Isr
// MiniportISR is a required function if the driver's NIC generates
// interrupts.
// Parameters:
// InterruptRecognized
// Points to a variable in which MiniportISR returns whether
// the NIC actually generated the interrupt. MiniportISR sets this
// to TRUE if it detects that the interrupt came from the NIC.
// QueueMiniportHandleInterrupt
// Points to a variable that MiniportISR sets to TRUE if the
// MiniportHandleInterrupt function should be called to complete
// the interrupt-driven I/O operation.
// IRQL:
// DIRQL
// Return Mode:
// Synchronous
//
// NOTE
// Miniports that do not provide MiniportDisable/EnableInterrupt
// functionality must have their ISRs called on every interrupt.
//
VOID E100bexAdapter::Isr(
OUT PBOOLEAN InterruptRecognized,
OUT PBOOLEAN QueueMiniportHandleInterrupt
)
{
// Make sure this is our NIC that generated that interrupt
// Clear the interrupt condition register before returning.
// Check if this card is causing the interrupt
if ( m_pCard->IsInterrupting() )
{
*InterruptRecognized = TRUE;
*QueueMiniportHandleInterrupt = TRUE;
// Disable interrupts on the card
m_pCard->DisableInterrupt();
}
else
{
*InterruptRecognized = FALSE;
*QueueMiniportHandleInterrupt = FALSE;
}
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::HandleInterrupt
// MiniportHandleInterrupt is a required function if a driver's
// NIC generates interrupts. Does the deferred processing of all
// outstanding interrupt operations and starts any new operations.
// Parameters:
// none
// IRQL:
// IRQL DISPATCH_LEVEL
// Return Mode:
// Synchronous
// NOTE
// When MiniportHandleInterrupt is called, interrupts are disabled
// on the NIC, either by the MiniportISR or MiniportDisableInterrupt.
// Before it returns control, MiniportHandleInterrupt can re-enable
// interrupts on the NIC. Otherwise, NDIS calls a driver-supplied
// MiniportEnableInterrupt function to do so when MiniportHandleInterrupt
// returns control.
VOID E100bexAdapter::HandleInterrupt(void)
{
TRACE2(("E100bexAdapter::HandleInterrupt() Entered\n"))
// TODO: Process NIC's events: get frames, statuses, etc.
// This is where the "meat" of the driver is expected to be.
// Count can be changed to other values
// to optimize for hardware/protocol timing differences
USHORT Count = 2;
// Acquire spin lock
m_Lock.Lock();
TRACE2(("\n"))
// Make no more than 'Count' loops through the interrupt processing
// code. We don't want to loop forever in handle interrupt if we have
// interrupt processing to do, because this might lead to starvation
// problems with certain protocols if we are receiving data constantly.
while (Count--)
{
// Ack all pending interrupts now
if ( !m_pCard->AckPendingInterrupts() )
break;
// Go handle receive events
ProcessRXInterrupt();
// Cleanup transmits
ProcessTXInterrupt();
// Start the receive unit if it had stopped
StartReceiveUnit();
}
// Release spin lock
m_Lock.Unlock();
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::AsyncResetTimerCallback
//
// Parameters:
// none
// IRQL:
//
// Return Mode:
//
// NOTE
//
VOID E100bexAdapter::AsyncResetTimerCallback(void)
{
TRACE("E100bexAdapter::AsyncResetTimerCallback\n");
ResetComplete(NDIS_STATUS_SUCCESS);
TRACE("E100bexAdapter::AsyncResetTimerCallback: Calling StartReceiveUnit\n");
// Start the receive unit and indicate any pending receives that were
// left in the queue.
if ( StartReceiveUnit() )
{
TRACE2(("Indicating Receive complete\n"))
NdisMEthIndicateReceiveComplete(this);
}
m_pCard->EnableInterrupt();
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::SetupTransmitQueues
//
// Parameters:
// none
// IRQL:
//
// Return Mode:
//
// NOTE
//
VOID E100bexAdapter::SetupTransmitQueues(void)
{
// Initialize the command unit flags
m_TransmitIdle = TRUE;
m_ResumeWait = TRUE;
// Reset the TCB lists
m_TxCBList.Reset();
m_ActiveChainList.Reset();
m_CompletedChainList.Reset();
// Reset the coalesce list
m_CoalesceBufferList.Reset();
// Reset the list of queued NDIS_PACKETs
m_TxQueue.Reset();
// Setup the initial pointers to the HW and SW TCB data space
PD100SwTcb pSwTcb = (PD100SwTcb) m_XmitCached;
PTXCB_STRUC pHwTcb = (PTXCB_STRUC) m_XmitUnCached;
ULONG HwTcbPhys = NdisGetPhysicalAddressLow(m_XmitUnCachedPhys);
// Setup the initial pointers to the TBD data space.
// TBDs are located immediately following the TCBs
PTBD_STRUC pHwTbd = (PTBD_STRUC) (m_XmitUnCached + (sizeof(TXCB_STRUC) * m_NumTcb));
ULONG HwTbdPhys = HwTcbPhys + (sizeof(TXCB_STRUC) * m_NumTcb);
// Go through and set up each TCB
for (UINT TcbCount = 0; TcbCount < m_NumTcb; TcbCount++,
pSwTcb++, pHwTcb++, HwTcbPhys += sizeof(TXCB_STRUC),
pHwTbd = (PTBD_STRUC) (((ULONG_PTR) pHwTbd) +
((ULONG) (sizeof(TBD_STRUC) * m_NumTbdPerTcb))),
HwTbdPhys += (sizeof(TBD_STRUC) * m_NumTbdPerTcb))
{
#if DBG
pSwTcb->TcbNum = TcbCount;
#endif
TRACE (" TcbCount=%d\n", TcbCount);
TRACE (" pSwTcb=%lx\n", pSwTcb);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -