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

📄 send.c

📁 e100bex网卡驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
** COPYRIGHT (C) 1994-1997 INTEL CORPORATION                               **
** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON               **
** HTTP://WWW.INTEL.COM/                                                   **
** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND            **
** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER               **
****************************************************************************/

/****************************************************************************
Module Name:
    send.c

This driver runs on the following hardware:
    - 82557/82558 based PCI 10/100Mb ethernet adapters
    (aka Intel EtherExpress(TM) PRO Adapters)

Environment:
    Kernel Mode - Or whatever is the equivalent on WinNT

Abstract:
    This module contains the send routines and send interrupt handling code

Revision History
    - JCB 8/14/97 Example Driver Created
*****************************************************************************/

#include "precomp.h"
#pragma hdrstop
#pragma warning (disable: 4514 4706)

//-----------------------------------------------------------------------------
// Procedure: D100MultipleSend
//
// Description:This function takes an array from NDIS and puts as many as it can
//             in our list to be immediately transferred. Each packet has its
//             status set (NDIS_STATUS_RESOURCES, NDIS_STATUS_PENDED,
//             or NDIS_STATUS_SUCCESS) in the PacketArray individually.
//
//
// Arguments: MiniportAdapterContext (Adapter Structure pointer)
//            PacketArray - an array of pointers to NDIS_PACKET structs
//            PacketCount - number of packets in PacketArray
//
// Returns: nothing
//
//-----------------------------------------------------------------------------
VOID
D100MultipleSend(NDIS_HANDLE MiniportAdapterContext,
                 PPNDIS_PACKET PacketArray,
                 UINT NumberOfPackets)
{
    PD100_ADAPTER       Adapter;
    NDIS_STATUS         Status;
    UINT                PacketCount;

    DEBUGFUNC("D100MultipleSend");

    Adapter = PD100_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);

    NdisAcquireSpinLock(&Adapter->Lock);
    TRACE2(Adapter, ("\n"));
    DEBUGCHAR(Adapter,'"');

    // 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(PacketCount=0;PacketCount < NumberOfPackets; PacketCount++)
    {
        // check for a zero pointer
        ASSERT(PacketArray[PacketCount]);

        // begin stub
        // NDIS 5
        // for Task Offloading the driver could handle a
        // packet with a request to offload the checksum
        // by doing something like the following.
        // NOTE: this code could probably be put somewhere deeper
        // into the transmit code.
        /******************************************************************************
        {
        NDIS_PACKET_EXTENSION               PktExt;
        NDIS_TCP_IP_CHECKSUM_PACKET_INFO    ChksumPktInfo;

          PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);

            if (PktExt->NdisPacketInfo[ProtocolIdPacketInfo] == NDIS_PROTOCOL_ID_TCP_IP)
            {
                ChksumPktInfo.Value = (ULONG)PktExt->NdisPacketInfo[TcpIpChecksumPacketInfo];
                if (ChksumPktInfo.Transmit.NdisPacketChecksumV4)
                    {
                    //
                    // Perform  the appropriate checksumming operations on this packet
                    // as was set by the miniport with OID_GEN_TASK_OFFLOAD.
                    //
                    }
            }
        }
        ******************************************************************************/

        // NDIS 4
        // NOTE THIS CODE WILL NOT WORK, IT IS JUST FOR REFERENCE
        // before we send this packet, we might check for OOB
        // data that would indicate a high priority send
        // and we might use that data to call a different send
        // routine. It would be best to encapsulate the priority query
        // into a separate routine, but for example purposes lets leave it here.
        /******************************************************************************
        {
        MEDIA_SPECIFIC_INFORMATION MediaInfo;
        UINT InfoSize;

          NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(PacketArray[PacketCount],(PVOID) &MediaInfo, &InfoSize);

            if (InfoSize
            && (MediaInfo.ClassId == NdisClass802_3Priority) )
            {
                // note: this routine could possibly send a normal priority packet
                Status = SetupPrioritySend(Adapter,PacketArray[PacketCount]);
            }


        }
        ******************************************************************************/
        // end stub
        Status = SetupNextSend(Adapter, PacketArray[PacketCount]);

        if (Status == NDIS_STATUS_RESOURCES)
        {
            DEBUGCHAR(Adapter,'Q');

            // Queue This packet for the Deserialized Miniport
            Adapter->NumPacketsQueued++;
            EnqueuePacket(Adapter->FirstTxQueue, Adapter->LastTxQueue, PacketArray[PacketCount]);
            Status = NDIS_STATUS_PENDING;
        }

        NDIS_SET_PACKET_STATUS(PacketArray[PacketCount], Status);

    }

    NdisReleaseSpinLock(&Adapter->Lock);
    return;
}



