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

📄 e100bexadap.cpp

📁 nmE100bex网卡驱动程序
💻 CPP
📖 第 1 页 / 共 5 页
字号:
BOOLEAN E100bexAdapter::PrepareForTransmit(KNdisPacket Packet, PD100SwTcb SwTcb)
{
    UINT                        BytesCopied;
    PCOALESCE                   Coalesce;
    PTBD_STRUC                  LastTbd = (PTBD_STRUC) 0;
    PNDIS_PHYSICAL_ADDRESS_UNIT p;
    UINT                        ArrayIndex = 0;

    TRACE3(("Preparing to transmit SwTcb %08x Packet %08x\n", SwTcb, Packet))

    ASSERT(SwTcb);

    // Assign the packet
    SwTcb->Packet = Packet;

    // Init some variables in the SwTcb
    SwTcb->MapsUsed = 0;
    SwTcb->NumPhysDesc = 0;
    SwTcb->TbdsUsed = 0;
    SwTcb->Coalesce = (PCOALESCE) 0;
	SwTcb->CoalesceBufferLen = 0;

    // Get a virtual buffer count and packet length.
	Packet.Query(
		&SwTcb->NumPhysDesc,
		&SwTcb->BufferCount,
		&SwTcb->FirstBuffer,
		&SwTcb->PacketLength);

    ASSERT(SwTcb->FirstBuffer);
    ASSERT(SwTcb->BufferCount);
    ASSERT(SwTcb->NumPhysDesc);
    ASSERT(SwTcb->PacketLength);
    ASSERT(SwTcb->PacketLength <= 1514);
    ASSERT(SwTcb->BufferCount <= 512);
    ASSERT(SwTcb->NumPhysDesc <= 512);

    // if the packet is not a valid length, then error out
    if ((!SwTcb->PacketLength) || (SwTcb->PacketLength > MAXIMUM_ETHERNET_PACKET_SIZE))
        return FALSE;

    // start with the first buffer
    KNdisBuffer CurrBuff(SwTcb->FirstBuffer);

#if DBG
    SwTcb->BufferCountCheck = 0;
    SwTcb->NumPhysDescCheck = SwTcb->NumPhysDesc;
#endif

    // If the packet is less than minimum size, then we'll just copy the packet
    // into the data portion of the TCB.  This means that we won't be acquiring
    // any TBD's.  We also won't need to get a coalesce buffer.
    if (SwTcb->PacketLength <= MINIMUM_ETHERNET_PACKET_SIZE)
    {
        TRACE2(("short packet\n"))
        CurrBuff = NULL;
    }

    // If there are too many physical mappings, try to get a coalesce buffer.
    // We do this because its actually faster for us to copy many fragments
    // into a big buffer and give that big buffer to the adapter, than to have
    // the hardware fetch numerous small fragments (this often leads to
    // underruns). The NDIS tester often asks us to send packets that
    // have more than 30 physical components. This method also saves TBD resources.

    else if (SwTcb->NumPhysDesc > m_NumTbdPerTcb)
    {
        // Debug Code
        ASSERT(!SwTcb->Coalesce);
        TRACE2(("Failed-> Physical descriptors %d > num Tbd per Tcb %d\n",
            SwTcb->NumPhysDesc, m_NumTbdPerTcb));

        // Try to get the coalesce buffer
        if (!AcquireCoalesceBuffer(SwTcb))
            return (FALSE);
        CurrBuff = NULL;
    }

    //  Clear NumPhysDesc.
    SwTcb->NumPhysDesc = 0;

    // If we are not coalescing, and the frame is not short, then for each
    // virtual buffer, get the physical components.  We'll need these physical
    // attributes so that we can instruct the adapter to copy the fragments
    // across the bus and into the adapter's internal FIFO.
    for (UINT i = 0; CurrBuff.IsValid(); i++)
    {
        UINT    ArraySize = 0;

        // If the mapping is successful, and there are not too many, then this
        // is where they go.
        PNDIS_PHYSICAL_ADDRESS_UNIT pUnit = &SwTcb->PhysDesc[SwTcb->NumPhysDesc];

		// Decompose the virtual buffer into one or more physical buffers.
        NdisMStartBufferPhysicalMapping(*this,
            CurrBuff,
            m_NextFreeMapReg,
            TRUE,
            m_pUnits,
            &ArraySize);

#if DBG
        if (ArraySize == 0)
        {
            ASSERT(CurrBuff);
        }
#endif

        // Adjust free map register variables.  Since map registers are such
        // a precious system resource we dynamically use them when necessary,
        // rather than allocate so many map registers per TCB.
        m_NextFreeMapReg++;

        // check for wrap condition
        if (m_NextFreeMapReg == m_NumMapRegisters)
            m_NextFreeMapReg = 0;

        // Debug code
        TRACE3(("Buffer %d ArraySize %d\n", i, ArraySize))

        // Mark the number of valid buffer mappings and copy
        // the new mappings into the transmit descriptor.
        SwTcb->MapsUsed++;
        NdisMoveMemory((PVOID) pUnit,
            (PVOID) m_pUnits,
            ArraySize * sizeof(NDIS_PHYSICAL_ADDRESS_UNIT));

        SwTcb->NumPhysDesc += ArraySize;

        // Flush the current buffer because it could be cached
		CurrBuff.Flush();

        // point to the next buffer
        CurrBuff = CurrBuff.GetNext();

#if DBG
        SwTcb->BufferCountCheck++;
        ASSERT(SwTcb->BufferCountCheck <= SwTcb->BufferCount);
#endif

    }

    // ------------------------------- NOTE: ----------------------------------
    // At this point, we should have either locked down each physical fragment
    // through the use of map registers, or we should have a coalesce buffer,
    // or we should have a short packet that we'll copy into the TCB data area.

#if DBG
    // Check to make sure that our buffer count was valid
    if (SwTcb->MapsUsed)
    {
        ASSERT(SwTcb->BufferCountCheck == SwTcb->BufferCount);
    }
#endif

    // Check for coalesce buffer
    if (SwTcb->Coalesce)
    {
        ASSERT(SwTcb->CoalesceBufferLen);
        ASSERT(!SwTcb->NumPhysDesc);
        ASSERT(!SwTcb->MapsUsed);

        Coalesce = SwTcb->Coalesce;
        ASSERT(Coalesce->OwningTcb == (PVOID) SwTcb);

        // Copy the packet into the coalesce buffer
        ASSERT(SwTcb->PacketLength <= MAXIMUM_ETHERNET_PACKET_SIZE);

		// Copy all of the packet data to our coalesce buffer
        CopyFromPacketToBuffer(
            SwTcb->Packet,
            SwTcb->PacketLength,
            (PCHAR) Coalesce->CoalesceBufferPtr,
            SwTcb->FirstBuffer,
            &BytesCopied);

        ASSERT(BytesCopied == SwTcb->PacketLength);

        SwTcb->TbdsUsed = 1;
    }

    // Check if we a doing a fragmented send with TBDs
    else if (SwTcb->NumPhysDesc)
    {
        SwTcb->TbdsUsed = SwTcb->NumPhysDesc;
        ASSERT(!SwTcb->CoalesceBufferLen);
        ASSERT(SwTcb->MapsUsed);
    }

    // check if we are using the TCB's data area with no TBDs.  This should
    // only happen on frames that are <= the minimum ethernet length
    else if ((!SwTcb->NumPhysDesc) && (!SwTcb->Coalesce))
    {
        ASSERT(!SwTcb->CoalesceBufferLen);
        ASSERT(!SwTcb->NumPhysDesc);
        ASSERT(!SwTcb->MapsUsed);

        ASSERT(SwTcb->PacketLength <= MINIMUM_ETHERNET_PACKET_SIZE);

        // Copy the packet into the immediate data portion of the TCB.
        CopyFromPacketToBuffer(
            SwTcb->Packet,
            SwTcb->PacketLength,
            (PCHAR) &SwTcb->Tcb->TxCbData,
            SwTcb->FirstBuffer,
            &BytesCopied);

        ASSERT(BytesCopied == SwTcb->PacketLength);
    }

    // ------------------------------- NOTE: ----------------------------------
    // At this point, any copying of of data into a coalesce buffer or into the
    // the TCB itself should be complete.  Now the last thing left to do in
    // this routine is to setup the TBD array if TBDs are being used for this
    // particular transmit frame.

    for (i = 0; i < SwTcb->TbdsUsed; i++)
    {
        PTBD_STRUC  Tbd;

        // Setup pointer to the particular TBD
        Tbd = SwTcb->FirstTbd + i;
        TRACE3(("Setting TBD num %d at virtual addr %x\n", i, Tbd))

        // Assign the physical address of the transmit buffer, and the
        // TBD count to the TCB.
        if (SwTcb->Coalesce)
        {
            Tbd->TbdBufferAddress = Coalesce->CoalesceBufferPhys;
            Tbd->TbdCount = (ULONG) SwTcb->CoalesceBufferLen;
        }
        else
        {
            p = &SwTcb->PhysDesc[ArrayIndex];
            Tbd->TbdBufferAddress = NdisGetPhysicalAddressLow(p->PhysicalAddress);
            Tbd->TbdCount = (ULONG) p->Length;

            ASSERT(p->Length <= 0x00003fff);
            TRACE3(("Buff %d len %d phys %08x\n", ArrayIndex, p->Length, Tbd->TbdBufferAddress))

        }
        ArrayIndex++;
    }

    return (TRUE);
}


