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