⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 e100bexadap.cpp

📁 nmE100bex网卡驱动程序
💻 CPP
📖 第 1 页 / 共 5 页
字号:
{
	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 + -