]> Zhao Yanbai Git Server - minix.git/commitdiff
Import of dpeth 3c501/3c509b/.. ethernet driver by
authorBen Gras <ben@minix3.org>
Wed, 29 Jun 2005 10:16:46 +0000 (10:16 +0000)
committerBen Gras <ben@minix3.org>
Wed, 29 Jun 2005 10:16:46 +0000 (10:16 +0000)
Giovanni Falzoni <fgalzoni@inwind.it>.

25 files changed:
drivers/Makefile
drivers/dpeth/3c501.c [new file with mode: 0644]
drivers/dpeth/3c501.h [new file with mode: 0644]
drivers/dpeth/3c503.c [new file with mode: 0644]
drivers/dpeth/3c503.h [new file with mode: 0644]
drivers/dpeth/3c509.c [new file with mode: 0644]
drivers/dpeth/3c509.h [new file with mode: 0644]
drivers/dpeth/8390.c [new file with mode: 0644]
drivers/dpeth/8390.h [new file with mode: 0644]
drivers/dpeth/Makefile [new file with mode: 0644]
drivers/dpeth/README [new file with mode: 0644]
drivers/dpeth/devio.c [new file with mode: 0644]
drivers/dpeth/dp.c [new file with mode: 0644]
drivers/dpeth/dp.h [new file with mode: 0644]
drivers/dpeth/ne.c [new file with mode: 0644]
drivers/dpeth/ne.h [new file with mode: 0644]
drivers/dpeth/netbuff.c [new file with mode: 0644]
drivers/dpeth/wd.c [new file with mode: 0644]
drivers/dpeth/wd.h [new file with mode: 0644]
include/minix/com.h
include/minix/config.h
kernel/klib386.s
kernel/table.c
servers/is/dmp_kernel.c
tools/Makefile

index 610af2bc21e024997538ab35eddc067d0247320e..3af5bcb3dfd4679019898d110e08887575bd27a4 100644 (file)
@@ -23,4 +23,4 @@ all install depend clean:
        cd ./printer && $(MAKE) $@
        cd ./rtl8139 && $(MAKE) $@
        cd ./fxp && $(MAKE) $@
