Giovanni Falzoni <fgalzoni@inwind.it>.
cd ./printer && $(MAKE) $@
cd ./rtl8139 && $(MAKE) $@
cd ./fxp && $(MAKE) $@
-
+ cd ./dpeth && $(MAKE) $@
--- /dev/null
+/*
+** File: 3c501.c Jan. 14, 1997
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** Revision 2.0 2005/06/26 16:16:46 lsodgf0
+** Initial revision for Minix 3.0.6
+**
+** $Id$
+*/
+
+#include "drivers.h"
+#include <minix/com.h>
+#include <net/hton.h>
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#include "dp.h"
+
+#if (ENABLE_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 **/
--- /dev/null
+/*
+** File: 3c501.h Jan. 14, 1997
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** 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 **/
--- /dev/null
+/*
+** File: 3c503.c Dec. 20, 1996
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** Revision 2.0 2005/06/26 16:16:46 lsodgf0
+** Initial revision for Minix 3.0.6
+**
+** $Id$
+*/
+
+#include "drivers.h"
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#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 **/
--- /dev/null
+/*
+** File: 3c503.h Dec. 20, 1996
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** 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 **/
--- /dev/null
+/*
+** File: 3c509.c Jun. 01, 2000
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** This file contains specific implementation of the ethernet
+** device driver for 3Com Etherlink III (3c509) boards.
+** NOTE: The board has to be setup to disable PnP and to assign
+** I/O base and IRQ. The driver is for ISA bus only
+**
+** $Log$
+** Revision 1.1 2005/06/29 10:16:46 beng
+** Import of dpeth 3c501/3c509b/.. ethernet driver by
+** Giovanni Falzoni <fgalzoni@inwind.it>.
+**
+** Revision 2.0 2005/06/26 16:16:46 lsodgf0
+** Initial revision for Minix 3.0.6
+**
+** $Id$
+*/
+
+#include "drivers.h"
+#include <minix/com.h>
+#include <net/hton.h>
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+
+#include "dp.h"
+
+#if ENABLE_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 **/
--- /dev/null
+/*
+** File: 3c509.h Jun. 01, 2000
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** 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 **/
--- /dev/null
+/*
+** File: 8390.c May 02, 2000
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** Revision 2.0 2005/06/26 16:16:46 lsodgf0
+** Initial revision for Minix 3.0.6
+**
+** $Id$
+*/
+
+#include "drivers.h"
+#include <minix/com.h>
+#include <net/hton.h>
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#include "dp.h"
+
+#if (ENABLE_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 **/
--- /dev/null
+/*
+** File: 8390.h May 02, 2000
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** 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 **/
--- /dev/null
+##
+## 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 <fgalzoni@inwind.it>.
+##
+## 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
--- /dev/null
+
+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 <fgalzoni@inwind.it>.
+
+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$
--- /dev/null
+/*
+** File: devio.c Jun. 11, 2005
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** Revision 2.0 2005/06/26 16:16:46 lsodgf0
+** Initial revision for Minix 3.0.6
+**
+** $Id$
+*/
+
+#include "drivers.h"
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#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 **/
--- /dev/null
+/*
+** File: eth.c Version 1.00, Jan. 14, 1997
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** Revision 2.0 2005/06/26 16:16:46 lsodgf0
+** Initial revision for Minix 3.0.6
+**
+** $Id$
+*/
+
+#include "drivers.h"
+#include <minix/keymap.h>
+#include <net/hton.h>
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+
+#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 **/
--- /dev/null
+/*
+** File: eth.h Version 1.00, Jan. 14, 1997
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** 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 <ibm/portio.h>
+#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 **/
--- /dev/null
+/*
+** 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 <philip@cs.vu.nl>
+** PchId: ne2000.c,v 1.4 1996/01/19 23:30:34 philip Exp
+**
+** Modified: Jun. 08, 2000 by Giovanni Falzoni <gfalzoni@inwind.it>
+** 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 <fgalzoni@inwind.it>.
+**
+** Revision 2.0 2005/06/26 16:16:46 lsodgf0
+** Initial revision for Minix 3.0.6
+**
+** $Id$
+*/
+
+#include "drivers.h"
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#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 **/
--- /dev/null
+/*
+** File: ne.h
+**
+** Created: March 15, 1994 by Philip Homburg <philip@cs.vu.nl>
+** $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 <fgalzoni@inwind.it>.
+**
+** 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 **/
--- /dev/null
+/*
+** File: netbuff.c Jun. 10, 2000
+**
+** Author: Giovanni Falzoni <gfalzoni@inwind.it>
+**
+** 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 <fgalzoni@inwind.it>.
+**
+** Revision 2.0 2005/06/26 16:16:46 lsodgf0
+** Initial revision for Minix 3.0.6
+**
+** $Id$
+*/
+
+#include "drivers.h"
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#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 **/
--- /dev/null
+/*
+** 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 <gfalzoni@inwind.it>
+** 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 <fgalzoni@inwind.it>.
+**
+** Revision 2.0 2005/06/26 16:16:46 lsodgf0
+** Initial revision for Minix 3.0.6
+**
+** $Id$
+*/
+
+#include "drivers.h"
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#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 **/
--- /dev/null
+/*
+** 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 <fgalzoni@inwind.it>.
+**
+** 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 **/
#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 )
/*===========================================================================*
#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)
#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) */
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
#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" },
};
"clock", /* 00 */
"keyboard", /* 01 */
"cascade", /* 02 */
- "eth/rs232", /* 03 */
+ "rs232", /* 03 */
"rs232", /* 04 */
- "xt_wini", /* 05 */
+ "NIC(eth)", /* 05 */
"floppy", /* 06 */
"printer", /* 07 */
"", /* 08 */
../drivers/printer/printer \
../drivers/rtl8139/rtl8139 \
../drivers/fxp/fxp \
+ ../drivers/dpeth/dpeth \
../servers/init/init \
# bootdev.img