mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
802 lines
21 KiB
802 lines
21 KiB
//**********************************************************************
|
|
//**********************************************************************
|
|
//
|
|
// File Name: TRANSMIT.C
|
|
//
|
|
// Program Name: NetFlex NDIS 3.0 Miniport Driver
|
|
//
|
|
// Companion Files: None
|
|
//
|
|
// Function: This module contains the NetFlex Miniport Driver
|
|
// interface routines called by the Wrapper and the
|
|
// configuration manager.
|
|
//
|
|
// (c) Compaq Computer Corporation, 1992,1993,1994
|
|
//
|
|
// This file is licensed by Compaq Computer Corporation to Microsoft
|
|
// Corporation pursuant to the letter of August 20, 1992 from
|
|
// Gary Stimac to Mark Baber.
|
|
//
|
|
// History:
|
|
//
|
|
// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
|
|
//
|
|
//**********************************************************************
|
|
//**********************************************************************
|
|
|
|
//-------------------------------------
|
|
// Include all general companion files
|
|
//-------------------------------------
|
|
|
|
#include <ndis.h>
|
|
#include "tmsstrct.h"
|
|
#include "macstrct.h"
|
|
#include "adapter.h"
|
|
#include "protos.h"
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexProcessXmit
|
|
//
|
|
// Description: This routine looks through the tranmit lists
|
|
// and calls the send complete routines of the
|
|
// bindings whose sends have completed.
|
|
//
|
|
// Input: acb - Pointer to the Adapter's acb
|
|
//
|
|
// Output: None
|
|
//
|
|
// Calls: NetFlexDequeue_TwoPtrQ,
|
|
// NetFlexEnqueue_TwoPtrQ_Tail
|
|
//
|
|
// Called_By: NetFlexDPR
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
VOID
|
|
FASTCALL
|
|
NetFlexProcessXmit(
|
|
PACB acb
|
|
)
|
|
{
|
|
PXMIT xmitptr;
|
|
UINT curmap;
|
|
PNDIS_PACKET packet;
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
PNDIS_BUFFER SourceBuffer;
|
|
ULONG XmitedOk = 0;
|
|
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisAcquireSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
xmitptr = acb->acb_xmit_ahead;
|
|
|
|
if ((xmitptr == NULL) ||
|
|
!(xmitptr->XMIT_CSTAT & XCSTAT_COMPLETE))
|
|
{
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisReleaseSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Increment the interrupt count.
|
|
//
|
|
acb->acb_int_count++;
|
|
|
|
//
|
|
// For each completed frame issue a NdisMSendComplete.
|
|
// Before completing the send, release the mapping of
|
|
// the phyical buffers if we are using the protocol's buffers.
|
|
//
|
|
while (xmitptr->XMIT_CSTAT & XCSTAT_COMPLETE)
|
|
{
|
|
XmitedOk++;
|
|
|
|
//
|
|
// Check the status of the transmit and update the
|
|
// counter accordingly.
|
|
//
|
|
if (xmitptr->XMIT_CSTAT & XCSTAT_ERROR)
|
|
{
|
|
// Transmit error
|
|
//
|
|
DebugPrint(1,("NF(%d): Xmit Error CSTAT = 0x%x\n",acb->anum,xmitptr->XMIT_CSTAT));
|
|
acb->acb_gen_objs.frames_xmitd_err++;
|
|
XmitedOk--;
|
|
status = NDIS_STATUS_FAILURE;
|
|
}
|
|
else if (( xmitptr->XMIT_CSTAT & 0xff00) &&
|
|
((xmitptr->XMIT_CSTAT & 0xff00) != 0xcc00))
|
|
{
|
|
// FS indicates something happened
|
|
//
|
|
DebugPrint(1,("NF(%d): Xmit: FS = 0x%x\n",acb->anum,xmitptr->XMIT_CSTAT));
|
|
status = ((xmitptr->XMIT_CSTAT & XCSTAT_GOODFS) != XCSTAT_GOODFS)
|
|
? NDIS_STATUS_NOT_RECOGNIZED : NDIS_STATUS_NOT_COPIED;
|
|
}
|
|
|
|
//
|
|
// Get the info we need from the sof.
|
|
//
|
|
curmap = xmitptr->XMIT_MapReg;
|
|
packet = xmitptr->XMIT_Packet;
|
|
|
|
//
|
|
// Clean up the transmit lists and the transmit queues.
|
|
//
|
|
xmitptr->XMIT_CSTAT = 0;
|
|
xmitptr->XMIT_Packet = NULL;
|
|
|
|
if (xmitptr->XMIT_OurBufferPtr == NULL)
|
|
{
|
|
// Normal Xmit Packet
|
|
//
|
|
NdisQueryPacket(
|
|
packet,
|
|
NULL,
|
|
NULL,
|
|
(PNDIS_BUFFER *)&SourceBuffer,
|
|
NULL);
|
|
while (SourceBuffer)
|
|
{
|
|
NdisMCompleteBufferPhysicalMapping(
|
|
acb->acb_handle,
|
|
(PNDIS_BUFFER)SourceBuffer,
|
|
curmap);
|
|
curmap++;
|
|
if (curmap == acb->acb_maxmaps)
|
|
{
|
|
curmap = 0;
|
|
}
|
|
|
|
NdisGetNextBuffer(SourceBuffer, &SourceBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We've used one of our adapter buffers, so put the adapter
|
|
// buffer back on the free list.
|
|
//
|
|
if (xmitptr->XMIT_OurBufferPtr->BufferSize != acb->acb_smallbufsz)
|
|
{
|
|
xmitptr->XMIT_OurBufferPtr->Next = acb->OurBuffersListHead;
|
|
acb->OurBuffersListHead = xmitptr->XMIT_OurBufferPtr;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// small buffer
|
|
//
|
|
xmitptr->XMIT_OurBufferPtr->Next = acb->SmallBuffersListHead;
|
|
acb->SmallBuffersListHead = xmitptr->XMIT_OurBufferPtr;
|
|
}
|
|
xmitptr->XMIT_OurBufferPtr = NULL;
|
|
}
|
|
|
|
//
|
|
// Point to next xmit
|
|
//
|
|
if (xmitptr == acb->acb_xmit_atail)
|
|
{
|
|
// Set the list to null, also have to
|
|
// the ahead pointer, since if we had run
|
|
// out of xmit buffers, the wrapper can call
|
|
// our sendhandler during the completion.
|
|
//
|
|
xmitptr = acb->acb_xmit_ahead = acb->acb_xmit_atail = NULL;
|
|
}
|
|
else
|
|
{
|
|
// Point to the next xmit list
|
|
//
|
|
xmitptr = xmitptr->XMIT_Next;
|
|
}
|
|
|
|
//
|
|
// Increase the number of available xmit lists
|
|
//
|
|
acb->acb_avail_xmit++;
|
|
|
|
//
|
|
// Complete the request
|
|
//
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisReleaseSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
if (packet != NULL)
|
|
{
|
|
NdisMSendComplete(acb->acb_handle, packet, status);
|
|
}
|
|
else
|
|
{
|
|
NdisMSendResourcesAvailable(acb->acb_handle);
|
|
}
|
|
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisAcquireSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
if (xmitptr == NULL)
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Update the head of the active lists if we ran into a non-completed
|
|
// list.
|
|
//
|
|
if (xmitptr)
|
|
{
|
|
acb->acb_xmit_ahead = xmitptr;
|
|
}
|
|
|
|
if (acb->acb_xmit_ahead)
|
|
{
|
|
//
|
|
// Issue a xmit valid adapter interrupt
|
|
//
|
|
NdisRawWritePortUshort(acb->SifIntPort, (USHORT) SIFINT_XMTVALID);
|
|
}
|
|
|
|
acb->acb_gen_objs.frames_xmitd_ok += XmitedOk;
|
|
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisReleaseSpinLock(&acb->XmitLock);
|
|
}
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexTransmitStatus
|
|
//
|
|
// Description: This routine detemined the action to take
|
|
// depending on the reason for the xmit interrupt
|
|
//
|
|
// Input: acb - Pointer to the Adapter's acb
|
|
//
|
|
// Output: None
|
|
//
|
|
// Calls: NdisRawWritePortUshort,
|
|
// NetFlexDequeue_TwoPtrQ,
|
|
// NetFlexSendNextSCB,
|
|
// NetFlexEnqueue_TwoPtrQ_Tail
|
|
//
|
|
// Called_By: NetFlexDPR
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
VOID
|
|
NetFlexTransmitStatus(
|
|
PACB acb
|
|
)
|
|
{
|
|
PXMIT xmitptr;
|
|
UINT curmap;
|
|
PNDIS_PACKET packet;
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
PNDIS_BUFFER SourceBuffer;
|
|
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisAcquireSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
if (acb->acb_xmit_ahead == NULL)
|
|
{
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisReleaseSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// We have received a list error. Determine the type of list error
|
|
// in order to tell the protocol what happened.
|
|
//
|
|
acb->acb_gen_objs.frames_xmitd_err++;
|
|
xmitptr = acb->acb_xmit_ahead;
|
|
|
|
DebugPrint(1,("NF(%d): xmitptr = %x, Cstat = %x\n",acb->anum,xmitptr,xmitptr->XMIT_CSTAT));
|
|
|
|
switch (acb->acb_ssb_virtptr->SSB_Status & 0xff00)
|
|
{
|
|
case XSTAT_FRAME_SIZE_ERROR:
|
|
case XSTAT_ILLEGAL_FRAME_FORMAT:
|
|
case XSTAT_ACCESS_PRIORITY_ERR:
|
|
DebugPrint(1,("NF(%d): Frame sz err, illegal format or access priority\n",acb->anum));
|
|
status = NDIS_STATUS_INVALID_PACKET;
|
|
break;
|
|
case XSTAT_XMIT_THRESHOLD:
|
|
case XSTAT_ODD_ADDRESS:
|
|
case XSTAT_FRAME_ERROR:
|
|
case XSTAT_UNENABLE_MAC_FRAME:
|
|
acb->acb_gen_objs.frames_xmitd_err++;
|
|
DebugPrint(1,("NF(%d): threshold, frame error or unenable\n",acb->anum));
|
|
status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
default:
|
|
acb->acb_gen_objs.frames_xmitd_err++;
|
|
DebugPrint(1,("NF(%d): Unknown error\n",acb->anum));
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the info we need from the sof.
|
|
//
|
|
curmap = xmitptr->XMIT_MapReg;
|
|
packet = xmitptr->XMIT_Packet;
|
|
|
|
//
|
|
// Clean up the transmit lists and the transmit queues.
|
|
//
|
|
xmitptr->XMIT_CSTAT = 0;
|
|
xmitptr->XMIT_Packet = NULL;
|
|
|
|
//
|
|
// Take the error list off the active list. Set up the waiting list
|
|
// to either point to the next list of the active queue or the next
|
|
// available list from transmission.
|
|
//
|
|
if (acb->acb_state == AS_OPENED)
|
|
{
|
|
if (acb->acb_xmit_atail == xmitptr)
|
|
{
|
|
acb->acb_xmit_whead = acb->acb_xmit_wtail = xmitptr->XMIT_Next;
|
|
}
|
|
else
|
|
{
|
|
acb->acb_xmit_whead = xmitptr->XMIT_Next;
|
|
acb->acb_xmit_wtail = acb->acb_xmit_atail;
|
|
}
|
|
acb->acb_xmit_atail = acb->acb_xmit_ahead = NULL;
|
|
|
|
//
|
|
// Send off the transmit command to the adapter since the transmit
|
|
// command completes when a list error is encountered.
|
|
//
|
|
if (acb->acb_scb_virtptr->SCB_Cmd == 0)
|
|
{
|
|
NetFlexSendNextSCB(acb);
|
|
}
|
|
else if (!acb->acb_scbclearout)
|
|
{
|
|
acb->acb_scbclearout = TRUE;
|
|
NdisRawWritePortUshort(acb->SifIntPort, (USHORT) SIFINT_SCBREQST);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
acb->acb_xmit_atail = acb->acb_xmit_ahead = NULL;
|
|
}
|
|
acb->acb_avail_xmit++;
|
|
|
|
if (xmitptr->XMIT_OurBufferPtr != NULL)
|
|
{
|
|
// We've used one of our adapter buffers, so put the adapter
|
|
// buffer back on the free list.
|
|
//
|
|
if (xmitptr->XMIT_OurBufferPtr->BufferSize != acb->acb_smallbufsz)
|
|
{
|
|
xmitptr->XMIT_OurBufferPtr->Next = acb->OurBuffersListHead;
|
|
acb->OurBuffersListHead = xmitptr->XMIT_OurBufferPtr;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// small buffer
|
|
//
|
|
xmitptr->XMIT_OurBufferPtr->Next = acb->SmallBuffersListHead;
|
|
acb->SmallBuffersListHead = xmitptr->XMIT_OurBufferPtr;
|
|
}
|
|
xmitptr->XMIT_OurBufferPtr = NULL;
|
|
}
|
|
else
|
|
{
|
|
NdisQueryPacket(
|
|
packet,
|
|
NULL,
|
|
NULL,
|
|
(PNDIS_BUFFER *)&SourceBuffer,
|
|
NULL);
|
|
|
|
while (SourceBuffer)
|
|
{
|
|
NdisMCompleteBufferPhysicalMapping(
|
|
acb->acb_handle,
|
|
(PNDIS_BUFFER)SourceBuffer,
|
|
curmap);
|
|
|
|
curmap++;
|
|
if (curmap == acb->acb_maxmaps)
|
|
{
|
|
curmap = 0;
|
|
}
|
|
|
|
NdisGetNextBuffer(SourceBuffer, &SourceBuffer);
|
|
}
|
|
}
|
|
//
|
|
// Complete the request
|
|
//
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisReleaseSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
if (packet)
|
|
{
|
|
NdisMSendComplete(acb->acb_handle, packet, status);
|
|
}
|
|
else
|
|
{
|
|
NdisMSendResourcesAvailable(acb->acb_handle);
|
|
}
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexSend
|
|
//
|
|
// Description: This routine places the given packet on the
|
|
// adapter's transmit list.
|
|
//
|
|
// Input:
|
|
// MiniportAdapterContext - The context value
|
|
// returned by the Miniport when the adapter was
|
|
// initialized. In reality, it is a pointer to ACB
|
|
//
|
|
// Packet - A pointer to a descriptor for the packet
|
|
// that is to be transmitted.
|
|
//
|
|
// Flags - The send options to use.
|
|
//
|
|
// Output: Returns NDIS_STATUS_SUCCESS for a successful
|
|
// completion. Otherwise, an error code is
|
|
// returned.
|
|
//
|
|
// Calls: NdisQueryPacket,NdisQueryBuffer,NdisMoveMemory
|
|
// NdisGetNextBuffer,NdisGetBufferPhysicalAddress
|
|
// NdisWritePortUshort,NetFlexEnqueue_TwoPtrQ_Tail
|
|
// NetFlexDequeue_OnePtrQ_Head,SWAPL,SWAPS
|
|
//
|
|
// Called_By: Wrapper
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
NDIS_STATUS NetFlexSend(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PNDIS_PACKET Packet,
|
|
IN UINT Flags
|
|
)
|
|
{
|
|
PACB acb = (PACB) MiniportAdapterContext;
|
|
PXMIT xmitptr;
|
|
|
|
UINT PhysicalBufferCount, BufferCount;
|
|
UINT TotalPacketLength;
|
|
PNDIS_BUFFER SourceBuffer;
|
|
PUSHORT avail_xmits;
|
|
|
|
|
|
UINT curmap,j,i;
|
|
UINT arraysize;
|
|
ULONG physbufptr;
|
|
NDIS_STATUS status = NDIS_STATUS_PENDING;
|
|
|
|
NDIS_PHYSICAL_ADDRESS_UNIT physaddrarray[MAX_BUFS_PER_XMIT];
|
|
|
|
//
|
|
// if we are in full duplex mode then acquire the xmit spin lock.
|
|
//
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisAcquireSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
avail_xmits = &acb->acb_avail_xmit;
|
|
|
|
//
|
|
// Do we have at least one available xmit list?
|
|
//
|
|
if (*avail_xmits)
|
|
{
|
|
// Yes, See if we can process this send request
|
|
//
|
|
NdisQueryPacket(
|
|
Packet,
|
|
(PUINT)&PhysicalBufferCount,
|
|
(PUINT)&BufferCount,
|
|
(PNDIS_BUFFER *)(&SourceBuffer),
|
|
(PUINT)(&TotalPacketLength));
|
|
|
|
//
|
|
// Point to the head of the xmit list
|
|
//
|
|
xmitptr = acb->acb_xmit_head;
|
|
|
|
//
|
|
// Do we need to use our own buffer?
|
|
//
|
|
if ((PhysicalBufferCount <= MAX_BUFS_PER_XMIT) &&
|
|
(TotalPacketLength > acb->acb_smallbufsz ||
|
|
acb->SmallBuffersListHead == NULL))
|
|
{
|
|
// Clean the Data fields
|
|
//
|
|
NdisZeroMemory(xmitptr->XMIT_Data, SIZE_XMIT_DATA);
|
|
|
|
// With the new fpa mac code we can only use 1
|
|
// xmit list per xmit. Point the head pointer to the next
|
|
// available list. At this point we are guaranteed less than
|
|
// MAX_BUFS_PER_XMIT buffers per xmit = 1 xmit list.
|
|
//
|
|
|
|
curmap = acb->acb_curmap;
|
|
acb->acb_curmap += BufferCount;
|
|
if (acb->acb_curmap >= acb->acb_maxmaps)
|
|
{
|
|
acb->acb_curmap -= acb->acb_maxmaps;
|
|
}
|
|
|
|
xmitptr->XMIT_MapReg = curmap;
|
|
|
|
i=0;
|
|
while (SourceBuffer != NULL)
|
|
{
|
|
NdisMStartBufferPhysicalMapping(
|
|
acb->acb_handle,
|
|
SourceBuffer,
|
|
curmap,
|
|
TRUE,
|
|
physaddrarray,
|
|
&arraysize);
|
|
|
|
curmap++;
|
|
if (curmap == acb->acb_maxmaps)
|
|
{
|
|
curmap = 0;
|
|
}
|
|
|
|
for (j=0; j < arraysize; j++)
|
|
{
|
|
physbufptr = SWAPL(NdisGetPhysicalAddressLow(physaddrarray[j].PhysicalAddress));
|
|
xmitptr->XMIT_Data[i].DataCount = (USHORT)(SWAPS(physaddrarray[j].Length)) | DATA_NOT_LAST;
|
|
xmitptr->XMIT_Data[i].DataHi = (USHORT)physbufptr;
|
|
xmitptr->XMIT_Data[i].DataLo = (USHORT)(physbufptr >> 16);
|
|
PhysicalBufferCount--;
|
|
i++;
|
|
}
|
|
NdisFlushBuffer(SourceBuffer, TRUE);
|
|
NdisGetNextBuffer(SourceBuffer, &SourceBuffer);
|
|
}
|
|
|
|
xmitptr->XMIT_Data[i-1].DataCount &= DATA_LAST;
|
|
xmitptr->XMIT_Fsize = (SHORT)(SWAPS((USHORT)TotalPacketLength));
|
|
xmitptr->XMIT_Packet = Packet;
|
|
xmitptr->XMIT_OurBufferPtr = NULL;
|
|
}
|
|
else
|
|
{
|
|
// We need to constrain the packet into our own buffer
|
|
//
|
|
if (((PhysicalBufferCount > MAX_BUFS_PER_XMIT) &&
|
|
(acb->OurBuffersListHead != NULL)) ||
|
|
((acb->SmallBuffersListHead != NULL) &&
|
|
(TotalPacketLength <= acb->acb_smallbufsz)))
|
|
{
|
|
status = NetFlexConstrainPacket(
|
|
acb,
|
|
xmitptr,
|
|
Packet,
|
|
PhysicalBufferCount,
|
|
SourceBuffer,
|
|
TotalPacketLength);
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisReleaseSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we don't have any buffers at this time...
|
|
// See if we can process any transmits, freeing up any that are completed...
|
|
//
|
|
DebugPrint(1,("NF(%d): No empty Xmit Buffers to transfer into\n",acb->anum));
|
|
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisReleaseSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
return(NDIS_STATUS_RESOURCES);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update all the pointers...
|
|
//
|
|
acb->acb_xmit_head = xmitptr->XMIT_Next;
|
|
|
|
xmitptr->XMIT_Timeout = 0;
|
|
|
|
#ifdef XMIT_INTS
|
|
|
|
//
|
|
// Leave the original FInt setting
|
|
//
|
|
xmitptr->XMIT_CSTAT =
|
|
((xmitptr->XMIT_Number % acb->XmitIntRatio) == 0) ? XCSTAT_GO_INT : XCSTAT_GO;
|
|
#else
|
|
xmitptr->XMIT_CSTAT = XCSTAT_GO;
|
|
#endif
|
|
|
|
//
|
|
// Update Tail Pointer
|
|
//
|
|
acb->acb_xmit_atail = xmitptr;
|
|
|
|
//
|
|
// Update the head if this is the first one...
|
|
//
|
|
if (acb->acb_xmit_ahead == NULL)
|
|
{
|
|
acb->acb_xmit_ahead = xmitptr;
|
|
}
|
|
|
|
//
|
|
// If the transmitter had stalled because it ran out of
|
|
// valid lists, issue an adapter int to pickup this new valid one.
|
|
//
|
|
NdisRawWritePortUshort(acb->SifIntPort, (USHORT) SIFINT_XMTVALID);
|
|
|
|
//
|
|
// Indicate we've taken one of the ints
|
|
//
|
|
(*avail_xmits)--;
|
|
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisReleaseSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
// No, We don't have any transmits at this time...
|
|
//
|
|
DebugPrint(2,("NF(%d): Send, Out of Xmit Lists...\n",acb->anum));
|
|
|
|
if (acb->FullDuplexEnabled)
|
|
{
|
|
NdisReleaseSpinLock(&acb->XmitLock);
|
|
}
|
|
|
|
return(NDIS_STATUS_RESOURCES);
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexConstrainPacket
|
|
//
|
|
// Description: This routine combines the packet fragments
|
|
// into our own buffer for transmition.
|
|
//
|
|
// Called_By: NetFlexSend
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
NDIS_STATUS
|
|
NetFlexConstrainPacket(
|
|
PACB acb,
|
|
PXMIT xmitptr,
|
|
PNDIS_PACKET Packet,
|
|
UINT PhysicalBufferCount,
|
|
PNDIS_BUFFER SourceBuffer,
|
|
UINT TotalPacketLength
|
|
)
|
|
{
|
|
PVOID SourceData; // Points to the virtual address of the source buffers data.
|
|
UINT SourceLength; // Number of bytes of data in the source buffer.
|
|
PCHAR CurrentDestination; // Pointer to virtual address for the adapter buffer
|
|
UINT TotalDataMoved = 0;
|
|
ULONG AdapterPhysicalBufferPtr;
|
|
|
|
PBUFFER_DESCRIPTOR BufferDescriptor;
|
|
|
|
if (TotalPacketLength > acb->acb_smallbufsz)
|
|
{
|
|
BufferDescriptor = acb->OurBuffersListHead;
|
|
|
|
if (!BufferDescriptor)
|
|
{
|
|
return(NDIS_STATUS_RESOURCES);
|
|
}
|
|
|
|
acb->OurBuffersListHead = BufferDescriptor->Next;
|
|
BufferDescriptor->Next = NULL;
|
|
}
|
|
else
|
|
{
|
|
BufferDescriptor = acb->SmallBuffersListHead;
|
|
|
|
if (!BufferDescriptor)
|
|
{
|
|
return(NDIS_STATUS_RESOURCES);
|
|
}
|
|
|
|
acb->SmallBuffersListHead = BufferDescriptor->Next;
|
|
BufferDescriptor->Next = NULL;
|
|
}
|
|
|
|
//
|
|
// Clear out the data fields in the xmit list
|
|
//
|
|
NdisZeroMemory(xmitptr->XMIT_Data, SIZE_XMIT_DATA);
|
|
|
|
//
|
|
// Copy the packet's buffers into our buffer
|
|
//
|
|
CurrentDestination = BufferDescriptor->VirtualBuffer;
|
|
BufferDescriptor->DataLength = TotalPacketLength;
|
|
|
|
do
|
|
{
|
|
// Get Buffer info
|
|
//
|
|
NdisQueryBuffer(SourceBuffer, &SourceData, &SourceLength);
|
|
|
|
// Copy this buffer
|
|
//
|
|
NdisMoveMemory(CurrentDestination, SourceData, SourceLength);
|
|
|
|
//
|
|
// Update destination address
|
|
//
|
|
CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
|
|
|
|
//
|
|
// Update count of packet length.
|
|
//
|
|
TotalDataMoved += SourceLength;
|
|
|
|
//
|
|
// Get the next buffers information
|
|
//
|
|
NdisGetNextBuffer(SourceBuffer, &SourceBuffer);
|
|
|
|
} while (SourceBuffer != NULL);
|
|
|
|
|
|
NdisFlushBuffer(BufferDescriptor->FlushBuffer, TRUE);
|
|
|
|
AdapterPhysicalBufferPtr =
|
|
SWAPL(NdisGetPhysicalAddressLow(BufferDescriptor->PhysicalBuffer));
|
|
|
|
xmitptr->XMIT_OurBufferPtr = BufferDescriptor;
|
|
xmitptr->XMIT_Data[0].DataCount = (USHORT)(SWAPS((USHORT)TotalPacketLength)) & DATA_LAST;
|
|
xmitptr->XMIT_Data[0].DataHi = (USHORT) AdapterPhysicalBufferPtr;
|
|
xmitptr->XMIT_Data[0].DataLo = (USHORT)(AdapterPhysicalBufferPtr >> 16);
|
|
xmitptr->XMIT_Fsize = (SHORT)(SWAPS((USHORT)TotalPacketLength));
|
|
xmitptr->XMIT_Packet = NULL;
|
|
|
|
|
|
DebugPrint(2,("NF(%d): Using internal buffer\n",acb->anum));
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|