//-----------------------------------------------------------------------------
// Procedure:   E100bexAdapter::AcquireCoalesceBuffer
//
// Description: This routine will attempt to acquire a coalesce buffer, if
//              there were too many physical vectors for a single packet.
//              The coalesce buffer will allow us to double buffer using a
//              only a single destination buffer.
//
// Arguments:
//      SwTcb - Pointer to a software structure that represents a hardware TCB.
//
// Returns:
//      TRUE If we were able to acquire the necessary Coalesce buffer.
//      FALSE If we were not able to get a coalesce buffer.
//-----------------------------------------------------------------------------
BOOLEAN E100bexAdapter::AcquireCoalesceBuffer(PD100SwTcb SwTcb)
{

    // Debug code.
    ASSERT(SwTcb);
    ASSERT(!SwTcb->Coalesce);
    ASSERT(!SwTcb->CoalesceBufferLen);
    //    ASSERT(!SwTcb->MapsUsed);

    // Check preconditions for use. Return FALSE if there are none
    // available.
    if (m_CoalesceBufferList.IsEmpty())
    {
        TRACE2(("No free coalesce buffers!!!\n"))
        return (FALSE);
    }

    // Allocate the coalesce buffer from the list. The SwTcb will now
    // own it until it's returned to the list.

    SwTcb->Coalesce = m_CoalesceBufferList.RemoveHead();

    SwTcb->Coalesce->OwningTcb = (PVOID) SwTcb;
    SwTcb->CoalesceBufferLen = SwTcb->PacketLength;

    TRACE2(("Acquired CoalesceBuffer %08x \n", SwTcb->Coalesce))
    return (TRUE);
}