-
+       cd ./dpeth && $(MAKE) $@
diff --git a/drivers/dpeth/3c501.c b/drivers/dpeth/3c501.c
new file mode 100644 (file)
index 0000000..d99eeba
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/3c501.h b/drivers/dpeth/3c501.h
new file mode 100644 (file)
index 0000000..c7b2663
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/3c503.c b/drivers/dpeth/3c503.c
new file mode 100644 (file)
index 0000000..45b4ca5
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/3c503.h b/drivers/dpeth/3c503.h
new file mode 100644 (file)
index 0000000..f0b89bc
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/3c509.c b/drivers/dpeth/3c509.c
new file mode 100644 (file)
index 0000000..d3a182c
--- /dev/null
@@ -0,0 +1,603 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/3c509.h b/drivers/dpeth/3c509.h
new file mode 100644 (file)
index 0000000..bcbdba6
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/8390.c b/drivers/dpeth/8390.c
new file mode 100644 (file)
index 0000000..8c7231a
--- /dev/null
@@ -0,0 +1,739 @@
+/*
+**  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), &eth_type);
+#endif
+       length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
+       next = header.dr_next;
+
+       if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) {
+               printf("%s: packet with strange length arrived: %d\n", dep->de_name, length);
+               dep->de_stat.ets_recvErr += 1;
+               next = curr;
+
+       } else if (next < dep->de_startpage || next >= dep->de_stoppage) {
+               printf("%s: strange next page\n", dep->de_name);
+               dep->de_stat.ets_recvErr += 1;
+               next = curr;
+
+#ifdef ETH_IGN_PROTO
+       } else if (eth_type == eth_ign_proto) {
+               /* Hack: ignore packets of a given protocol */
+               static int first = TRUE;
+               if (first) {
+                       first = FALSE;
+                       printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto));
+               }
+               next = curr;
+#endif
+       } else if (header.dr_status & RSR_FO) {
+               /* This is very serious, issue a warning and reset buffers */
+               printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name);
+               dep->de_stat.ets_fifoOver += 1;
+               next = curr;
+
+       } else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) {
+
+               if (!(dep->de_flags & DEF_READING)) break;
+
+               (dep->de_nic2userf) (dep, pageno, length);
+               dep->de_read_s = length;
+               dep->de_flags |= DEF_ACK_RECV;
+               dep->de_flags &= NOT(DEF_READING);
+               packet_processed = TRUE;
+       }
+       dep->bytes_Rx += (long) length;
+       dep->de_stat.ets_packetR += 1;
+       outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1);
+       pageno = next;
+
+  } while (!packet_processed);
+#if 0
+  if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
+       /* The chip is stopped, and all arrived packets delivered */
+       (*dep->de_resetf) (dep);
+  dep->de_flags &= NOT(DEF_STOPPED);
+#endif
+  return;
+}
+
+/*
+**  Name:      void ns_interrupt(dpeth_t * dep)
+**  Function:  Handles interrupt.
+*/
+static void ns_interrupt(dpeth_t * dep)
+{
+  int isr, tsr;
+  int size, queue;
+
+  while ((isr = inb_reg0(dep, DP_ISR)) != 0) {
+
+       outb_reg0(dep, DP_ISR, isr);
+       if (isr & (ISR_PTX | ISR_TXE)) {
+
+               tsr = inb_reg0(dep, DP_TSR);
+               if (tsr & TSR_PTX) {
+                       dep->de_stat.ets_packetT++;
+               }
+               if (tsr & TSR_COL) dep->de_stat.ets_collision++;
+               if (tsr & (TSR_ABT | TSR_FU)) {
+                       dep->de_stat.ets_fifoUnder++;
+               }
+               if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) {
+                       printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr);
+                       dep->de_stat.ets_sendErr++;
+               }
+               queue = dep->de_sendq_tail;
+
+               if (!(dep->de_sendq[queue].sq_filled)) {        /* Hardware bug? */
+                       printf("%s: transmit interrupt, but not sending\n", dep->de_name);
+                       continue;
+               }
+               dep->de_sendq[queue].sq_filled = FALSE;
+               if (++queue == dep->de_sendq_nr) queue = 0;
+               dep->de_sendq_tail = queue;
+               if (dep->de_sendq[queue].sq_filled) {
+                       ns_start_xmit(dep, dep->de_sendq[queue].sq_size,
+                               dep->de_sendq[queue].sq_sendpage);
+               }
+               if (dep->de_flags & DEF_SENDING) {
+                       ns_send(dep, TRUE, dep->de_send_s);
+               }
+       }
+       if (isr & ISR_PRX) {
+               ns_recv(dep, TRUE, 0);
+       }
+       if (isr & ISR_RXE) {
+               printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR));
+               dep->de_stat.ets_recvErr++;
+       }
+       if (isr & ISR_CNT) {
+               dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
+               dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
+               dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
+       }
+       if (isr & ISR_OVW) {
+               printf("%s: got overwrite warning\n", dep->de_name);
+       }
+       if (isr & ISR_RDC) {
+               /* Nothing to do */
+       }
+       if (isr & ISR_RST) {
+               /* This means we got an interrupt but the ethernet
+                * chip is shutdown. We set the flag DEF_STOPPED, and
+                * continue processing arrived packets. When the
+                * receive buffer is empty, we reset the dp8390. */
+               printf("%s: network interface stopped\n", dep->de_name);
+               dep->de_flags |= DEF_STOPPED;
+               break;
+       }
+  }
+  if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) {
+
+       /* The chip is stopped, and all arrived packets delivered */
+       ns_reset(dep);
+       dep->de_flags &= NOT(DEF_STOPPED);
+  }
+  return;
+}
+
+/*
+**  Name:      void ns_init(dpeth_t *dep)
+**  Function:  Initializes the NS 8390
+*/
+void ns_init(dpeth_t * dep)
+{
+  int dp_reg;
+  int ix;
+
+  /* NS8390 initialization (as recommended in National Semiconductor specs) */
+  outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA);        /* 0x21 */
+#if PIO16 == 0
+  outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
+#else
+  outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) |
+                       DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
+#endif
+  outb_reg0(dep, DP_RBCR0, 0);
+  outb_reg0(dep, DP_RBCR1, 0);
+  outb_reg0(dep, DP_RCR, RCR_MON);     /* Sets Monitor mode */
+  outb_reg0(dep, DP_TCR, TCR_INTERNAL);        /* Sets Loopback mode 1 */
+  outb_reg0(dep, DP_PSTART, dep->de_startpage);
+  outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
+  outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
+  outb_reg0(dep, DP_ISR, 0xFF);        /* Clears Interrupt Status Register */
+  outb_reg0(dep, DP_IMR, 0);   /* Clears Interrupt Mask Register */
+
+  /* Copies station address in page 1 registers */
+  outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA); /* Selects Page 1 */
+  for (ix = 0; ix < SA_ADDR_LEN; ix += 1)      /* Initializes address */
+       outb_reg1(dep, DP_PAR0 + ix, dep->de_address.ea_addr[ix]);
+  for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1)   /* Initializes address */
+       outb_reg1(dep, ix, 0xFF);
+
+  outb_reg1(dep, DP_CURR, dep->de_startpage);
+  outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA); /* Selects Page 0 */
+
+  inb_reg0(dep, DP_CNTR0);     /* Resets counters by reading them */
+  inb_reg0(dep, DP_CNTR1);
+  inb_reg0(dep, DP_CNTR2);
+
+  dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE;
+  outb_reg0(dep, DP_ISR, 0xFF);        /* Clears Interrupt Status Register */
+  outb_reg0(dep, DP_IMR, dp_reg);      /* Sets Interrupt Mask register */
+
+  dp_reg = 0;
+  if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
+  if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
+  if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
+  outb_reg0(dep, DP_RCR, dp_reg);      /* Sets receive as requested */
+  outb_reg0(dep, DP_TCR, TCR_NORMAL);  /* Sets transmitter */
+
+  outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);   /* Starts board */
+
+  /* Initializes the send queue. */
+  for (ix = 0; ix < dep->de_sendq_nr; ix += 1)
+       dep->de_sendq[ix].sq_filled = 0;
+  dep->de_sendq_head = dep->de_sendq_tail = 0;
+
+  /* Device specific functions */
+  if (!dep->de_prog_IO) {
+       dep->de_user2nicf = mem_user2nic;
+       dep->de_nic2userf = mem_nic2user;
+       dep->de_getblockf = mem_getblock;
+  } else {
+#if PIO16 == 0
+       dep->de_user2nicf = pio_user2nic;
+       dep->de_nic2userf = pio_nic2user;
+       dep->de_getblockf = pio_getblock;
+#else
+#error Missing I/O functions for pio 16 bits
+#endif
+  }
+  dep->de_recvf = ns_recv;
+  dep->de_sendf = ns_send;
+  dep->de_flagsf = ns_reinit;
+  dep->de_resetf = ns_reset;
+  dep->de_getstatsf = ns_stats;
+  dep->de_dumpstatsf = ns_dodump;
+  dep->de_interruptf = ns_interrupt;
+
+  return;                      /* Done */
+}
+
+#if PIO16 == 1
+
+/*
+**  Name:      void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
+**  Function:  Copies a packet from user area to board (Prog. I/O, 16bits).
+*/
+static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
+{
+  u8_t two_bytes[2];
+  phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes);
+  vir_bytes ecount = (pktsize + 1) & NOT(0x0001);
+  int bytes, ix = 0, odd_byte = 0;
+  iovec_dat_t *iovp = &dep->de_write_iovec;
+
+  outb_reg0(dep, DP_ISR, ISR_RDC);
+  dp_read_setup(dep, ecount, pageno * DP_PAGESIZE);
+
+  do {
+       bytes = iovp->iod_iovec[ix].iov_size;
+       if (bytes > pktsize) bytes = pktsize;
+
+       phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
+       if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
+
+       if (odd_byte) {
+               phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1);
+               out_word(dep->de_data_port, *(u16_t *)two_bytes);
+               pktsize--;
+               bytes--;
+               phys_user++;
+               odd_byte = 0;
+               if (!bytes) continue;
+       }
+       ecount = bytes & NOT(0x0001);
+       if (ecount != 0) {
+               phys_outsw(dep->de_data_port, phys_user, ecount);
+               pktsize -= ecount;
+               bytes -= ecount;
+               phys_user += ecount;
+       }
+       if (bytes) {
+               phys_copy(phys_user, phys_2bytes, (phys_bytes) 1);
+               pktsize--;
+               bytes--;
+               phys_user++;
+               odd_byte = 1;
+       }
+       if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
+               dp_next_iovec(iovp);
+               ix = 0;
+       }
+
+  }  while (bytes > 0);
+
+  if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes);
+  for (ix = 0; ix < 100; ix++) {
+       if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
+  }
+  if (ix == 100) {
+       panic(dep->de_name, RdmaErrMsg, NO_NUM);
+  }
+  return;
+}
+
+/*
+**  Name:      void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize)
+**  Function:  Copies a packet from board to user area (Prog. I/O, 16bits).
+*/
+static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count)
+{
+  phys_bytes phys_user;
+  vir_bytes ecount;
+  int bytes, i;
+  u8_t two_bytes[2];
+  phys_bytes phys_2bytes;
+  int odd_byte;
+
+  ecount = (count + 1) & ~1;
+  phys_2bytes = vir2phys(two_bytes);
+  odd_byte = 0;
+
+  dp_read_setup(dep, ecount, nic_addr);
+
+  i = 0;
+  while (count > 0) {
+       if (i >= IOVEC_NR) {
+               dp_next_iovec(iovp);
+               i = 0;
+               continue;
+       }
+       bytes = iovp->iod_iovec[i].iov_size;
+       if (bytes > count) bytes = count;
+
+       phys_user = numap(iovp->iod_proc_nr,
+                         iovp->iod_iovec[i].iov_addr, bytes);
+       if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
+       if (odd_byte) {
+               phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1);
+               count--;
+               bytes--;
+               phys_user++;
+               odd_byte = 0;
+               if (!bytes) continue;
+       }
+       ecount = bytes & ~1;
+       if (ecount != 0) {
+               phys_insw(dep->de_data_port, phys_user, ecount);
+               count -= ecount;
+               bytes -= ecount;
+               phys_user += ecount;
+       }
+       if (bytes) {
+               *(u16_t *) two_bytes = in_word(dep->de_data_port);
+               phys_copy(phys_2bytes, phys_user, (phys_bytes) 1);
+               count--;
+               bytes--;
+               phys_user++;
+               odd_byte = 1;
+       }
+  }
+  return;
+}
+
+#endif                         /* PIO16 == 1 */
+
+#endif                         /* ENABLE_NETWORKING && ENABLE_DP8390 */
+
+/** end 8390.c **/
diff --git a/drivers/dpeth/8390.h b/drivers/dpeth/8390.h
new file mode 100644 (file)
index 0000000..e88ab2e
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/Makefile b/drivers/dpeth/Makefile
new file mode 100644 (file)
index 0000000..d404db5
--- /dev/null
@@ -0,0 +1,52 @@
+##
+##  Makefile for ISA ethernet drivers  May  02, 2000
+##
+##  $Log$
+##  Revision 1.1  2005/06/29 10:16:46  beng
+##  Import of dpeth 3c501/3c509b/.. ethernet driver by
+##  Giovanni Falzoni <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
diff --git a/drivers/dpeth/README b/drivers/dpeth/README
new file mode 100644 (file)
index 0000000..cfa96e0
--- /dev/null
@@ -0,0 +1,38 @@
+
+This is my implementation of a new network task 
+for the Minix kernel.  I did it initially to handle
+a 3c501 board (Etherlink), but those board are so
+unstable that it is not worth using them except for
+learning how to implement a driver.  When I got a
+3c509b board (Etherlink III) it was easier to
+write the code to handle them.  
+
+The Minix code in 'dp8390.c' is too specific for the
+National chip set, so what I did was to remove as 
+much as I needed of the code dependant from the chip
+and produce a generic task that, I hope, will be able
+to handle many more cards.
+
+$Log$
+Revision 1.1  2005/06/29 10:16:46  beng
+Import of dpeth 3c501/3c509b/.. ethernet driver by
+Giovanni Falzoni <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$
diff --git a/drivers/dpeth/devio.c b/drivers/dpeth/devio.c
new file mode 100644 (file)
index 0000000..ee16fda
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+**  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  **/
diff --git a/drivers/dpeth/dp.c b/drivers/dpeth/dp.c
new file mode 100644 (file)
index 0000000..6c04589
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/dp.h b/drivers/dpeth/dp.h
new file mode 100644 (file)
index 0000000..de4f034
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/ne.c b/drivers/dpeth/ne.c
new file mode 100644 (file)
index 0000000..4829e18
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+**  File:      ne.c    Jun. 08, 2000
+**
+**  Driver for the NE*000 ethernet cards and derivates.
+**  This file contains only the ne specific code,
+**  the rest is in 8390.c   Code specific for ISA bus only
+**
+**  Created:   March 15, 1994 by Philip Homburg <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 **/
diff --git a/drivers/dpeth/ne.h b/drivers/dpeth/ne.h
new file mode 100644 (file)
index 0000000..391d256
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/netbuff.c b/drivers/dpeth/netbuff.c
new file mode 100644 (file)
index 0000000..327fcf7
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+**  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 **/
diff --git a/drivers/dpeth/wd.c b/drivers/dpeth/wd.c
new file mode 100644 (file)
index 0000000..6ac888d
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+**  File:      wd.c
+**
+**  Driver for the Ethercard (WD80x3) and derivates
+**  This file contains only the wd80x3 specific code,
+**  the rest is in 8390.c
+**
+**  Created:   March 14, 1994 by Philip Homburg
+**  PchId:
+**
+**  Modified: Jun. 08, 2000 by Giovanni Falzoni <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 **/
diff --git a/drivers/dpeth/wd.h b/drivers/dpeth/wd.h
new file mode 100644 (file)
index 0000000..c3001ed
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+**  File: wd.h
+**   
+**  Created:   before Dec 28, 1992 by Philip Homburg
+**  $PchId: wdeth.h,v 1.4 1995/12/22 08:36:57 philip Exp $
+**
+**  $Log$
+**  Revision 1.1  2005/06/29 10:16:46  beng
+**  Import of dpeth 3c501/3c509b/.. ethernet driver by
+**  Giovanni Falzoni <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 **/
index 545504e25fedfa6ce0512113b548a664ee36ba19..51954ada3b50bb36eeaa3a67c5abe5b7ce824241 100755 (executable)
 #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 )      
 
 
 /*===========================================================================*
index e980a5bf2959e721749c946a7678f341e2b645a6..2cb996b189c4ddecb11ee077bff82460b4770395 100755 (executable)
@@ -32,7 +32,7 @@
 #endif
 
 /* Number of slots in the process table for non-kernel processes. */
