2020-09-30 17:12:29 +02:00

293 lines
5.7 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}