293 lines
5.7 KiB
C
293 lines
5.7 KiB
C
/*++
|
||
|
||
Copyright (c) 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
send.c
|
||
|
||
Abstract:
|
||
|
||
Ndis 3.0 MAC driver for the 3Com Etherlink III
|
||
|
||
|
||
Author:
|
||
|
||
Brian Lieuallen (BrianLie) 12/14/92
|
||
|
||
|
||
Environment:
|
||
|
||
Kernel Mode Operating Systems : NT
|
||
|
||
Revision History:
|
||
|
||
Portions borrowed from ELNK3 driver by
|
||
Earle R. Horton (EarleH)
|
||
|
||
|
||
|
||
--*/
|
||
|
||
|
||
|
||
#include <ndis.h>
|
||
#include <efilter.h>
|
||
|
||
|
||
#include "debug.h"
|
||
|
||
|
||
#include "elnk3hrd.h"
|
||
#include "elnk3sft.h"
|
||
#include "elnk3.h"
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
NDIS_STATUS
|
||
Elnk3MacSend(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN PNDIS_PACKET Packet,
|
||
IN UINT Flags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
MacSend
|
||
|
||
|
||
Arguments:
|
||
See NDIS 3.0 spec
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
PELNK3_ADAPTER pAdapter = MacBindingHandle;
|
||
UINT PacketLength;
|
||
BOOLEAN Retry=FALSE;
|
||
ULONG FreeFifoBytes;
|
||
ULONG PadBuffer=0;
|
||
|
||
IF_SEND_LOUD(DbgPrint("MacSend called Packets\n");)
|
||
|
||
NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
|
||
|
||
//
|
||
// Here we check to make sure the packet meets some size constraints
|
||
//
|
||
|
||
if (PacketLength < 14 || PacketLength > 1514) {
|
||
|
||
IF_LOUD(DbgPrint("MovePacketToCard: Packet too long or too short\n");)
|
||
|
||
return NDIS_STATUS_FAILURE;
|
||
|
||
}
|
||
|
||
//
|
||
// See if there is enough room in the fifo to send it now.
|
||
//
|
||
FreeFifoBytes=ELNK3_READ_PORT_USHORT(pAdapter,PORT_TxFree);
|
||
|
||
if ((FreeFifoBytes) < ELNK3_ROUND_TO_DWORD(PacketLength)+4) {
|
||
//
|
||
// Nope, Ask for a transmit availible interrupt when there is
|
||
//
|
||
ELNK3_COMMAND(pAdapter, EC_SET_TX_AVAILIBLE, ELNK3_ROUND_TO_DWORD(PacketLength)+4);
|
||
|
||
return NDIS_STATUS_RESOURCES;
|
||
|
||
}
|
||
|
||
do {
|
||
|
||
|
||
UCHAR XmitStatus;
|
||
PNDIS_BUFFER CurBuffer;
|
||
PUCHAR BufferAddress;
|
||
UINT Len;
|
||
ULONG Pad;
|
||
PVOID Port=pAdapter->PortOffsets[PORT_TxFIFO];
|
||
|
||
|
||
|
||
NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL);
|
||
|
||
NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &Len);
|
||
|
||
|
||
//
|
||
// Write out the length and a pad word
|
||
//
|
||
|
||
NdisRawWritePortUlong(Port,(PacketLength & 0x7ff));
|
||
|
||
while (1) {
|
||
|
||
NdisRawWritePortBufferUlong(
|
||
(ULONG)Port,
|
||
(PULONG)BufferAddress,
|
||
Len >> 2
|
||
);
|
||
|
||
|
||
if ((Len & 3) != 0) {
|
||
|
||
NdisRawWritePortBufferUchar(
|
||
Port,
|
||
BufferAddress+(Len & 0xfffffffc),
|
||
(Len & 3)
|
||
);
|
||
|
||
}
|
||
|
||
|
||
NdisGetNextBuffer(CurBuffer, &CurBuffer);
|
||
|
||
if (CurBuffer==NULL) {
|
||
//
|
||
// done
|
||
//
|
||
break;
|
||
}
|
||
|
||
NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &Len);
|
||
|
||
}
|
||
|
||
Pad=(ELNK3_ROUND_TO_DWORD(PacketLength) - PacketLength);
|
||
|
||
if (Pad != 0) {
|
||
|
||
NdisRawWritePortBufferUchar(
|
||
(ULONG)Port,
|
||
(PUCHAR)&PadBuffer,
|
||
Pad
|
||
);
|
||
|
||
|
||
}
|
||
|
||
|
||
Retry=FALSE;
|
||
|
||
//
|
||
// Check the status, if it underan then it would be set now
|
||
//
|
||
ELNK3ReadAdapterUchar(pAdapter,PORT_TxStatus,&XmitStatus);
|
||
|
||
if ((XmitStatus & TX_STATUS_COMPLETE) && (XmitStatus & TX_STATUS_UNDERRUN)) {
|
||
//
|
||
// The transmitter under-ran. Restart it and try again
|
||
//
|
||
|
||
IF_LOG(0xaa,0xcc, PacketLength);
|
||
|
||
HandleXmtInterrupts(pAdapter);
|
||
|
||
Retry=TRUE;
|
||
|
||
}
|
||
|
||
|
||
} while (Retry);
|
||
|
||
//
|
||
// we sent something
|
||
//
|
||
NdisMSendResourcesAvailable(pAdapter->NdisAdapterHandle);
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
HandleXmtInterrupts(
|
||
PELNK3_ADAPTER pAdapter
|
||
)
|
||
{
|
||
UCHAR XmitStatus;
|
||
|
||
|
||
|
||
ELNK3ReadAdapterUchar(pAdapter,PORT_TxStatus,&XmitStatus);
|
||
|
||
IF_LOUD (DbgPrint("ELNK3: HandleXmitInts: Status=%02x\n",XmitStatus);)
|
||
|
||
if (XmitStatus != 0) {
|
||
//
|
||
// pop the tx status
|
||
//
|
||
ELNK3WriteAdapterUchar(pAdapter,PORT_TxStatus,0);
|
||
|
||
if ((XmitStatus & TX_STATUS_JABBER)
|
||
||
|
||
(XmitStatus & TX_STATUS_UNDERRUN)) {
|
||
//
|
||
// If it is one of these then it the xmiter needs to be reset
|
||
//
|
||
ELNK3_COMMAND(pAdapter,EC_TX_RESET,0);
|
||
ELNK3_WAIT_NOT_BUSY(pAdapter);
|
||
|
||
ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0);
|
||
|
||
//
|
||
// Could use a better message, But...
|
||
//
|
||
//
|
||
// Commented out so as not to alarm people with random events
|
||
// in the registry.
|
||
//
|
||
// NdisWriteErrorLogEntry(
|
||
// pAdapter->NdisAdapterHandle,
|
||
// NDIS_ERROR_CODE_TIMEOUT,
|
||
// 3,
|
||
// pAdapter->FramesXmitGood,
|
||
// pAdapter->TxStartThreshold,
|
||
// pAdapter->TxStartThresholdInc
|
||
// );
|
||
|
||
if ((XmitStatus & TX_STATUS_UNDERRUN)) {
|
||
//
|
||
// Underrun bump up the threshold
|
||
//
|
||
pAdapter->TxStartThreshold+=pAdapter->TxStartThresholdInc;
|
||
|
||
if (pAdapter->TxStartThreshold > 2040) {
|
||
|
||
pAdapter->TxStartThreshold=2040;
|
||
}
|
||
}
|
||
|
||
ELNK3_COMMAND(pAdapter,EC_SET_TX_START,(USHORT)pAdapter->TxStartThreshold & 0x7ff);
|
||
|
||
} else {
|
||
//
|
||
// Otherwise the xmitter just needs to be restarted
|
||
//
|
||
|
||
ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0);
|
||
}
|
||
|
||
pAdapter->FramesXmitBad++;
|
||
}
|
||
|
||
|
||
IF_SEND_LOUD (DbgPrint("HandleXmitInts: Exit\n");)
|
||
|
||
return TRUE;
|
||
}
|