VOID E100bexAdapter::CopyFromPacketToBuffer(
	KNdisPacket Packet,
	UINT BytesToCopy,
	PCHAR DestBuffer,
	KNdisBuffer FirstBuffer,
	PUINT BytesCopied)

{
    PNDIS_BUFFER    CurrentBuffer;
    PVOID           VirtualAddress;
    UINT            CurrentLength;
    UINT            AmountToMove;

    *BytesCopied = 0;
    if (!BytesToCopy)
        return;

    CurrentBuffer = FirstBuffer;

    NdisQueryBuffer(
        CurrentBuffer,
        &VirtualAddress,
        &CurrentLength);

    while (BytesToCopy)
    {
        while (!CurrentLength)
        {
            NdisGetNextBuffer(
                CurrentBuffer,
                &CurrentBuffer);

            // If we've reached the end of the packet.  We return with what
            // we've done so far (which must be shorter than requested).
            if (!CurrentBuffer)
                return;

            NdisQueryBuffer(
                CurrentBuffer,
                &VirtualAddress,
                &CurrentLength);
        }


        // Compute how much data to move from this fragment
        if (CurrentLength > BytesToCopy)
            AmountToMove = BytesToCopy;
        else
            AmountToMove = CurrentLength;

        // Copy the data.
        NdisMoveMemory(DestBuffer, VirtualAddress, AmountToMove);

        // Update destination pointer
        DestBuffer = (PCHAR) DestBuffer + AmountToMove;

        // Update counters
        *BytesCopied +=AmountToMove;
        BytesToCopy -=AmountToMove;
        CurrentLength = 0;
    }
}


////////////////////////////////////////////////////////////////////
// E100bexAdapter::ReturnPacket
//
// This method is called when NDIS returns a packet previuosly
// indicated by IndicateReceive() back to the miniport
//
// Parameters:
//		Packet 
//			Points to a packet descriptor specifying the packet 
// IRQL: 
//		DISPATCH_LEVEL
// Return Mode:
//		n/a
// NOTE:
//		The packet returns to the "free list" in the Rx area. 
//		Reclaim() does the necessary reset of the chained buffer
//		and OOB data if any.
VOID E100bexAdapter::ReturnPacket(IN PNDIS_PACKET Packet)
{
	TRACE("E100bexAdapter::ReturnPacket() Entered Packet=%X\n", Packet);

	// Reclaim the packet back into our receive area
	// Note: Can't hold spin lock while calling this method
	m_pRxArea->Reclaim(Packet);
}


////////////////////////////////////////////////////////////////////
// E100bexAdapter::CheckForHang
//		Optional function that reports the state of the NIC or monitors
//		 the responsiveness of an underlying device driver.
// Parameters:
//		none
// IRQL: 
//		IRQL DISPATCH_LEVEL
// Return Mode:
//		Synchronous
// NOTE:
//		By default, the NDIS library calls MiniportCheckForHang 
//		approximately every two seconds. If MiniportCheckForHang returns
//		TRUE, NDIS then calls the driver's MiniportReset function. 
BOOLEAN E100bexAdapter::CheckForHang(void)

⌨️ 快捷键说明

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