-#define NR_PROCS         64
+#define NR_PROCS         64 
 
 /* The buffer cache should be made as large as you can afford. */
 #if (MACHINE == IBM_PC && _WORD_SIZE == 2)
@@ -92,7 +92,7 @@
 #define DMA_SECTORS        1   /* DMA buffer size (must be >= 1) */
 
 /* Enable or disable networking drivers. */
-#define ENABLE_DP8390   0      /* enable DP8390 ethernet driver */
+#define ENABLE_DPETH    1      /* enable DP8390 ethernet driver */
 #define   ENABLE_WDETH     0   /*   add Western Digital WD80x3 */
 #define   ENABLE_NE2000    0   /*   add Novell NE1000/NE2000 */
 #define   ENABLE_3C503     0   /*   add 3Com Etherlink II (3c503) */
index 1a9097351467ce856eaef71d2be91b836262a7a6..d2308891101e1a049c9390fbaae239ea653c3bc4 100755 (executable)
@@ -256,7 +256,7 @@ _phys_insb:
        mov     edx, 8(ebp)             ! port to read from
        mov     edi, 12(ebp)            ! destination addr
        mov     ecx, 16(ebp)            ! byte count
-       shr     ecx, 1                  ! word count
+!      shr     ecx, 1                  ! word count
    rep insb                            ! input many bytes
        pop     es
        pop     edi
