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.
292 lines
5.7 KiB
292 lines
5.7 KiB
/*++
|
|
|
|
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;
|
|
}
|