From 6be8c4d8a367cbdd62199ee707dea2e41791e828 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Wed, 29 Jun 2005 10:16:46 +0000 Subject: [PATCH] Import of dpeth 3c501/3c509b/.. ethernet driver by Giovanni Falzoni . --- drivers/Makefile | 2 +- drivers/dpeth/3c501.c | 428 +++++++++++++++++++++++ drivers/dpeth/3c501.h | 71 ++++ drivers/dpeth/3c503.c | 175 ++++++++++ drivers/dpeth/3c503.h | 72 ++++ drivers/dpeth/3c509.c | 603 ++++++++++++++++++++++++++++++++ drivers/dpeth/3c509.h | 164 +++++++++ drivers/dpeth/8390.c | 739 ++++++++++++++++++++++++++++++++++++++++ drivers/dpeth/8390.h | 172 ++++++++++ drivers/dpeth/Makefile | 52 +++ drivers/dpeth/README | 38 +++ drivers/dpeth/devio.c | 141 ++++++++ drivers/dpeth/dp.c | 641 ++++++++++++++++++++++++++++++++++ drivers/dpeth/dp.h | 269 +++++++++++++++ drivers/dpeth/ne.c | 201 +++++++++++ drivers/dpeth/ne.h | 37 ++ drivers/dpeth/netbuff.c | 176 ++++++++++ drivers/dpeth/wd.c | 323 ++++++++++++++++++ drivers/dpeth/wd.h | 103 ++++++ include/minix/com.h | 16 +- include/minix/config.h | 4 +- kernel/klib386.s | 2 +- kernel/table.c | 3 + servers/is/dmp_kernel.c | 4 +- tools/Makefile | 1 + 25 files changed, 4424 insertions(+), 13 deletions(-) create mode 100644 drivers/dpeth/3c501.c create mode 100644 drivers/dpeth/3c501.h create mode 100644 drivers/dpeth/3c503.c create mode 100644 drivers/dpeth/3c503.h create mode 100644 drivers/dpeth/3c509.c create mode 100644 drivers/dpeth/3c509.h create mode 100644 drivers/dpeth/8390.c create mode 100644 drivers/dpeth/8390.h create mode 100644 drivers/dpeth/Makefile create mode 100644 drivers/dpeth/README create mode 100644 drivers/dpeth/devio.c create mode 100644 drivers/dpeth/dp.c create mode 100644 drivers/dpeth/dp.h create mode 100644 drivers/dpeth/ne.c create mode 100644 drivers/dpeth/ne.h create mode 100644 drivers/dpeth/netbuff.c create mode 100644 drivers/dpeth/wd.c create mode 100644 drivers/dpeth/wd.h diff --git a/drivers/Makefile b/drivers/Makefile index 610af2bc2..3af5bcb3d 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -23,4 +23,4 @@ all install depend clean: cd ./printer && $(MAKE) $@ cd ./rtl8139 && $(MAKE) $@ cd ./fxp && $(MAKE) $@ - + cd ./dpeth && $(MAKE) $@ diff --git a/drivers/dpeth/3c501.c b/drivers/dpeth/3c501.c new file mode 100644 index 000000000..d99eeba43 --- /dev/null +++ b/drivers/dpeth/3c501.c @@ -0,0 +1,428 @@ +/* +** File: 3c501.c Jan. 14, 1997 +** +** Author: Giovanni Falzoni +** +** This file contains specific implementation of the ethernet +** device driver for 3Com Etherlink (3c501) boards. This is a +** very old board and its performances are very poor for today +** network environments. +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#include "drivers.h" +#include +#include +#include +#include +#include "dp.h" + +#if (ENABLE_NETWORKING == 1 && ENABLE_3C501 == 1) + +#include "3c501.h" + +static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,}; +static buff_t *TxBuff = NULL; + +/* +** Name: void el1_getstats(dpeth_t *dep) +** Function: Reads statistics counters from board. +**/ +static void el1_getstats(dpeth_t * dep) +{ + + return; /* Nothing to do */ +} + +/* +** Name: void el1_reset(dpeth_t *dep) +** Function: Reset function specific for Etherlink hardware. +*/ +static void el1_reset(dpeth_t * dep) +{ + int ix; + + for (ix = 0; ix < 8; ix += 1) /* Resets the board */ + outb_el1(dep, EL1_CSR, ECSR_RESET); + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); + + /* Set Ethernet Address on controller */ + outb_el1(dep, EL1_CSR, ECSR_LOOP); /* Loopback mode */ + for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1) + outb_el1(dep, ix, StationAddress[ix]); + + lock(); + /* Enable DMA/Interrupt, gain control of Buffer */ + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); + /* Clear RX packet area */ + outw_el1(dep, EL1_RECVPTR, 0); + /* Enable transmit/receive configuration and flush pending interrupts */ + outb_el1(dep, EL1_XMIT, EXSR_IDLE | EXSR_16JAM | EXSR_JAM | EXSR_UNDER); + outb_el1(dep, EL1_RECV, dep->de_recv_mode); + inb_el1(dep, EL1_RECV); + inb_el1(dep, EL1_XMIT); + dep->de_flags &= NOT(DEF_XMIT_BUSY); + unlock(); + return; /* Done */ +} + +/* +** Name: void el1_dumpstats(dpeth_t *dep, int port, vir_bytes size) +** Function: Dumps counter on screen (support for console display). +*/ +static void el1_dumpstats(dpeth_t * dep) +{ + + return; +} + +/* +** Name: void el1_mode_init(dpeth_t *dep) +** Function: Initializes receicer mode +*/ +static void el1_mode_init(dpeth_t * dep) +{ + + if (dep->de_flags & DEF_BROAD) { + dep->de_recv_mode = ERSR_BROAD | ERSR_RMASK; + + } else if (dep->de_flags & DEF_PROMISC) { + dep->de_recv_mode = ERSR_ALL | ERSR_RMASK; + + } else if (dep->de_flags & DEF_MULTI) { + dep->de_recv_mode = ERSR_MULTI | ERSR_RMASK; + + } else { + dep->de_recv_mode = ERSR_NONE | ERSR_RMASK; + } + outb_el1(dep, EL1_RECV, dep->de_recv_mode); + inb_el1(dep, EL1_RECV); + return; +} + +/* +** Name: void el1_recv(dpeth_t *dep, int from, int size) +** Function: Receive function. Called from interrupt handler to +** unload recv. buffer or from main (packet to client) +*/ +static void el1_recv(dpeth_t * dep, int from, int size) +{ + buff_t *rxptr; + + while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) { + + /* Remove buffer from queue and free buffer */ + lock(); + 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 */ + mem2user(dep, rxptr); + + /* Reply information */ + 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 el1_send(dpeth_t *dep, int from_int, int pktsize) +** Function: Send function. Called from main to transit a packet or +** from interrupt handler when a new packet was queued. +*/ +static void el1_send(dpeth_t * dep, int from_int, int pktsize) +{ + buff_t *txbuff; + clock_t now; + + if (from_int == FALSE) { + + if ((txbuff = alloc_buff(dep, pktsize + sizeof(buff_t))) != NULL) { + + /* Fill transmit buffer from user area */ + txbuff->next = NULL; + txbuff->size = pktsize; + txbuff->client = dep->de_client; + user2mem(dep, txbuff); + } else + panic(dep->de_name, "out of memory for Tx", NO_NUM); + + } else if ((txbuff = dep->de_xmitq_head) != NULL) { + + /* Get first packet in queue */ + lock(); + if (dep->de_xmitq_tail == dep->de_xmitq_head) + dep->de_xmitq_head = dep->de_xmitq_tail = NULL; + else + dep->de_xmitq_head = txbuff->next; + unlock(); + pktsize = txbuff->size; + + } else + panic(dep->de_name, "should not be sending ", NO_NUM); + + if ((dep->de_flags & DEF_XMIT_BUSY)) { + if (from_int) panic(dep->de_name, "should not be sending ", NO_NUM); + getuptime(&now); + if ((now - dep->de_xmit_start) > 4) { + /* Transmitter timed out */ + DEBUG(printf("3c501: transmitter timed out ... \n")); + dep->de_stat.ets_sendErr += 1; + dep->de_flags &= NOT(DEF_XMIT_BUSY); + el1_reset(dep); + } + + /* Queue packet */ + lock(); /* Queue packet to receive queue */ + if (dep->de_xmitq_head == NULL) + dep->de_xmitq_head = txbuff; + else + dep->de_xmitq_tail->next = txbuff; + dep->de_xmitq_tail = txbuff; + unlock(); + } else { + /* Save for retransmission */ + TxBuff = txbuff; + dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND); + + /* Setup board for packet loading */ + lock(); /* Buffer to processor */ + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); + inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */ + inb_el1(dep, EL1_XMIT); + outw_el1(dep, EL1_RECVPTR, 0); /* Clears RX packet area */ + + /* Loads packet */ + outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize)); + outsb(dep->de_data_port, SELF, txbuff->buffer, pktsize); + /* Starts transmitter */ + outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize)); + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); /* There it goes... */ + unlock(); + + getuptime(&dep->de_xmit_start); + dep->de_flags &= NOT(DEF_SENDING); + } + return; +} + +/* +** Name: void el1_stop(dpeth_t *dep) +** Function: Stops board and disable interrupts. +*/ +static void el1_stop(dpeth_t * dep) +{ + int ix; + + DEBUG(printf("%s: stopping Etherlink ....\n", dep->de_name)); + for (ix = 0; ix < 8; ix += 1) /* Reset board */ + outb_el1(dep, EL1_CSR, ECSR_RESET); + outb_el1(dep, EL1_CSR, ECSR_SYS); + sys_irqdisable(&dep->de_hook); /* Disable interrupt */ + return; +} + +/* +** Name: void el1_interrupt(dpeth_t *dep) +** Function: Interrupt handler. Acknwledges transmit interrupts +** or unloads receive buffer to memory queue. +*/ +static void el1_interrupt(dpeth_t * dep) +{ + u16_t csr, isr; + int pktsize; + buff_t *rxptr; + + csr = inb_el1(dep, EL1_CSR); + if ((csr & ECSR_XMIT) && (dep->de_flags & DEF_XMIT_BUSY)) { + + /* Got a transmit interrupt */ + isr = inb_el1(dep, EL1_XMIT); + if ((isr & (EXSR_16JAM | EXSR_UNDER | EXSR_JAM)) || !(isr & EXSR_IDLE)) { + DEBUG(printf("3c501: got xmit interrupt (ASR=0x%02X XSR=0x%02X)\n", csr, isr)); + if (isr & EXSR_JAM) { + /* Sending, packet got a collision */ + dep->de_stat.ets_collision += 1; + /* Put pointer back to beginning of packet */ + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); + outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - TxBuff->size)); + /* And retrigger transmission */ + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); + return; + + } else if ((isr & EXSR_16JAM) || !(isr & EXSR_IDLE)) { + dep->de_stat.ets_sendErr += 1; + + } else if (isr & EXSR_UNDER) { + dep->de_stat.ets_fifoUnder += 1; + } + DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr)); + el1_reset(dep); + + } else { + /** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/ + /* Packet transmitted successfully */ + dep->de_stat.ets_packetT += 1; + dep->bytes_Tx += (long) (TxBuff->size); + free_buff(dep, TxBuff); + dep->de_flags &= NOT(DEF_XMIT_BUSY); + if ((dep->de_flags & DEF_SENDING) && dep->de_xmitq_head) { + /* Pending transmit request available in queue */ + el1_send(dep, TRUE, 0); + if (dep->de_flags & (DEF_XMIT_BUSY | DEF_ACK_SEND)) + return; + } + } + + } else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) { + + /* Got a receive interrupt */ + isr = inb_el1(dep, EL1_RECV); + pktsize = inw_el1(dep, EL1_RECVPTR); + if ((isr & ERSR_RERROR) || (isr & ERSR_STALE)) { + DEBUG(printf("Rx0 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize)); + dep->de_stat.ets_recvErr += 1; + + } else if (pktsize < ETH_MIN_PACK_SIZE || pktsize > ETH_MAX_PACK_SIZE) { + DEBUG(printf("Rx1 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize)); + dep->de_stat.ets_recvErr += 1; + + } else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) { + /* Memory not available. Drop packet */ + dep->de_stat.ets_fifoOver += 1; + + } else if (isr & (ERSR_GOOD | ERSR_ANY)) { + /* Got a good packet. Read it from buffer */ + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); + outw_el1(dep, EL1_XMITPTR, 0); + insb(dep->de_data_port, SELF, rxptr->buffer, pktsize); + rxptr->next = NULL; + rxptr->size = pktsize; + dep->de_stat.ets_packetR += 1; + dep->bytes_Rx += (long) 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 */ + el1_recv(dep, TRUE, 0); + } + } else { /* Nasty condition, should never happen */ + DEBUG( + printf("3c501: got interrupt with status 0x%02X\n" + " de_flags=0x%04X XSR=0x%02X RSR=0x%02X \n" + " xmit buffer = 0x%4X recv buffer = 0x%4X\n", + csr, dep->de_flags, + inb_el1(dep, EL1_RECV), + inb_el1(dep, EL1_XMIT), + inw_el1(dep, EL1_XMITPTR), + inw_el1(dep, EL1_RECVPTR)) + ); + el1_reset(dep); + } + + /* Move into receive mode */ + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV); + outw_el1(dep, EL1_RECVPTR, 0); + /* Be sure that interrupts are cleared */ + inb_el1(dep, EL1_RECV); + inb_el1(dep, EL1_XMIT); + return; +} + +/* +** Name: void el1_init(dpeth_t *dep) +** Function: Initalizes board hardware and driver data structures. +*/ +static void el1_init(dpeth_t * dep) +{ + int ix; + + dep->de_irq &= NOT(DEI_DEFAULT); /* Strip the default flag. */ + dep->de_offset_page = 0; + dep->de_data_port = dep->de_base_port + EL1_DATAPORT; + + el1_reset(dep); /* Reset and initialize board */ + + /* Start receiver (default mode) */ + outw_el1(dep, EL1_RECVPTR, 0); + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV); + + /* Initializes buffer pool */ + init_buff(dep, NULL); + el1_mode_init(dep); + + printf("%s: Etherlink (%s) at %X:%d - ", + dep->de_name, "3c501", dep->de_base_port, dep->de_irq); + for (ix = 0; ix < SA_ADDR_LEN; ix += 1) + printf("%02X%c", (dep->de_address.ea_addr[ix] = StationAddress[ix]), + ix < SA_ADDR_LEN - 1 ? ':' : '\n'); + + /* Device specific functions */ + dep->de_recvf = el1_recv; + dep->de_sendf = el1_send; + dep->de_flagsf = el1_mode_init; + dep->de_resetf = el1_reset; + dep->de_getstatsf = el1_getstats; + dep->de_dumpstatsf = el1_dumpstats; + dep->de_interruptf = el1_interrupt; + + return; /* Done */ +} + +/* +** Name: int el1_probe(dpeth_t *dep) +** Function: Checks for presence of the board. +*/ +PUBLIC int el1_probe(dpeth_t * dep) +{ + int ix; + + for (ix = 0; ix < 8; ix += 1) /* Reset the board */ + outb_el1(dep, EL1_CSR, ECSR_RESET); + outb_el1(dep, EL1_CSR, ECSR_SYS); /* Leaves buffer to system */ + + /* Check station address */ + for (ix = 0; ix < SA_ADDR_LEN; ix += 1) { + outw_el1(dep, EL1_XMITPTR, ix); + StationAddress[ix] = inb_el1(dep, EL1_SAPROM); + } + if (StationAddress[0] != 0x02 || /* Etherlink Station address */ + StationAddress[1] != 0x60 || /* MUST be 02:60:8c:xx:xx:xx */ + StationAddress[2] != 0x8C) + return FALSE; /* No Etherlink board at this address */ + + dep->de_ramsize = 0; /* RAM size is meaningless */ + dep->de_linmem = 0L; /* Access is via I/O port */ + + /* Device specific functions */ + dep->de_initf = el1_init; + dep->de_stopf = el1_stop; + + return TRUE; /* Etherlink board found */ +} + +#endif /* ENABLE_NETWORKING */ + +/** 3c501.c **/ diff --git a/drivers/dpeth/3c501.h b/drivers/dpeth/3c501.h new file mode 100644 index 000000000..c7b266336 --- /dev/null +++ b/drivers/dpeth/3c501.h @@ -0,0 +1,71 @@ +/* +** File: 3c501.h Jan. 14, 1997 +** +** Author: Giovanni Falzoni +** +** Interface description for 3Com Etherlink boards +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +/* The various board command registers */ +#define EL1_ADDRESS 0x00 /* Board station address, 6 bytes */ +#define EL1_RECV 0x06 /* Board Receive Config/Status Reg. */ +#define EL1_XMIT 0x07 /* Board Transmit Config/Status Reg. */ +#define EL1_XMITPTR 0x08 /* Transmit buffer pointer (word access) */ +#define EL1_RECVPTR 0x0A /* Receive buffer pointer (word access) */ +#define EL1_SAPROM 0x0C /* Window on Station Addr prom */ +#define EL1_CSR 0x0E /* Board Command/Status Register */ +#define EL1_DATAPORT 0x0F /* Window on packet buffer (Data Port) */ + +/* Bits in EL1_RECV, interrupt enable on write, status when read */ +#define ERSR_NONE 0x00 /* Match mode in bits 5-6 (wo) */ +#define ERSR_ALL 0x40 /* Promiscuous receive (wo) */ +#define ERSR_BROAD 0x80 /* Station address plus broadcast (wo) */ +#define ERSR_MULTI 0x80 /* Station address plus multicast 0xC0 */ +#define ERSR_STALE 0x80 /* Receive status previously read (ro) */ +#define ERSR_GOOD 0x20 /* Well formed packets only (rw) */ +#define ERSR_ANY 0x10 /* Any packet, even with errors (rw) */ +#define ERSR_SHORT 0x08 /* Short frame (rw) */ +#define ERSR_DRIBBLE 0x04 /* Dribble error (rw) */ +#define ERSR_FCS 0x02 /* CRC error (rw) */ +#define ERSR_OVER 0x01 /* Data overflow (rw) */ + +#define ERSR_RERROR (ERSR_SHORT|ERSR_DRIBBLE|ERSR_FCS|ERSR_OVER) +#define ERSR_RMASK (ERSR_GOOD|ERSR_RERROR)/*(ERSR_GOOD|ERSR_ANY|ERSR_RERROR)*/ + +/* Bits in EL1_XMIT, interrupt enable on write, status when read */ +#define EXSR_IDLE 0x08 /* Transmit idle (send completed) */ +#define EXSR_16JAM 0x04 /* Packet sending got 16 collisions */ +#define EXSR_JAM 0x02 /* Packet sending got a collision */ +#define EXSR_UNDER 0x01 /* Data underflow in sending */ + +/* Bits in EL1_CSR (Configuration Status Register) */ +#define ECSR_RESET 0x80 /* Reset the controller (wo) */ +#define ECSR_XMTBSY 0x80 /* Transmitter busy (ro) */ +#define ECSR_RIDE 0x01 /* Request interrupt/DMA enable (rw) */ +#define ECSR_DMA 0x20 /* DMA request (rw) */ +#define ECSR_EDMA 0x10 /* DMA done (ro) */ +#define ECSR_CRC 0x02 /* Causes CRC error on transmit (wo) */ +#define ECSR_RCVBSY 0x01 /* Receive in progress (ro) */ +#define ECSR_LOOP (3<<2) /* 2 bit field in bits 2,3, loopback */ +#define ECSR_RECV (2<<2) /* Gives buffer to receiver (rw) */ +#define ECSR_XMIT (1<<2) /* Gives buffer to transmit (rw) */ +#define ECSR_SYS (0<<2) /* Gives buffer to processor (wo) */ + +#define EL1_BFRSIZ 2048 /* Number of bytes in board buffer */ + +#define inb_el1(dep,reg) (inb(dep->de_base_port+(reg))) +#define inw_el1(dep,reg) (inw(dep->de_base_port+(reg))) +#define outb_el1(dep,reg,data) (outb(dep->de_base_port+(reg),data)) +#define outw_el1(dep,reg,data) (outw(dep->de_base_port+(reg),data)) + +/** 3c501.h **/ diff --git a/drivers/dpeth/3c503.c b/drivers/dpeth/3c503.c new file mode 100644 index 000000000..45b4ca517 --- /dev/null +++ b/drivers/dpeth/3c503.c @@ -0,0 +1,175 @@ +/* +** File: 3c503.c Dec. 20, 1996 +** +** Author: Giovanni Falzoni +** +** Driver for the Etherlink II boards. Works in shared memory mode. +** Programmed I/O could be used as well but would result in poor +** performances. This file contains only the board specific code, +** the rest is in 8390.c Code specific for ISA bus only +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#include "drivers.h" +#include +#include +#include "dp.h" + +#if ENABLE_NETWORKING == 1 && ENABLE_3C503 == 1 + +#include "8390.h" +#include "3c503.h" + +/* +** Name: void el2_init(dpeth_t *dep); +** Function: Initalize hardware and data structures. +*/ +static void el2_init(dpeth_t * dep) +{ + int ix, irq; + int sendq_nr; + int cntr; + + /* Map the address PROM to lower I/O address range */ + cntr = inb_el2(dep, EL2_CNTR); + outb_el2(dep, EL2_CNTR, cntr | ECNTR_SAPROM); + + /* Read station address from PROM */ + for (ix = EL2_EA0; ix <= EL2_EA5; ix += 1) + dep->de_address.ea_addr[ix] = inb_el2(dep, ix); + + /* Map the 8390 back to lower I/O address range */ + outb_el2(dep, EL2_CNTR, cntr); + + /* Enable memory, but turn off interrupts until we are ready */ + outb_el2(dep, EL2_CFGR, ECFGR_IRQOFF); + + dep->de_data_port = dep->de_dp8390_port = dep->de_base_port; + dep->de_prog_IO = FALSE; /* Programmed I/O not yet available */ + + /* Check width of data bus */ + outb_el2(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STP); + outb_el2(dep, DP_DCR, 0); + outb_el2(dep, DP_CR, CR_PS_P2 | CR_NO_DMA | CR_STP); + dep->de_16bit = (inb_el2(dep, DP_DCR) & DCR_WTS) != 0; + outb_el2(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STP); + + /* Allocate one send buffer (1.5kb) per 8kb of on board memory. */ + /* Only 8kb of 3c503/16 boards are used to avoid specific routines */ + sendq_nr = dep->de_ramsize / 0x2000; + if (sendq_nr < 1) + sendq_nr = 1; + else if (sendq_nr > SENDQ_NR) + sendq_nr = SENDQ_NR; + + dep->de_sendq_nr = sendq_nr; + for (ix = 0; ix < sendq_nr; ix++) + dep->de_sendq[ix].sq_sendpage = (ix * SENDQ_PAGES) + EL2_SM_START_PG; + + dep->de_startpage = (ix * SENDQ_PAGES) + EL2_SM_START_PG; + dep->de_stoppage = EL2_SM_STOP_PG; + + outb_el2(dep, EL2_STARTPG, dep->de_startpage); + outb_el2(dep, EL2_STOPPG, dep->de_stoppage); + + /* Point the vector pointer registers somewhere ?harmless?. */ + outb_el2(dep, EL2_VP2, 0xFF); /* Point at the ROM restart location */ + outb_el2(dep, EL2_VP1, 0xFF); /* 0xFFFF:0000 (from original sources) */ + outb_el2(dep, EL2_VP0, 0x00); /* - What for protected mode? */ + + /* Set interrupt level for 3c503 */ + irq = (dep->de_irq &= ~DEI_DEFAULT); /* Strip the default flag. */ + if (irq == 9) irq = 2; + if (irq < 2 || irq > 5) panic(dep->de_name, "bad 3c503 irq configuration", irq); + outb_el2(dep, EL2_IDCFG, (0x04 << irq)); + + outb_el2(dep, EL2_DRQCNT, 0x08); /* Set burst size to 8 */ + outb_el2(dep, EL2_DMAAH, EL2_SM_START_PG); /* Put start of TX */ + outb_el2(dep, EL2_DMAAL, 0x00); /* buffer in the GA DMA reg */ + + outb_el2(dep, EL2_CFGR, ECFGR_NORM); /* Enable shared memory */ + + ns_init(dep); /* Initialize DP controller */ + + printf("%s: Etherlink II%s (%s) at %X:%d:%05lX - ", + dep->de_name, dep->de_16bit ? "/16" : "", "3c503", + dep->de_base_port, dep->de_irq, + dep->de_linmem + dep->de_offset_page); + for (ix = 0; ix < SA_ADDR_LEN; ix += 1) + printf("%02X%c", dep->de_address.ea_addr[ix], + ix < SA_ADDR_LEN - 1 ? ':' : '\n'); + return; +} + +/* +** Name: void el2_stop(dpeth_t *dep); +** Function: Stops board by disabling interrupts. +*/ +static void el2_stop(dpeth_t * dep) +{ + + outb_el2(dep, EL2_CFGR, ECFGR_IRQOFF); + sys_irqdisable(&dep->de_hook); /* disable interrupts */ + return; +} + +/* +** Name: void el2_probe(dpeth_t *dep); +** Function: Probe for the presence of an EtherLink II card. +** Initialize memory addressing if card detected. +*/ +int el2_probe(dpeth_t * dep) +{ + int iobase, membase; + int thin; + + /* Thin ethernet or AUI? */ + thin = (dep->de_linmem & 1) ? ECNTR_AUI : ECNTR_THIN; + + /* Location registers should have 1 bit set */ + if (!(iobase = inb_el2(dep, EL2_IOBASE))) return FALSE; + if (!((membase = inb_el2(dep, EL2_MEMBASE)) & 0xF0)) return FALSE; + if ((iobase & (iobase - 1)) || (membase & (membase - 1))) return FALSE; + + /* Resets board */ + outb_el2(dep, EL2_CNTR, ECNTR_RESET | thin); + milli_delay(1); + outb_el2(dep, EL2_CNTR, thin); + milli_delay(5); + + /* Map the address PROM to lower I/O address range */ + outb_el2(dep, EL2_CNTR, ECNTR_SAPROM | thin); + if (inb_el2(dep, EL2_EA0) != 0x02 || /* Etherlink II Station address */ + inb_el2(dep, EL2_EA1) != 0x60 || /* MUST be 02:60:8c:xx:xx:xx */ + inb_el2(dep, EL2_EA2) != 0x8C) + return FALSE; /* No Etherlink board at this address */ + + /* Map the 8390 back to lower I/O address range */ + outb_el2(dep, EL2_CNTR, thin); + + /* Setup shared memory addressing for 3c503 */ + dep->de_linmem = ((membase & 0xC0) ? EL2_BASE_0D8000 : EL2_BASE_0C8000) + + ((membase & 0xA0) ? (EL2_BASE_0CC000 - EL2_BASE_0C8000) : 0x0000); + + /* Shared memory starts at 0x2000 (8kb window) */ + dep->de_offset_page = (EL2_SM_START_PG * DP_PAGESIZE); + dep->de_linmem -= dep->de_offset_page; + dep->de_ramsize = (EL2_SM_STOP_PG - EL2_SM_START_PG) * DP_PAGESIZE; + + /* Board initialization and stop functions */ + dep->de_initf = el2_init; + dep->de_stopf = el2_stop; + return TRUE; +} +#endif /* ENABLE_NETWORKING && ENABLE_3C503 */ + +/** 3c503.c **/ diff --git a/drivers/dpeth/3c503.h b/drivers/dpeth/3c503.h new file mode 100644 index 000000000..f0b89bc7c --- /dev/null +++ b/drivers/dpeth/3c503.h @@ -0,0 +1,72 @@ +/* +** File: 3c503.h Dec. 20, 1996 +** +** Author: Giovanni Falzoni +** +** Interface description for 3Com Etherlink II boards +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#define EL2_MEMTEST 0 /* Set to 1 for on board memory test */ + +#define EL2_GA 0x0400 /* Offset of registers in Gate Array */ + +/* EtherLink II card */ + +#define EL2_STARTPG (EL2_GA+0x00) /* Start page matching DP_PSTARTPG */ +#define EL2_STOPPG (EL2_GA+0x01) /* Stop page matching DP_PSTOPPG */ +#define EL2_DRQCNT (EL2_GA+0x02) /* DMA burst count */ +#define EL2_IOBASE (EL2_GA+0x03) /* I/O base jumpers (bit coded) */ +#define EL2_MEMBASE (EL2_GA+0x04) /* Memory base jumpers (bit coded) */ +#define EL2_CFGR (EL2_GA+0x05) /* Configuration Register for GA */ +#define EL2_CNTR (EL2_GA+0x06) /* Control(write) and status(read) */ +#define EL2_STATUS (EL2_GA+0x07) +#define EL2_IDCFG (EL2_GA+0x08) /* Interrupt/DMA configuration reg */ +#define EL2_DMAAH (EL2_GA+0x09) /* DMA address register (High byte) */ +#define EL2_DMAAL (EL2_GA+0x0A) /* DMA address register (Low byte) */ +#define EL2_VP2 (EL2_GA+0x0B) /* Vector pointer - set to */ +#define EL2_VP1 (EL2_GA+0x0C) /* reset address (0xFFFF:0) */ +#define EL2_VP0 (EL2_GA+0x0D) /* */ +#define EL2_FIFOH (EL2_GA+0x0E) /* FIFO for progr. I/O (High byte) */ +#define EL2_FIFOL (EL2_GA+0x0F) /* FIFO for progr. I/O (Low byte) */ + +#define EL2_EA0 0x00 /* Most significant byte of ethernet address */ +#define EL2_EA1 0x01 +#define EL2_EA2 0x02 +#define EL2_EA3 0x03 +#define EL2_EA4 0x04 +#define EL2_EA5 0x05 /* Least significant byte of ethernet address */ + +/* Bits in EL2_CNTR register */ +#define ECNTR_RESET 0x01 /* Software Reset */ +#define ECNTR_THIN 0x02 /* Onboard transceiver enable */ +#define ECNTR_AUI 0x00 /* Onboard transceiver disable */ +#define ECNTR_SAPROM 0x04 /* Map the station address prom */ + +/* Bits in EL2_CFGR register */ +#define ECFGR_NORM 0x49 /* Enable 8k shared memory, no DMA, TC int */ +#define ECFGR_IRQOFF 0xC9 /* As above, disable 8390 IRQ */ + +/* Shared memory management parameters */ +#define EL2_SM_START_PG 0x20 /* First page of TX buffer */ +#define EL2_SM_STOP_PG 0x40 /* Last page +1 of RX ring */ + +/* Physical addresses where an Etherlink board can be configured */ +#define EL2_BASE_0C8000 0x0C8000 +#define EL2_BASE_0CC000 0x0CC000 +#define EL2_BASE_0D8000 0x0D8000 +#define EL2_BASE_0DC000 0x0DC000 + +#define inb_el2(dep,reg) (inb((dep)->de_base_port+(reg))) +#define outb_el2(dep,reg,data) (outb((dep)->de_base_port+(reg),(data))) + +/** 3c503.h **/ diff --git a/drivers/dpeth/3c509.c b/drivers/dpeth/3c509.c new file mode 100644 index 000000000..d3a182c5d --- /dev/null +++ b/drivers/dpeth/3c509.c @@ -0,0 +1,603 @@ +/* +** File: 3c509.c Jun. 01, 2000 +** +** Author: Giovanni Falzoni +** +** 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 +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#include "drivers.h" +#include +#include +#include +#include + +#include "dp.h" + +#if ENABLE_NETWORKING == 1 && 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) { + outw_el3(dep, REG_CmdStatus, CMD_StopIntXcvr); + /* milli_delay(5); */ + + } else if (dep->de_if_port == TP_XCVR) { + SetWindow(WNO_Diagnostics); + outw_el3(dep, REG_MediaStatus, inw_el3(dep, REG_MediaStatus) & + NOT((MediaLBeatEnable | MediaJabberEnable))); + /* milli_delay(5); */ + } + DEBUG(printf("%s: stopping Etherlink ... \n", dep->de_name)); + /* Issues a global reset + outw_el3(dep, REG_CmdStatus, CMD_GlobalReset); */ + sys_irqdisable(&dep->de_hook); /* Disable interrupt */ + + return; +} + +/* +** Name: void el3_interrupt(dpeth_t *dep) +** Function: Interrupt handler. Acknwledges transmit interrupts +** or unloads receive buffer to memory queue. +*/ +static void el3_interrupt(dpeth_t * dep) +{ + int loop; + unsigned short isr; + + for (loop = 5; loop > 0 && ((isr = inw_el3(dep, REG_CmdStatus)) & + (INT_Latch | INT_RxComplete | INT_UpdateStats)); loop -= 1) { + + if (isr & INT_RxComplete) /* Got a new packet */ + el3_rx_complete(dep); + + if (isr & INT_TxAvailable) { /* Tx has room for big packets */ + DEBUG(printf("3c509: got Tx interrupt, Status=0x%04x\n", isr);) + dep->de_flags &= NOT(DEF_XMIT_BUSY); + outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | INT_TxAvailable); + if (dep->de_flags & DEF_SENDING) /* Send pending */ + el3_send(dep, TRUE, dep->de_send_s); + } + if (isr & (INT_AdapterFail | INT_RxEarly | INT_UpdateStats)) { + + if (isr & INT_UpdateStats) /* Empties statistics */ + el3_getstats(dep); + + if (isr & INT_RxEarly) /* Not really used. Do nothing */ + outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | (INT_RxEarly)); + + if (isr & INT_AdapterFail) { + /* Adapter error. Reset and re-enable receiver */ + DEBUG(printf("3c509: got Rx fail interrupt, Status=0x%04x\n", isr);) + el3_rx_mode(dep); + outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | INT_AdapterFail); + } + } + + /* Acknowledge interrupt */ + outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | (INT_Latch | INT_Requested)); + } + return; +} + +/* +** Name: unsigned el3_read_eeprom(port_t port, unsigned address); +** Function: Reads the EEPROM at specified address +*/ +static unsigned el3_read_eeprom(port_t port, unsigned address) +{ + unsigned int result; + int bit; + + address |= EL3_READ_EEPROM; + outb(port, address); + milli_delay(5); /* Allows EEPROM reads */ + for (result = 0, bit = 16; bit > 0; bit -= 1) { + result = (result << 1) | (inb(port) & 0x0001); + } + return result; +} + +/* +** Name: void el3_read_StationAddress(dpeth_t *dep) +** Function: Reads station address from board +*/ +static void el3_read_StationAddress(dpeth_t * dep) +{ + unsigned int ix, rc; + + for (ix = EE_3COM_NODE_ADDR; ix < SA_ADDR_LEN;) { + /* Accesses with word No. */ + rc = el3_read_eeprom(dep->de_id_port, ix / 2); + /* Swaps bytes of word */ + dep->de_address.ea_addr[ix++] = (rc >> 8) & 0xFF; + dep->de_address.ea_addr[ix++] = rc & 0xFF; + } + return; +} + +/* +** Name: void el3_open(dpeth_t *dep) +** Function: Initalizes board hardware and driver data structures. +*/ +static void el3_open(dpeth_t * dep) +{ + unsigned int AddrCfgReg, ResCfgReg; + unsigned int ix; + + el3_read_StationAddress(dep); /* Get ethernet address */ + + /* Get address and resource configurations */ + AddrCfgReg = el3_read_eeprom(dep->de_id_port, EE_ADDR_CFG); + ResCfgReg = el3_read_eeprom(dep->de_id_port, EE_RESOURCE_CFG); + outb(dep->de_id_port, EL3_ACTIVATE); /* Activate the board */ + + /* Gets xcvr configuration */ + dep->de_if_port = AddrCfgReg & EL3_CONFIG_XCVR_MASK; + + AddrCfgReg = ((AddrCfgReg & EL3_CONFIG_IOBASE_MASK) << 4) + EL3_IO_BASE_ADDR; + if (AddrCfgReg != dep->de_base_port) + panic(dep->de_name, "Bad I/O port for Etherlink board", NO_NUM); + + ResCfgReg >>= 12; + dep->de_irq &= NOT(DEI_DEFAULT); /* Strips the default flag */ + if (ResCfgReg != dep->de_irq) panic(dep->de_name, "Bad IRQ for Etherlink board", NO_NUM); + + SetWindow(WNO_Setup); + + /* Reset transmitter and receiver */ + outw_el3(dep, REG_CmdStatus, CMD_TxReset); + outw_el3(dep, REG_CmdStatus, CMD_RxReset); + + /* Enable the adapter */ + outb_el3(dep, REG_CfgControl, EL3_EnableAdapter); + /* Disable Status bits */ + outw_el3(dep, REG_CmdStatus, CMD_SetStatusEnab + 0x00); + + /* Set "my own" address */ + SetWindow(WNO_StationAddress); + for (ix = 0; ix < 6; ix += 1) + outb_el3(dep, REG_SA0_1 + ix, dep->de_address.ea_addr[ix]); + + /* Start Transceivers as required */ + if (dep->de_if_port == BNC_XCVR) { + /* Start internal transceiver for Coaxial cable */ + outw_el3(dep, REG_CmdStatus, CMD_StartIntXcvr); + milli_delay(5); + + } else if (dep->de_if_port == TP_XCVR) { + /* Start internal transceiver for Twisted pair cable */ + SetWindow(WNO_Diagnostics); + outw_el3(dep, REG_MediaStatus, + inw_el3(dep, REG_MediaStatus) | (MediaLBeatEnable | MediaJabberEnable)); + } + + /* Switch to the statistic window, and clear counts (by reading) */ + SetWindow(WNO_Statistics); + for (ix = REG_TxCarrierLost; ix <= REG_TxDefer; ix += 1) inb_el3(dep, ix); + inw_el3(dep, REG_RxBytes); + inw_el3(dep, REG_TxBytes); + + /* Switch to operating window for normal use */ + SetWindow(WNO_Operating); + + /* Receive individual address & broadcast. (Mofified later by rx_mode) */ + outw_el3(dep, REG_CmdStatus, CMD_SetRxFilter | + (FilterIndividual | FilterBroadcast)); + + /* Turn on statistics */ + outw_el3(dep, REG_CmdStatus, CMD_StatsEnable); + + /* Enable transmitter and receiver */ + outw_el3(dep, REG_CmdStatus, CMD_TxEnable); + outw_el3(dep, REG_CmdStatus, CMD_RxEnable); + + /* Enable all the status bits */ + outw_el3(dep, REG_CmdStatus, CMD_SetStatusEnab | 0xFF); + + /* Acknowledge all interrupts to clear adapter. Enable interrupts */ + outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | 0xFF); + outw_el3(dep, REG_CmdStatus, CMD_SetIntMask | + (INT_Latch | INT_TxAvailable | INT_RxComplete | INT_UpdateStats)); + + /* Ready to operate, sets the environment for eth_task */ + dep->de_data_port = dep->de_base_port; + /* Allocates Rx/Tx buffers */ + init_buff(dep, NULL); + + /* Device specific functions */ + dep->de_recvf = el3_recv; + dep->de_sendf = el3_send; + dep->de_flagsf = el3_rx_mode; + dep->de_resetf = el3_reset; + dep->de_getstatsf = el3_getstats; + dep->de_dumpstatsf = el3_dodump; + dep->de_interruptf = el3_interrupt; + + printf("%s: Etherlink III (%s) at %X:%d, %s port - ", + dep->de_name, "3c509", dep->de_base_port, dep->de_irq, + IfNamesMsg[dep->de_if_port >> 14]); + for (ix = 0; ix < SA_ADDR_LEN; ix += 1) + printf("%02X%c", dep->de_address.ea_addr[ix], + ix < SA_ADDR_LEN - 1 ? ':' : '\n'); + + return; /* Done */ +} + +/* +** Name: unsigned int el3_checksum(port_t port); +** Function: Reads EEPROM and computes checksum. +*/ +static unsigned short el3_checksum(port_t port) +{ + unsigned short rc, checksum, address; + unsigned char lo, hi; + + for (checksum = address = 0; address < 15; address += 1) { + rc = el3_read_eeprom(port, address); + lo = rc & 0xFF; + hi = (rc >> 8) & 0xFF; + if ((address == EE_PROD_ID && (rc & EE_PROD_ID_MASK) != EL3_PRODUCT_ID) || + (address == EE_3COM_CODE && rc != EL3_3COM_CODE)) + return address; + if (address == EE_ADDR_CFG || + address == EE_RESOURCE_CFG || + address == EE_SW_CONFIG_INFO) { + lo ^= hi; + hi = 0; + } else { + hi ^= lo; + lo = 0; + } + rc = ((unsigned) hi << 8) + lo; + checksum ^= rc; + } + rc = el3_read_eeprom(port, address); + return(checksum ^= rc); /* If OK checksum is 0 */ +} + +/* +** Name: void el3_write_id(port_t port); +** Function: Writes the ID sequence to the board. +*/ +static void el3_write_id(port_t port) +{ + int ix, pattern; + + outb(port, 0); /* Selects the ID port */ + outb(port, 0); /* Resets hardware pattern generator */ + for (pattern = ix = 0x00FF; ix > 0; ix -= 1) { + outb(port, pattern); + pattern <<= 1; + pattern = (pattern & 0x0100) ? pattern ^ 0xCF : pattern; + } + return; +} + +/* +** Name: int el3_probe(dpeth_t *dep) +** Function: Checks for presence of the board. +*/ +PUBLIC int el3_probe(dpeth_t * dep) +{ + port_t id_port; + + /* Don't ask me what is this for !! */ + outb(0x0279, 0x02); /* Select PnP config control register. */ + outb(0x0A79, 0x02); /* Return to WaitForKey state. */ + /* Tests I/O ports in the 0x1xF range for a valid ID port */ + for (id_port = 0x110; id_port < 0x200; id_port += 0x10) { + outb(id_port, 0x00); + outb(id_port, 0xFF); + if (inb(id_port) & 0x01) break; + } + if (id_port == 0x200) return 0; /* No board responding */ + + el3_write_id(id_port); + outb(id_port, EL3_ID_GLOBAL_RESET); /* Reset the board */ + milli_delay(5); /* Technical reference says 162 micro sec. */ + el3_write_id(id_port); + outb(id_port, EL3_SET_TAG_REGISTER); + milli_delay(5); + + dep->de_id_port = id_port; /* Stores ID port No. */ + dep->de_ramsize = /* RAM size is meaningless */ + dep->de_offset_page = 0; + dep->de_linmem = 0L; /* Access is via I/O port */ + + /* Device specific functions */ + dep->de_initf = el3_open; + dep->de_stopf = el3_close; + + return(el3_checksum(id_port) == 0); /* Etherlink board found/not found */ +} + +#endif /* ENABLE_NETWORKING */ + +/** 3c509.c **/ diff --git a/drivers/dpeth/3c509.h b/drivers/dpeth/3c509.h new file mode 100644 index 000000000..bcbdba605 --- /dev/null +++ b/drivers/dpeth/3c509.h @@ -0,0 +1,164 @@ +/* +** File: 3c509.h Jun. 01, 2000 +** +** Author: Giovanni Falzoni +** +** Interface description for 3Com Etherlink III board. +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +/* Command codes */ +#define CMD_GlobalReset 0x0000 /* resets adapter (power up status) */ +#define CMD_SelectWindow (1<<11) /* select register window */ +#define CMD_StartIntXcvr (2<<11) /* start internal transciver */ +#define CMD_RxDisable (3<<11) /* rx disable */ +#define CMD_RxEnable (4<<11) /* rx enable */ +#define CMD_RxReset (5<<11) /* rx reset */ +#define CMD_RxDiscard (8<<11) /* rx discard top packet */ +#define CMD_TxEnable (9<<11) /* tx enable */ +#define CMD_TxDisable (10<<11) /* tx disable */ +#define CMD_TxReset (11<<11) /* tx reset */ +#define CMD_Acknowledge (13<<11) /* acknowledge interrupt */ +#define CMD_SetIntMask (14<<11) /* set interrupt mask */ +#define CMD_SetStatusEnab (15<<11) /* set read zero mask */ +#define CMD_SetRxFilter (16<<11) /* set rx filter */ +#define CMD_SetTxAvailable (18<<11) /* set tx available threshold */ +#define CMD_StatsEnable (21<<11) /* statistics enable */ +#define CMD_StatsDisable (22<<11) /* statistics disable */ +#define CMD_StopIntXcvr (23<<11) /* start internal transciver */ + +/* Status register bits (INT for interrupt sources, ST for the rest) */ +#define INT_Latch 0x0001 /* interrupt latch */ +#define INT_AdapterFail 0x0002 /* adapter failure */ +#define INT_TxComplete 0x0004 /* tx complete */ +#define INT_TxAvailable 0x0008 /* tx available */ +#define INT_RxComplete 0x0010 /* rx complete */ +#define INT_RxEarly 0x0020 /* rx early */ +#define INT_Requested 0x0040 /* interrupt requested */ +#define INT_UpdateStats 0x0080 /* update statistics */ + +/* Rx Status register bits */ +#define RXS_Error 0x4000 /* error in packet */ +#define RXS_Length 0x07FF /* bytes in RxFIFO */ +#define RXS_ErrType 0x3800 /* Rx error type, bit 13-11 */ +#define RXS_Overrun 0x0000 /* overrun error */ +#define RXS_Oversize 0x0800 /* oversize packet error */ +#define RXS_Dribble 0x1000 /* dribble bit (not an error) */ +#define RXS_Runt 0x1800 /* runt packet error */ +#define RXS_Framing 0x2000 /* framing error */ +#define RXS_CRC 0x2800 /* CRC error */ + +/* Tx Status register bits */ + +/* Window Numbers */ +#define WNO_Setup 0x0000 /* setup/configuration */ +#define WNO_Operating 0x0001 /* operating set */ +#define WNO_StationAddress 0x0002 /* station address setup/read */ +#define WNO_Diagnostics 0x0004 /* diagnostics */ +#define WNO_Statistics 0x0006 /* statistics */ + +/* Register offsets - Window 1 (WNO_Operating) */ +#define REG_CmdStatus 0x000E /* command/status */ +#define REG_TxFree 0x000C /* free transmit bytes */ +#define REG_TxStatus 0x000B /* transmit status (byte) */ +#define REG_RxStatus 0x0008 /* receive status */ +#define REG_RxFIFO 0x0000 /* RxFIFO read */ +#define REG_TxFIFO 0x0000 /* TxFIFO write */ + +/* Register offsets - Window 0 (WNO_Setup) */ +#define REG_CfgControl 0x0004 /* configuration control */ + +/* Register offsets - Window 2 (WNO_StationAddress) */ +#define REG_SA0_1 0x0000 /* station address bytes 0,1 */ + +/* Register offsets - Window 3 (WNO_FIFO) */ + +/* Register offsets - Window 4 (WNO_Diagnostics) */ +#define REG_MediaStatus 0x000A /* media type/status */ + +/* Register offsets - Window 5 (WNO_Readable) */ + +/* Register offsets - Window 6 (WNO_Statistics) */ +#define REG_TxBytes 0x000C /* tx bytes ok */ +#define REG_RxBytes 0x000A /* rx bytes ok */ +#define REG_TxDefer 0x0008 /* tx frames deferred (byte) */ +#define REG_RxFrames 0x0007 /* rx frames ok (byte) */ +#define REG_TxFrames 0x0006 /* tx frames ok (byte) */ +#define REG_RxDiscarded 0x0005 /* rx frames discarded (byte) */ +#define REG_TxLate 0x0004 /* tx frames late coll. (byte) */ +#define REG_TxSingleColl 0x0003 /* tx frames one coll. (byte) */ +#define REG_TxMultColl 0x0002 /* tx frames mult. coll. (byte) */ +#define REG_TxNoCD 0x0001 /* tx frames no CDheartbt (byte) */ +#define REG_TxCarrierLost 0x0000 /* tx frames carrier lost (byte) */ + +/* Various command arguments */ + +#define FilterIndividual 0x0001 /* individual address */ +#define FilterMulticast 0x0002 /* multicast/group addresses */ +#define FilterBroadcast 0x0004 /* broadcast address */ +#define FilterPromiscuous 0x0008 /* promiscuous mode */ + +/* Resource Configuration Register bits */ +#define EL3_CONFIG_IRQ_MASK 0xF000 + +/* Address Configuration Register bits */ +#define EL3_CONFIG_XCVR_MASK 0xC000 +#define EL3_CONFIG_IOBASE_MASK 0x001F + +#define TP_XCVR 0x0000 +#define BNC_XCVR 0xC000 +#define AUI_XCVR 0x4000 + +#define EL3_IO_BASE_ADDR 0x200 + +/* Transmit Preamble */ + +/* Bits in various diagnostics registers */ +#define MediaLBeatEnable 0x0080 /* link beat enable (TP) */ +#define MediaJabberEnable 0x0040 /* jabber enable (TP) */ + +/* Board identification codes, byte swapped in Rev 0 */ +#define EL3_3COM_CODE 0x6D50 /* EISA manufacturer code */ +#define EL3_PRODUCT_ID 0x9050 /* Product ID for ISA board */ + +/* EEProm access */ +#define EE_3COM_NODE_ADDR 0x00 +#define EE_PROD_ID 0x03 +#define EE_MANUFACTURING_DATA 0x04 +#define EE_3COM_CODE 0x07 +#define EE_ADDR_CFG 0x08 +#define EE_RESOURCE_CFG 0x09 +#define EE_SW_CONFIG_INFO 0x0D +#define EE_PROD_ID_MASK 0xF0FF /* Mask off revision nibble */ + +/* Contention logic */ +#define EL3_READ_EEPROM 0x80 +#define EL3_ID_GLOBAL_RESET 0xC0 +#define EL3_SET_TAG_REGISTER 0xD0 +#define EL3_ACTIVATE_AND_SET_IO 0xE0 +#define EL3_ACTIVATE 0xFF + +/* Software Configuration Register bits */ + +/* Configuration Control Register bits */ +#define EL3_EnableAdapter 0x01 + +/* EL3 access macros */ +#define inb_el3(dep,reg) (inb((dep)->de_base_port+(reg))) +#define inw_el3(dep,reg) (inw((dep)->de_base_port+(reg))) +#define outb_el3(dep,reg,data) (outb((dep)->de_base_port+(reg),(data))) +#define outw_el3(dep,reg,data) (outw((dep)->de_base_port+(reg),(data))) + +#define SetWindow(win) \ + outw(dep->de_base_port+REG_CmdStatus,CMD_SelectWindow|(win)) + +/** 3c509.h **/ diff --git a/drivers/dpeth/8390.c b/drivers/dpeth/8390.c new file mode 100644 index 000000000..8c7231a3a --- /dev/null +++ b/drivers/dpeth/8390.c @@ -0,0 +1,739 @@ +/* +** File: 8390.c May 02, 2000 +** +** Author: Giovanni Falzoni +** +** This file contains an ethernet device driver for NICs +** equipped with the National Semiconductor NS 8390 chip. +** It has to be associated with the board specific driver. +** Rewritten from Minix 2.0.0 ethernet driver dp8390.c +** to extract the NS 8390 common functions. +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#include "drivers.h" +#include +#include +#include +#include +#include "dp.h" + +#if (ENABLE_NETWORKING == 1 && ENABLE_DP8390 == 1) + +#define PIO16 0 /* NOTE: pio 16 functions missing */ + +#include "8390.h" + +static const char RdmaErrMsg[] = "remote dma failed to complete"; + +/* +** Name: void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset); +** Function: Sets the board for reading/writing. +*/ +static void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset) +{ + + if (mode == CR_DM_RW) outb_reg0(dep, DP_ISR, ISR_RDC); + outb_reg0(dep, DP_RBCR0, size & 0xFF); + outb_reg0(dep, DP_RBCR1, (size >> 8) & 0xFF); + outb_reg0(dep, DP_RSAR0, offset & 0xFF); + outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF); + mode |= (CR_PS_P0 | CR_STA); + outb_reg0(dep, DP_CR, mode); + return; +} + +/* +** Name: void ns_start_xmit(dpeth_t *dep, int size, int pageno); +** Function: Sets the board for for transmitting and fires it. +*/ +static void ns_start_xmit(dpeth_t * dep, int size, int pageno) +{ + + outb_reg0(dep, DP_TPSR, pageno); + outb_reg0(dep, DP_TBCR1, size >> 8); + outb_reg0(dep, DP_TBCR0, size & 0xFF); + outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */ + return; +} + +/* +** Name: void mem_getblock(dpeth_t *dep, u16_t offset, +** int size, void *dst) +** Function: Reads a block of packet from board (shared memory). +*/ +static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst) +{ + + sys_datacopy(dep->de_memsegm, dep->de_linmem + offset, + SELF, (vir_bytes)dst, size); + return; +} + +/* +** Name: void mem_nic2user(dpeth_t *dep, int pageno, int pktsize); +** Function: Copies a packet from board to user area (shared memory). +*/ +static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize) +{ + phys_bytes offset, phys_user; + iovec_dat_t *iovp = &dep->de_read_iovec; + int bytes, ix = 0; + + /* Computes shared memory address (skipping receive header) */ + offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t); + + do { /* Reads chuncks of packet into user area */ + + bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */ + if (bytes > pktsize) bytes = pktsize; + + /* Reads from board to user area */ + if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) { + + /* Circular buffer wrap-around */ + bytes = dep->de_stoppage * DP_PAGESIZE - offset; + sys_datacopy(dep->de_memsegm, dep->de_linmem + offset, + iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes); + pktsize -= bytes; + phys_user += bytes; + bytes = iovp->iod_iovec[ix].iov_size - bytes; + if (bytes > pktsize) bytes = pktsize; + offset = dep->de_startpage * DP_PAGESIZE; + } + sys_datacopy(dep->de_memsegm, dep->de_linmem + offset, + iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes); + offset += bytes; + + if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ + dp_next_iovec(iovp); + ix = 0; + } + /* Till packet done */ + } while ((pktsize -= bytes) > 0); + return; +} + +/* +** Name: void mem_user2nic(dpeth_t *dep, int pageno, int pktsize) +** Function: Copies a packet from user area to board (shared memory). +*/ +static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize) +{ + phys_bytes offset, phys_user; + iovec_dat_t *iovp = &dep->de_write_iovec; + int bytes, ix = 0; + + /* Computes shared memory address */ + offset = dep->de_linmem + pageno * DP_PAGESIZE; + + do { /* Reads chuncks of packet from user area */ + + bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */ + if (bytes > pktsize) bytes = pktsize; + + /* Reads from user area to board (shared memory) */ + sys_datacopy(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, + dep->de_memsegm, dep->de_linmem + offset, bytes); + offset += bytes; + + if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ + dp_next_iovec(iovp); + ix = 0; + } + /* Till packet done */ + } while ((pktsize -= bytes) > 0); + return; +} + +/* +** Name: void pio_getblock(dpeth_t *dep, u16_t offset, +** int size, void *dst) +** Function: Reads a block of packet from board (Prog. I/O). +*/ +static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst) +{ + + /* Sets up board for reading */ + ns_rw_setup(dep, CR_DM_RR, size, offset); + +#if PIO16 == 0 + insb(dep->de_data_port, SELF, dst, size); +#else + if (dep->de_16bit == TRUE) { + insw(dep->de_data_port, dst, size); + } else { + insb(dep->de_data_port, dst, size); + } +#endif + return; +} + +/* +** Name: void pio_nic2user(dpeth_t *dep, int pageno, int pktsize) +** Function: Copies a packet from board to user area (Prog. I/O). +*/ +static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize) +{ + phys_bytes phys_user; + iovec_dat_t *iovp = &dep->de_read_iovec; + unsigned offset; int bytes, ix = 0; + + /* Computes memory address (skipping receive header) */ + offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t); + /* Sets up board for reading */ + ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ? + (dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset); + + do { /* Reads chuncks of packet into user area */ + + bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */ + if (bytes > pktsize) bytes = pktsize; + + if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) { + + /* Circular buffer wrap-around */ + bytes = dep->de_stoppage * DP_PAGESIZE - offset; + insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes); + pktsize -= bytes; + iovp->iod_iovec[ix].iov_addr += bytes; + bytes = iovp->iod_iovec[ix].iov_size - bytes; + if (bytes > pktsize) bytes = pktsize; + offset = dep->de_startpage * DP_PAGESIZE; + ns_rw_setup(dep, CR_DM_RR, pktsize, offset); + } + insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes); + offset += bytes; + + if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ + dp_next_iovec(iovp); + ix = 0; + } + /* Till packet done */ + } while ((pktsize -= bytes) > 0); + return; +} + +/* +** Name: void pio_user2nic(dpeth_t *dep, int pageno, int pktsize) +** Function: Copies a packet from user area to board (Prog. I/O). +*/ +static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize) +{ + phys_bytes phys_user; + iovec_dat_t *iovp = &dep->de_write_iovec; + int bytes, ix = 0; + + /* Sets up board for writing */ + ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE); + + do { /* Reads chuncks of packet from user area */ + + bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */ + if (bytes > pktsize) bytes = pktsize; + outsb(dep->de_data_port, iovp->iod_proc_nr, + (void*)(iovp->iod_iovec[ix].iov_addr), bytes); + + if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */ + dp_next_iovec(iovp); + ix = 0; + } + /* Till packet done */ + } while ((pktsize -= bytes) > 0); + + for (ix = 0; ix < 100; ix += 1) { + if (inb_reg0(dep, DP_ISR) & ISR_RDC) break; + } + if (ix == 100) { + panic(dep->de_name, RdmaErrMsg, NO_NUM); + } + return; +} + +/* +** Name: void ns_stats(dpeth_t * dep) +** Function: Updates counters reading from device +*/ +static void ns_stats(dpeth_t * dep) +{ + + dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0); + dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1); + dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2); + return; +} + +/* +** Name: void ns_dodump(dpeth_t * dep) +** Function: Displays statistics (a request from F5 key). +*/ +static void ns_dodump(dpeth_t * dep) +{ + + ns_stats(dep); /* Forces reading fo counters from board */ + return; +} + +/* +** Name: void ns_reinit(dpeth_t *dep) +** Function: Updates receiver configuration. +*/ +static void ns_reinit(dpeth_t * dep) +{ + int dp_reg = 0; + + if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM; + if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB; + if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM; + outb_reg0(dep, DP_CR, CR_PS_P0); + outb_reg0(dep, DP_RCR, dp_reg); + return; +} + +/* +** Name: void ns_send(dpeth_t * dep, int from_int, int size) +** Function: Transfers packet to device and starts sending. +*/ +static void ns_send(dpeth_t * dep, int from_int, int size) +{ + int queue; + + if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) { + if (from_int) panic(dep->de_name, "should not be sending ", NO_NUM); + dep->de_send_s = size; + return; + } + (dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size); + dep->bytes_Tx += (long) size; + dep->de_sendq[queue].sq_filled = TRUE; + dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND); + if (dep->de_sendq_tail == queue) { /* there it goes.. */ + ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage); + } else + dep->de_sendq[queue].sq_size = size; + + if (++queue == dep->de_sendq_nr) queue = 0; + dep->de_sendq_head = queue; + dep->de_flags &= NOT(DEF_SENDING); + + return; +} + +/* +** Name: void ns_reset(dpeth_t *dep) +** Function: Resets device. +*/ +static void ns_reset(dpeth_t * dep) +{ + int ix; + + /* Stop chip */ + outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA); + outb_reg0(dep, DP_RBCR0, 0); + outb_reg0(dep, DP_RBCR1, 0); + for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1) + /* Do nothing */ ; + outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST); + outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); + outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST); + + /* Acknowledge the ISR_RDC (remote dma) interrupt. */ + for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1) + /* Do nothing */ ; + outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC)); + + /* Reset the transmit ring. If we were transmitting a packet, we + * pretend that the packet is processed. Higher layers will + * retransmit if the packet wasn't actually sent. */ + dep->de_sendq_head = dep->de_sendq_tail = 0; + for (ix = 0; ix < dep->de_sendq_nr; ix++) + dep->de_sendq[ix].sq_filled = FALSE; + ns_send(dep, TRUE, dep->de_send_s); + return; +} + +/* +** Name: void ns_recv(dpeth_t *dep, int fromint, int size) +** Function: Gets a packet from device +*/ +static void ns_recv(dpeth_t *dep, int fromint, int size) +{ + dp_rcvhdr_t header; + dp_rcvhdr_t dummy; + unsigned pageno, curr, next; + vir_bytes length; + int packet_processed = FALSE; +#ifdef ETH_IGN_PROTO + u16_t eth_type; +#endif + + pageno = inb_reg0(dep, DP_BNRY) + 1; + if (pageno == dep->de_stoppage) pageno = dep->de_startpage; + + do { + /* */ + outb_reg0(dep, DP_CR, CR_PS_P1); + curr = inb_reg1(dep, DP_CURR); + outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA); + + if (curr == pageno) break; + + (dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header); +#ifdef ETH_IGN_PROTO + (dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), ð_type); +#endif + length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t); + next = header.dr_next; + + if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) { + printf("%s: packet with strange length arrived: %d\n", dep->de_name, length); + dep->de_stat.ets_recvErr += 1; + next = curr; + + } else if (next < dep->de_startpage || next >= dep->de_stoppage) { + printf("%s: strange next page\n", dep->de_name); + dep->de_stat.ets_recvErr += 1; + next = curr; + +#ifdef ETH_IGN_PROTO + } else if (eth_type == eth_ign_proto) { + /* Hack: ignore packets of a given protocol */ + static int first = TRUE; + if (first) { + first = FALSE; + printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto)); + } + next = curr; +#endif + } else if (header.dr_status & RSR_FO) { + /* This is very serious, issue a warning and reset buffers */ + printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name); + dep->de_stat.ets_fifoOver += 1; + next = curr; + + } else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) { + + if (!(dep->de_flags & DEF_READING)) break; + + (dep->de_nic2userf) (dep, pageno, length); + dep->de_read_s = length; + dep->de_flags |= DEF_ACK_RECV; + dep->de_flags &= NOT(DEF_READING); + packet_processed = TRUE; + } + dep->bytes_Rx += (long) length; + dep->de_stat.ets_packetR += 1; + outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1); + pageno = next; + + } while (!packet_processed); +#if 0 + if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) + /* The chip is stopped, and all arrived packets delivered */ + (*dep->de_resetf) (dep); + dep->de_flags &= NOT(DEF_STOPPED); +#endif + return; +} + +/* +** Name: void ns_interrupt(dpeth_t * dep) +** Function: Handles interrupt. +*/ +static void ns_interrupt(dpeth_t * dep) +{ + int isr, tsr; + int size, queue; + + while ((isr = inb_reg0(dep, DP_ISR)) != 0) { + + outb_reg0(dep, DP_ISR, isr); + if (isr & (ISR_PTX | ISR_TXE)) { + + tsr = inb_reg0(dep, DP_TSR); + if (tsr & TSR_PTX) { + dep->de_stat.ets_packetT++; + } + if (tsr & TSR_COL) dep->de_stat.ets_collision++; + if (tsr & (TSR_ABT | TSR_FU)) { + dep->de_stat.ets_fifoUnder++; + } + if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) { + printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr); + dep->de_stat.ets_sendErr++; + } + queue = dep->de_sendq_tail; + + if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */ + printf("%s: transmit interrupt, but not sending\n", dep->de_name); + continue; + } + dep->de_sendq[queue].sq_filled = FALSE; + if (++queue == dep->de_sendq_nr) queue = 0; + dep->de_sendq_tail = queue; + if (dep->de_sendq[queue].sq_filled) { + ns_start_xmit(dep, dep->de_sendq[queue].sq_size, + dep->de_sendq[queue].sq_sendpage); + } + if (dep->de_flags & DEF_SENDING) { + ns_send(dep, TRUE, dep->de_send_s); + } + } + if (isr & ISR_PRX) { + ns_recv(dep, TRUE, 0); + } + if (isr & ISR_RXE) { + printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR)); + dep->de_stat.ets_recvErr++; + } + if (isr & ISR_CNT) { + dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0); + dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1); + dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2); + } + if (isr & ISR_OVW) { + printf("%s: got overwrite warning\n", dep->de_name); + } + if (isr & ISR_RDC) { + /* Nothing to do */ + } + if (isr & ISR_RST) { + /* This means we got an interrupt but the ethernet + * chip is shutdown. We set the flag DEF_STOPPED, and + * continue processing arrived packets. When the + * receive buffer is empty, we reset the dp8390. */ + printf("%s: network interface stopped\n", dep->de_name); + dep->de_flags |= DEF_STOPPED; + break; + } + } + if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) { + + /* The chip is stopped, and all arrived packets delivered */ + ns_reset(dep); + dep->de_flags &= NOT(DEF_STOPPED); + } + return; +} + +/* +** Name: void ns_init(dpeth_t *dep) +** Function: Initializes the NS 8390 +*/ +void ns_init(dpeth_t * dep) +{ + int dp_reg; + int ix; + + /* NS8390 initialization (as recommended in National Semiconductor specs) */ + outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */ +#if PIO16 == 0 + outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS)); +#else + outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) | + DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS)); +#endif + outb_reg0(dep, DP_RBCR0, 0); + outb_reg0(dep, DP_RBCR1, 0); + outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */ + outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Sets Loopback mode 1 */ + outb_reg0(dep, DP_PSTART, dep->de_startpage); + outb_reg0(dep, DP_PSTOP, dep->de_stoppage); + outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1); + outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */ + outb_reg0(dep, DP_IMR, 0); /* Clears Interrupt Mask Register */ + + /* Copies station address in page 1 registers */ + outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA); /* Selects Page 1 */ + for (ix = 0; ix < SA_ADDR_LEN; ix += 1) /* Initializes address */ + outb_reg1(dep, DP_PAR0 + ix, dep->de_address.ea_addr[ix]); + for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1) /* Initializes address */ + outb_reg1(dep, ix, 0xFF); + + outb_reg1(dep, DP_CURR, dep->de_startpage); + outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA); /* Selects Page 0 */ + + inb_reg0(dep, DP_CNTR0); /* Resets counters by reading them */ + inb_reg0(dep, DP_CNTR1); + inb_reg0(dep, DP_CNTR2); + + dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE; + outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */ + outb_reg0(dep, DP_IMR, dp_reg); /* Sets Interrupt Mask register */ + + dp_reg = 0; + if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM; + if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB; + if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM; + outb_reg0(dep, DP_RCR, dp_reg); /* Sets receive as requested */ + outb_reg0(dep, DP_TCR, TCR_NORMAL); /* Sets transmitter */ + + outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); /* Starts board */ + + /* Initializes the send queue. */ + for (ix = 0; ix < dep->de_sendq_nr; ix += 1) + dep->de_sendq[ix].sq_filled = 0; + dep->de_sendq_head = dep->de_sendq_tail = 0; + + /* Device specific functions */ + if (!dep->de_prog_IO) { + dep->de_user2nicf = mem_user2nic; + dep->de_nic2userf = mem_nic2user; + dep->de_getblockf = mem_getblock; + } else { +#if PIO16 == 0 + dep->de_user2nicf = pio_user2nic; + dep->de_nic2userf = pio_nic2user; + dep->de_getblockf = pio_getblock; +#else +#error Missing I/O functions for pio 16 bits +#endif + } + dep->de_recvf = ns_recv; + dep->de_sendf = ns_send; + dep->de_flagsf = ns_reinit; + dep->de_resetf = ns_reset; + dep->de_getstatsf = ns_stats; + dep->de_dumpstatsf = ns_dodump; + dep->de_interruptf = ns_interrupt; + + return; /* Done */ +} + +#if PIO16 == 1 + +/* +** Name: void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize) +** Function: Copies a packet from user area to board (Prog. I/O, 16bits). +*/ +static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize) +{ + u8_t two_bytes[2]; + phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes); + vir_bytes ecount = (pktsize + 1) & NOT(0x0001); + int bytes, ix = 0, odd_byte = 0; + iovec_dat_t *iovp = &dep->de_write_iovec; + + outb_reg0(dep, DP_ISR, ISR_RDC); + dp_read_setup(dep, ecount, pageno * DP_PAGESIZE); + + do { + bytes = iovp->iod_iovec[ix].iov_size; + if (bytes > pktsize) bytes = pktsize; + + phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes); + if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM); + + if (odd_byte) { + phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1); + out_word(dep->de_data_port, *(u16_t *)two_bytes); + pktsize--; + bytes--; + phys_user++; + odd_byte = 0; + if (!bytes) continue; + } + ecount = bytes & NOT(0x0001); + if (ecount != 0) { + phys_outsw(dep->de_data_port, phys_user, ecount); + pktsize -= ecount; + bytes -= ecount; + phys_user += ecount; + } + if (bytes) { + phys_copy(phys_user, phys_2bytes, (phys_bytes) 1); + pktsize--; + bytes--; + phys_user++; + odd_byte = 1; + } + if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */ + dp_next_iovec(iovp); + ix = 0; + } + + } while (bytes > 0); + + if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes); + for (ix = 0; ix < 100; ix++) { + if (inb_reg0(dep, DP_ISR) & ISR_RDC) break; + } + if (ix == 100) { + panic(dep->de_name, RdmaErrMsg, NO_NUM); + } + return; +} + +/* +** Name: void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize) +** Function: Copies a packet from board to user area (Prog. I/O, 16bits). +*/ +static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count) +{ + phys_bytes phys_user; + vir_bytes ecount; + int bytes, i; + u8_t two_bytes[2]; + phys_bytes phys_2bytes; + int odd_byte; + + ecount = (count + 1) & ~1; + phys_2bytes = vir2phys(two_bytes); + odd_byte = 0; + + dp_read_setup(dep, ecount, nic_addr); + + i = 0; + while (count > 0) { + if (i >= IOVEC_NR) { + dp_next_iovec(iovp); + i = 0; + continue; + } + bytes = iovp->iod_iovec[i].iov_size; + if (bytes > count) bytes = count; + + phys_user = numap(iovp->iod_proc_nr, + iovp->iod_iovec[i].iov_addr, bytes); + if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM); + if (odd_byte) { + phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1); + count--; + bytes--; + phys_user++; + odd_byte = 0; + if (!bytes) continue; + } + ecount = bytes & ~1; + if (ecount != 0) { + phys_insw(dep->de_data_port, phys_user, ecount); + count -= ecount; + bytes -= ecount; + phys_user += ecount; + } + if (bytes) { + *(u16_t *) two_bytes = in_word(dep->de_data_port); + phys_copy(phys_2bytes, phys_user, (phys_bytes) 1); + count--; + bytes--; + phys_user++; + odd_byte = 1; + } + } + return; +} + +#endif /* PIO16 == 1 */ + +#endif /* ENABLE_NETWORKING && ENABLE_DP8390 */ + +/** end 8390.c **/ diff --git a/drivers/dpeth/8390.h b/drivers/dpeth/8390.h new file mode 100644 index 000000000..e88ab2e36 --- /dev/null +++ b/drivers/dpeth/8390.h @@ -0,0 +1,172 @@ +/* +** File: 8390.h May 02, 2000 +** +** Author: Giovanni Falzoni +** +** National Semiconductor NS 8390 Network Interface Controller +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + + +#define DP_PAGESIZE 256 /* NS 8390 page size */ +#define SENDQ_PAGES 6 /* SENDQ_PAGES * DP_PAGESIZE >= 1514 bytes */ + +/* Page 0, read/write ------------- */ +#define DP_CR 0x00 /* Command Register RW */ +#define DP_CLDA0 0x01 /* Current Local Dma Address 0 RO */ +#define DP_PSTART 0x01 /* Page Start Register WO */ +#define DP_CLDA1 0x02 /* Current Local Dma Address 1 RO */ +#define DP_PSTOP 0x02 /* Page Stop Register WO */ +#define DP_BNRY 0x03 /* Boundary Pointer RW */ +#define DP_TSR 0x04 /* Transmit Status Register RO */ +#define DP_TPSR 0x04 /* Transmit Page Start Register WO */ +#define DP_NCR 0x05 /* No. of Collisions Register RO */ +#define DP_TBCR0 0x05 /* Transmit Byte Count Reg. 0 WO */ +#define DP_FIFO 0x06 /* Fifo RO */ +#define DP_TBCR1 0x06 /* Transmit Byte Count Reg. 1 WO */ +#define DP_ISR 0x07 /* Interrupt Status Register RW */ +#define DP_CRDA0 0x08 /* Current Remote Dma Addr.Low RO */ +#define DP_RSAR0 0x08 /* Remote Start Address Low WO */ +#define DP_CRDA1 0x09 /* Current Remote Dma Addr.High RO */ +#define DP_RSAR1 0x09 /* Remote Start Address High WO */ +#define DP_RBCR0 0x0A /* Remote Byte Count Low WO */ +#define DP_RBCR1 0x0B /* Remote Byte Count Hihg WO */ +#define DP_RSR 0x0C /* Receive Status Register RO */ +#define DP_RCR 0x0C /* Receive Config. Register WO */ +#define DP_CNTR0 0x0D /* Tally Counter 0 RO */ +#define DP_TCR 0x0D /* Transmit Config. Register WO */ +#define DP_CNTR1 0x0E /* Tally Counter 1 RO */ +#define DP_DCR 0x0E /* Data Configuration Register WO */ +#define DP_CNTR2 0x0F /* Tally Counter 2 RO */ +#define DP_IMR 0x0F /* Interrupt Mask Register WO */ + + /* Page 1, read/write -------------- */ +/* DP_CR 0x00 Command Register */ +#define DP_PAR0 0x01 /* Physical Address Register 0 */ +#define DP_PAR1 0x02 /* Physical Address Register 1 */ +#define DP_PAR2 0x03 /* Physical Address Register 2 */ +#define DP_PAR3 0x04 /* Physical Address Register 3 */ +#define DP_PAR4 0x05 /* Physical Address Register 4 */ +#define DP_PAR5 0x06 /* Physical Address Register 5 */ +#define DP_CURR 0x07 /* Current Page Register */ +#define DP_MAR0 0x08 /* Multicast Address Register 0 */ +#define DP_MAR1 0x09 /* Multicast Address Register 1 */ +#define DP_MAR2 0x0A /* Multicast Address Register 2 */ +#define DP_MAR3 0x0B /* Multicast Address Register 3 */ +#define DP_MAR4 0x0C /* Multicast Address Register 4 */ +#define DP_MAR5 0x0D /* Multicast Address Register 5 */ +#define DP_MAR6 0x0E /* Multicast Address Register 6 */ +#define DP_MAR7 0x0F /* Multicast Address Register 7 */ + +/* Bits in dp_cr */ +#define CR_STP 0x01 /* Stop: software reset */ +#define CR_STA 0x02 /* Start: activate NIC */ +#define CR_TXP 0x04 /* Transmit Packet */ +#define CR_DMA 0x38 /* Mask for DMA control */ +#define CR_DM_RR 0x08 /* DMA: Remote Read */ +#define CR_DM_RW 0x10 /* DMA: Remote Write */ +#define CR_DM_SP 0x18 /* DMA: Send Packet */ +#define CR_NO_DMA 0x20 /* DMA: Stop Remote DMA Operation */ +#define CR_PS 0xC0 /* Mask for Page Select */ +#define CR_PS_P0 0x00 /* Register Page 0 */ +#define CR_PS_P1 0x40 /* Register Page 1 */ +#define CR_PS_P2 0x80 /* Register Page 2 */ + +/* Bits in dp_isr */ +#define ISR_MASK 0x3F +#define ISR_PRX 0x01 /* Packet Received with no errors */ +#define ISR_PTX 0x02 /* Packet Transmitted with no errors */ +#define ISR_RXE 0x04 /* Receive Error */ +#define ISR_TXE 0x08 /* Transmit Error */ +#define ISR_OVW 0x10 /* Overwrite Warning */ +#define ISR_CNT 0x20 /* Counter Overflow */ +#define ISR_RDC 0x40 /* Remote DMA Complete */ +#define ISR_RST 0x80 /* Reset Status */ + +/* Bits in dp_imr */ +#define IMR_PRXE 0x01 /* Packet Received Enable */ +#define IMR_PTXE 0x02 /* Packet Transmitted Enable */ +#define IMR_RXEE 0x04 /* Receive Error Enable */ +#define IMR_TXEE 0x08 /* Transmit Error Enable */ +#define IMR_OVWE 0x10 /* Overwrite Warning Enable */ +#define IMR_CNTE 0x20 /* Counter Overflow Enable */ +#define IMR_RDCE 0x40 /* DMA Complete Enable */ + +/* Bits in dp_dcr */ +#define DCR_WTS 0x01 /* Word Transfer Select */ +#define DCR_BYTEWIDE 0x00 /* WTS: byte wide transfers */ +#define DCR_WORDWIDE 0x01 /* WTS: word wide transfers */ +#define DCR_BOS 0x02 /* Byte Order Select */ +#define DCR_LTLENDIAN 0x00 /* BOS: Little Endian */ +#define DCR_BIGENDIAN 0x02 /* BOS: Big Endian */ +#define DCR_LAS 0x04 /* Long Address Select */ +#define DCR_BMS 0x08 /* Burst Mode Select */ +#define DCR_AR 0x10 /* Autoinitialize Remote */ +#define DCR_FTS 0x60 /* Fifo Threshold Select */ +#define DCR_2BYTES 0x00 /* Fifo Threshold: 2 bytes */ +#define DCR_4BYTES 0x20 /* Fifo Threshold: 4 bytes */ +#define DCR_8BYTES 0x40 /* Fifo Threshold: 8 bytes */ +#define DCR_12BYTES 0x60 /* Fifo Threshold: 12 bytes */ + +/* Bits in dp_tcr */ +#define TCR_CRC 0x01 /* Inhibit CRC */ +#define TCR_ELC 0x06 /* Encoded Loopback Control */ +#define TCR_NORMAL 0x00 /* ELC: Normal Operation */ +#define TCR_INTERNAL 0x02 /* ELC: Internal Loopback */ +#define TCR_0EXTERNAL 0x04 /* ELC: External Loopback LPBK=0 */ +#define TCR_1EXTERNAL 0x06 /* ELC: External Loopback LPBK=1 */ +#define TCR_ATD 0x08 /* Auto Transmit */ +#define TCR_OFST 0x10 /* Collision Offset Enable */ + +/* Bits in dp_tsr */ +#define TSR_PTX 0x01 /* Packet Transmitted (without error) */ +#define TSR_DFR 0x02 /* Transmit Deferred */ +#define TSR_COL 0x04 /* Transmit Collided */ +#define TSR_ABT 0x08 /* Transmit Aborted */ +#define TSR_CRS 0x10 /* Carrier Sense Lost */ +#define TSR_FU 0x20 /* FIFO Underrun */ +#define TSR_CDH 0x40 /* CD Heartbeat */ +#define TSR_OWC 0x80 /* Out of Window Collision */ + +/* Bits in dp_rcr */ +#define RCR_SEP 0x01 /* Save Errored Packets */ +#define RCR_AR 0x02 /* Accept Runt Packets */ +#define RCR_AB 0x04 /* Accept Broadcast */ +#define RCR_AM 0x08 /* Accept Multicast */ +#define RCR_PRO 0x10 /* Physical Promiscuous */ +#define RCR_MON 0x20 /* Monitor Mode */ + +/* Bits in dp_rsr */ +#define RSR_PRX 0x01 /* Packet Received Intact */ +#define RSR_CRC 0x02 /* CRC Error */ +#define RSR_FAE 0x04 /* Frame Alignment Error */ +#define RSR_FO 0x08 /* FIFO Overrun */ +#define RSR_MPA 0x10 /* Missed Packet */ +#define RSR_PHY 0x20 /* Multicast Address Match !! */ +#define RSR_DIS 0x40 /* Receiver Disabled */ + +/* Some macros to simplify accessing the dp8390 */ +#define inb_reg0(dep,reg) (inb(dep->de_dp8390_port+reg)) +#define outb_reg0(dep,reg,data) (outb(dep->de_dp8390_port+reg,data)) +#define inb_reg1(dep,reg) (inb(dep->de_dp8390_port+reg)) +#define outb_reg1(dep,reg,data) (outb(dep->de_dp8390_port+reg,data)) + +typedef struct dp_rcvhdr { + u8_t dr_status; /* Copy of rsr */ + u8_t dr_next; /* Pointer to next packet */ + u8_t dr_rbcl; /* Receive Byte Count Low */ + u8_t dr_rbch; /* Receive Byte Count High */ +} dp_rcvhdr_t; + +void ns_init(dpeth_t *); + +/** 8390.h **/ diff --git a/drivers/dpeth/Makefile b/drivers/dpeth/Makefile new file mode 100644 index 000000000..d404db5f3 --- /dev/null +++ b/drivers/dpeth/Makefile @@ -0,0 +1,52 @@ +## +## Makefile for ISA ethernet drivers May 02, 2000 +## +## $Log$ +## Revision 1.1 2005/06/29 10:16:46 beng +## Import of dpeth 3c501/3c509b/.. ethernet driver by +## Giovanni Falzoni . +## +## Revision 2.0 2005/06/26 16:16:46 lsodgf0 +## Initial revision for Minix 3.0.6 +## +## $Id$ + +## Programs, flags, etc. +DRIVER = dpeth + +debug = 0 + +CC = exec cc +LD = $(CC) +CPPFLAGS= -I.. -I/usr/include -Ddebug=$(debug) +CFLAGS = -ws $(CPPFLAGS) +LDFLAGS = -i -o $@ + +SRCS = 3c501.c 3c509.c 3c503.c ne.c wd.c 8390.c devio.c netbuff.c dp.c +OBJS = 3c501.o 3c509.o 3c503.o ne.o wd.o 8390.o devio.o netbuff.o dp.o +LIBS = -lutils -lsys # -ltimers + +## Build rules +all build: $(DRIVER) + +$(DRIVER): $(OBJS) + $(CC) $(OBJS) $(LIBS) $(LDFLAGS) + install -S 4kw $(DRIVER) + +## Install with other drivers +install: /usr/sbin/drivers/$(DRIVER) +/usr/sbin/drivers/$(DRIVER): $(DRIVER) + install -o root -cs $? $@ + +## Generate dependencies + +depend: + /usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +## Clean directory +clean: + @rm -f $(DRIVER) *.o *.BAK + +include .depend + +## end diff --git a/drivers/dpeth/README b/drivers/dpeth/README new file mode 100644 index 000000000..cfa96e0bd --- /dev/null +++ b/drivers/dpeth/README @@ -0,0 +1,38 @@ + +This is my implementation of a new network task +for the Minix kernel. I did it initially to handle +a 3c501 board (Etherlink), but those board are so +unstable that it is not worth using them except for +learning how to implement a driver. When I got a +3c509b board (Etherlink III) it was easier to +write the code to handle them. + +The Minix code in 'dp8390.c' is too specific for the +National chip set, so what I did was to remove as +much as I needed of the code dependant from the chip +and produce a generic task that, I hope, will be able +to handle many more cards. + +$Log$ +Revision 1.1 2005/06/29 10:16:46 beng +Import of dpeth 3c501/3c509b/.. ethernet driver by +Giovanni Falzoni . + +Revision 1.3 2004/04/14 12:49:07 lsodgf0 +Changes for porting to Minix 2.0.4 run on BOCHS + +Revision 1.2 2002/03/25 14:16:09 lsodgf0 +The driver for the NEx000 has been rewritten to be +operational with the ACCTON 18xx (an NE1000 clone) +The I/O routines for 16 bit cards are still untested.. + +Revision 1.1 2002/02/09 09:35:09 lsodgf0 +Initial revision +The package is not fully tested, i.e. I had only 3Com +boards (3c501, 3c503, 3c503/16 and 3c509b) and WD8003. +I got also a NE1000 clone but it was not fully +operational and I could not appreciate the results. +For this reason the changes done to the interface +to I/O for 8 and 16 bits are not tested. + +$Id$ diff --git a/drivers/dpeth/devio.c b/drivers/dpeth/devio.c new file mode 100644 index 000000000..ee16fdacb --- /dev/null +++ b/drivers/dpeth/devio.c @@ -0,0 +1,141 @@ +/* +** File: devio.c Jun. 11, 2005 +** +** Author: Giovanni Falzoni +** +** This file contains the routines for readind/writing +** from/to the device registers. +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#include "drivers.h" +#include +#include +#include "dp.h" + +#if ENABLE_NETWORKING == 1 +#if USE_IOPL == 0 + +static void warning(const char *type, int err) +{ + + printf("Warning: eth#0 sys_%s failed (%d)\n", type, err); + return; +} + +/* +** Name: unsigned int inb(unsigned short int port); +** Function: Reads a byte from specified i/o port. +*/ +PUBLIC unsigned int inb(unsigned short port) +{ + unsigned int value; + int rc; + + if ((rc = sys_inb(port, &value)) != OK) warning("inb", rc); + return value; +} + +/* +** Name: unsigned int inw(unsigned short int port); +** Function: Reads a word from specified i/o port. +*/ +PUBLIC unsigned int inw(unsigned short port) +{ + unsigned int value; + int rc; + + if ((rc = sys_inw(port, &value)) != OK) warning("inw", rc); + return value; +} + +/* +** Name: unsigned int insb(unsigned short int port, int proc_nr, void *buffer, int count); +** Function: Reads a sequence of bytes from specified i/o port to user space buffer. +*/ +PUBLIC void insb(unsigned short int port, int proc_nr, void *buffer, int count) +{ + int rc; + + if ((rc = sys_insb(port, proc_nr, buffer, count)) != OK) + warning("insb", rc); + return; +} + +/* +** Name: unsigned int insw(unsigned short int port, int proc_nr, void *buffer, int count); +** Function: Reads a sequence of words from specified i/o port to user space buffer. +*/ +PUBLIC void insw(unsigned short int port, int proc_nr, void *buffer, int count) +{ + int rc; + + if ((rc = sys_insw(port, proc_nr, buffer, count)) != OK) + warning("insw", rc); + return; +} + +/* +** Name: void outb(unsigned short int port, unsigned long value); +** Function: Writes a byte to specified i/o port. +*/ +PUBLIC void outb(unsigned short port, unsigned long value) +{ + int rc; + + if ((rc = sys_outb(port, value)) != OK) warning("outb", rc); + return; +} + +/* +** Name: void outw(unsigned short int port, unsigned long value); +** Function: Writes a word to specified i/o port. +*/ +PUBLIC void outw(unsigned short port, unsigned long value) +{ + int rc; + + if ((rc = sys_outw(port, value)) != OK) warning("outw", rc); + return; +} + +/* +** Name: void outsb(unsigned short int port, int proc_nr, void *buffer, int count); +** Function: Writes a sequence of bytes from user space to specified i/o port. +*/ +PUBLIC void outsb(unsigned short port, int proc_nr, void *buffer, int count) +{ + int rc; + + if ((rc = sys_outsb(port, proc_nr, buffer, count)) != OK) + warning("outsb", rc); + return; +} + +/* +** Name: void outsw(unsigned short int port, int proc_nr, void *buffer, int count); +** Function: Writes a sequence of bytes from user space to specified i/o port. +*/ +PUBLIC void outsw(unsigned short port, int proc_nr, void *buffer, int count) +{ + int rc; + + if ((rc = sys_outsw(port, proc_nr, buffer, count)) != OK) + warning("outsw", rc); + return; +} + +#else +#error To be implemented +#endif /* USE_IOPL */ +#endif /* ENABLE_NETWORKING */ +/** devio.c **/ diff --git a/drivers/dpeth/dp.c b/drivers/dpeth/dp.c new file mode 100644 index 000000000..6c04589cb --- /dev/null +++ b/drivers/dpeth/dp.c @@ -0,0 +1,641 @@ +/* +** File: eth.c Version 1.00, Jan. 14, 1997 +** +** Author: Giovanni Falzoni +** +** This file contains the ethernet device driver main task. +** It has to be integrated with the board specific drivers. +** It is a rewriting of Minix 2.0.0 ethernet driver (dp8390.c) +** to remove bord specific code. It should operate (I hope) +** with any board driver. +** +** The valid messages and their parameters are: +** +** m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR +** +------------+---------+---------+--------+-------+---------+ +** | HARD_INT | | | | | | NOTIFICATION|0 +** +------------+---------+---------+--------+-------+---------+ +** | SYN_ALARM | | | | | | NOTIFICATION|1 +** +------------+---------+---------+--------+-------+---------+ +** | HARD_STOP | | | | | | NOTIFICATION|4 +** +------------+---------+---------+--------+-------+---------+ +** | FKEY_PRESSED | | | | | (99) +** +------------+---------+---------+--------+-------+---------+ +** | DL_WRITE | port nr | proc nr | count | mode | address | (3) +** +------------+---------+---------+--------+-------+---------+ +** | DL_WRITEV | port nr | proc nr | count | mode | address | (4) +** +------------+---------+---------+--------+-------+---------+ +** | DL_READ | port nr | proc nr | count | | address | (5) +** +------------+---------+---------+--------+-------+---------+ +** | DL_READV | port nr | proc nr | count | | address | (6) +** +------------+---------+---------+--------+-------+---------+ +** | DL_INIT | port nr | proc nr | | mode | address | (7) +** +------------+---------+---------+--------+-------+---------+ +** | DL_STOP | port_nr | | | | | (8) +** +------------+---------+---------+--------+-------+---------+ +** | DL_GETSTAT | port nr | proc nr | | | address | (9) +** +------------+---------+---------+--------+-------+---------+ +** +** The messages sent are: +** +** m-type DL_PORT DL_PROC DL_COUNT DL_STAT DL_CLCK +** +------------+---------+---------+--------+---------+---------+ +** |DL_TASK_REPL| port nr | proc nr |rd-count| err|stat| clock | (21) +** +------------+---------+---------+--------+---------+---------+ +** +** m_type m3_i1 m3_i2 m3_ca1 +** +------------+---------+---------+---------------+ +** |DL_INIT_REPL| port nr |last port| ethernet addr | (20) +** +------------+---------+---------+---------------+ +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#include "drivers.h" +#include +#include +#include +#include + +#include "dp.h" + +#if ENABLE_NETWORKING == 1 + +/* +** Local data +*/ +static dpeth_t de_table[DE_PORT_NR]; +static int dpeth_tasknr = ANY; + +typedef struct dp_conf { /* Configuration description structure */ + port_t dpc_port; + int dpc_irq; + phys_bytes dpc_mem; + char *dpc_envvar; +} dp_conf_t; + +/* Device default configuration */ +static dp_conf_t dp_conf[DE_PORT_NR] = { + /* I/O port, IRQ, Buff addr, Env. var, Buf. selector */ + { 0x300, 5, 0xC8000, "DPETH0", }, + { 0x280, 10, 0xCC000, "DPETH1", }, +}; + +static const char CopyErrMsg[] = "unable to read/write user data"; +static const char PortErrMsg[] = "illegal port"; +static const char RecvErrMsg[] = "receive failed"; +static const char SendErrMsg[] = "send failed"; +static const char SizeErrMsg[] = "illegal packet size"; +static const char TypeErrMsg[] = "illegal message type"; +static const char DevName[] = "eth#?"; + +/* +** Name: void reply(dpeth_t *dep, int err) +** Function: Fills a DL_TASK_REPLY reply message and sends it. +*/ +static void reply(dpeth_t * dep, int err) +{ + message reply; + int status = FALSE; + + if (dep->de_flags & DEF_ACK_SEND) status |= DL_PACK_SEND; + if (dep->de_flags & DEF_ACK_RECV) status |= DL_PACK_RECV; + + reply.m_type = DL_TASK_REPLY; + reply.DL_PORT = dep - de_table; + reply.DL_PROC = dep->de_client; + reply.DL_STAT = status | ((u32_t) err << 16); + reply.DL_COUNT = dep->de_read_s; + getuptime(&reply.DL_CLCK); + + DEBUG(printf("\t reply %d (%ld)\n", reply.m_type, reply.DL_STAT)); + + if ((status = send(dep->de_client, &reply)) != OK) + panic(dep->de_name, SendErrMsg, dep->de_client); + + dep->de_read_s = 0; + dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV); + return; +} + +/* +** Name: void dp_confaddr(dpeth_t *dep) +** Function: Chechs environment for a User defined ethernet address. +*/ +static void dp_confaddr(dpeth_t * dep) +{ + static char ea_fmt[] = "x:x:x:x:x:x"; + char ea_key[16]; + int ix; + long val; + + strcpy(ea_key, dp_conf[dep - de_table].dpc_envvar); + strcat(ea_key, "_EA"); + + for (ix = 0; ix < SA_ADDR_LEN; ix++) { + val = dep->de_address.ea_addr[ix]; + if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET) + break; + dep->de_address.ea_addr[ix] = val; + } + + if (ix != 0 && ix != SA_ADDR_LEN) + /* It's all or nothing, force a panic */ + env_parse(ea_key, "?", 0, &val, 0L, 0L); + return; +} + +/* +** Name: void update_conf(dpeth_t *dep, dp_conf_t *dcp) +** Function: Gets the default settings from 'dp_conf' table and +** modifies them from the environment. +*/ +static void update_conf(dpeth_t * dep, dp_conf_t * dcp) +{ + static char dpc_fmt[] = "x:d:x"; + long val; + + dep->de_mode = DEM_SINK; + val = dcp->dpc_port; /* Get I/O port address */ + switch (env_parse(dcp->dpc_envvar, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) { + case EP_OFF: dep->de_mode = DEM_DISABLED; break; + case EP_ON: + case EP_SET: dep->de_mode = DEM_ENABLED; break; + } + dep->de_base_port = val; + + val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */ + env_parse(dcp->dpc_envvar, dpc_fmt, 1, &val, 0L, (long) NR_IRQ_VECTORS - 1); + dep->de_irq = val; + + val = dcp->dpc_mem; /* Get shared memory address */ + env_parse(dcp->dpc_envvar, dpc_fmt, 2, &val, 0L, LONG_MAX); + dep->de_linmem = val; + + return; +} + +/* +** Name: void do_dump(message *mp) +** Function: Displays statistics on screen (SFx key from console) +*/ +static void do_dump(message *mp) +{ + dpeth_t *dep; + int port; + + printf("\n\n"); + for (port = 0, dep = de_table; port < DE_PORT_NR; port += 1, dep += 1) { + + if (dep->de_mode == DEM_DISABLED) continue; + + printf("%s statistics:\t\t", dep->de_name); + + /* Network interface status */ + printf("Status: 0x%04x\n\n", dep->de_flags); + + (*dep->de_dumpstatsf) (dep); + + /* Transmitted/received bytes */ + printf("Tx bytes:%10ld\t", dep->bytes_Tx); + printf("Rx bytes:%10ld\n", dep->bytes_Rx); + + /* Transmitted/received packets */ + printf("Tx OK: %8ld\t", dep->de_stat.ets_packetT); + printf("Rx OK: %8ld\n", dep->de_stat.ets_packetR); + + /* Transmit/receive errors */ + printf("Tx Err: %8ld\t", dep->de_stat.ets_sendErr); + printf("Rx Err: %8ld\n", dep->de_stat.ets_recvErr); + + /* Transmit unnerruns/receive overrruns */ + printf("Tx Und: %8ld\t", dep->de_stat.ets_fifoUnder); + printf("Rx Ovr: %8ld\n", dep->de_stat.ets_fifoOver); + + /* Transmit collisions/receive CRC errors */ + printf("Tx Coll: %8ld\t", dep->de_stat.ets_collision); + printf("Rx CRC: %8ld\n", dep->de_stat.ets_CRCerr); + } + return; +} + +/* +** Name: void get_userdata(int user_proc, vir_bytes user_addr, int count, void *loc_addr) +** Function: Copies data from user area. +*/ +static void get_userdata(int user_proc, vir_bytes user_addr, int count, void *loc_addr) +{ + int rc; + vir_bytes len; + + len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t); + if ((rc = sys_datacopy(user_proc, user_addr, SELF, (vir_bytes)loc_addr, len)) != OK) + panic(DevName, CopyErrMsg, rc); + return; +} + +/* +** Name: void do_first_init(dpeth_t *dep, dp_conf_t *dcp); +** Function: Init action to setup task +*/ +static void do_first_init(dpeth_t *dep, dp_conf_t *dcp) +{ + + if (dep->de_linmem != 0) { + dep->de_memsegm = BIOS_SEG; + /* phys2seg(&dep->de_memsegm, &dep->de_memoffs, dep->de_linmem); */ + } else + dep->de_linmem = 0xFFFF0000; + + /* Make sure statisics are cleared */ + memset((void *) &(dep->de_stat), 0, sizeof(eth_stat_t)); + + /* Device specific initialization */ + (*dep->de_initf) (dep); + + /* Set the interrupt handler policy */ + sys_irqsetpolicy(dep->de_irq, IRQ_REENABLE, &dep->de_hook); + sys_irqenable(&dep->de_hook); + + return; +} + +/* +** Name: void do_init(message *mp) +** Function: Checks for hardware presence. +** Provides initialization of hardware and data structures +*/ +static void do_init(message * mp) +{ + int port; + dpeth_t *dep; + dp_conf_t *dcp; + message reply_mess; + + port = mp->DL_PORT; + if (port >= 0 && port < DE_PORT_NR) { + + dep = &de_table[port]; + dcp = &dp_conf[port]; + strcpy(dep->de_name, DevName); + dep->de_name[4] = '0' + port; + + if (dep->de_mode == DEM_DISABLED) { + + update_conf(dep, dcp); /* First time thru */ + if (dep->de_mode == DEM_ENABLED && + !el1_probe(dep) && /* Probe for 3c501 */ + !wdeth_probe(dep) && /* Probe for WD80x3 */ + !ne_probe(dep) && /* Probe for NEx000 */ + !el2_probe(dep) && /* Probe for 3c503 */ + !el3_probe(dep)) { /* Probe for 3c509 */ + printf("%s: warning no ethernet card found at 0x%04X\n", + dep->de_name, dep->de_base_port); + dep->de_mode = DEM_DISABLED; + } + } + + /* 'de_mode' may change if probe routines fail, test again */ + switch (dep->de_mode) { + + case DEM_DISABLED: + /* Device is configured OFF or hardware probe failed */ + port = ENXIO; + break; + + case DEM_ENABLED: + /* Device is present and probed */ + if (dep->de_flags == DEF_EMPTY) { + /* These actions only the first time */ + do_first_init(dep, dcp); + dep->de_flags |= DEF_ENABLED; + } + dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD); + if (mp->DL_MODE & DL_PROMISC_REQ) + dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD; + if (mp->DL_MODE & DL_MULTI_REQ) dep->de_flags |= DEF_MULTI; + if (mp->DL_MODE & DL_BROAD_REQ) dep->de_flags |= DEF_BROAD; + (*dep->de_flagsf) (dep); + dep->de_client = mp->m_source; + break; + + case DEM_SINK: + /* Device not present (sink mode) */ + memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t)); + dp_confaddr(dep); /* Station address from env. */ + break; + + default: break; + } + *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address; + + } else /* Port number is out of range */ + port = ENXIO; + + reply_mess.m_type = DL_INIT_REPLY; + reply_mess.m3_i1 = port; + reply_mess.m3_i2 = DE_PORT_NR; + DEBUG(printf("\t reply %d\n", reply_mess.m_type)); + if (send(mp->m_source, &reply_mess) != OK) /* Can't send */ + panic(dep->de_name, SendErrMsg, mp->m_source); + + return; +} + +/* +** Name: void dp_next_iovec(iovec_dat_t *iovp) +** Function: Retrieves data from next iovec element. +*/ +PUBLIC void dp_next_iovec(iovec_dat_t * iovp) +{ + + iovp->iod_iovec_s -= IOVEC_NR; + iovp->iod_iovec_addr += IOVEC_NR * sizeof(iovec_t); + get_userdata(iovp->iod_proc_nr, iovp->iod_iovec_addr, + iovp->iod_iovec_s, iovp->iod_iovec); + return; +} + +/* +** Name: int calc_iovec_size(iovec_dat_t *iovp) +** Function: Compute the size of a request. +*/ +static int calc_iovec_size(iovec_dat_t * iovp) +{ + int size, ix; + + size = ix = 0; + do { + size += iovp->iod_iovec[ix].iov_size; + if (++ix >= IOVEC_NR) { + dp_next_iovec(iovp); + ix = 0; + } + + /* Till all vectors added */ + } while (ix < iovp->iod_iovec_s); + return size; +} + +/* +** Name: void do_vwrite(message *mp, int vectored) +** Function: +*/ +static void do_vwrite(message * mp, int vectored) +{ + int port, size; + dpeth_t *dep; + + port = mp->DL_PORT; + if (port < 0 || port >= DE_PORT_NR) /* Check for illegal port number */ + panic(dep->de_name, PortErrMsg, port); + + dep = &de_table[port]; + dep->de_client = mp->DL_PROC; + + if (dep->de_mode == DEM_ENABLED) { + + if (dep->de_flags & DEF_SENDING) /* Is sending in progress? */ + panic(dep->de_name, "send already in progress ", NO_NUM); + + dep->de_write_iovec.iod_proc_nr = mp->DL_PROC; + if (vectored) { + get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR, + mp->DL_COUNT, dep->de_write_iovec.iod_iovec); + dep->de_write_iovec.iod_iovec_s = mp->DL_COUNT; + dep->de_write_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR; + size = calc_iovec_size(&dep->de_write_iovec); + } else { + dep->de_write_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR; + dep->de_write_iovec.iod_iovec[0].iov_size = size = mp->DL_COUNT; + dep->de_write_iovec.iod_iovec_s = 1; + dep->de_write_iovec.iod_iovec_addr = 0; + } + if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE) + panic(dep->de_name, SizeErrMsg, size); + + dep->de_flags |= DEF_SENDING; + (*dep->de_sendf) (dep, FALSE, size); + + } else if (dep->de_mode == DEM_SINK) + dep->de_flags |= DEF_ACK_SEND; + + reply(dep, OK); + return; +} + +/* +** Name: void do_vread(message *mp, int vectored) +** Function: +*/ +static void do_vread(message * mp, int vectored) +{ + int port, size; + dpeth_t *dep; + + port = mp->DL_PORT; + if (port < 0 || port >= DE_PORT_NR) /* Check for illegal port number */ + panic(dep->de_name, PortErrMsg, port); + + dep = &de_table[port]; + dep->de_client = mp->DL_PROC; + + if (dep->de_mode == DEM_ENABLED) { + + if (dep->de_flags & DEF_READING) /* Reading in progress */ + panic(dep->de_name, "read already in progress", NO_NUM); + + dep->de_read_iovec.iod_proc_nr = mp->DL_PROC; + if (vectored) { + get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR, + mp->DL_COUNT, dep->de_read_iovec.iod_iovec); + dep->de_read_iovec.iod_iovec_s = mp->DL_COUNT; + dep->de_read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR; + size = calc_iovec_size(&dep->de_read_iovec); + } else { + dep->de_read_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR; + dep->de_read_iovec.iod_iovec[0].iov_size = size = mp->DL_COUNT; + dep->de_read_iovec.iod_iovec_s = 1; + dep->de_read_iovec.iod_iovec_addr = 0; + } + if (size < ETH_MAX_PACK_SIZE) panic(dep->de_name, SizeErrMsg, size); + + dep->de_flags |= DEF_READING; + (*dep->de_recvf) (dep, FALSE, size); +#if 0 + if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) + /* The chip is stopped, and all arrived packets delivered */ + (*dep->de_resetf) (dep); + dep->de_flags &= NOT(DEF_STOPPED); +#endif + } + reply(dep, OK); + return; +} + +/* +** Name: void do_getstat(message *mp) +** Function: Reports device statistics. +*/ +static void do_getstat(message * mp) +{ + int port, rc; + dpeth_t *dep; + + port = mp->DL_PORT; + if (port < 0 || port >= DE_PORT_NR) /* Check for illegal port number */ + panic(dep->de_name, PortErrMsg, port); + + dep = &de_table[port]; + dep->de_client = mp->DL_PROC; + + if (dep->de_mode == DEM_ENABLED) (*dep->de_getstatsf) (dep); + if ((rc = sys_datacopy(SELF, (vir_bytes)&dep->de_stat, + mp->DL_PROC, (vir_bytes)mp->DL_ADDR, + (vir_bytes) sizeof(dep->de_stat))) != OK) + panic(DevName, CopyErrMsg, rc); + reply(dep, OK); + return; +} + +/* +** Name: void do_stop(message *mp) +** Function: Stops network interface. +*/ +static void do_stop(message * mp) +{ + int port; + dpeth_t *dep; + + port = mp->DL_PORT; + if (port < 0 || port >= DE_PORT_NR) /* Check for illegal port number */ + panic(dep->de_name, PortErrMsg, port); + + dep = &de_table[port]; + if (dep->de_mode == DEM_ENABLED && (dep->de_flags & DEF_ENABLED)) { + + /* Stop device */ + (dep->de_stopf) (dep); + dep->de_flags = DEF_EMPTY; + dep->de_mode = DEM_DISABLED; + } + return; +} + +static void do_watchdog(void *message) +{ + + DEBUG(printf("\t no reply")); + return; +} + +/* +** Name: int dpeth_task(void) +** Function: Main entry for dp task +*/ +PUBLIC int main(void) +{ + message m; + dpeth_t *dep; + int rc, fkeys, sfkeys; + + /* Get precess number */ + if ((rc = getprocnr(&dpeth_tasknr)) != OK) + panic(DevName, "getprocnr() failed", rc); +#if defined USE_IOPL + /* Request direct access to hardware I/O ports */ + if ((rc = sys_enable_iop(dpeth_tasknr)) != OK) + panic(DevName, "sys_enable_iop() failed", rc); +#endif + /* Request function key for debug dumps */ + fkeys = sfkeys = 0; bit_set(sfkeys, 8); + if ((fkey_map(fkeys, sfkeys)) != OK) + printf("%s: couldn't program Shift+F8 key (%d)\n", DevName, errno); + +#ifdef ETH_IGN_PROTO + { + static u16_t eth_ign_proto = 0; + long val; + val = 0xFFFF; + env_parse("ETH_IGN_PROTO", "x", 0, &val, 0x0000L, 0xFFFFL); + eth_ign_proto = htons((u16_t) val); + } +#endif + + printf("DPETH: ethernet driver task initialized (process No. %d)\n", dpeth_tasknr); + while (TRUE) { + if ((rc = receive(ANY, &m)) != OK) panic(dep->de_name, RecvErrMsg, rc); + + DEBUG(printf("eth: got message %d, ", m.m_type)); + + switch (m.m_type) { + case DL_WRITE: /* Write message to device */ + do_vwrite(&m, FALSE); + break; + case DL_WRITEV: /* Write message to device */ + do_vwrite(&m, TRUE); + break; + case DL_READ: /* Read message from device */ + do_vread(&m, FALSE); + break; + case DL_READV: /* Read message from device */ + do_vread(&m, TRUE); + break; + case DL_INIT: /* Initialize device */ + do_init(&m); + break; + case DL_GETSTAT: /* Get device statistics */ + do_getstat(&m); + break; + case SYN_ALARM: /* to be defined */ + do_watchdog(&m); + break; + case DL_STOP: /* Stop device */ + do_stop(&m); + break; + case HARD_STOP: /* Shut down */ + for (rc = 0; rc < DE_PORT_NR; rc += 1) { + if (de_table[rc].de_mode == DEM_ENABLED) { + m.m_type = DL_STOP; + m.DL_PORT = rc; + do_stop(&m); + } + } + sys_exit(0); + break; + case HARD_INT: /* Interrupt from device */ + for (dep = de_table; dep < &de_table[DE_PORT_NR]; dep += 1) { + /* If device is enabled and interrupt pending */ + if (dep->de_mode == DEM_ENABLED) { + /* dep->de_int_pending = FALSE; */ + (*dep->de_interruptf) (dep); + if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV)) + reply(dep, OK); + /* enable_irq(&dep->de_hook); */ + } + } + break; + case FKEY_PRESSED: /* Function key pressed */ + do_dump(&m); + break; + default: /* Invalid message type */ + panic(DevName, TypeErrMsg, m.m_type); + break; + } + } + return OK; /* Never reached, but keeps compiler happy */ +} + +#else +int main(void) { return 0; } +#endif /* ENABLE_NETWORKING */ + +/** dp.c **/ diff --git a/drivers/dpeth/dp.h b/drivers/dpeth/dp.h new file mode 100644 index 000000000..de4f034b4 --- /dev/null +++ b/drivers/dpeth/dp.h @@ -0,0 +1,269 @@ +/* +** File: eth.h Version 1.00, Jan. 14, 1997 +** +** Author: Giovanni Falzoni +** +** Interface description for ethernet device driver +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#undef ENABLE_3C501 +#undef ENABLE_3C503 +#undef ENABLE_3C509 +#undef ENABLE_NE2000 +#undef ENABLE_WDETH +#undef ENABLE_DP8390 + +#define ENABLE_NETWORKING ENABLE_DPETH /** (from /usr/include/minix/config.h **/ + +#define ENABLE_3C501 1 /* enable 3Com Etherlink I board */ +#define ENABLE_3C503 1 /* enable 3Com Etherlink II board */ +#define ENABLE_3C509 1 /* enable 3Com Etherlink III board */ +#define ENABLE_NE2000 1 /* enable Novell N2000 board */ +#define ENABLE_WDETH 1 /* enable Western Digital WD80x3 */ + +#define ENABLE_DP8390 (ENABLE_3C503|ENABLE_WDETH|ENABLE_NE2000) +#define HAVE_BUFFERS (ENABLE_3C501|ENABLE_3C509) + +#undef NULL +#define NULL ((void *)0) +#define NOT(x) (~(x)) + +#if debug == 1 +# define DEBUG(statm) statm +#else +# define DEBUG(statm) +#endif + +typedef struct _m_hdr_t { /* Buffer handling header */ + struct _m_hdr_t *next; + int size; +} m_hdr_t; + +typedef struct _buff_t { /* Receive/Transmit buffer header */ + struct _buff_t *next; + int size; + int client; + char buffer[2]; +} buff_t; + +struct dpeth; +struct iovec_dat; +typedef void (*dp_eth_t) (struct dpeth *); +typedef void (*dp_send_recv_t) (struct dpeth *, int, int); + +#if ENABLE_DP8390 == 1 +typedef void (*dp_user2nicf_t) (struct dpeth *, int, int); +typedef void (*dp_nic2userf_t) (struct dpeth *, int, int); +typedef void (*dp_getblock_t) (struct dpeth *, u16_t, int, void *); +#endif + +#define DE_PORT_NR 2 /* Number of devices supported */ +#define SENDQ_NR 2 /* Size of the send queue */ +#define IOVEC_NR 16 /* Number of IOVEC entries at a time */ + +typedef struct iovec_dat { + iovec_t iod_iovec[IOVEC_NR]; + int iod_iovec_s; + int iod_proc_nr; + vir_bytes iod_iovec_addr; +} iovec_dat_t; + +typedef struct dpeth { + /* The de_base_port field is the starting point of the probe. The + * conf routine also fills de_linmem and de_irq. If the probe routine + * knows the irq and/or memory address because they are hardwired in + * the board, the probe should modify these fields. Futhermore, the + * probe routine should also fill in de_initf and de_stopf fields + * with the appropriate function pointers and set de_prog_IO iff + * programmed I/O is to be used. + * + * The initf function fills the following fields. Only cards that do + * programmed I/O fill in the de_data_port field. In addition, the + * init routine has to fill in the sendq data structures. */ + + /* Board hardware interface */ + port_t de_base_port; + port_t de_data_port; /* For boards using Prog. I/O for xmit/recv */ + + int de_irq; + /* int de_int_pending; */ + int de_hook; /* V306 irq_hook_t de_hook; */ + + char de_name[8]; + +#define DEI_DEFAULT 0x8000 + + phys_bytes de_linmem; /* For boards using shared memory */ + unsigned short de_memsegm; + vir_bytes de_memoffs; + int de_ramsize; /* Size of on board memory */ + int de_offset_page; /* Offset of shared memory page */ + + /* Board specific functions */ + dp_eth_t de_initf; + dp_eth_t de_stopf; + dp_eth_t de_resetf; + dp_eth_t de_flagsf; + dp_eth_t de_getstatsf; + dp_eth_t de_dumpstatsf; + dp_eth_t de_interruptf; + dp_send_recv_t de_recvf; + dp_send_recv_t de_sendf; + + ether_addr_t de_address; /* Ethernet Address */ + eth_stat_t de_stat; /* Ethernet Statistics */ + unsigned long bytes_Tx; /* Total bytes sent/received */ + unsigned long bytes_Rx; + +#define SA_ADDR_LEN sizeof(ether_addr_t) + + int de_flags; /* Send/Receive mode (Configuration) */ + +#define DEF_EMPTY 0x0000 +#define DEF_READING 0x0001 +#define DEF_RECV_BUSY 0x0002 +#define DEF_ACK_RECV 0x0004 +#define DEF_SENDING 0x0010 +#define DEF_XMIT_BUSY 0x0020 +#define DEF_ACK_SEND 0x0040 +#define DEF_PROMISC 0x0100 +#define DEF_MULTI 0x0200 +#define DEF_BROAD 0x0400 +#define DEF_ENABLED 0x2000 +#define DEF_STOPPED 0x4000 + + int de_mode; /* Status of the Interface */ + +#define DEM_DISABLED 0x0000 +#define DEM_SINK 0x0001 +#define DEM_ENABLED 0x0002 + + /* Temporary storage for RECV/SEND requests */ + iovec_dat_t de_read_iovec; + iovec_dat_t de_write_iovec; + vir_bytes de_read_s; + vir_bytes de_send_s; + int de_client; +/* + message de_sendmsg; + iovec_dat_t de_tmp_iovec; +*/ +#if ENABLE_DP8390 == 1 + /* For use by NS DP8390 driver */ + port_t de_dp8390_port; + int de_prog_IO; + int de_16bit; + int de_startpage; + int de_stoppage; + + /* Do it yourself send queue */ + struct sendq { + int sq_filled; /* This buffer contains a packet */ + int sq_size; /* with this size */ + int sq_sendpage; /* starting page of the buffer */ + } de_sendq[SENDQ_NR]; + int de_sendq_nr; + int de_sendq_head; /* Enqueue at the head */ + int de_sendq_tail; /* Dequeue at the tail */ + + dp_user2nicf_t de_user2nicf; + dp_nic2userf_t de_nic2userf; + dp_getblock_t de_getblockf; +#endif + +#if ENABLE_3C509 == 1 + /* For use by 3Com Etherlink III (3c509) driver */ + port_t de_id_port; + port_t de_if_port; +#endif + +#if ENABLE_3C501 == 1 || ENABLE_3C509 == 1 + /* For use by 3Com Etherlink (3c501 and 3c509) driver */ + buff_t *de_recvq_head; + buff_t *de_recvq_tail; + buff_t *de_xmitq_head; + buff_t *de_xmitq_tail; + u16_t de_recv_mode; + clock_t de_xmit_start; +#endif + +} dpeth_t; + +/* + * Function definitions + */ + +/* dp.c */ +void dp_next_iovec(iovec_dat_t * iovp); + +/* devio.c */ +#if defined USE_IOPL +#include +#else +unsigned int inb(unsigned short int); +unsigned int inw(unsigned short int); +void insb(unsigned short int, int, void *, int); +void insw(unsigned short int, int, void *, int); +void outb(unsigned short int, unsigned long); +void outw(unsigned short int, unsigned long); +void outsb(unsigned short int, int, void *, int); +void outsw(unsigned short int, int, void *, int); +#endif + +/* netbuff.c */ +void *alloc_buff(dpeth_t *, int); +void free_buff(dpeth_t *, void *); +void init_buff(dpeth_t *, buff_t **); +void mem2user(dpeth_t *, buff_t *); +void user2mem(dpeth_t *, buff_t *); + +/* 3c501.c */ +#if ENABLE_3C501 == 1 +int el1_probe(dpeth_t *); +#else +#define el1_probe(x) (0) +#endif + +/* 3c503.c */ +#if ENABLE_3C503 == 1 +int el2_probe(dpeth_t *); +#else +#define el2_probe(x) (0) +#endif + +/* 3c509.c */ +#if ENABLE_3C509 == 1 +int el3_probe(dpeth_t *); +#else +#define el3_probe(x) (0) +#endif + +/* ne.c */ +#if ENABLE_NE2000 == 1 +int ne_probe(dpeth_t * dep); +#else +#define ne_probe(x) (0) +#endif + +/* wd.c */ +#if ENABLE_WDETH == 1 +int wdeth_probe(dpeth_t * dep); +#else +#define wdeth_probe(x) (0) +#endif + +#define lock() sys_irqdisable(&dep->de_hook); +#define unlock() sys_irqenable(&dep->de_hook); +#define milli_delay(t) tickdelay(1) + +/** dp.h **/ diff --git a/drivers/dpeth/ne.c b/drivers/dpeth/ne.c new file mode 100644 index 000000000..4829e18e2 --- /dev/null +++ b/drivers/dpeth/ne.c @@ -0,0 +1,201 @@ +/* +** File: ne.c Jun. 08, 2000 +** +** Driver for the NE*000 ethernet cards and derivates. +** This file contains only the ne specific code, +** the rest is in 8390.c Code specific for ISA bus only +** +** Created: March 15, 1994 by Philip Homburg +** PchId: ne2000.c,v 1.4 1996/01/19 23:30:34 philip Exp +** +** Modified: Jun. 08, 2000 by Giovanni Falzoni +** Adapted to interface new main network task. +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#include "drivers.h" +#include +#include +#include "dp.h" + +#if (ENABLE_NETWORKING == 1 && ENABLE_NE2000 == 1) + +#include "8390.h" +#include "ne.h" + +/* +** Name: void ne_reset(dpeth_t * dep); +** Function: Resets the board and checks if reset cycle completes +*/ +static int ne_reset(dpeth_t * dep) +{ + int count = 0; + + /* Reset the ethernet card */ + outb_ne(dep, NE_RESET, inb_ne(dep, NE_RESET)); + do { + if (++count > 10) return FALSE; /* 20 mSecs. timeout */ + milli_delay(2); + } while ((inb_ne(dep, DP_ISR) & ISR_RST) == 0); + return TRUE; +} + +/* +** Name: void ne_close(dpeth_t * dep); +** Function: Stops the board by resetting it and masking interrupts. +*/ +static void ne_close(dpeth_t * dep) +{ + + (void)ne_reset(dep); + outb_ne(dep, DP_ISR, 0xFF); + sys_irqdisable(&dep->de_hook); + return; +} + +/* +** Name: void ne_init(dpeth_t * dep); +** Function: Initialize the board making it ready to work. +*/ +static void ne_init(dpeth_t * dep) +{ + int ix; + + dep->de_data_port = dep->de_base_port + NE_DATA; + if (dep->de_16bit) { + dep->de_ramsize = NE2000_SIZE; + dep->de_offset_page = NE2000_START / DP_PAGESIZE; + } else { + dep->de_ramsize = NE1000_SIZE; + dep->de_offset_page = NE1000_START / DP_PAGESIZE; + } + + /* Allocates two send buffers from onboard RAM */ + dep->de_sendq_nr = SENDQ_NR; + for (ix = 0; ix < SENDQ_NR; ix += 1) { + dep->de_sendq[ix].sq_sendpage = dep->de_offset_page + ix * SENDQ_PAGES; + } + + /* Remaining onboard RAM allocated for receiving */ + dep->de_startpage = dep->de_offset_page + ix * SENDQ_PAGES; + dep->de_stoppage = dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE; + + /* Can't override the default IRQ. */ + dep->de_irq &= NOT(DEI_DEFAULT); + + ns_init(dep); /* Initialize DP controller */ + + printf("%s: NE%d000 (%dkB RAM) at %X:%d - ", + dep->de_name, + dep->de_16bit ? 2 : 1, + dep->de_ramsize / 1024, + dep->de_base_port, dep->de_irq); + for (ix = 0; ix < SA_ADDR_LEN; ix += 1) + printf("%02X%c", dep->de_address.ea_addr[ix], ix < SA_ADDR_LEN - 1 ? ':' : '\n'); + return; +} + +/* +** Name: int ne_probe(dpeth_t * dep); +** Function: Probe for the presence of a NE*000 card by testing +** whether the board is reachable through the dp8390. +** Note that the NE1000 is an 8bit card and has a memory +** region distict from the 16bit NE2000. +*/ +PUBLIC int ne_probe(dpeth_t * dep) +{ + int ix, wd, loc1, loc2; + char EPROM[32]; + static const struct { + unsigned char offset; + unsigned char value; + } InitSeq[] = + { + { /* Selects page 0. */ + DP_CR, (CR_NO_DMA | CR_PS_P0 | CR_STP), + }, + { /* Set byte-wide access and 8 bytes burst mode. */ + DP_DCR, (DCR_8BYTES | DCR_BMS), + }, + { /* Clears the count registers. */ + DP_RBCR0, 0x00, }, { DP_RBCR1, 0x00, + }, + { /* Mask completion irq. */ + DP_IMR, 0x00, }, { DP_ISR, 0xFF, + }, + { /* Set receiver to monitor */ + DP_RCR, RCR_MON, + }, + { /* and transmitter to loopback mode. */ + DP_TCR, TCR_INTERNAL, + }, + { /* Transmit 32 bytes */ + DP_RBCR0, 32, }, { DP_RBCR1, 0, + }, + { /* DMA starting at 0x0000. */ + DP_RSAR0, 0x00, }, { DP_RSAR1, 0x00, + }, + { /* Start board (reads) */ + DP_CR, (CR_PS_P0 | CR_DM_RR | CR_STA), + }, + }; + + dep->de_dp8390_port = dep->de_base_port + NE_DP8390; + + if ((loc1 = inb_ne(dep, NE_DP8390)) == 0xFF) return FALSE; + + /* Check if the dp8390 is really there */ + outb_ne(dep, DP_CR, CR_STP | CR_NO_DMA | CR_PS_P1); + loc2 = inb_ne(dep, DP_MAR5); /* Saves one byte of the address */ + outb_ne(dep, DP_MAR5, 0xFF); /* Write 0xFF to it (same offset as DP_CNTR0) */ + outb_ne(dep, DP_CR, CR_NO_DMA | CR_PS_P0); /* Back to page 0 */ + inb_ne(dep, DP_CNTR0); /* Reading counter resets it */ + if (inb_ne(dep, DP_CNTR0) != 0) { + outb_ne(dep, NE_DP8390, loc1); /* Try to restore modified bytes */ + outb_ne(dep, DP_TCR, loc2); + return FALSE; + } + + /* Try to reset the board */ + if (ne_reset(dep) == FALSE) return FALSE; + + /* Checks whether the board is 8/16bits and a real NE*000 or clone */ + for (ix = 0; ix < sizeof(InitSeq)/sizeof(InitSeq[0]); ix += 1) { + outb_ne(dep, InitSeq[ix].offset, InitSeq[ix].value); + } + for (ix = 0, wd = 1; ix < 32; ix += 2) { + EPROM[ix + 0] = inb_ne(dep, NE_DATA); + EPROM[ix + 1] = inb_ne(dep, NE_DATA); + /* NE2000s and clones read same value for even and odd addresses */ + if (EPROM[ix + 0] != EPROM[ix + 1]) wd = 0; + } + if (wd == 1) { /* Normalize EPROM contents for NE2000 */ + for (ix = 0; ix < 16; ix += 1) EPROM[ix] = EPROM[ix * 2]; + } + /* Real NE*000 and good clones have '0x57' at locations 14 and 15 */ + if (EPROM[14] != 0x57 || EPROM[15] != 0x57) return FALSE; + + /* Setup the ethernet address. */ + for (ix = 0; ix < SA_ADDR_LEN; ix += 1) { + dep->de_address.ea_addr[ix] = EPROM[ix]; + } + dep->de_16bit = wd; + dep->de_linmem = 0; /* Uses Programmed I/O only */ + dep->de_prog_IO = 1; + dep->de_initf = ne_init; + dep->de_stopf = ne_close; + return TRUE; +} + +#endif /* ENABLE_NETWORKING && ENABLE_NE2000 */ + +/** ne.c **/ diff --git a/drivers/dpeth/ne.h b/drivers/dpeth/ne.h new file mode 100644 index 000000000..391d256cc --- /dev/null +++ b/drivers/dpeth/ne.h @@ -0,0 +1,37 @@ +/* +** File: ne.h +** +** Created: March 15, 1994 by Philip Homburg +** $PchId: ne2000.h,v 1.2 1995/12/22 08:42:31 philip Exp $ +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#ifndef NE2000_H +#define NE2000_H + +#define NE_DP8390 0x00 +#define NE_DATA 0x10 +#define NE_RESET 0x1F + +#define NE1000_START 0x2000 +#define NE1000_SIZE 0x2000 +#define NE2000_START 0x4000 +#define NE2000_SIZE 0x4000 + +#define inb_ne(dep, reg) (inb(dep->de_base_port+reg)) +#define outb_ne(dep, reg, data) (outb(dep->de_base_port+reg, data)) +#define inw_ne(dep, reg) (inw(dep->de_base_port+reg)) +#define outw_ne(dep, reg, data) (outw(dep->de_base_port+reg, data)) + +#endif /* NE2000_H */ + +/** ne.h **/ diff --git a/drivers/dpeth/netbuff.c b/drivers/dpeth/netbuff.c new file mode 100644 index 000000000..327fcf74c --- /dev/null +++ b/drivers/dpeth/netbuff.c @@ -0,0 +1,176 @@ +/* +** File: netbuff.c Jun. 10, 2000 +** +** Author: Giovanni Falzoni +** +** This file contains specific implementation of buffering +** for network packets. +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#include "drivers.h" +#include +#include +#include "dp.h" + +#if ENABLE_NETWORKING == 1 && HAVE_BUFFERS == 1 + +static m_hdr_t *allocptr = NULL; +static char tx_rx_buff[8192]; + +/* +** Name: void *alloc_buff(dpeth_t *dep, int size) +** Function: Allocates a buffer from the common pool. +*/ +PUBLIC void *alloc_buff(dpeth_t *dep, int size) +{ + m_hdr_t *ptr, *wrk = allocptr; + int units = ((size + sizeof(m_hdr_t) - 1) / sizeof(m_hdr_t)) + 1; + + lock(); + for (ptr = wrk->next;; wrk = ptr, ptr = ptr->next) { + if (ptr->size >= units) { + /* Memory is available, carve requested size from pool */ + if (ptr->size == units) { + wrk->next = ptr->next; + } else { + /* Get memory from top address */ + ptr->size -= units; + ptr += ptr->size; + ptr->size = units; + } + allocptr = wrk; + unlock(); + return ptr + 1; + } + if (ptr == allocptr) break; + } + unlock(); + return NULL; /* No memory available */ +} + +/* +** Name: void free_buff(dpeth_t *dep, void *blk) +** Function: Returns a buffer to the common pool. +*/ +PUBLIC void free_buff(dpeth_t *dep, void *blk) +{ + m_hdr_t *wrk, *ptr = (m_hdr_t *) blk - 1; + + lock(); /* Scan linked list for the correct place */ + for (wrk = allocptr; !(ptr > wrk && ptr < wrk->next); wrk = wrk->next) + if (wrk >= wrk->next && (ptr > wrk || ptr < wrk->next)) break; + + /* Check if adjacent block is free and join blocks */ + if (ptr + ptr->size == wrk->next) { + ptr->size += wrk->next->size; + ptr->next = wrk->next->next; + } else + ptr->next = wrk->next; + if (wrk + wrk->size == ptr) { + wrk->size += ptr->size; + wrk->next = ptr->next; + } else + wrk->next = ptr; + allocptr = wrk; /* Point allocptr to block just released */ + unlock(); + return; +} + +/* +** Name: void init_buff(dpeth_t *dep, buff_t **tx_buff) +** Function: Initalizes driver data structures. +*/ +PUBLIC void init_buff(dpeth_t *dep, buff_t **tx_buff) +{ + + /* Initializes buffer pool */ + if (allocptr == NULL) { + m_hdr_t *rx = (m_hdr_t *) tx_rx_buff; + rx->next = allocptr = rx; + rx->size = 0; + rx += 1; + rx->next = NULL; + rx->size = (sizeof(tx_rx_buff) / sizeof(m_hdr_t)) - 1; + free_buff(dep, rx + 1); + dep->de_recvq_tail = dep->de_recvq_head = NULL; + if (tx_buff != NULL) { + *tx_buff = alloc_buff(dep, ETH_MAX_PACK_SIZE + sizeof(buff_t)); + (*tx_buff)->size = 0; + } + } + return; /* Done */ +} + +/* +** Name: void mem2user(dpeth_t *dep, buff_t *rxbuff); +** Function: Copies a packet from local buffer to user area. +*/ +PUBLIC void mem2user(dpeth_t *dep, buff_t *rxbuff) +{ + phys_bytes phys_user; + int bytes, ix = 0; + iovec_dat_t *iovp = &dep->de_read_iovec; + int pktsize = rxbuff->size; + char *buffer = rxbuff->buffer; + + do { /* Reads chuncks of packet into user buffers */ + + bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */ + if (bytes > pktsize) bytes = pktsize; + + /* Reads from Rx buffer to user area */ + sys_datacopy(SELF, (vir_bytes)buffer, iovp->iod_proc_nr, + iovp->iod_iovec[ix].iov_addr, bytes); + buffer += bytes; + + if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ + dp_next_iovec(iovp); + ix = 0; + } + /* Till packet done */ + } while ((pktsize -= bytes) > 0); + return; +} + +/* +** Name: void user2mem(dpeth_t *dep, buff_t *txbuff) +** Function: Copies a packet from user area to local buffer. +*/ +PUBLIC void user2mem(dpeth_t *dep, buff_t *txbuff) +{ + phys_bytes phys_user; + int bytes, ix = 0; + iovec_dat_t *iovp = &dep->de_write_iovec; + int pktsize = txbuff->size; + char *buffer = txbuff->buffer; + + do { /* Reads chuncks of packet from user buffers */ + + bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */ + if (bytes > pktsize) bytes = pktsize; + sys_datacopy(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, + SELF, (vir_bytes)buffer, bytes); + buffer += bytes; + + if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ + dp_next_iovec(iovp); + ix = 0; + } + /* Till packet done */ + } while ((pktsize -= bytes) > 0); + return; +} + +#endif /* ENABLE_NETWORKING */ + +/** netbuff.c **/ diff --git a/drivers/dpeth/wd.c b/drivers/dpeth/wd.c new file mode 100644 index 000000000..6ac888d24 --- /dev/null +++ b/drivers/dpeth/wd.c @@ -0,0 +1,323 @@ +/* +** File: wd.c +** +** Driver for the Ethercard (WD80x3) and derivates +** This file contains only the wd80x3 specific code, +** the rest is in 8390.c +** +** Created: March 14, 1994 by Philip Homburg +** PchId: +** +** Modified: Jun. 08, 2000 by Giovanni Falzoni +** Adaptation to interfacing new main network task. +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#include "drivers.h" +#include +#include +#include "dp.h" + +#if (ENABLE_NETWORKING == 1 && ENABLE_WDETH == 1) + +#include "8390.h" +#include "wd.h" + +#define WET_ETHERNET 0x01 /* Ethernet transceiver */ +#define WET_STARLAN 0x02 /* Starlan transceiver */ +#define WET_INTERF_CHIP 0x04 /* has a WD83C583 interface chip */ +#define WET_BRD_16BIT 0x08 /* 16 bit board */ +#define WET_SLT_16BIT 0x10 /* 16 bit slot */ +#define WET_790 0x20 /* '790 chip */ + +static const int we_int_table[8] = {9, 3, 5, 7, 10, 11, 15, 4}; +static const int we_790int_table[8] = {0, 9, 3, 5, 7, 10, 11, 15}; + +_PROTOTYPE(static void we_init, (dpeth_t * dep)); +_PROTOTYPE(static void we_stop, (dpeth_t * dep)); +_PROTOTYPE(static int we_aliasing, (dpeth_t * dep)); +_PROTOTYPE(static int we_interface_chip, (dpeth_t * dep)); +_PROTOTYPE(static int we_16bitboard, (dpeth_t * dep)); +_PROTOTYPE(static int we_16bitslot, (dpeth_t * dep)); +_PROTOTYPE(static int we_ultra, (dpeth_t * dep)); + +/*===========================================================================* + * wdeth_probe * + *===========================================================================*/ +int wdeth_probe(dep) +dpeth_t *dep; +{ + int sum; + + if (dep->de_linmem == 0) + return FALSE; /* No shared memory, so no WD board */ + + sum = inb_we(dep, EPL_EA0) + inb_we(dep, EPL_EA1) + + inb_we(dep, EPL_EA2) + inb_we(dep, EPL_EA3) + + inb_we(dep, EPL_EA4) + inb_we(dep, EPL_EA5) + + inb_we(dep, EPL_TLB) + inb_we(dep, EPL_CHKSUM); + if ((sum & 0xFF) != 0xFF) + return FALSE; /* No ethernet board at this address */ + + dep->de_initf = we_init; + dep->de_stopf = we_stop; + dep->de_prog_IO = 0; + return TRUE; +} + +/*===========================================================================* + * we_init * + *===========================================================================*/ +static void we_init(dep) +dpeth_t *dep; +{ + int i, int_indx, int_nr; + int tlb, rambit, revision; + int icr, irr, hwr, b, gcr; + int we_type; + int sendq_nr; + + for (i = 0; i < 6; i += 1) { + dep->de_address.ea_addr[i] = inb_we(dep, EPL_EA0 + i); + } + + dep->de_dp8390_port = dep->de_base_port + EPL_DP8390; + + dep->de_16bit = 0; + + we_type = 0; + we_type |= WET_ETHERNET; /* assume ethernet */ + if (we_ultra(dep)) we_type |= WET_790; + if (!we_aliasing(dep)) { + if (we_interface_chip(dep)) we_type |= WET_INTERF_CHIP; + if (we_16bitboard(dep)) { + we_type |= WET_BRD_16BIT; + if (we_16bitslot(dep)) we_type |= WET_SLT_16BIT; + } + } + if (we_type & WET_SLT_16BIT) dep->de_16bit = 1; + + /* Look at the on board ram size. */ + tlb = inb_we(dep, EPL_TLB); + revision = tlb & E_TLB_REV; + rambit = tlb & E_TLB_RAM; + + if (dep->de_ramsize != 0) { + /* Size set from boot environment. */ + } else if (revision < 2) { + dep->de_ramsize = 0x2000; /* 8K */ + if (we_type & WET_BRD_16BIT) + dep->de_ramsize = 0x4000; /* 16K */ + else if ((we_type & WET_INTERF_CHIP) && + inb_we(dep, EPL_ICR) & E_ICR_MEMBIT) { + dep->de_ramsize = 0x8000; /* 32K */ + } + } else { + if (we_type & WET_BRD_16BIT) { + /* 32K or 16K */ + dep->de_ramsize = rambit ? 0x8000 : 0x4000; + } else { + /* 32K or 8K */ + dep->de_ramsize = rambit ? 0x8000 : 0x2000; + } + } + + if (we_type & WET_790) { + outb_we(dep, EPL_MSR, E_MSR_RESET); + if ((we_type & (WET_BRD_16BIT | WET_SLT_16BIT)) == + (WET_BRD_16BIT | WET_SLT_16BIT)) { + outb_we(dep, EPL_LAAR, E_LAAR_LAN16E | E_LAAR_MEM16E); + } + } else if (we_type & WET_BRD_16BIT) { + if (we_type & WET_SLT_16BIT) { + outb_we(dep, EPL_LAAR, E_LAAR_A19 | E_LAAR_SOFTINT | + E_LAAR_LAN16E | E_LAAR_MEM16E); + } else { + outb_we(dep, EPL_LAAR, E_LAAR_A19 | E_LAAR_SOFTINT | + E_LAAR_LAN16E); + } + } + if (we_type & WET_790) { + outb_we(dep, EPL_MSR, E_MSR_MENABLE); + hwr = inb_we(dep, EPL_790_HWR); + outb_we(dep, EPL_790_HWR, hwr | E_790_HWR_SWH); + b = inb_we(dep, EPL_790_B); + outb_we(dep, EPL_790_B, ((dep->de_linmem >> 13) & 0x0f) | + ((dep->de_linmem >> 11) & 0x40) | (b & 0xb0)); + outb_we(dep, EPL_790_HWR, hwr & ~E_790_HWR_SWH); + } else { + outb_we(dep, EPL_MSR, E_MSR_RESET); + outb_we(dep, EPL_MSR, E_MSR_MENABLE | + ((dep->de_linmem >> 13) & E_MSR_MEMADDR)); + } + + if ((we_type & WET_INTERF_CHIP) && !(we_type & WET_790)) { + icr = inb_we(dep, EPL_ICR); + irr = inb_we(dep, EPL_IRR); + int_indx = (icr & E_ICR_IR2) | ((irr & (E_IRR_IR0 | E_IRR_IR1)) >> 5); + int_nr = we_int_table[int_indx]; + DEBUG(printf("%s: encoded irq= %d\n", dep->de_name, int_nr)); + if (dep->de_irq & DEI_DEFAULT) dep->de_irq = int_nr; + outb_we(dep, EPL_IRR, irr | E_IRR_IEN); + } + if (we_type & WET_790) { + hwr = inb_we(dep, EPL_790_HWR); + outb_we(dep, EPL_790_HWR, hwr | E_790_HWR_SWH); + + gcr = inb_we(dep, EPL_790_GCR); + + outb_we(dep, EPL_790_HWR, hwr & ~E_790_HWR_SWH); + + int_indx = ((gcr & E_790_GCR_IR2) >> 4) | + ((gcr & (E_790_GCR_IR1 | E_790_GCR_IR0)) >> 2); + int_nr = we_790int_table[int_indx]; + DEBUG(printf("%s: encoded irq= %d\n", dep->de_name, int_nr)); + if (dep->de_irq & DEI_DEFAULT) dep->de_irq = int_nr; + icr = inb_we(dep, EPL_790_ICR); + outb_we(dep, EPL_790_ICR, icr | E_790_ICR_EIL); + } + + /* Strip the "default flag." */ + dep->de_irq &= ~DEI_DEFAULT; + + dep->de_offset_page = 0; /* Shared memory starts at 0 */ + /* Allocate one send buffer (1.5KB) per 8KB of on board memory. + sendq_nr = dep->de_ramsize / 0x2000; + if (sendq_nr < 1) + sendq_nr = 1; + else if (sendq_nr > SENDQ_NR) */ + sendq_nr = SENDQ_NR; + dep->de_sendq_nr = sendq_nr; + for (i = 0; i < sendq_nr; i++) { + dep->de_sendq[i].sq_sendpage = i * SENDQ_PAGES; + } + dep->de_startpage = i * SENDQ_PAGES; + dep->de_stoppage = dep->de_ramsize / DP_PAGESIZE; + + ns_init(dep); /* Initialize DP controller */ + + printf("%s: WD80%d3 (%dkB RAM) at %X:%d:%lX - ", + dep->de_name, + we_type & WET_BRD_16BIT ? 1 : 0, + dep->de_ramsize / 1024, + dep->de_base_port, + dep->de_irq, + dep->de_linmem); + for (i = 0; i < SA_ADDR_LEN; i += 1) + printf("%02X%c", dep->de_address.ea_addr[i], + i < SA_ADDR_LEN - 1 ? ':' : '\n'); + + return; +} + +/*===========================================================================* + * we_stop * + *===========================================================================*/ +static void we_stop(dep) +dpeth_t *dep; +{ + + if (dep->de_16bit) outb_we(dep, EPL_LAAR, E_LAAR_A19 | E_LAAR_LAN16E); + outb_we(dep, EPL_MSR, E_MSR_RESET); + outb_we(dep, EPL_MSR, 0); + sys_irqdisable(&dep->de_hook); + return; +} + +/*===========================================================================* + * we_aliasing * + *===========================================================================*/ +static int we_aliasing(dep) +dpeth_t *dep; +{ +/* Determine whether wd8003 hardware performs register aliasing. This implies + * an old WD8003E board. */ + + if (inb_we(dep, EPL_REG1) != inb_we(dep, EPL_EA1)) return 0; + if (inb_we(dep, EPL_REG2) != inb_we(dep, EPL_EA2)) return 0; + if (inb_we(dep, EPL_REG3) != inb_we(dep, EPL_EA3)) return 0; + if (inb_we(dep, EPL_REG4) != inb_we(dep, EPL_EA4)) return 0; + if (inb_we(dep, EPL_REG7) != inb_we(dep, EPL_CHKSUM)) return 0; + return 1; +} + +/*===========================================================================* + * we_interface_chip * + *===========================================================================*/ +static int we_interface_chip(dep) +dpeth_t *dep; +{ +/* Determine if the board has an interface chip. */ + + outb_we(dep, EPL_GP2, 0x35); + if (inb_we(dep, EPL_GP2) != 0x35) return 0; + outb_we(dep, EPL_GP2, 0x3A); + if (inb_we(dep, EPL_GP2) != 0x3A) return 0; + return 1; +} + +/*===========================================================================* + * we_16bitboard * + *===========================================================================*/ +static int we_16bitboard(dep) +dpeth_t *dep; +{ +/* Determine whether the board is capable of doing 16 bit memory moves. + * If the 16 bit enable bit is unchangable by software we'll assume an + * 8 bit board. + */ + int icr; + u8_t tlb; + + icr = inb_we(dep, EPL_ICR); + + outb_we(dep, EPL_ICR, icr ^ E_ICR_16BIT); + if (inb_we(dep, EPL_ICR) == icr) { + tlb = inb_we(dep, EPL_TLB); + + DEBUG(printf("%s: tlb= 0x%x\n", dep->de_name, tlb)); + + return tlb == E_TLB_EB || tlb == E_TLB_E || + tlb == E_TLB_SMCE || tlb == E_TLB_SMC8216C; + } + outb_we(dep, EPL_ICR, icr); + return 1; +} + + +/*===========================================================================* + * we_16bitslot * + *===========================================================================*/ +static int we_16bitslot(dep) +dpeth_t *dep; +{ +/* Determine if the 16 bit board in plugged into a 16 bit slot. */ + + return !!(inb_we(dep, EPL_ICR) & E_ICR_16BIT); +} + +/*===========================================================================* + * we_ultra * + *===========================================================================*/ +static int we_ultra(dep) +dpeth_t *dep; +{ +/* Determine if we has an '790 chip. */ + u8_t tlb; + + tlb = inb_we(dep, EPL_TLB); + return tlb == E_TLB_SMC8216C; +} + +#endif /* ENABLE_NETWORKING && ENABLE_WDETH */ + +/** wd.c **/ diff --git a/drivers/dpeth/wd.h b/drivers/dpeth/wd.h new file mode 100644 index 000000000..c3001edfa --- /dev/null +++ b/drivers/dpeth/wd.h @@ -0,0 +1,103 @@ +/* +** File: wd.h +** +** Created: before Dec 28, 1992 by Philip Homburg +** $PchId: wdeth.h,v 1.4 1995/12/22 08:36:57 philip Exp $ +** +** $Log$ +** Revision 1.1 2005/06/29 10:16:46 beng +** Import of dpeth 3c501/3c509b/.. ethernet driver by +** Giovanni Falzoni . +** +** Revision 2.0 2005/06/26 16:16:46 lsodgf0 +** Initial revision for Minix 3.0.6 +** +** $Id$ +*/ + +#ifndef WDETH_H +#define WDETH_H + +/* Western Digital Ethercard Plus, or WD8003E card. */ + +#define EPL_REG0 0x0 /* Control(write) and status(read) */ +#define EPL_REG1 0x1 +#define EPL_REG2 0x2 +#define EPL_REG3 0x3 +#define EPL_REG4 0x4 +#define EPL_REG5 0x5 +#define EPL_REG6 0x6 +#define EPL_REG7 0x7 +#define EPL_EA0 0x8 /* Most significant eaddr byte */ +#define EPL_EA1 0x9 +#define EPL_EA2 0xA +#define EPL_EA3 0xB +#define EPL_EA4 0xC +#define EPL_EA5 0xD /* Least significant eaddr byte */ +#define EPL_TLB 0xE +#define EPL_CHKSUM 0xF /* sum from epl_ea0 upto here is 0xFF */ +#define EPL_DP8390 0x10 /* NatSemi chip */ + +#define EPL_MSR EPL_REG0/* memory select register */ +#define EPL_ICR EPL_REG1/* interface configuration register */ +#define EPL_IRR EPL_REG4/* interrupt request register (IRR) */ +#define EPL_790_HWR EPL_REG4/* '790 hardware support register */ +#define EPL_LAAR EPL_REG5/* LA address register (write only) */ +#define EPL_790_ICR EPL_REG6/* '790 interrupt control register */ +#define EPL_GP2 EPL_REG7/* general purpose register 2 */ +#define EPL_790_B EPL_EA3 /* '790 memory register */ +#define EPL_790_GCR EPL_EA5 /* '790 General Control Register */ + +/* Bits in EPL_MSR */ +#define E_MSR_MEMADDR 0x3F /* Bits SA18-SA13, SA19 implicit 1 */ +#define E_MSR_MENABLE 0x40 /* Memory Enable */ +#define E_MSR_RESET 0x80 /* Software Reset */ + +/* Bits in EPL_ICR */ +#define E_ICR_16BIT 0x01 /* 16 bit bus */ +#define E_ICR_IR2 0x04 /* bit 2 of encoded IRQ */ +#define E_ICR_MEMBIT 0x08 /* 583 mem size mask */ + +/* Bits in EPL_IRR */ +#define E_IRR_IR0 0x20 /* bit 0 of encoded IRQ */ +#define E_IRR_IR1 0x40 /* bit 1 of encoded IRQ */ +#define E_IRR_IEN 0x80 /* enable interrupts */ + +/* Bits in EPL_LAAR */ +#define E_LAAR_A19 0x01 /* address lines for above 1M ram */ +#define E_LAAR_A20 0x02 /* address lines for above 1M ram */ +#define E_LAAR_A21 0x04 /* address lines for above 1M ram */ +#define E_LAAR_A22 0x08 /* address lines for above 1M ram */ +#define E_LAAR_A23 0x10 /* address lines for above 1M ram */ +#define E_LAAR_SOFTINT 0x20 /* enable software interrupt */ +#define E_LAAR_LAN16E 0x40 /* enables 16 bit RAM for LAN */ +#define E_LAAR_MEM16E 0x80 /* enables 16 bit RAM for host */ + +/* Bits and values in EPL_TLB */ +#define E_TLB_EB 0x05 /* WD8013EB */ +#define E_TLB_E 0x27 /* WD8013 Elite */ +#define E_TLB_SMCE 0x29 /* SMC Elite 16 */ +#define E_TLB_SMC8216C 0x2B /* SMC 8216 C */ + +#define E_TLB_REV 0x1F /* revision mask */ +#define E_TLB_SOFT 0x20 /* soft config */ +#define E_TLB_RAM 0x40 /* extra ram bit */ + +/* Bits in EPL_790_HWR */ +#define E_790_HWR_SWH 0x80 /* switch register set */ + +/* Bits in EPL_790_ICR */ +#define E_790_ICR_EIL 0x01 /* enable interrupts */ + +/* Bits in EPL_790_GCR when E_790_HWR_SWH is set in EPL_790_HWR */ +#define E_790_GCR_IR0 0x04 /* bit 0 of encoded IRQ */ +#define E_790_GCR_IR1 0x08 /* bit 1 of encoded IRQ */ +#define E_790_GCR_IR2 0x40 /* bit 2 of encoded IRQ */ + + +#define inb_we(dep, reg) (inb(dep->de_base_port+reg)) +#define outb_we(dep, reg, data) (outb(dep->de_base_port+reg, data)) + +#endif /* WDETH_H */ + +/** wd.h **/ diff --git a/include/minix/com.h b/include/minix/com.h index 545504e25..51954ada3 100755 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -37,17 +37,19 @@ #define IS_PROC_NR 5 /* information server */ #define TTY 6 /* terminal (TTY) driver */ #define MEMORY 8 /* memory driver (RAM disk, null, etc.) */ -#define AT_WINI (MEMORY + ENABLE_AT_WINI) /* AT Winchester */ -#define FLOPPY (AT_WINI + ENABLE_FLOPPY) /* floppy disk */ -#define PRINTER (FLOPPY + ENABLE_PRINTER) /* Centronics */ -#define USR8139 (PRINTER + ENABLE_RTL8139) /* Realtek RTL8139 */ -#define FXP (USR8139 + ENABLE_FXP) /* Intel Pro/100 */ -#define INIT_PROC_NR (FXP + 1) /* init -- goes multiuser */ +#define AT_WINI (MEMORY + ENABLE_AT_WINI) /* AT Winchester */ +#define FLOPPY (AT_WINI + ENABLE_FLOPPY) /* floppy disk */ +#define PRINTER (FLOPPY + ENABLE_PRINTER) /* Centronics */ +#define USR8139 (PRINTER + ENABLE_RTL8139) /* Realtek RTL8139 */ +#define FXP (USR8139 + ENABLE_FXP) /* Intel Pro/100 */ +#define DPETH (FXP + ENABLE_DPETH) /* ISA Network task */ +#define INIT_PROC_NR (DPETH + 1) /* init -- goes multiuser */ /* Number of processes contained in the system image. */ #define IMAGE_SIZE (NR_TASKS + \ 5 + ENABLE_AT_WINI + ENABLE_FLOPPY + \ - ENABLE_PRINTER + ENABLE_RTL8139 + ENABLE_FXP + 1 ) + ENABLE_PRINTER + ENABLE_RTL8139 + ENABLE_FXP + \ + ENABLE_DPETH + 1 ) /*===========================================================================* diff --git a/include/minix/config.h b/include/minix/config.h index e980a5bf2..2cb996b18 100755 --- a/include/minix/config.h +++ b/include/minix/config.h @@ -32,7 +32,7 @@ #endif /* Number of slots in the process table for non-kernel processes. */ -#define NR_PROCS 64 +#define NR_PROCS 64 /* The buffer cache should be made as large as you can afford. */ #if (MACHINE == IBM_PC && _WORD_SIZE == 2) @@ -92,7 +92,7 @@ #define DMA_SECTORS 1 /* DMA buffer size (must be >= 1) */ /* Enable or disable networking drivers. */ -#define ENABLE_DP8390 0 /* enable DP8390 ethernet driver */ +#define ENABLE_DPETH 1 /* enable DP8390 ethernet driver */ #define ENABLE_WDETH 0 /* add Western Digital WD80x3 */ #define ENABLE_NE2000 0 /* add Novell NE1000/NE2000 */ #define ENABLE_3C503 0 /* add 3Com Etherlink II (3c503) */ diff --git a/kernel/klib386.s b/kernel/klib386.s index 1a9097351..d23088911 100755 --- a/kernel/klib386.s +++ b/kernel/klib386.s @@ -256,7 +256,7 @@ _phys_insb: mov edx, 8(ebp) ! port to read from mov edi, 12(ebp) ! destination addr mov ecx, 16(ebp) ! byte count - shr ecx, 1 ! word count +! shr ecx, 1 ! word count rep insb ! input many bytes pop es pop edi diff --git a/kernel/table.c b/kernel/table.c index dc6e4c96b..743c997f4 100755 --- a/kernel/table.c +++ b/kernel/table.c @@ -84,6 +84,9 @@ PUBLIC struct system_image image[] = { #endif #if ENABLE_FXP { FXP, 0, 0, 2, 0, SYSTEM_CALL_MASK, ALLOW_ALL_MASK, "FXP" }, +#endif +#if ENABLE_DPETH + { DPETH, 0, 0, 2, 0, SYSTEM_CALL_MASK, ALLOW_ALL_MASK, "DPETH" }, #endif { INIT_PROC_NR, 0, 0, USER_Q, 0, USER_CALL_MASK, USER_PROC_SENDMASK, "INIT" }, }; diff --git a/servers/is/dmp_kernel.c b/servers/is/dmp_kernel.c index aeb85b61b..6d859f5f9 100644 --- a/servers/is/dmp_kernel.c +++ b/servers/is/dmp_kernel.c @@ -138,9 +138,9 @@ PUBLIC void irqtab_dmp() "clock", /* 00 */ "keyboard", /* 01 */ "cascade", /* 02 */ - "eth/rs232", /* 03 */ + "rs232", /* 03 */ "rs232", /* 04 */ - "xt_wini", /* 05 */ + "NIC(eth)", /* 05 */ "floppy", /* 06 */ "printer", /* 07 */ "", /* 08 */ diff --git a/tools/Makefile b/tools/Makefile index 7c9a7e5cb..25e8a9044 100755 --- a/tools/Makefile +++ b/tools/Makefile @@ -18,6 +18,7 @@ PROGRAMS= ../kernel/kernel \ ../drivers/printer/printer \ ../drivers/rtl8139/rtl8139 \ ../drivers/fxp/fxp \ + ../drivers/dpeth/dpeth \ ../servers/init/init \ # bootdev.img -- 2.44.0