index dc6e4c96ba468558fe92e23cb7bb33a99c83b559..743c997f49ac218026b804d38beb9b835d3dd74a 100755 (executable)
@@ -84,6 +84,9 @@ PUBLIC struct system_image image[] = {
 #endif
 #if ENABLE_FXP
  { FXP, 0,                0, 2, 0,           SYSTEM_CALL_MASK,  ALLOW_ALL_MASK,  "FXP" },
+#endif
+#if ENABLE_DPETH
+ { DPETH, 0,              0, 2, 0,           SYSTEM_CALL_MASK,  ALLOW_ALL_MASK,  "DPETH" },
 #endif
  { INIT_PROC_NR, 0,            0,   USER_Q, 0,         USER_CALL_MASK,    USER_PROC_SENDMASK,    "INIT"    },
 };
index aeb85b61bf14f172c4ef771494da52735728bd9f..6d859f5f9be16ee2460f17220880a300ba0aaaee 100644 (file)
@@ -138,9 +138,9 @@ PUBLIC void irqtab_dmp()
        "clock",        /* 00 */
        "keyboard",     /* 01 */
        "cascade",      /* 02 */
-       "eth/rs232",    /* 03 */
+       "rs232",        /* 03 */
        "rs232",        /* 04 */
-       "xt_wini",      /* 05 */
+       "NIC(eth)",     /* 05 */
        "floppy",       /* 06 */
        "printer",      /* 07 */
        "",     /* 08 */
index 7c9a7e5cb6b27ad78863b41d110dc2bdd8c83765..25e8a9044f15fbb29d4f305525c661f28e7ac115 100755 (executable)
@@ -18,6 +18,7 @@ PROGRAMS=     ../kernel/kernel \
        ../drivers/printer/printer \
        ../drivers/rtl8139/rtl8139 \
        ../drivers/fxp/fxp \
+       ../drivers/dpeth/dpeth \
        ../servers/init/init \
 #      bootdev.img