📄 send.c
字号:
/****************************************************************************
** 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 + -