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

📄 e100bexadap.cpp

📁 nmE100bex网卡驱动程序
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    {
        SendComplete(m_TxQueue.RemoveHead(), NDIS_STATUS_FAILURE);
    }

	while (!m_ActiveChainList.IsEmpty())
    {
        // here we have to fail any sends that haven't completed yet
        PD100SwTcb pSwTcb = m_ActiveChainList.RemoveHead();

        // If this wasn't a multicast command, then we need to check to see
        // if we need to issue send complete
        if ((pSwTcb->Tcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
        {
            // Do a send Complete for this frame
            SendComplete(pSwTcb->Packet, NDIS_STATUS_FAILURE);
        }
    }

    // Abort the Receive unit so the hardware doesn't continue to receive packets.  If
    // the Receive unit is not aborted, the hardware could still DMA receive packets
    // into host memory after a warm boot.
    m_pCard->AbortReceiveUnit();

	// Wait 30 Milliseconds for the device to abort the RU.  
	// Try to avoid reseting the PHY when the RU is active.
    StallExecution(30);

    // Reset the PHY chip.  This is done so that after a warm boot, the PHY will
    // be in a known state, with auto-negotiation enabled.
    m_pCard->ResetPhy();
}


////////////////////////////////////////////////////////////////////
// E100bexAdapter::Reset
//
// MiniportReset is a required function that issues a hardware reset
// to the NIC and/or resets the driver's software state.
//
// Parameters:
//		AddressingReset
//			Points to a variable that MiniportReset sets to TRUE if the
//			NDIS library should call MiniportSetInformation to restore
//			addressing information to the current values.
// IRQL: 
//		DISPATCH_LEVEL
// Return Mode:
//		Asynchronous
NDIS_STATUS E100bexAdapter::Reset
			(OUT PBOOLEAN AddressingReset)
{
	TRACE("E100bexAdapter::Reset() Entered\n");

    m_Lock.Lock();

    *AddressingReset = TRUE;

    // Disable interrupts while re-initializing the transmit structures
    m_pCard->DisableInterrupt();

    // The NDIS 5 support for deserialized miniports requires that
    // when reset is called, the driver de-queue and fail all uncompleted
    // sends, and complete any uncompleted sends. Essentially there must be
    // no pending send requests left when this routine is exited.


    // we will fail all sends that are left right now.
    TRACE("DeQing: ");

    while(!m_TxQueue.IsEmpty())
    {

        // we must release the lock here before returning control to ndis
        // (even temporarily like this)
        m_Lock.Unlock();
        SendComplete(m_TxQueue.RemoveHead(), NDIS_STATUS_FAILURE);
        m_Lock.Lock();
    }
    TRACE("\nDone!\n");

    // clean up all the packets we have successfully TX'd
    ProcessTXInterrupt();

	while (!m_ActiveChainList.IsEmpty())
    {
        // here we have to fail any sends that haven't completed yet
        PD100SwTcb pSwTcb = m_ActiveChainList.RemoveHead();

        // If this wasn't a multicast command, then we need to check to see
        // if we need to issue send complete
        if ((pSwTcb->Tcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
        {
	        m_Lock.Unlock();
            // Do a send Complete for this frame
            SendComplete(pSwTcb->Packet, NDIS_STATUS_FAILURE);
	        m_Lock.Lock();
        }
    }

	// Cancel the timer
	m_Timer.Cancel();

    // Issue a selective reset to make the CU idle.  This will also abort
    // the RU, and make the receive unit go idle.
    m_pCard->IssueSelectiveReset();

    // since the d100/d101 both assert the interrupt line after reset,
    // try disabling ints here, because nothing is handled
    // on a reset interrupt anyway.
    m_pCard->DisableInterrupt();

    // Clear out our software transmit structures
    NdisZeroMemory((PVOID) m_XmitCached, m_XmitCachedSize);

    // re-init the map register related variables
    m_NextFreeMapReg = 0;
    m_OldestUsedMapReg = 0;

    // re-initialize the transmit structures
    TRACE("Reset: Calling SetupTransmitQueues\n");
    SetupTransmitQueues();

    // set a timer to call back in 500 ms so the 
    // spinlock is not held too long
	m_Timer.Set(500);

    m_Lock.Unlock();

    // return NDIS_STATUS_PENDING so that this can be finished later
	return NDIS_STATUS_PENDING;
}
	

////////////////////////////////////////////////////////////////////
// E100bexAdapter::Shutdown
//
// MiniportShutdown does nothing more than restore the NIC to its 
// initial state (before the miniport's DriverEntry function runs)
//
// Parameters:
//		None
// IRQL: 
//		If MiniportShutdown is called due to a user-initiated system shutdown,
//		it runs at IRQL PASSIVE_LEVEL in a system-thread context. If it is called
//		due to an unrecoverable error, MiniportShutdown runs at an arbitrary IRQL
//		and in the context of whatever component raised the error. 
// Return Mode:
//		Synchronous
VOID E100bexAdapter::Shutdown(void)
{
	TRACE("E100bexAdapter::Shutdown() Entered\n");

	// Disable the device's interrupt line.
	m_pCard->DisableInterrupt();

    // Abort the Receive unit so the hardware doesn't continue to receive packets.  If
    // the Receive unit is not aborted, the hardware could still DMA receive packets
    // into host memory after a warm boot.
    m_pCard->AbortReceiveUnit();

	// Wait 30 Milliseconds for the device to abort the RU.  This really
	// is not necessary, but I'm a little paranoid about reseting the PHY
	// when the RU is active.
	StallExecution(30);

	// Reset the PHY chip.  We do this so that after a warm boot, the PHY will
	// be in a known state, with auto-negotiation enabled.
	m_pCard->ResetPhy();
}


////////////////////////////////////////////////////////////////////
// E100bexAdapter::SendPackets
//
// Transfers a protocol-supplied packet over the network
//
// Parameters:
//		PacketArray 
//			Points to an array of packet descriptors specifying the data to be transmitted. 
//		NumberOfPackets 
//			Specifies the number of packets in the array.
// IRQL: 
//		DISPATCH_LEVEL
// Return Mode:
//		Asynchronous
// NOTE:
VOID E100bexAdapter::SendPackets(
			IN	PPNDIS_PACKET			PacketArray,
			IN	UINT					NumberOfPackets
			)
{
    NDIS_STATUS         Status;

	TRACE("E100bexAdapter::SendPackets() Entered\n");

    m_Lock.Lock();
    
    UINT PacketIndex;
	KNdisPacketArray PktArray(PacketArray, NumberOfPackets);
	KNdisPacket Pkt;

    // Take each packet in the array and return a status for it
    // if we return one packet with a NDIS_STATUS_RESOURCES,
    // the MiniPort layer assumes the rest of the packets have the same status
    // its up to the protocol to check those statuses after we return
    for(PacketIndex=0;PacketIndex < NumberOfPackets; PacketIndex++)
    {
        Pkt = PktArray[PacketIndex];
		
		// check for a zero pointer
        ASSERT(Pkt.IsValid());

		Status = SetupNextSend(Pkt);

        if (Status == NDIS_STATUS_RESOURCES)
        {
            // Queue This packet for the Deserialized Miniport
            m_TxQueue.InsertTail(Pkt);
            Status = NDIS_STATUS_PENDING;
        }

        Pkt.STATUS(Status);
    }

    m_Lock.Unlock();
    return;
}


//-----------------------------------------------------------------------------
// Procedure:   SetupNextSend
//
// Description: This routine is called by SendPackets.  It will setup all of the
//              necessary structures (TCBs, TBDs, etc.) to send a packet.  If
//              the device has the necessary resources, the packet will be
//              sent out on the active chain.  If the device doesn't have the
//              resources to send the packet, then the routine will return
//              NDIS_STATUS_RESOURCES.
//
//              The intention is to have this routine run only on a 82557
//              or a 82558 in compatibility mode (indicated by Enhanced = FALSE
//              in the registry)
// Arguments:
//      Packet - The KNdisPacket that is to be transmitted.
// Returns:
//      NDIS_STATUS_SUCCESS - We copied the entire packet into a host buffer,
//                            (either it was a short frame, or we coalesced
//                            the packet into a host buffer), so we can
//                            immediately return the buffer back to the upper
//                            layers.
//      NDIS_STATUS_PENDING - If we were able to acquire the necessary TBD's
//                            or Coalesce buffer for the packet.  This means
//                            that the device will send this packet soon.
//                            Eventually we'll return the packet back to the
//                            protocol stack by using the "SendComplete" call.
//      NDIS_STATUS_RESOURCES - We didn't have the resouces (TCBs or TBDs) to
//                              accept this packet. The NDIS packet should
//                              queue this packet, and give it back to us at a
//                              later time.
//-----------------------------------------------------------------------------
NDIS_STATUS E100bexAdapter::SetupNextSend(KNdisPacket& Packet)
{

    PD100SwTcb          SwTcb;
    PTXCB_STRUC         HwTcb;
    NDIS_STATUS         Status;

	// Attempt to acquire a Software TCB for the packet
    SwTcb = m_TxCBList.RemoveHead();

    if (!SwTcb)
    {
        TRACE2(("FailNoTcb\n"))

        // No TCBs available so return NO_RESOURCES
        Status = NDIS_STATUS_RESOURCES;
        return (Status);
    }
    
    // this next line tries to workaround the case where
    // on a D101 we can wrap our queue by setting the
    // 'S' bit on our head
    if (m_TxCBList.IsEmpty())
    {
        TRACE2(("Don't WRAP queue!!! Fail With Only 1 TCB left\n"))
        m_TxCBList.InsertHead(SwTcb);
        Status = NDIS_STATUS_RESOURCES;
        return(Status);
    }

    // Prepare the TCB for transmission of this packet
    if (PrepareForTransmit(Packet, SwTcb))
    {

        // debug stuff
        TRACE3(("Assigning SwTcb %08x to 557\n", SwTcb))
        ASSERT(SwTcb);

        HwTcb = SwTcb->Tcb;
        HwTcb->TxCbHeader.CbStatus = 0;
        HwTcb->TxCbThreshold = (UCHAR) m_AiThreshold;

        // If the packet is small then we don't use any TBDs, and we send
        // the packet in simplified mode.
        if (SwTcb->PacketLength <= MINIMUM_ETHERNET_PACKET_SIZE)
        {
            // Prep the hardware TCB.  This Tcb will not point to any TBDs
            // because the entire frame will be located in the TCB's data
            // area.
            HwTcb->TxCbHeader.CbCommand = CB_S_BIT | CB_TRANSMIT;
            HwTcb->TxCbTbdPointer = DRIVER_NULL;
            HwTcb->TxCbTbdNumber = 0;
            HwTcb->TxCbCount = (CB_TX_EOF_BIT | 0x003C);
        }

        // If the packet is not small then we do use TBDs, and thus send the
        // packet using flexible mode.
        else
        {
            // Prep the hardware TCB
            HwTcb->TxCbHeader.CbCommand = CB_S_BIT | CB_TRANSMIT | CB_TX_SF_BIT;
            HwTcb->TxCbTbdPointer = SwTcb->FirstTbdPhys;
            HwTcb->TxCbTbdNumber = (UCHAR) SwTcb->TbdsUsed;
            HwTcb->TxCbCount = 0;
        }

        // If the transmit unit is idle (very first transmit) then we must
        // setup the general pointer and issue a full CU-start
        if (m_TransmitIdle)
        {
            TRACE2(("CU is idle -- First TCB added to Active List\n"))

            m_ActiveChainList.InsertTail(SwTcb);

			m_pCard->StartTransmitUnit(SwTcb->TcbPhys);

            m_TransmitIdle = FALSE;
            m_ResumeWait = TRUE;
        }

        // If the command unit has already been started, then append this
        // TCB onto the end of the transmit chain, and issue a CU-Resume.
        else
        {
            TRACE2(("adding TCB to Active chain\n"))

            m_ActiveChainList.InsertTail(SwTcb);

            // Clear the suspend bit on the previous packet.
            SwTcb->PreviousTcb->TxCbHeader.CbCommand &= ~CB_S_BIT;

			m_pCard->ResumeCommandUnit();
        }


        // return NDIS_STATUS_PENDING and then later make a "SendComplete" call
        // to return the packet the protocol stack.
        Status = NDIS_STATUS_PENDING;
#if DBG
        m_txsent++;
#endif
    }

    // If PrepareForTransmit didn't succeed, then put the TCB back on the free
    // list, and return the proper error code
    else
    {
        if ((!SwTcb->PacketLength) || (SwTcb->PacketLength > MAXIMUM_ETHERNET_PACKET_SIZE))
            Status = NDIS_STATUS_INVALID_PACKET;

        else
            Status = NDIS_STATUS_RESOURCES;

        // If prepare failed, then put the TCB back on queue because
        // we don't have an available coalesce buffer
        m_TxCBList.InsertHead(SwTcb);
    }

    return (Status);
}


//-----------------------------------------------------------------------------
// Procedure:   PrepareForTransmit
//
// Description: This routine will Prepare a software TCB, and a set
//              of linked TBDs, for the packet that is passed in.  When this
//              routine returns, this packet will be ready to send through the
//              adapter, and onto the medium.
//
// Arguments:
//      Packet - A KNdisPacket that is to be transmitted.
//      SwTcb - Pointer to a software structure that represents a hardware TCB.
//
// Returns:
//      TRUE If we were able to acquire the necessary TBD's or Coalesce buffer
//           for the packet in we are attempting to prepare for transmission.
//      FALSE If we needed a coalesce buffer, and we didn't have any available.
//-----------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -