📄 3c509.c
字号:
/*** File: 3c509.c Jun. 01, 2000**** Author: Giovanni Falzoni <gfalzoni@inwind.it>**** This file contains specific implementation of the ethernet** device driver for 3Com Etherlink III (3c509) boards.** NOTE: The board has to be setup to disable PnP and to assign** I/O base and IRQ. The driver is for ISA bus only**** $Id: 3c509.c,v 1.3 2005/08/05 19:08:43 beng Exp $*/#include "drivers.h"#include <minix/com.h>#include <net/hton.h>#include <net/gen/ether.h>#include <net/gen/eth_io.h>#include "dp.h"#if (ENABLE_3C509 == 1)#include "3c509.h"static const char *const IfNamesMsg[] = { "10BaseT", "AUI", "unknown", "BNC",};/*** Name: void el3_update_stats(dpeth_t *dep)** Function: Reads statistic counters from board** and updates local counters.*/static void el3_update_stats(dpeth_t * dep){ /* Disables statistics while reading and switches to the correct window */ outw_el3(dep, REG_CmdStatus, CMD_StatsDisable); SetWindow(WNO_Statistics); /* Reads everything, adding values to the local counters */ dep->de_stat.ets_sendErr += inb_el3(dep, REG_TxCarrierLost); /* Reg. 00 */ dep->de_stat.ets_sendErr += inb_el3(dep, REG_TxNoCD); /* Reg. 01 */ dep->de_stat.ets_collision += inb_el3(dep, REG_TxMultColl); /* Reg. 02 */ dep->de_stat.ets_collision += inb_el3(dep, REG_TxSingleColl); /* Reg. 03 */ dep->de_stat.ets_collision += inb_el3(dep, REG_TxLate); /* Reg. 04 */ dep->de_stat.ets_recvErr += inb_el3(dep, REG_RxDiscarded); /* Reg. 05 */ dep->de_stat.ets_packetT += inb_el3(dep, REG_TxFrames); /* Reg. 06 */ dep->de_stat.ets_packetR += inb_el3(dep, REG_RxFrames); /* Reg. 07 */ dep->de_stat.ets_transDef += inb_el3(dep, REG_TxDefer); /* Reg. 08 */ dep->bytes_Rx += (unsigned) inw_el3(dep, REG_RxBytes); /* Reg. 10 */ dep->bytes_Tx += (unsigned) inw_el3(dep, REG_TxBytes); /* Reg. 12 */ /* Goes back to operating window and enables statistics */ SetWindow(WNO_Operating); outw_el3(dep, REG_CmdStatus, CMD_StatsEnable); return;}/*** Name: void el3_getstats(dpeth_t *dep)** Function: Reads statistics counters from board.*/static void el3_getstats(dpeth_t * dep){ lock(); el3_update_stats(dep); unlock(); return;}/*** Name: void el3_dodump(dpeth_t *dep)** Function: Dumps counter on screen (support for console display).*/static void el3_dodump(dpeth_t * dep){ el3_getstats(dep); return;}/*** Name: void el3_rx_mode(dpeth_t *dep)** Function: Initializes receiver mode*/static void el3_rx_mode(dpeth_t * dep){ dep->de_recv_mode = FilterIndividual; if (dep->de_flags & DEF_BROAD) dep->de_recv_mode |= FilterBroadcast; if (dep->de_flags & DEF_MULTI) dep->de_recv_mode |= FilterMulticast; if (dep->de_flags & DEF_PROMISC) dep->de_recv_mode |= FilterPromiscuous; outw_el3(dep, REG_CmdStatus, CMD_RxReset); outw_el3(dep, REG_CmdStatus, CMD_SetRxFilter | dep->de_recv_mode); outw_el3(dep, REG_CmdStatus, CMD_RxEnable); return;}/*** Name: void el3_reset(dpeth_t *dep)** Function: Reset function specific for Etherlink hardware.*/static void el3_reset(dpeth_t * dep){ return; /* Done */}/*** Name: void el3_write_fifo(dpeth_t * dep, int pktsize);** Function: Writes a packet from user area to board.** Remark: Writing a word/dword at a time may result faster** but is a lot more complicated. Let's go simpler way.*/static void el3_write_fifo(dpeth_t * dep, int pktsize){ phys_bytes phys_user; int bytes, ix = 0; iovec_dat_t *iovp = &dep->de_write_iovec; int padding = pktsize; do { /* Writes chuncks of packet from user buffers */ bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */ if (bytes > pktsize) bytes = pktsize; /* Writes from user buffer to Tx FIFO */ outsb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes); if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ dp_next_iovec(iovp); ix = 0; } /* Till packet done */ } while ((pktsize -= bytes) > 0); while ((padding++ % sizeof(long)) != 0) outb(dep->de_data_port, 0x00); return;}/*** Name: void el3_recv(dpeth_t *dep, int fromint, int size)** Function: Receive function. Called from interrupt handler or** from main to unload recv. buffer (packet to client)*/static void el3_recv(dpeth_t *dep, int fromint, int size){ buff_t *rxptr; while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) { lock(); /* Remove buffer from queue */ if (dep->de_recvq_tail == dep->de_recvq_head) dep->de_recvq_head = dep->de_recvq_tail = NULL; else dep->de_recvq_head = rxptr->next; unlock(); /* Copy buffer to user area and free it */ mem2user(dep, rxptr); dep->de_read_s = rxptr->size; dep->de_flags |= DEF_ACK_RECV; dep->de_flags &= NOT(DEF_READING); /* Return buffer to the idle pool */ free_buff(dep, rxptr); } return;}/*** Name: void el3_rx_complete(dpeth_t * dep);** Function: Upon receiving a packet, provides status checks** and if packet is OK copies it to local buffer.*/static void el3_rx_complete(dpeth_t * dep){ short int RxStatus; int pktsize; buff_t *rxptr; RxStatus = inw_el3(dep, REG_RxStatus); pktsize = RxStatus & RXS_Length; /* Mask off packet length */ if (RxStatus & RXS_Error) { /* First checks for receiving errors */ RxStatus &= RXS_ErrType; switch (RxStatus) { /* Bad packet (see error type) */ case RXS_Dribble: case RXS_Oversize: case RXS_Runt: dep->de_stat.ets_recvErr += 1; break; case RXS_Overrun: dep->de_stat.ets_OVW += 1; break; case RXS_Framing: dep->de_stat.ets_frameAll += 1; break; case RXS_CRC: dep->de_stat.ets_CRCerr += 1; break; } } else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) { /* Memory not available. Drop packet */ dep->de_stat.ets_fifoOver += 1; } else { /* Good packet. Read it from FIFO */ insb(dep->de_data_port, SELF, rxptr->buffer, pktsize); rxptr->next = NULL; rxptr->size = pktsize; lock(); /* Queue packet to receive queue */ if (dep->de_recvq_head == NULL) dep->de_recvq_head = rxptr; else dep->de_recvq_tail->next = rxptr; dep->de_recvq_tail = rxptr; unlock(); /* Reply to pending Receive requests, if any */ el3_recv(dep, TRUE, pktsize); } /* Discard top packet from queue */ outw_el3(dep, REG_CmdStatus, CMD_RxDiscard); return;}/*** Name: void el3_send(dpeth_t *dep, int count)** Function: Send function. Called from main to transit a packet or** from interrupt handler when Tx FIFO gets available.*/static void el3_send(dpeth_t * dep, int from_int, int count){ clock_t now; int ix; short int TxStatus; getuptime(&now); if ((dep->de_flags & DEF_XMIT_BUSY) && (now - dep->de_xmit_start) > 4) { DEBUG(printf("3c509: Transmitter timed out. Resetting ....\n");) dep->de_stat.ets_sendErr += 1; /* Resets and restars the transmitter */ outw_el3(dep, REG_CmdStatus, CMD_TxReset); outw_el3(dep, REG_CmdStatus, CMD_TxEnable); dep->de_flags &= NOT(DEF_XMIT_BUSY); } if (!(dep->de_flags & DEF_XMIT_BUSY)) { /* Writes Transmitter preamble 1st Word (packet len, no ints) */ outw_el3(dep, REG_TxFIFO, count); /* Writes Transmitter preamble 2nd Word (all zero) */ outw_el3(dep, REG_TxFIFO, 0); /* Writes packet */ el3_write_fifo(dep, count); getuptime(&dep->de_xmit_start); dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND); if (inw_el3(dep, REG_TxFree) > ETH_MAX_PACK_SIZE) { /* Tx has enough room for a packet of maximum size */ dep->de_flags &= NOT(DEF_XMIT_BUSY | DEF_SENDING); } else { /* Interrupt driver when enough room is available */ outw_el3(dep, REG_CmdStatus, CMD_SetTxAvailable | ETH_MAX_PACK_SIZE); dep->de_flags &= NOT(DEF_SENDING); } /* Pops Tx status stack */ for (ix = 4; --ix && (TxStatus = inb_el3(dep, REG_TxStatus)) > 0;) { if (TxStatus & 0x38) dep->de_stat.ets_sendErr += 1; if (TxStatus & 0x30) outw_el3(dep, REG_CmdStatus, CMD_TxReset); if (TxStatus & 0x3C) outw_el3(dep, REG_CmdStatus, CMD_TxEnable); outb_el3(dep, REG_TxStatus, 0); } } return;}/*** Name: void el3_close(dpeth_t *dep)** Function: Stops board and makes it ready to shut down.*/static void el3_close(dpeth_t * dep){ /* Disables statistics, Receiver and Transmitter */ outw_el3(dep, REG_CmdStatus, CMD_StatsDisable); outw_el3(dep, REG_CmdStatus, CMD_RxDisable); outw_el3(dep, REG_CmdStatus, CMD_TxDisable); if (dep->de_if_port == BNC_XCVR) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -