/*++ Copyright (c) 1992 Microsoft Corporation Module Name: send.c Abstract: This file handles sending packets the Ungermann Bass Ethernet Controller. This driver conforms to the NDIS 3.0 interface. Author: Brian Lieuallen (BrianLie) 07/02/92 Environment: Kernel Mode Operating Systems : NT and other lesser OS's Revision History: Brian Lieuallen BrianLie 12/15/93 Made it a mini-port --*/ #include #include #include "niudata.h" #include "debug.h" #include "ubhard.h" #include "ubsoft.h" #include "ubnei.h" #include "map.h" BOOLEAN CardSend( IN PUBNEI_ADAPTER pAdapter, IN PNDIS_PACKET pPacket, IN UINT PacketLength ); BOOLEAN UbneiMapSendBufferSync( PSEND_SYNC_CONTEXT pSync ); BOOLEAN UbneiGiveSendBufferToCardSync( PSEND_SYNC_CONTEXT pSync ); NDIS_STATUS UbneiMacSend( IN NDIS_HANDLE MacBindingHandle, IN PNDIS_PACKET pPacket, IN UINT Flags ) /*++ Routine Description: MacSend Arguments: See NDIS 3.0 spec Return Value: --*/ { PUBNEI_ADAPTER pAdapter = MacBindingHandle; UINT PacketLength; BOOLEAN SendResult; IF_LOG('s'); ASSERT_RECEIVE_WINDOW( pAdapter); IF_SEND_LOUD(DbgPrint("MacSend called Packets\n");) NdisQueryPacket(pPacket, 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; } // No packets queued, so we have a good chance // being able to complete this send right now. // After all the card has enough buffers for // ~32 full size frames. // SendResult=CardSend(pAdapter, pPacket, PacketLength); if (SendResult) { // // It's gone, were out of here! // // Since we sent it down to the card we don't need the card // to generate an interrupt // ASSERT_RECEIVE_WINDOW( pAdapter); UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(((PLOWNIUDATA)(pAdapter->pCardRam))->HostQueuedTransmits),0); NdisMSendResourcesAvailable(pAdapter->NdisAdapterHandle); return NDIS_STATUS_SUCCESS; } else { // // No card buffers left, queue it and tell the card // to interrupt us when there is room. // IF_LOUD(DbgPrint("UBNEI: No card send resources\n");) IF_LOG('o'); pAdapter->WaitingForXmitInterrupt=TRUE; ASSERT_RECEIVE_WINDOW( pAdapter); UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(((PLOWNIUDATA)(pAdapter->pCardRam))->HostQueuedTransmits),1); return NDIS_STATUS_RESOURCES; } } BOOLEAN CardSend( IN PUBNEI_ADAPTER pAdapter, IN PNDIS_PACKET pPacket, IN UINT PacketLength ) /*++ Routine Description: This routine checks the cards transmit ring buffer to see if a send can take place. If it can then it removes the buffer from the free transmit buffer ring buffer and places it on the to be transimitted ring buffer. Arguments: pAdapt - pointer to the adapter block Return Value: returns TRUE if it was able to copy the send data to the card FALSE indicates that there are no free transmit buffers currently --*/ { SEND_SYNC_CONTEXT SyncContext; BOOLEAN OkToSend; SyncContext.pAdapter=pAdapter; if (PacketLength<60) { PacketLength=60; } SyncContext.PacketLength=PacketLength; OkToSend=NdisMSynchronizeWithInterrupt( &pAdapter->NdisInterrupt, UbneiMapSendBufferSync, &SyncContext ); if (OkToSend) { // // If we can send now the sync routine left the correct // window mapped in for us to copy to the send buffer // { PUCHAR CurAddress, BufAddress; UINT Len; PNDIS_BUFFER CurBuffer; // // Memory mapped, just copy each buffer over. // NdisQueryPacket(pPacket, NULL, NULL, &CurBuffer, NULL); CurAddress = SyncContext.SendBuffer; while (CurBuffer) { NdisQueryBuffer(CurBuffer, (PVOID *)&BufAddress, &Len); UBNEI_MOVE_MEM_TO_SHARED_RAM(CurAddress, BufAddress, Len); CurAddress += Len; NdisGetNextBuffer(CurBuffer, &CurBuffer); } } NdisMSynchronizeWithInterrupt( &pAdapter->NdisInterrupt, UbneiGiveSendBufferToCardSync, &SyncContext ); } return OkToSend; } BOOLEAN UbneiMapSendBufferSync( PSEND_SYNC_CONTEXT pSync ) { PUBNEI_ADAPTER pAdapter=pSync->pAdapter; PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapter->pDataWindow; PTBD pTBD; UCHAR TmpUchar2; UCHAR MapWindow; USHORT TbdOffset; USHORT BufferOffset; SET_DATAWINDOW(pAdapter,INTERRUPT_ENABLED); // // Check to see if there are any free TBD descriptors. If not then // we can't do any sends now // UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&pSync->TbdIndex, &(pDataWindow->FreeTDBs.SRB_ReadPtr[0])); UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar2, &(pDataWindow->FreeTDBs.SRB_WritePtr[0])); if (pSync->TbdIndex == TmpUchar2 ) { SET_RECDWINDOW(pAdapter,INTERRUPT_ENABLED); return FALSE; } // // Get the address of the TBD in the NIU data segment // UBNEI_MOVE_SHARED_RAM_TO_USHORT(&TbdOffset, &(pDataWindow->FreeTDBs.SRB_Offsets[pSync->TbdIndex]) ); pTBD=(PTBD)((PUCHAR)pAdapter->pCardRam+TbdOffset); // // Set the length of the frame to be sent in the TBD // UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pTBD->TBD_Frame_Length), (USHORT)pSync->PacketLength); UBNEI_MOVE_USHORT_TO_SHARED_RAM(&(pTBD->TBD_EOF_and_Length), (USHORT)pSync->PacketLength | 0x8000); // // Get a pointer to the TBD buffer located in the NIU code segment // Under the current version of download code the transmit buffer is // is 1514 bytes long, so this makes things easy // UBNEI_MOVE_SHARED_RAM_TO_USHORT(&BufferOffset, &(pTBD->TBD_Buffer_offset)); pSync->SendBuffer=(PUCHAR)pAdapter->pCardRam + BufferOffset; // // Set the map register to point to the correct window to access // the send buffer // UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&MapWindow, &(pTBD->TBD_Buffer_Map)); pAdapter->MapRegSync.NewMapRegister=MapWindow | INTERRUPT_ENABLED; UbneiMapRegisterChangeSync(&pAdapter->MapRegSync); return TRUE; } BOOLEAN UbneiGiveSendBufferToCardSync( PSEND_SYNC_CONTEXT pSync ) { PUBNEI_ADAPTER pAdapter=pSync->pAdapter; PHIGHNIUDATA pDataWindow = (PHIGHNIUDATA) pAdapter->pDataWindow; UCHAR TmpUchar1; SET_DATAWINDOW(pAdapter,INTERRUPT_ENABLED); // // To actually give the data to the NIU to send, we remove the this // TBD from the FreeTDB buffer and add it to XmtFrames buffer // UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->FreeTDBs.SRB_ReadPtr[0]), pSync->TbdIndex + 1); UBNEI_MOVE_SHARED_RAM_TO_UCHAR(&TmpUchar1, &(pDataWindow->XmtFrames.SRB_WritePtr[0])); UBNEI_MOVE_UCHAR_TO_SHARED_RAM(&(pDataWindow->XmtFrames.SRB_WritePtr[0]), TmpUchar1 + 1); SET_RECDWINDOW(pAdapter,INTERRUPT_ENABLED); return TRUE; }