//-----------------------------------------------------------------------------
// Procedure:   SetupNextSend
//
// Description: This routine is called by D100Send.  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:
//      Adapter - ptr to Adapter object instance
//      Packet - A pointer to a descriptor for the packet 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
SetupNextSend(PD100_ADAPTER Adapter,
              PNDIS_PACKET Packet)
{
    PD100SwTcb          SwTcb;
    PTXCB_STRUC         HwTcb;
    NDIS_STATUS         Status;

    DEBUGFUNC("SetupNextSend");
    TRACE2(Adapter, ("\n"));


    //    DEBUGCHAR(Adapter,'T');
    // Attempt to acquire a Software TCB for the packet
    SwTcb = (PD100SwTcb) QueuePopHead(&Adapter->TxCBList);

    if (!(SwTcb))
    {
        TRACE2(Adapter, ("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 (QueueEmpty(&Adapter->TxCBList))
    {
        TRACE2(Adapter,("Don't WRAP queue!!! Fail With Only 1 TCB left\n"));
        QueuePushHead(&Adapter->TxCBList, &SwTcb->Link);
        Status = NDIS_STATUS_RESOURCES;
        return(Status);
    }

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

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

        HwTcb = SwTcb->Tcb;
        HwTcb->TxCbHeader.CbStatus = 0;
        HwTcb->TxCbThreshold = (UCHAR) Adapter->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 (Adapter->TransmitIdle)
        {
            TRACE2(Adapter, ("CU is idle -- First TCB added to Active List\n"));


            QueuePutTail(&Adapter->ActiveChainList, &SwTcb->Link);

            // Wait for the SCB to clear before we set the general pointer
            WaitScb(Adapter);

            // Don't try to start the transmitter if the command unit is not
            // idle ((not idle) == (Cu-Suspended or Cu-Active)).
            if ((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_IDLE)
            {
                TRACESTR(Adapter, ("CU Not IDLE\n"));
                ASSERT(0);
                NdisStallExecution(25);
            }

            Adapter->CSRAddress->ScbGeneralPointer = SwTcb->TcbPhys;

            D100IssueScbCommand(Adapter, SCB_CUC_START, FALSE);

            Adapter->TransmitIdle = FALSE;
            Adapter->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(Adapter, ("adding TCB to Active chain\n"));

            QueuePutTail(&Adapter->ActiveChainList, &SwTcb->Link);

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

            // Issue a CU-Resume command to the device.  We only need to do a
            // WaitScb if the last command was NOT a RESUME.
            if (Adapter->ResumeWait)
            {
                if (!D100IssueScbCommand(Adapter, SCB_CUC_RESUME, TRUE))
                {
                    TRACESTR(Adapter, ("CU-resume failed\n"));
                }
            }
            else
                D100IssueScbCommand(Adapter, SCB_CUC_RESUME, FALSE);
        }


        // return NDIS_STATUS_PENDING and then later make a "SendComplete" call
        // to return the packet the protocol stack.
        Status = NDIS_STATUS_PENDING;
#if DBG
        Adapter->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
        QueuePushHead(&Adapter->TxCBList, &SwTcb->Link);
    }

    //    DEBUGCHAR(Adapter,'t');

    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

⌨️ 快捷键说明

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