]> Zhao Yanbai Git Server - minix.git/commitdiff
Added dp8390 driver. Additional env_parse functions that take argc and argv.
authorPhilip Homburg <philip@cs.vu.nl>
Fri, 5 Aug 2005 09:53:08 +0000 (09:53 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Fri, 5 Aug 2005 09:53:08 +0000 (09:53 +0000)
16 files changed:
drivers/Makefile
drivers/dp8390/3c503.c [new file with mode: 0644]
drivers/dp8390/3c503.h [new file with mode: 0644]
drivers/dp8390/Makefile [new file with mode: 0644]
drivers/dp8390/dp8390.c [new file with mode: 0644]
drivers/dp8390/dp8390.h [new file with mode: 0644]
drivers/dp8390/local.h [new file with mode: 0644]
drivers/dp8390/ne2000.c [new file with mode: 0644]
drivers/dp8390/ne2000.h [new file with mode: 0644]
drivers/dp8390/rtl8029.c [new file with mode: 0644]
drivers/dp8390/rtl8029.h [new file with mode: 0644]
drivers/dp8390/wdeth.c [new file with mode: 0644]
drivers/dp8390/wdeth.h [new file with mode: 0644]
include/minix/sysutil.h
lib/sysutil/env_parse.c
lib/sysutil/env_prefix.c

index ea91997250b631b5e0805d334d8ff0a936b144ff..eaefc09b11cf8ee742b2fd962c7525f26257e9bb 100644 (file)
@@ -28,3 +28,4 @@ all install depend clean:
        cd ./bios_wini && $(MAKE) $@
        cd ./cmos && $(MAKE) $@
        cd ./random && $(MAKE) $@
+       cd ./dp8390 && $(MAKE) $@
diff --git a/drivers/dp8390/3c503.c b/drivers/dp8390/3c503.c
new file mode 100644 (file)
index 0000000..d1f317d
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ *     3c503.c         A shared memory driver for Etherlink II board.
+ *
+ *     Created:        Dec. 20, 1996 by G. Falzoni <falzoni@marina.scn.de>
+ *
+ *     Inspired by the TNET package by M. Ostrowski, the driver for Linux
+ *     by D. Becker, the Crynwr 3c503 packet driver, and the Amoeba driver.
+ *
+ *     It works in shared memory mode and should be used with the
+ *     device driver for NS 8390 based cards of Minix.  Programmed
+ *     I/O could be used as well but would result in poor performance.
+ */
+
+#include "../drivers.h"
+
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+
+#include "local.h"
+#include "dp8390.h"
+#include "3c503.h"
+
+#if ENABLE_3C503
+
+#define MILLIS_TO_TICKS(m)  (((m)*HZ/1000)+1)
+
+_PROTOTYPE(static void el2_init, (dpeth_t *dep));
+_PROTOTYPE(static void el2_stop, (dpeth_t *dep));
+_PROTOTYPE( static void milli_delay, (unsigned long millis)            );
+
+
+/*===========================================================================*
+ *                             el2_init                                     *
+ *===========================================================================*/
+static void el2_init(dep)
+dpeth_t * dep;
+{
+  /* Initalize hardware and data structures. */
+  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 = 0;         /* Programmed I/O not yet available */
+
+  /* Check width of data bus:
+   * 1. Write 0 to WTS bit.  The board will drive it to 1 if it is a
+   *    16-bit card.
+   * 2. Select page 2
+   * 3. See if it is a 16-bit card
+   * 4. Select page 0
+   */
+  outb_el2(dep, DP_CR, CR_PS_P0|CR_DM_ABORT|CR_STP);
+  outb_el2(dep, DP_DCR, 0);
+  outb_el2(dep, DP_CR, CR_PS_P2|CR_DM_ABORT|CR_STP);
+  dep->de_16bit = (inb_el2(dep, DP_DCR) & DCR_WTS) != 0;
+  outb_el2(dep, DP_CR, CR_PS_P0|CR_DM_ABORT|CR_STP);
+
+  /* Allocate one send buffer (1.5KB) per 8KB of on board memory. */
+  sendq_nr = (dep->de_ramsize - dep->de_offset_page) / 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("", "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 */
+
+  if (!debug) {
+       printf("%s: 3c503 at %X:%d:%lX\n",
+               dep->de_name, dep->de_base_port, dep->de_irq,
+               dep->de_linmem + dep->de_offset_page);
+  } else {
+       printf("%s: 3Com Etherlink II %sat I/O address 0x%X, "
+                       "memory address 0x%lX, irq %d\n",
+               dep->de_name, dep->de_16bit ? "(16-bit) " : "",
+               dep->de_base_port,
+               dep->de_linmem + dep->de_offset_page,
+               dep->de_irq);
+  }
+}
+
+
+/*===========================================================================*
+ *                             el2_stop                                     *
+ *===========================================================================*/
+static void el2_stop(dep)
+dpeth_t * dep;
+{
+  /* Stops board by disabling interrupts. */
+
+#if DEBUG
+  printf("%s: stopping Etherlink\n", dep->de_name);
+#endif
+  outb_el2(dep, EL2_CFGR, ECFGR_IRQOFF);
+  return;
+}
+
+
+/*===========================================================================*
+ *                             el2_probe                                    *
+ *===========================================================================*/
+int el2_probe(dep)
+dpeth_t * dep;
+{
+  /* Probe for the presence of an EtherLink II card.  Initialize memory
+   * addressing if card detected.
+   */
+  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 0;
+  if (!((membase = inb_el2(dep, EL2_MEMBASE)) & 0xF0)) return 0;
+  if ((iobase & (iobase - 1)) || (membase & (membase - 1))) return 0;
+
+  /* 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 0;               /* 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);
+  dep->de_offset_page = (EL2_SM_START_PG * DP_PAGESIZE);
+  dep->de_ramsize = (EL2_SM_STOP_PG - EL2_SM_START_PG) * DP_PAGESIZE;
+
+  /* (Bad kludge, something Philip needs to look into. -- kjb) */
+  dep->de_linmem -= dep->de_offset_page;
+  dep->de_ramsize += dep->de_offset_page;
+
+  /* Board initialization and stop functions */
+  dep->de_initf = el2_init;
+  dep->de_stopf = el2_stop;
+  return 1;
+}
+
+static void milli_delay(unsigned long millis)
+{
+       tickdelay(MILLIS_TO_TICKS(millis));
+}
+
+#endif /* ENABLE_3C503 */
+
+/** 3c503.c **/
+
+/*
+ * $PchId: 3c503.c,v 1.3 2003/09/10 15:33:04 philip Exp $
+ */
diff --git a/drivers/dp8390/3c503.h b/drivers/dp8390/3c503.h
new file mode 100644 (file)
index 0000000..cd9ed46
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *     3c503.h         A shared memory driver for Etherlink II board.
+ *
+ *     Created:        Dec. 20, 1996 by G. Falzoni <falzoni@marina.scn.de>
+ */
+
+#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 **/
+
+/*
+ * $PchId: 3c503.h,v 1.3 2003/09/10 15:34:29 philip Exp $
+ */
diff --git a/drivers/dp8390/Makefile b/drivers/dp8390/Makefile
new file mode 100644 (file)
index 0000000..e633e85
--- /dev/null
@@ -0,0 +1,44 @@
+# Makefile for dp8390 driver
+DRIVER = dp8390
+
+# directories
+u = /usr
+i = $u/include
+s = $i/sys
+m = $i/minix
+b = $i/ibm
+d = ..
+
+# programs, flags, etc.
+CC =   exec cc
+CFLAGS = -I$i
+LDFLAGS = -i 
+LIBS = -lsys -lsysutil -ltimers
+
+OBJ = 3c503.o dp8390.o ne2000.o rtl8029.o wdeth.o
+LIBPCI = $d/libpci/pci.o $d/libpci/pci_table.o
+
+# build local binary
+all build:     $(DRIVER)
+$(DRIVER):     $(OBJ) $(LIBPCI)
+       $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBPCI) $(LIBS)
+       install -S 256w $(DRIVER)
+
+$(LIBPCI): 
+       cd $d/libpci && $(MAKE) 
+
+# install with other drivers
+install:       /usr/sbin/$(DRIVER)
+/usr/sbin/$(DRIVER):   $(DRIVER)
+       install -o root -cs $? $@
+
+# clean up local files
+clean:
+       rm -f *.o *.bak $(DRIVER)
+
+depend: 
+       /usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c ../libpci/*.c > .depend
+
+# Include generated dependencies.
+include .depend
+
diff --git a/drivers/dp8390/dp8390.c b/drivers/dp8390/dp8390.c
new file mode 100644 (file)
index 0000000..b6b91f9
--- /dev/null
@@ -0,0 +1,1986 @@
+/*
+ * dp8390.c
+ *
+ * This file contains a ethernet device driver for NS dp8390 based ethernet
+ * cards.
+ *
+ * The valid messages and their parameters are:
+ *
+ *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR
+ * |------------+----------+---------+----------+---------+---------|
+ * | HARDINT   |          |         |          |         |         |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_WRITE  | port nr  | proc nr | count    | mode    | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_WRITEV | port nr  | proc nr | count    | mode    | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_READ   | port nr  | proc nr | count    |         | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_READV  | port nr  | proc nr | count    |         | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_INIT   | port nr  | proc nr | mode     |         | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_GETSTAT        | port nr  | proc nr |          |         | address |
+ * |------------|----------|---------|----------|---------|---------|
+ * | DL_STOP   | port_nr  |         |          |         |         |
+ * |------------|----------|---------|----------|---------|---------|
+ *
+ * The messages sent are:
+ *
+ *   m-type       DL_PORT    DL_PROC   DL_COUNT   DL_STAT   DL_CLCK
+ * |-------------+----------+---------+----------+---------+---------|
+ * |DL_TASK_REPLY| port nr  | proc nr | rd-count | err|stat| clock   |
+ * |-------------+----------+---------+----------+---------+---------|
+ *
+ *   m_type       m3_i1     m3_i2       m3_ca1
+ * |-------------+---------+-----------+---------------|
+ * |DL_INIT_REPLY| port nr | last port | ethernet addr |
+ * |-------------+---------+-----------+---------------|
+ *
+ * Created:    before Dec 28, 1992 by Philip Homburg <philip@f-mnx.phicoh.com>
+ *
+ * Modified Mar 10 1994 by Philip Homburg
+ *     Become a generic dp8390 driver.
+ *
+ * Modified Dec 20 1996 by G. Falzoni <falzoni@marina.scn.de>
+ *     Added support for 3c503 boards.
+ */
+
+#include "../drivers.h"
+
+#include <stdlib.h>
+#include <minix/com.h>
+#include <net/hton.h>
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#include "assert.h"
+
+#include "local.h"
+#include "dp8390.h"
+
+#define DE_PORT_NR     3
+
+static dpeth_t de_table[DE_PORT_NR];
+static u16_t eth_ign_proto;
+static int arg_c;
+static char **arg_v;
+
+/* Configuration */
+typedef struct dp_conf
+{
+       port_t dpc_port;
+       int dpc_irq;
+       phys_bytes dpc_mem;
+       char *dpc_envvar;
+} dp_conf_t;
+
+dp_conf_t dp_conf[]=   /* Card addresses */
+{
+       /* I/O port, IRQ,  Buffer address,  Env. var. */
+       {  0x280,     3,    0xD0000,        "DPETH0"    },
+       {  0x300,     5,    0xC8000,        "DPETH1"    },
+       {  0x380,    10,    0xD8000,        "DPETH2"    },
+};
+
+/* Test if dp_conf has exactly DE_PORT_NR entries.  If not then you will see
+ * the error: "array size is negative".
+ */
+extern int ___dummy[DE_PORT_NR == sizeof(dp_conf)/sizeof(dp_conf[0]) ? 1 : -1];
+
+/* Card inits configured out? */
+#if !ENABLE_WDETH
+#define wdeth_probe(dep)       (0)
+#endif
+#if !ENABLE_NE2000
+#define ne_probe(dep)          (0)
+#endif
+#if !ENABLE_3C503
+#define el2_probe(dep)         (0)
+#endif
+
+/* Some clones of the dp8390 and the PC emulator 'Bochs' require the CR_STA
+ * on writes to the CR register. Additional CR_STAs do not appear to hurt
+ * genuine dp8390s
+ */
+#define CR_EXTRA       CR_STA
+
+#if ENABLE_PCI
+_PROTOTYPE( static void pci_conf, (void)                               );
+#endif
+_PROTOTYPE( static void do_vwrite, (message *mp, int from_int,
+                                                       int vectored)   );
+_PROTOTYPE( static void do_vread, (message *mp, int vectored)          );
+_PROTOTYPE( static void do_init, (message *mp)                         );
+_PROTOTYPE( static void do_int, (dpeth_t *dep)                         );
+_PROTOTYPE( static void do_getstat, (message *mp)                      );
+_PROTOTYPE( static void do_stop, (message *mp)                         );
+_PROTOTYPE( static void dp_init, (dpeth_t *dep)                                );
+_PROTOTYPE( static void dp_confaddr, (dpeth_t *dep)                    );
+_PROTOTYPE( static void dp_reinit, (dpeth_t *dep)                      );
+_PROTOTYPE( static void dp_reset, (dpeth_t *dep)                       );
+_PROTOTYPE( static void dp_check_ints, (dpeth_t *dep)                  );
+_PROTOTYPE( static void dp_recv, (dpeth_t *dep)                                );
+_PROTOTYPE( static void dp_send, (dpeth_t *dep)                                );
+_PROTOTYPE( static void dp8390_stop, (void)                            );
+_PROTOTYPE( static void dp_getblock, (dpeth_t *dep, int page,
+                               size_t offset, size_t size, void *dst)  );
+_PROTOTYPE( static void dp_pio8_getblock, (dpeth_t *dep, int page,
+                               size_t offset, size_t size, void *dst)  );
+_PROTOTYPE( static void dp_pio16_getblock, (dpeth_t *dep, int page,
+                               size_t offset, size_t size, void *dst)  );
+_PROTOTYPE( static int dp_pkt2user, (dpeth_t *dep, int page,
+                                                       int length)     );
+_PROTOTYPE( static void dp_user2nic, (dpeth_t *dep, iovec_dat_t *iovp, 
+               vir_bytes offset, int nic_addr, vir_bytes count)        );
+_PROTOTYPE( static void dp_pio8_user2nic, (dpeth_t *dep,
+                               iovec_dat_t *iovp, vir_bytes offset,
+                               int nic_addr, vir_bytes count)          );
+_PROTOTYPE( static void dp_pio16_user2nic, (dpeth_t *dep,
+                               iovec_dat_t *iovp, vir_bytes offset,
+                               int nic_addr, vir_bytes count)          );
+_PROTOTYPE( static void dp_nic2user, (dpeth_t *dep, int nic_addr, 
+               iovec_dat_t *iovp, vir_bytes offset, vir_bytes count)   );
+_PROTOTYPE( static void dp_pio8_nic2user, (dpeth_t *dep, int nic_addr, 
+               iovec_dat_t *iovp, vir_bytes offset, vir_bytes count)   );
+_PROTOTYPE( static void dp_pio16_nic2user, (dpeth_t *dep, int nic_addr, 
+               iovec_dat_t *iovp, vir_bytes offset, vir_bytes count)   );
+_PROTOTYPE( static void dp_next_iovec, (iovec_dat_t *iovp)             );
+_PROTOTYPE( static void conf_hw, (dpeth_t *dep)                                );
+_PROTOTYPE( static void update_conf, (dpeth_t *dep, dp_conf_t *dcp)    );
+_PROTOTYPE( static int calc_iovec_size, (iovec_dat_t *iovp)            );
+_PROTOTYPE( static void reply, (dpeth_t *dep, int err, int may_block)  );
+_PROTOTYPE( static void mess_reply, (message *req, message *reply)     );
+_PROTOTYPE( static void get_userdata, (int user_proc,
+               vir_bytes user_addr, vir_bytes count, void *loc_addr)   );
+_PROTOTYPE( static void put_userdata, (int user_proc,
+               vir_bytes user_addr, vir_bytes count, void *loc_addr)   );
+_PROTOTYPE( static void insb, (port_t port, void *buf, size_t size)                            );
+_PROTOTYPE( static void insw, (port_t port, void *buf, size_t size)                            );
+_PROTOTYPE( static void do_vir_insb, (port_t port, int proc,
+                                       vir_bytes buf, size_t size)     );
+_PROTOTYPE( static void do_vir_insw, (port_t port, int proc,
+                                       vir_bytes buf, size_t size)     );
+_PROTOTYPE( static void do_vir_outsb, (port_t port, int proc,
+                                       vir_bytes buf, size_t size)     );
+_PROTOTYPE( static void do_vir_outsw, (port_t port, int proc,
+                                       vir_bytes buf, size_t size)     );
+
+/*===========================================================================*
+ *                             dpeth_task                                   *
+ *===========================================================================*/
+int main(int argc, char *argv[])
+{
+       message m;
+       int i, irq, r;
+       dpeth_t *dep;
+       long v;
+
+       arg_c= argc;
+       arg_v= argv;
+
+       for (i= 0, dep= de_table; i<DE_PORT_NR; i++, dep++)
+       {
+               strcpy(dep->de_name, "dp8390#0");
+               dep->de_name[7] += i;
+       }
+
+       v= 0;
+       (void) env_parse_x(arg_c, arg_v, 
+               "ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
+       eth_ign_proto= htons((u16_t) v);
+
+       while (TRUE)
+       {
+               if ((r= receive(ANY, &m)) != OK)
+                       panic("", "dp8390: receive failed", r);
+
+               switch (m.m_type)
+               {
+               case DL_WRITE:  do_vwrite(&m, FALSE, FALSE);    break;
+               case DL_WRITEV: do_vwrite(&m, FALSE, TRUE);     break;
+               case DL_READ:   do_vread(&m, FALSE);            break;
+               case DL_READV:  do_vread(&m, TRUE);             break;
+               case DL_INIT:   do_init(&m);                    break;
+               case DL_GETSTAT: do_getstat(&m);                break;
+               case DL_STOP:   do_stop(&m);                    break;
+               case HARD_INT:
+                       for (i= 0, dep= &de_table[0]; i<DE_PORT_NR; i++, dep++)
+                       {
+                               if (dep->de_mode != DEM_ENABLED)
+                                       continue;
+                               assert(dep->de_flags & DEF_ENABLED);
+                               irq= dep->de_irq;
+                               assert(irq >= 0 && irq < NR_IRQ_VECTORS);
+                               if (dep->de_int_pending || 1)
+                               {
+                                       dep->de_int_pending= 0;
+                                       dp_check_ints(dep);
+                                       do_int(dep);
+                                       r= sys_irqenable(&dep->de_hook);
+                                       if (r != OK)
+                                       {
+                                               panic("DP8390", 
+                                               "unable enable interrupts", r);
+                                       }
+                               }
+                       }
+                       break;
+               case SYS_SIG:   {
+                       sigset_t sigset = m.NOTIFY_ARG;
+                       if (sigismember(&sigset, SIGKSTOP)) dp8390_stop();
+                       break;
+               }
+               case SYN_ALARM:
+                       printf("dp8390: strange, got SYN_ALARM\n");
+                       break;
+               default:
+                       panic("", "dp8390: illegal message", m.m_type);
+               }
+       }
+}
+
+
+#if 0
+/*===========================================================================*
+ *                             dp8390_dump                                  *
+ *===========================================================================*/
+void dp8390_dump()
+{
+       dpeth_t *dep;
+       int i, isr;
+
+       printf("\n");
+       for (i= 0, dep = &de_table[0]; i<DE_PORT_NR; i++, dep++)
+       {
+#if XXX
+               if (dep->de_mode == DEM_DISABLED)
+                       printf("dp8390 port %d is disabled\n", i);
+               else if (dep->de_mode == DEM_SINK)
+                       printf("dp8390 port %d is in sink mode\n", i);
+#endif
+
+               if (dep->de_mode != DEM_ENABLED)
+                       continue;
+
+               printf("dp8390 statistics of port %d:\n", i);
+
+               printf("recvErr    :%8ld\t", dep->de_stat.ets_recvErr);
+               printf("sendErr    :%8ld\t", dep->de_stat.ets_sendErr);
+               printf("OVW        :%8ld\n", dep->de_stat.ets_OVW);
+
+               printf("CRCerr     :%8ld\t", dep->de_stat.ets_CRCerr);
+               printf("frameAll   :%8ld\t", dep->de_stat.ets_frameAll);
+               printf("missedP    :%8ld\n", dep->de_stat.ets_missedP);
+
+               printf("packetR    :%8ld\t", dep->de_stat.ets_packetR);
+               printf("packetT    :%8ld\t", dep->de_stat.ets_packetT);
+               printf("transDef   :%8ld\n", dep->de_stat.ets_transDef);
+
+               printf("collision  :%8ld\t", dep->de_stat.ets_collision);
+               printf("transAb    :%8ld\t", dep->de_stat.ets_transAb);
+               printf("carrSense  :%8ld\n", dep->de_stat.ets_carrSense);
+
+               printf("fifoUnder  :%8ld\t", dep->de_stat.ets_fifoUnder);
+               printf("fifoOver   :%8ld\t", dep->de_stat.ets_fifoOver);
+               printf("CDheartbeat:%8ld\n", dep->de_stat.ets_CDheartbeat);
+
+               printf("OWC        :%8ld\t", dep->de_stat.ets_OWC);
+
+               isr= inb_reg0(dep, DP_ISR);
+               printf("dp_isr = 0x%x + 0x%x, de_flags = 0x%x\n", isr,
+                                       inb_reg0(dep, DP_ISR), dep->de_flags);
+       }
+}
+#endif
+
+
+/*===========================================================================*
+ *                             dp8390_stop                                  *
+ *===========================================================================*/
+static void dp8390_stop()
+{
+       message mess;
+       int i;
+
+       for (i= 0; i<DE_PORT_NR; i++)
+       {
+               if (de_table[i].de_mode != DEM_ENABLED)
+                       continue;
+               mess.m_type= DL_STOP;
+               mess.DL_PORT= i;
+               do_stop(&mess);
+       }
+}
+
+#if ENABLE_PCI
+/*===========================================================================*
+ *                             pci_conf                                     *
+ *===========================================================================*/
+static void pci_conf()
+{
+       int i, h;
+       char *envvar;
+       struct dpeth *dep;
+       static char envfmt[] = "*:d.d.d";
+       long v;
+       static int first_time= 1;
+
+       if (!first_time)
+               return;
+       first_time= 0;
+
+       for (i= 0, dep= de_table; i<DE_PORT_NR; i++, dep++)
+       {
+               envvar= dp_conf[i].dpc_envvar;
+               if (!(dep->de_pci= env_prefix_x(arg_c, arg_v, envvar, "pci")))
+                       continue;       /* no PCI config */
+               v= 0;
+               (void) env_parse_x(arg_c, arg_v, envvar, envfmt, 1, &v, 0, 255);
+               dep->de_pcibus= v;
+               v= 0;
+               (void) env_parse_x(arg_c, arg_v, envvar, envfmt, 2, &v, 0, 255);
+               dep->de_pcidev= v;
+               v= 0;
+               (void) env_parse_x(arg_c, arg_v, envvar, envfmt, 3, &v, 0, 255);
+               dep->de_pcifunc= v;
+       }
+
+       for (h= 1; h >= 0; h--) {
+               for (i= 0, dep= de_table; i<DE_PORT_NR; i++, dep++)
+               {
+                       if (!dep->de_pci)
+                               continue;
+                       if (((dep->de_pcibus | dep->de_pcidev |
+                               dep->de_pcifunc) != 0) != h)
+                       {
+                               continue;
+                       }
+                       if (!rtl_probe(dep))
+                               dep->de_pci= -1;
+               }
+       }
+}
+#endif /* ENABLE_PCI */
+
+/*===========================================================================*
+ *                             do_vwrite                                    *
+ *===========================================================================*/
+static void do_vwrite(mp, from_int, vectored)
+message *mp;
+int from_int;
+int vectored;
+{
+       int port, count, size;
+       int sendq_head;
+       dpeth_t *dep;
+
+       port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (port < 0 || port >= DE_PORT_NR)
+               panic("", "dp8390: illegal port", port);
+       dep= &de_table[port];
+       dep->de_client= mp->DL_PROC;
+
+       if (dep->de_mode == DEM_SINK)
+       {
+               assert(!from_int);
+               dep->de_flags |= DEF_PACK_SEND;
+               reply(dep, OK, FALSE);
+               return;
+       }
+       assert(dep->de_mode == DEM_ENABLED);
+       assert(dep->de_flags & DEF_ENABLED);
+       if (dep->de_flags & DEF_SEND_AVAIL)
+               panic("", "dp8390: send already in progress", NO_NUM);
+
+       sendq_head= dep->de_sendq_head;
+       if (dep->de_sendq[sendq_head].sq_filled)
+       {
+               if (from_int)
+                       panic("", "dp8390: should not be sending\n", NO_NUM);
+               dep->de_sendmsg= *mp;
+               dep->de_flags |= DEF_SEND_AVAIL;
+               reply(dep, OK, FALSE);
+               return;
+       }
+       assert(!(dep->de_flags & DEF_PACK_SEND));
+
+       if (vectored)
+       {
+               get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
+                       (count > IOVEC_NR ? IOVEC_NR : count) *
+                       sizeof(iovec_t), dep->de_write_iovec.iod_iovec);
+               dep->de_write_iovec.iod_iovec_s = count;
+               dep->de_write_iovec.iod_proc_nr = mp->DL_PROC;
+               dep->de_write_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
+
+               dep->de_tmp_iovec = dep->de_write_iovec;
+               size = calc_iovec_size(&dep->de_tmp_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 =
+                       mp->DL_COUNT;
+               dep->de_write_iovec.iod_iovec_s = 1;
+               dep->de_write_iovec.iod_proc_nr = mp->DL_PROC;
+               dep->de_write_iovec.iod_iovec_addr = 0;
+               size= mp->DL_COUNT;
+       }
+       if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
+       {
+               panic("", "dp8390: invalid packet size", size);
+       }
+       (dep->de_user2nicf)(dep, &dep->de_write_iovec, 0,
+               dep->de_sendq[sendq_head].sq_sendpage * DP_PAGESIZE,
+               size);
+       dep->de_sendq[sendq_head].sq_filled= TRUE;
+       if (dep->de_sendq_tail == sendq_head)
+       {
+               outb_reg0(dep, DP_TPSR, dep->de_sendq[sendq_head].sq_sendpage);
+               outb_reg0(dep, DP_TBCR1, size >> 8);
+               outb_reg0(dep, DP_TBCR0, size & 0xff);
+               outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);/* there it goes.. */
+       }
+       else
+               dep->de_sendq[sendq_head].sq_size= size;
+       
+       if (++sendq_head == dep->de_sendq_nr)
+               sendq_head= 0;
+       assert(sendq_head < SENDQ_NR);
+       dep->de_sendq_head= sendq_head;
+
+       dep->de_flags |= DEF_PACK_SEND;
+
+       /* If the interrupt handler called, don't send a reply. The reply
+        * will be sent after all interrupts are handled. 
+        */
+       if (from_int)
+               return;
+       reply(dep, OK, FALSE);
+
+       assert(dep->de_mode == DEM_ENABLED);
+       assert(dep->de_flags & DEF_ENABLED);
+}
+
+
+/*===========================================================================*
+ *                             do_vread                                     *
+ *===========================================================================*/
+static void do_vread(mp, vectored)
+message *mp;
+int vectored;
+{
+       int port, count;
+       int size;
+       dpeth_t *dep;
+
+       port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (port < 0 || port >= DE_PORT_NR)
+               panic("", "dp8390: illegal port", port);
+       dep= &de_table[port];
+       dep->de_client= mp->DL_PROC;
+       if (dep->de_mode == DEM_SINK)
+       {
+               reply(dep, OK, FALSE);
+               return;
+       }
+       assert(dep->de_mode == DEM_ENABLED);
+       assert(dep->de_flags & DEF_ENABLED);
+
+       if(dep->de_flags & DEF_READING)
+               panic("", "dp8390: read already in progress", NO_NUM);
+
+       if (vectored)
+       {
+               get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
+                       (count > IOVEC_NR ? IOVEC_NR : count) *
+                       sizeof(iovec_t), dep->de_read_iovec.iod_iovec);
+               dep->de_read_iovec.iod_iovec_s = count;
+               dep->de_read_iovec.iod_proc_nr = mp->DL_PROC;
+               dep->de_read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
+
+               dep->de_tmp_iovec = dep->de_read_iovec;
+               size= calc_iovec_size(&dep->de_tmp_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 =
+                       mp->DL_COUNT;
+               dep->de_read_iovec.iod_iovec_s = 1;
+               dep->de_read_iovec.iod_proc_nr = mp->DL_PROC;
+               dep->de_read_iovec.iod_iovec_addr = 0;
+               size= count;
+       }
+       if (size < ETH_MAX_PACK_SIZE_TAGGED)
+               panic("", "dp8390: wrong packet size", size);
+       dep->de_flags |= DEF_READING;
+
+       dp_recv(dep);
+
+       if ((dep->de_flags & (DEF_READING|DEF_STOPPED)) ==
+               (DEF_READING|DEF_STOPPED))
+       {
+               /* The chip is stopped, and all arrived packets are 
+                * delivered.
+                */
+               dp_reset(dep);
+       }
+       reply(dep, OK, FALSE);
+}
+
+
+/*===========================================================================*
+ *                             do_init                                      *
+ *===========================================================================*/
+static void do_init(mp)
+message *mp;
+{
+       int port;
+       dpeth_t *dep;
+       message reply_mess;
+
+#if ENABLE_PCI
+       pci_conf(); /* Configure PCI devices. */
+#endif
+
+       port = mp->DL_PORT;
+       if (port < 0 || port >= DE_PORT_NR)
+       {
+               reply_mess.m_type= DL_INIT_REPLY;
+               reply_mess.m3_i1= ENXIO;
+               mess_reply(mp, &reply_mess);
+               return;
+       }
+       dep= &de_table[port];
+       if (dep->de_mode == DEM_DISABLED)
+       {
+               /* This is the default, try to (re)locate the device. */
+               conf_hw(dep);
+               if (dep->de_mode == DEM_DISABLED)
+               {
+                       /* Probe failed, or the device is configured off. */
+                       reply_mess.m_type= DL_INIT_REPLY;
+                       reply_mess.m3_i1= ENXIO;
+                       mess_reply(mp, &reply_mess);
+                       return;
+               }
+               if (dep->de_mode == DEM_ENABLED)
+                       dp_init(dep);
+       }
+
+       if (dep->de_mode == DEM_SINK)
+       {
+               strncpy((char *) dep->de_address.ea_addr, "ZDP", 6);
+               dep->de_address.ea_addr[5] = port;
+               dp_confaddr(dep);
+               reply_mess.m_type = DL_INIT_REPLY;
+               reply_mess.m3_i1 = mp->DL_PORT;
+               reply_mess.m3_i2 = DE_PORT_NR;
+               *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
+               mess_reply(mp, &reply_mess);
+               return;
+       }
+       assert(dep->de_mode == DEM_ENABLED);
+       assert(dep->de_flags & DEF_ENABLED);
+
+       dep->de_flags &= ~(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_client = mp->m_source;
+       dp_reinit(dep);
+
+       reply_mess.m_type = DL_INIT_REPLY;
+       reply_mess.m3_i1 = mp->DL_PORT;
+       reply_mess.m3_i2 = DE_PORT_NR;
+       *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
+
+       mess_reply(mp, &reply_mess);
+}
+
+/*===========================================================================*
+ *                             do_int                                       *
+ *===========================================================================*/
+static void do_int(dep)
+dpeth_t *dep;
+{
+       if (dep->de_flags & (DEF_PACK_SEND | DEF_PACK_RECV))
+               reply(dep, OK, TRUE);
+}
+
+
+/*===========================================================================*
+ *                             do_getstat                                   *
+ *===========================================================================*/
+static void do_getstat(mp)
+message *mp;
+{
+       int port;
+       dpeth_t *dep;
+
+       port = mp->DL_PORT;
+       if (port < 0 || port >= DE_PORT_NR)
+               panic("", "dp8390: illegal port", port);
+       dep= &de_table[port];
+       dep->de_client= mp->DL_PROC;
+       if (dep->de_mode == DEM_SINK)
+       {
+               put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
+                       (vir_bytes) sizeof(dep->de_stat), &dep->de_stat);
+               reply(dep, OK, FALSE);
+               return;
+       }
+       assert(dep->de_mode == DEM_ENABLED);
+       assert(dep->de_flags & DEF_ENABLED);
+
+       dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
+       dep->de_stat.ets_frameAll += inb_reg0(dep, DP_CNTR1);
+       dep->de_stat.ets_missedP += inb_reg0(dep, DP_CNTR2);
+
+       put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
+               (vir_bytes) sizeof(dep->de_stat), &dep->de_stat);
+       reply(dep, OK, FALSE);
+}
+
+
+/*===========================================================================*
+ *                             do_stop                                      *
+ *===========================================================================*/
+static void do_stop(mp)
+message *mp;
+{
+       int port;
+       dpeth_t *dep;
+
+       port = mp->DL_PORT;
+
+       if (port < 0 || port >= DE_PORT_NR)
+               panic("", "dp8390: illegal port", port);
+       dep= &de_table[port];
+       if (dep->de_mode == DEM_SINK)
+               return;
+       assert(dep->de_mode == DEM_ENABLED);
+
+       if (!(dep->de_flags & DEF_ENABLED))
+               return;
+
+       outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
+       (dep->de_stopf)(dep);
+
+       dep->de_flags= DEF_EMPTY;
+}
+
+
+/*===========================================================================*
+ *                             dp_init                                      *
+ *===========================================================================*/
+static void dp_init(dep)
+dpeth_t *dep;
+{
+       int dp_rcr_reg;
+       int i, r;
+
+       /* General initialization */
+       dep->de_flags = DEF_EMPTY;
+       (*dep->de_initf)(dep);
+
+       dp_confaddr(dep);
+
+       if (debug)
+       {
+               printf("%s: Ethernet address ", dep->de_name);
+               for (i= 0; i < 6; i++)
+                       printf("%x%c", dep->de_address.ea_addr[i],
+                                                       i < 5 ? ':' : '\n');
+       }
+
+       /* Initialization of the dp8390 following the mandatory procedure
+        * in reference manual ("DP8390D/NS32490D NIC Network Interface
+        * Controller", National Semiconductor, July 1995, Page 29).
+        */
+       /* Step 1: */
+       outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
+       /* Step 2: */
+       if (dep->de_16bit)
+               outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
+       else
+               outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES | DCR_BMS);
+       /* Step 3: */
+       outb_reg0(dep, DP_RBCR0, 0);
+       outb_reg0(dep, DP_RBCR1, 0);
+       /* Step 4: */
+       dp_rcr_reg = 0;
+       if (dep->de_flags & DEF_PROMISC)
+               dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM;
+       if (dep->de_flags & DEF_BROAD)
+               dp_rcr_reg |= RCR_AB;
+       if (dep->de_flags & DEF_MULTI)
+               dp_rcr_reg |= RCR_AM;
+       outb_reg0(dep, DP_RCR, dp_rcr_reg);
+       /* Step 5: */
+       outb_reg0(dep, DP_TCR, TCR_INTERNAL);
+       /* Step 6: */
+       outb_reg0(dep, DP_BNRY, dep->de_startpage);
+       outb_reg0(dep, DP_PSTART, dep->de_startpage);
+       outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
+       /* Step 7: */
+       outb_reg0(dep, DP_ISR, 0xFF);
+       /* Step 8: */
+       outb_reg0(dep, DP_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE |
+               IMR_OVWE | IMR_CNTE);
+       /* Step 9: */
+       outb_reg0(dep, DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
+
+       outb_reg1(dep, DP_PAR0, dep->de_address.ea_addr[0]);
+       outb_reg1(dep, DP_PAR1, dep->de_address.ea_addr[1]);
+       outb_reg1(dep, DP_PAR2, dep->de_address.ea_addr[2]);
+       outb_reg1(dep, DP_PAR3, dep->de_address.ea_addr[3]);
+       outb_reg1(dep, DP_PAR4, dep->de_address.ea_addr[4]);
+       outb_reg1(dep, DP_PAR5, dep->de_address.ea_addr[5]);
+
+       outb_reg1(dep, DP_MAR0, 0xff);
+       outb_reg1(dep, DP_MAR1, 0xff);
+       outb_reg1(dep, DP_MAR2, 0xff);
+       outb_reg1(dep, DP_MAR3, 0xff);
+       outb_reg1(dep, DP_MAR4, 0xff);
+       outb_reg1(dep, DP_MAR5, 0xff);
+       outb_reg1(dep, DP_MAR6, 0xff);
+       outb_reg1(dep, DP_MAR7, 0xff);
+
+       outb_reg1(dep, DP_CURR, dep->de_startpage + 1);
+       /* Step 10: */
+       outb_reg0(dep, DP_CR, CR_DM_ABORT | CR_STA);
+       /* Step 11: */
+       outb_reg0(dep, DP_TCR, TCR_NORMAL);
+
+       inb_reg0(dep, DP_CNTR0);                /* reset counters by reading */
+       inb_reg0(dep, DP_CNTR1);
+       inb_reg0(dep, DP_CNTR2);
+
+       /* Finish the initialization. */
+       dep->de_flags |= DEF_ENABLED;
+       for (i= 0; i<dep->de_sendq_nr; i++)
+               dep->de_sendq[i].sq_filled= 0;
+       dep->de_sendq_head= 0;
+       dep->de_sendq_tail= 0;
+       if (!dep->de_prog_IO)
+       {
+               dep->de_user2nicf= dp_user2nic;
+               dep->de_nic2userf= dp_nic2user;
+               dep->de_getblockf= dp_getblock;
+       }
+       else if (dep->de_16bit)
+       {
+               dep->de_user2nicf= dp_pio16_user2nic;
+               dep->de_nic2userf= dp_pio16_nic2user;
+               dep->de_getblockf= dp_pio16_getblock;
+       }
+       else
+       {
+               dep->de_user2nicf= dp_pio8_user2nic;
+               dep->de_nic2userf= dp_pio8_nic2user;
+               dep->de_getblockf= dp_pio8_getblock;
+       }
+
+       /* Set the interrupt handler and policy. Do not automatically 
+        * reenable interrupts. Return the IRQ line number on interrupts.
+        */
+       dep->de_hook = dep->de_irq;
+       r= sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
+       if (r != OK)
+               panic("DP8390", "sys_irqsetpolicy failed", r);
+
+       r= sys_irqenable(&dep->de_hook);
+       if (r != OK)
+       {
+               panic("DP8390", "unable enable interrupts", r);
+       }
+}
+
+
+/*===========================================================================*
+ *                             dp_confaddr                                  *
+ *===========================================================================*/
+static void dp_confaddr(dep)
+dpeth_t *dep;
+{
+       int i;
+       char eakey[16];
+       static char eafmt[]= "x:x:x:x:x:x";
+       long v;
+
+       /* User defined ethernet address? */
+       strcpy(eakey, dp_conf[dep-de_table].dpc_envvar);
+       strcat(eakey, "_EA");
+
+       for (i= 0; i < 6; i++)
+       {
+               v= dep->de_address.ea_addr[i];
+               if (env_parse_x(arg_c, arg_v,
+                       eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
+               {
+                       break;
+               }
+               dep->de_address.ea_addr[i]= v;
+       }
+
+       if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
+}
+
+
+/*===========================================================================*
+ *                             dp_reinit                                    *
+ *===========================================================================*/
+static void dp_reinit(dep)
+dpeth_t *dep;
+{
+       int dp_rcr_reg;
+
+       outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
+
+       dp_rcr_reg = 0;
+       if (dep->de_flags & DEF_PROMISC)
+               dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM;
+       if (dep->de_flags & DEF_BROAD)
+               dp_rcr_reg |= RCR_AB;
+       if (dep->de_flags & DEF_MULTI)
+               dp_rcr_reg |= RCR_AM;
+       outb_reg0(dep, DP_RCR, dp_rcr_reg);
+}
+
+
+/*===========================================================================*
+ *                             dp_reset                                     *
+ *===========================================================================*/
+static void dp_reset(dep)
+dpeth_t *dep;
+{
+       int i;
+
+       /* Stop chip */
+       outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
+       outb_reg0(dep, DP_RBCR0, 0);
+       outb_reg0(dep, DP_RBCR1, 0);
+       for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
+               ; /* Do nothing */
+       outb_reg0(dep, DP_TCR, TCR_1EXTERNAL|TCR_OFST);
+       outb_reg0(dep, DP_CR, CR_STA|CR_DM_ABORT);
+       outb_reg0(dep, DP_TCR, TCR_NORMAL);
+
+       /* Acknowledge the ISR_RDC (remote dma) interrupt. */
+       for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); i++)
+               ; /* Do nothing */
+       outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & ~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 (i= 0; i<dep->de_sendq_nr; i++)
+               dep->de_sendq[i].sq_filled= 0;
+       dp_send(dep);
+       dep->de_flags &= ~DEF_STOPPED;
+}
+
+
+/*===========================================================================*
+ *                             dp_check_ints                                *
+ *===========================================================================*/
+static void dp_check_ints(dep)
+dpeth_t *dep;
+{
+       int isr, tsr;
+       int size, sendq_tail;
+
+       if (!(dep->de_flags & DEF_ENABLED))
+               panic("", "dp8390: got premature interrupt", NO_NUM);
+
+       for(;;)
+       {
+               isr = inb_reg0(dep, DP_ISR);
+               if (!isr)
+                       break;
+               outb_reg0(dep, DP_ISR, isr);
+               if (isr & (ISR_PTX|ISR_TXE))
+               {
+                       if (isr & ISR_TXE)
+                       {
+#if DEBUG
+ { printf("%s: got send Error\n", dep->de_name); }
+#endif
+                               dep->de_stat.ets_sendErr++;
+                       }
+                       else
+                       {
+                               tsr = inb_reg0(dep, DP_TSR);
+
+                               if (tsr & TSR_PTX) dep->de_stat.ets_packetT++;
+#if 0  /* Reserved in later manuals, should be ignored */
+                               if (!(tsr & TSR_DFR))
+                               {
+                                       /* In most (all?) implementations of
+                                        * the dp8390, this bit is set
+                                        * when the packet is not deferred
+                                        */
+                                       dep->de_stat.ets_transDef++;
+                               }
+#endif
+                               if (tsr & TSR_COL) dep->de_stat.ets_collision++;
+                               if (tsr & TSR_ABT) dep->de_stat.ets_transAb++;
+                               if (tsr & TSR_CRS) dep->de_stat.ets_carrSense++;
+                               if (tsr & TSR_FU
+                                       && ++dep->de_stat.ets_fifoUnder <= 10)
+                               {
+                                       printf("%s: fifo underrun\n",
+                                               dep->de_name);
+                               }
+                               if (tsr & TSR_CDH
+                                       && ++dep->de_stat.ets_CDheartbeat <= 10)
+                               {
+                                       printf("%s: CD heart beat failure\n",
+                                               dep->de_name);
+                               }
+                               if (tsr & TSR_OWC) dep->de_stat.ets_OWC++;
+                       }
+                       sendq_tail= dep->de_sendq_tail;
+
+                       if (!(dep->de_sendq[sendq_tail].sq_filled))
+                       {
+                               /* Software bug? */
+                               assert(!debug);
+
+                               /* Or hardware bug? */
+                               printf(
+                               "%s: transmit interrupt, but not sending\n",
+                                       dep->de_name);
+                               continue;
+                       }
+                       dep->de_sendq[sendq_tail].sq_filled= 0;
+                       if (++sendq_tail == dep->de_sendq_nr)
+                               sendq_tail= 0;
+                       dep->de_sendq_tail= sendq_tail;
+                       if (dep->de_sendq[sendq_tail].sq_filled)
+                       {
+                               size= dep->de_sendq[sendq_tail].sq_size;
+                               outb_reg0(dep, DP_TPSR,
+                                       dep->de_sendq[sendq_tail].sq_sendpage);
+                               outb_reg0(dep, DP_TBCR1, size >> 8);
+                               outb_reg0(dep, DP_TBCR0, size & 0xff);
+                               outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);
+                       }
+                       if (dep->de_flags & DEF_SEND_AVAIL)
+                               dp_send(dep);
+               }
+
+               if (isr & ISR_PRX)
+               {
+                       /* Only call dp_recv if there is a read request */
+                       if (dep->de_flags & DEF_READING)
+                               dp_recv(dep);
+               }
+               
+               if (isr & ISR_RXE) dep->de_stat.ets_recvErr++;
+               if (isr & ISR_CNT)
+               {
+                       dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
+                       dep->de_stat.ets_frameAll += inb_reg0(dep, DP_CNTR1);
+                       dep->de_stat.ets_missedP += inb_reg0(dep, DP_CNTR2);
+               }
+               if (isr & ISR_OVW)
+               {
+                       dep->de_stat.ets_OVW++;
+#if 0
+                       { printW(); printf(
+                               "%s: got overwrite warning\n", dep->de_name); }
+#endif
+                       if (dep->de_flags & DEF_READING)
+                       {
+                               printf(
+"dp_check_ints: strange: overwrite warning and pending read request\n");
+                               dp_recv(dep);
+                       }
+               }
+               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.
+                        */
+#if 0
+                        { printW(); printf(
+                               "%s: NIC stopped\n", dep->de_name); }
+#endif
+                       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 are 
+                * delivered.
+                */
+               dp_reset(dep);
+       }
+}
+
+
+/*===========================================================================*
+ *                             dp_recv                                      *
+ *===========================================================================*/
+static void dp_recv(dep)
+dpeth_t *dep;
+{
+       dp_rcvhdr_t header;
+       unsigned pageno, curr, next;
+       vir_bytes length;
+       int packet_processed, r;
+       u16_t eth_type;
+
+       packet_processed = FALSE;
+       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 | CR_EXTRA);
+               curr = inb_reg1(dep, DP_CURR);
+               outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
+
+               if (curr == pageno) break;
+
+               (dep->de_getblockf)(dep, pageno, (size_t)0, sizeof(header),
+                       &header);
+               (dep->de_getblockf)(dep, pageno, sizeof(header) +
+                       2*sizeof(ether_addr_t), sizeof(eth_type), &eth_type);
+
+               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_TAGGED)
+               {
+                       printf("%s: packet with strange length arrived: %d\n",
+                               dep->de_name, (int) length);
+                       next= curr;
+               }
+               else if (next < dep->de_startpage || next >= dep->de_stoppage)
+               {
+                       printf("%s: strange next page\n", dep->de_name);
+                       next= curr;
+               }
+               else if (eth_type == eth_ign_proto)
+               {
+                       /* Hack: ignore packets of a given protocol, useful
+                        * if you share a net with 80 computers sending
+                        * Amoeba FLIP broadcasts.  (Protocol 0x8146.)
+                        */
+                       static int first= 1;
+                       if (first)
+                       {
+                               first= 0;
+                               printf("%s: dropping proto 0x%04x packets\n",
+                                       dep->de_name,
+                                       ntohs(eth_ign_proto));
+                       }
+                       dep->de_stat.ets_packetR++;
+               }
+               else if (header.dr_status & RSR_FO)
+               {
+                       /* This is very serious, so we issue a warning and
+                        * reset the buffers */
+                       printf("%s: fifo overrun, resetting receive buffer\n",
+                               dep->de_name);
+                       dep->de_stat.ets_fifoOver++;
+                       next = curr;
+               }
+               else if ((header.dr_status & RSR_PRX) &&
+                                          (dep->de_flags & DEF_ENABLED))
+               {
+                       r = dp_pkt2user(dep, pageno, length);
+                       if (r != OK)
+                               return;
+
+                       packet_processed = TRUE;
+                       dep->de_stat.ets_packetR++;
+               }
+               if (next == dep->de_startpage)
+                       outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
+               else
+                       outb_reg0(dep, DP_BNRY, next - 1);
+
+               pageno = next;
+       }
+       while (!packet_processed);
+}
+
+
+/*===========================================================================*
+ *                             dp_send                                      *
+ *===========================================================================*/
+static void dp_send(dep)
+dpeth_t *dep;
+{
+       if (!(dep->de_flags & DEF_SEND_AVAIL))
+               return;
+
+       dep->de_flags &= ~DEF_SEND_AVAIL;
+       switch(dep->de_sendmsg.m_type)
+       {
+       case DL_WRITE:  do_vwrite(&dep->de_sendmsg, TRUE, FALSE);       break;
+       case DL_WRITEV: do_vwrite(&dep->de_sendmsg, TRUE, TRUE);        break;
+       default:
+               panic("", "dp8390: wrong type:", dep->de_sendmsg.m_type);
+               break;
+       }
+}
+
+
+/*===========================================================================*
+ *                             dp_getblock                                  *
+ *===========================================================================*/
+static void dp_getblock(dep, page, offset, size, dst)
+dpeth_t *dep;
+int page;
+size_t offset;
+size_t size;
+void *dst;
+{
+       int r;
+
+       offset = page * DP_PAGESIZE + offset;
+
+       r= sys_vircopy(SELF, D, (vir_bytes)dst, 
+               BIOS_SEG, D, dep->de_linmem + offset, size);
+
+       if (r != OK)
+               panic("DP8390", "dp_getblock: sys_vircopy failed", r);
+}
+
+
+/*===========================================================================*
+ *                             dp_pio8_getblock                             *
+ *===========================================================================*/
+static void dp_pio8_getblock(dep, page, offset, size, dst)
+dpeth_t *dep;
+int page;
+size_t offset;
+size_t size;
+void *dst;
+{
+       offset = page * DP_PAGESIZE + offset;
+       outb_reg0(dep, DP_RBCR0, size & 0xFF);
+       outb_reg0(dep, DP_RBCR1, size >> 8);
+       outb_reg0(dep, DP_RSAR0, offset & 0xFF);
+       outb_reg0(dep, DP_RSAR1, offset >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+
+       insb(dep->de_data_port, dst, size);
+}
+
+
+/*===========================================================================*
+ *                             dp_pio16_getblock                            *
+ *===========================================================================*/
+static void dp_pio16_getblock(dep, page, offset, size, dst)
+dpeth_t *dep;
+int page;
+size_t offset;
+size_t size;
+void *dst;
+{
+       offset = page * DP_PAGESIZE + offset;
+       outb_reg0(dep, DP_RBCR0, size & 0xFF);
+       outb_reg0(dep, DP_RBCR1, size >> 8);
+       outb_reg0(dep, DP_RSAR0, offset & 0xFF);
+       outb_reg0(dep, DP_RSAR1, offset >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+
+       assert (!(size & 1));
+       insw(dep->de_data_port, dst, size);
+}
+
+
+/*===========================================================================*
+ *                             dp_pkt2user                                  *
+ *===========================================================================*/
+static int dp_pkt2user(dep, page, length)
+dpeth_t *dep;
+int page, length;
+{
+       int last, count;
+
+       if (!(dep->de_flags & DEF_READING))
+               return EGENERIC;
+
+       last = page + (length - 1) / DP_PAGESIZE;
+       if (last >= dep->de_stoppage)
+       {
+               count = (dep->de_stoppage - page) * DP_PAGESIZE -
+                       sizeof(dp_rcvhdr_t);
+
+               /* Save read_iovec since we need it twice. */
+               dep->de_tmp_iovec = dep->de_read_iovec;
+               (dep->de_nic2userf)(dep, page * DP_PAGESIZE +
+                       sizeof(dp_rcvhdr_t), &dep->de_tmp_iovec, 0, count);
+               (dep->de_nic2userf)(dep, dep->de_startpage * DP_PAGESIZE, 
+                               &dep->de_read_iovec, count, length - count);
+       }
+       else
+       {
+               (dep->de_nic2userf)(dep, page * DP_PAGESIZE +
+                       sizeof(dp_rcvhdr_t), &dep->de_read_iovec, 0, length);
+       }
+
+       dep->de_read_s = length;
+       dep->de_flags |= DEF_PACK_RECV;
+       dep->de_flags &= ~DEF_READING;
+
+       return OK;
+}
+
+
+/*===========================================================================*
+ *                             dp_user2nic                                  *
+ *===========================================================================*/
+static void dp_user2nic(dep, iovp, offset, nic_addr, count)
+dpeth_t *dep;
+iovec_dat_t *iovp;
+vir_bytes offset;
+int nic_addr;
+vir_bytes count;
+{
+       vir_bytes vir_hw, vir_user;
+       int bytes, i, r;
+
+       vir_hw = dep->de_linmem + nic_addr;
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               r= sys_vircopy(iovp->iod_proc_nr, D,
+                       iovp->iod_iovec[i].iov_addr + offset,
+                       BIOS_SEG, D, vir_hw, bytes);
+               if (r != OK)
+                       panic("DP8390", "dp_user2nic: sys_vircopy failed", r);
+
+               count -= bytes;
+               vir_hw += bytes;
+               offset += bytes;
+       }
+       assert(count == 0);
+}
+
+
+/*===========================================================================*
+ *                             dp_pio8_user2nic                             *
+ *===========================================================================*/
+static void dp_pio8_user2nic(dep, iovp, offset, nic_addr, count)
+dpeth_t *dep;
+iovec_dat_t *iovp;
+vir_bytes offset;
+int nic_addr;
+vir_bytes count;
+{
+       phys_bytes phys_user;
+       int bytes, i;
+
+       outb_reg0(dep, DP_ISR, ISR_RDC);
+
+       outb_reg0(dep, DP_RBCR0, count & 0xFF);
+       outb_reg0(dep, DP_RBCR1, count >> 8);
+       outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
+       outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               do_vir_outsb(dep->de_data_port, iovp->iod_proc_nr,
+                       iovp->iod_iovec[i].iov_addr + offset, bytes);
+               count -= bytes;
+               offset += bytes;
+       }
+       assert(count == 0);
+
+       for (i= 0; i<100; i++)
+       {
+               if (inb_reg0(dep, DP_ISR) & ISR_RDC)
+                       break;
+       }
+       if (i == 100)
+       {
+               panic("", "dp8390: remote dma failed to complete", NO_NUM);
+       }
+}
+
+
+/*===========================================================================*
+ *                             dp_pio16_user2nic                            *
+ *===========================================================================*/
+static void dp_pio16_user2nic(dep, iovp, offset, nic_addr, count)
+dpeth_t *dep;
+iovec_dat_t *iovp;
+vir_bytes offset;
+int nic_addr;
+vir_bytes count;
+{
+       vir_bytes vir_user;
+       vir_bytes ecount;
+       int i, r, bytes, user_proc;
+       u8_t two_bytes[2];
+       int odd_byte;
+
+       ecount= (count+1) & ~1;
+       odd_byte= 0;
+
+       outb_reg0(dep, DP_ISR, ISR_RDC);
+       outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
+       outb_reg0(dep, DP_RBCR1, ecount >> 8);
+       outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
+       outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               user_proc= iovp->iod_proc_nr;
+               vir_user= iovp->iod_iovec[i].iov_addr + offset;
+               if (odd_byte)
+               {
+                       r= sys_vircopy(user_proc, D, vir_user, 
+                               SELF, D, (vir_bytes)&two_bytes[1], 1);
+                       if (r != OK)
+                       {
+                               panic("DP8390",
+                                       "dp_pio16_user2nic: sys_vircopy failed",
+                                       r);
+                       }
+                       outw(dep->de_data_port, *(u16_t *)two_bytes);
+                       count--;
+                       offset++;
+                       bytes--;
+                       vir_user++;
+                       odd_byte= 0;
+                       if (!bytes)
+                               continue;
+               }
+               ecount= bytes & ~1;
+               if (ecount != 0)
+               {
+                       do_vir_outsw(dep->de_data_port, user_proc, vir_user,
+                               ecount);
+                       count -= ecount;
+                       offset += ecount;
+                       bytes -= ecount;
+                       vir_user += ecount;
+               }
+               if (bytes)
+               {
+                       assert(bytes == 1);
+                       r= sys_vircopy(user_proc, D, vir_user, 
+                               SELF, D, (vir_bytes)&two_bytes[0], 1);
+                       if (r != OK)
+                       {
+                               panic("DP8390",
+                                       "dp_pio16_user2nic: sys_vircopy failed",
+                                       r);
+                       }
+                       count--;
+                       offset++;
+                       bytes--;
+                       vir_user++;
+                       odd_byte= 1;
+               }
+       }
+       assert(count == 0);
+
+       if (odd_byte)
+               outw(dep->de_data_port, *(u16_t *)two_bytes);
+
+       for (i= 0; i<100; i++)
+       {
+               if (inb_reg0(dep, DP_ISR) & ISR_RDC)
+                       break;
+       }
+       if (i == 100)
+       {
+               panic("", "dp8390: remote dma failed to complete", NO_NUM);
+       }
+}
+
+
+/*===========================================================================*
+ *                             dp_nic2user                                  *
+ *===========================================================================*/
+static void dp_nic2user(dep, nic_addr, iovp, offset, count)
+dpeth_t *dep;
+int nic_addr;
+iovec_dat_t *iovp;
+vir_bytes offset;
+vir_bytes count;
+{
+       vir_bytes vir_hw, vir_user;
+       int bytes, i, r;
+
+       vir_hw = dep->de_linmem + nic_addr;
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               r= sys_vircopy(BIOS_SEG, D, vir_hw,
+                       iovp->iod_proc_nr, D,
+                       iovp->iod_iovec[i].iov_addr + offset, bytes);
+               if (r != OK)
+                       panic("DP8390", "dp_nic2user: sys_vircopy failed", r);
+
+               count -= bytes;
+               vir_hw += bytes;
+               offset += bytes;
+       }
+       assert(count == 0);
+}
+
+
+/*===========================================================================*
+ *                             dp_pio8_nic2user                             *
+ *===========================================================================*/
+static void dp_pio8_nic2user(dep, nic_addr, iovp, offset, count)
+dpeth_t *dep;
+int nic_addr;
+iovec_dat_t *iovp;
+vir_bytes offset;
+vir_bytes count;
+{
+       phys_bytes phys_user;
+       int bytes, i;
+
+       outb_reg0(dep, DP_RBCR0, count & 0xFF);
+       outb_reg0(dep, DP_RBCR1, count >> 8);
+       outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
+       outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               do_vir_insb(dep->de_data_port, iovp->iod_proc_nr,
+                       iovp->iod_iovec[i].iov_addr + offset, bytes);
+               count -= bytes;
+               offset += bytes;
+       }
+       assert(count == 0);
+}
+
+
+/*===========================================================================*
+ *                             dp_pio16_nic2user                            *
+ *===========================================================================*/
+static void dp_pio16_nic2user(dep, nic_addr, iovp, offset, count)
+dpeth_t *dep;
+int nic_addr;
+iovec_dat_t *iovp;
+vir_bytes offset;
+vir_bytes count;
+{
+       vir_bytes vir_user;
+       vir_bytes ecount;
+       int i, r, bytes, user_proc;
+       u8_t two_bytes[2];
+       int odd_byte;
+
+       ecount= (count+1) & ~1;
+       odd_byte= 0;
+
+       outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
+       outb_reg0(dep, DP_RBCR1, ecount >> 8);
+       outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
+       outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               user_proc= iovp->iod_proc_nr;
+               vir_user= iovp->iod_iovec[i].iov_addr + offset;
+               if (odd_byte)
+               {
+                       r= sys_vircopy(SELF, D, (vir_bytes)&two_bytes[1],
+                               user_proc, D, vir_user,  1);
+                       if (r != OK)
+                       {
+                               panic("DP8390",
+                                       "dp_pio16_nic2user: sys_vircopy failed",
+                                       r);
+                       }
+                       count--;
+                       offset++;
+                       bytes--;
+                       vir_user++;
+                       odd_byte= 0;
+                       if (!bytes)
+                               continue;
+               }
+               ecount= bytes & ~1;
+               if (ecount != 0)
+               {
+                       do_vir_insw(dep->de_data_port, user_proc, vir_user,
+                               ecount);
+                       count -= ecount;
+                       offset += ecount;
+                       bytes -= ecount;
+                       vir_user += ecount;
+               }
+               if (bytes)
+               {
+                       assert(bytes == 1);
+                       *(u16_t *)two_bytes= inw(dep->de_data_port);
+                       r= sys_vircopy(SELF, D, (vir_bytes)&two_bytes[0],
+                               user_proc, D, vir_user,  1);
+                       if (r != OK)
+                       {
+                               panic("DP8390",
+                                       "dp_pio16_nic2user: sys_vircopy failed",
+                                       r);
+                       }
+                       count--;
+                       offset++;
+                       bytes--;
+                       vir_user++;
+                       odd_byte= 1;
+               }
+       }
+       assert(count == 0);
+}
+
+
+/*===========================================================================*
+ *                             dp_next_iovec                                        *
+ *===========================================================================*/
+static void dp_next_iovec(iovp)
+iovec_dat_t *iovp;
+{
+       assert(iovp->iod_iovec_s > IOVEC_NR);
+
+       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 > IOVEC_NR ? IOVEC_NR : iovp->iod_iovec_s) *
+               sizeof(iovec_t), iovp->iod_iovec); 
+}
+
+
+/*===========================================================================*
+ *                             conf_hw                                      *
+ *===========================================================================*/
+static void conf_hw(dep)
+dpeth_t *dep;
+{
+       static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0        /* ,... */ };
+
+       int ifnr;
+       dp_conf_t *dcp;
+
+       dep->de_mode= DEM_DISABLED;     /* Superfluous */
+       ifnr= dep-de_table;
+
+       dcp= &dp_conf[ifnr];
+       update_conf(dep, dcp);
+       if (dep->de_mode != DEM_ENABLED)
+               return;
+       if (!wdeth_probe(dep) && !ne_probe(dep) && !el2_probe(dep))
+       {
+               printf("%s: No ethernet card found at 0x%x\n", 
+                       dep->de_name, dep->de_base_port);
+               dep->de_mode= DEM_DISABLED;
+               return;
+       }
+
+/* XXX */ if (dep->de_linmem == 0) dep->de_linmem= 0xFFFF0000;
+
+       dep->de_flags = DEF_EMPTY;
+       dep->de_stat = empty_stat;
+}
+
+
+/*===========================================================================*
+ *                             update_conf                                  *
+ *===========================================================================*/
+static void update_conf(dep, dcp)
+dpeth_t *dep;
+dp_conf_t *dcp;
+{
+       long v;
+       static char dpc_fmt[] = "x:d:x:x";
+
+#if ENABLE_PCI
+       if (dep->de_pci)
+       {
+               if (dep->de_pci == 1)
+               {
+                       /* PCI device is present */
+                       dep->de_mode= DEM_ENABLED;
+               }
+               return;         /* Already configured */
+       }
+#endif
+
+       /* Get the default settings and modify them from the environment. */
+       dep->de_mode= DEM_SINK;
+       v= dcp->dpc_port;
+       switch (env_parse_x(arg_c, arg_v,
+               dcp->dpc_envvar, dpc_fmt, 0, &v, 0x0000L, 0xFFFFL)) {
+       case EP_OFF:
+               dep->de_mode= DEM_DISABLED;
+               break;
+       case EP_ON:
+       case EP_SET:
+               dep->de_mode= DEM_ENABLED;      /* Might become disabled if 
+                                                * all probes fail */
+               break;
+       }
+       dep->de_base_port= v;
+
+       v= dcp->dpc_irq | DEI_DEFAULT;
+       (void) env_parse_x(arg_c, arg_v, dcp->dpc_envvar, dpc_fmt, 1, &v, 0L,
+                                               (long) NR_IRQ_VECTORS - 1);
+       dep->de_irq= v;
+
+       v= dcp->dpc_mem;
+       (void) env_parse_x(arg_c, arg_v,
+               dcp->dpc_envvar, dpc_fmt, 2, &v, 0L, 0xFFFFFL);
+       dep->de_linmem= v;
+
+       v= 0;
+       (void) env_parse_x(arg_c, arg_v,
+               dcp->dpc_envvar, dpc_fmt, 3, &v, 0x2000L, 0x8000L);
+       dep->de_ramsize= v;
+}
+
+
+/*===========================================================================*
+ *                             calc_iovec_size                              *
+ *===========================================================================*/
+static int calc_iovec_size(iovp)
+iovec_dat_t *iovp;
+{
+       /* Calculate the size of a request. Note that the iovec_dat
+        * structure will be unusable after calc_iovec_size.
+        */
+       int size;
+       int i;
+
+       size= 0;
+       i= 0;
+       while (i < iovp->iod_iovec_s)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec(iovp);
+                       i= 0;
+                       continue;
+               }
+               size += iovp->iod_iovec[i].iov_size;
+               i++;
+       }
+       return size;
+}
+
+
+/*===========================================================================*
+ *                             reply                                        *
+ *===========================================================================*/
+static void reply(dep, err, may_block)
+dpeth_t *dep;
+int err;
+int may_block;
+{
+       message reply;
+       int status;
+       int r;
+
+       status = 0;
+       if (dep->de_flags & DEF_PACK_SEND)
+               status |= DL_PACK_SEND;
+       if (dep->de_flags & DEF_PACK_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;
+       reply.DL_CLCK = 0;      /* Don't know */
+       r= send(dep->de_client, &reply);
+
+       if (r == ELOCKED && may_block)
+       {
+               printf("send locked\n");
+               return;
+       }
+
+       if (r < 0)
+               panic("", "dp8390: send failed:", r);
+       
+       dep->de_read_s = 0;
+       dep->de_flags &= ~(DEF_PACK_SEND | DEF_PACK_RECV);
+}
+
+
+/*===========================================================================*
+ *                             mess_reply                                   *
+ *===========================================================================*/
+static void mess_reply(req, reply_mess)
+message *req;
+message *reply_mess;
+{
+       if (send(req->m_source, reply_mess) != OK)
+               panic("", "dp8390: unable to mess_reply", NO_NUM);
+}
+
+
+/*===========================================================================*
+ *                             get_userdata                                 *
+ *===========================================================================*/
+static void get_userdata(user_proc, user_addr, count, loc_addr)
+int user_proc;
+vir_bytes user_addr;
+vir_bytes count;
+void *loc_addr;
+{
+       int r;
+
+       r= sys_vircopy(user_proc, D, user_addr,
+               SELF, D, (vir_bytes)loc_addr, count);
+       if (r != OK)
+               panic("DP8390", "get_userdata: sys_vircopy failed", r);
+}
+
+
+/*===========================================================================*
+ *                             put_userdata                                 *
+ *===========================================================================*/
+static void put_userdata(user_proc, user_addr, count, loc_addr)
+int user_proc;
+vir_bytes user_addr;
+vir_bytes count;
+void *loc_addr;
+{
+       int r;
+
+       r= sys_vircopy(SELF, D, (vir_bytes)loc_addr, 
+               user_proc, D, user_addr, count);
+       if (r != OK)
+               panic("DP8390", "put_userdata: sys_vircopy failed", r);
+}
+
+u8_t inb(port_t port)
+{
+       int r;
+       u8_t value;
+
+       r= sys_inb(port, &value);
+       if (r != OK)
+               panic("DP8390","sys_inb failed", r);
+       return value;
+}
+
+u16_t inw(port_t port)
+{
+       int r;
+       u16_t value;
+
+       r= sys_inw(port, &value);
+       if (r != OK)
+               panic("DP8390", "sys_inw failed", r);
+       return value;
+}
+
+void outb(port_t port, u8_t value)
+{
+       int r;
+
+       r= sys_outb(port, value);
+       if (r != OK)
+               panic("DP8390", "sys_outb failed", r);
+}
+
+void outw(port_t port, u16_t value)
+{
+       int r;
+
+       r= sys_outw(port, value);
+       if (r != OK)
+               panic("DP8390", "sys_outw failed", r);
+}
+
+static void insb(port_t port, void *buf, size_t size)
+{
+       do_vir_insb(port, SELF, (vir_bytes)buf, size);
+}
+
+static void insw(port_t port, void *buf, size_t size)
+{
+       do_vir_insw(port, SELF, (vir_bytes)buf, size);
+}
+
+static void do_vir_insb(port_t port, int proc, vir_bytes buf, size_t size)
+{
+       int r;
+
+       r= sys_sdevio(DIO_INPUT, port, DIO_BYTE, proc, (void *)buf, size);
+       if (r != OK)
+               panic("DP8390", "sys_sdevio failed", r);
+}
+
+static void do_vir_insw(port_t port, int proc, vir_bytes buf, size_t size)
+{
+       int r;
+
+       r= sys_sdevio(DIO_INPUT, port, DIO_WORD, proc, (void *)buf, size);
+       if (r != OK)
+               panic("DP8390", "sys_sdevio failed", r);
+}
+
+static void do_vir_outsb(port_t port, int proc, vir_bytes buf, size_t size)
+{
+       int r;
+
+       r= sys_sdevio(DIO_OUTPUT, port, DIO_BYTE, proc, (void *)buf, size);
+       if (r != OK)
+               panic("DP8390", "sys_sdevio failed", r);
+}
+
+static void do_vir_outsw(port_t port, int proc, vir_bytes buf, size_t size)
+{
+       int r;
+
+       r= sys_sdevio(DIO_OUTPUT, port, DIO_WORD, proc, (void *)buf, size);
+       if (r != OK)
+               panic("DP8390", "sys_sdevio failed", r);
+}
+
+
+/*
+ * $PchId: dp8390.c,v 1.25 2005/02/10 17:32:07 philip Exp $
+ */
diff --git a/drivers/dp8390/dp8390.h b/drivers/dp8390/dp8390.h
new file mode 100644 (file)
index 0000000..24bdcd8
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+dp8390.h
+
+Created:       before Dec 28, 1992 by Philip Homburg
+*/
+
+/* National Semiconductor DP8390 Network Interface Controller. */
+
+                               /* Page 0, for reading ------------- */
+#define        DP_CR           0x0     /* Read side of Command Register     */
+#define        DP_CLDA0        0x1     /* Current Local Dma Address 0       */
+#define        DP_CLDA1        0x2     /* Current Local Dma Address 1       */
+#define        DP_BNRY         0x3     /* Boundary Pointer                  */
+#define        DP_TSR          0x4     /* Transmit Status Register          */
+#define        DP_NCR          0x5     /* Number of Collisions Register     */
+#define        DP_FIFO         0x6     /* Fifo ??                           */
+#define        DP_ISR          0x7     /* Interrupt Status Register         */
+#define        DP_CRDA0        0x8     /* Current Remote Dma Address 0      */
+#define        DP_CRDA1        0x9     /* Current Remote Dma Address 1      */
+#define        DP_DUM1         0xA     /* unused                            */
+#define        DP_DUM2         0xB     /* unused                            */
+#define        DP_RSR          0xC     /* Receive Status Register           */
+#define        DP_CNTR0        0xD     /* Tally Counter 0                   */
+#define        DP_CNTR1        0xE     /* Tally Counter 1                   */
+#define        DP_CNTR2        0xF     /* Tally Counter 2                   */
+
+                               /* Page 0, for writing ------------- */
+#define        DP_CR           0x0     /* Write side of Command Register    */
+#define        DP_PSTART       0x1     /* Page Start Register               */
+#define        DP_PSTOP        0x2     /* Page Stop Register                */
+#define        DP_BNRY         0x3     /* Boundary Pointer                  */
+#define        DP_TPSR         0x4     /* Transmit Page Start Register      */
+#define        DP_TBCR0        0x5     /* Transmit Byte Count Register 0    */
+#define        DP_TBCR1        0x6     /* Transmit Byte Count Register 1    */
+#define        DP_ISR          0x7     /* Interrupt Status Register         */
+#define        DP_RSAR0        0x8     /* Remote Start Address Register 0   */
+#define        DP_RSAR1        0x9     /* Remote Start Address Register 1   */
+#define        DP_RBCR0        0xA     /* Remote Byte Count Register 0      */
+#define        DP_RBCR1        0xB     /* Remote Byte Count Register 1      */
+#define        DP_RCR          0xC     /* Receive Configuration Register    */
+#define        DP_TCR          0xD     /* Transmit Configuration Register   */
+#define        DP_DCR          0xE     /* Data Configuration Register       */
+#define        DP_IMR          0xF     /* Interrupt Mask Register           */
+
+                               /* Page 1, read/write -------------- */
+#define        DP_CR           0x0     /* Command Register                  */
+#define        DP_PAR0         0x1     /* Physical Address Register 0       */
+#define        DP_PAR1         0x2     /* Physical Address Register 1       */
+#define        DP_PAR2         0x3     /* Physical Address Register 2       */
+#define        DP_PAR3         0x4     /* Physical Address Register 3       */
+#define        DP_PAR4         0x5     /* Physical Address Register 4       */
+#define        DP_PAR5         0x6     /* Physical Address Register 5       */
+#define        DP_CURR         0x7     /* Current Page Register             */
+#define        DP_MAR0         0x8     /* Multicast Address Register 0      */
+#define        DP_MAR1         0x9     /* Multicast Address Register 1      */
+#define        DP_MAR2         0xA     /* Multicast Address Register 2      */
+#define        DP_MAR3         0xB     /* Multicast Address Register 3      */
+#define        DP_MAR4         0xC     /* Multicast Address Register 4      */
+#define        DP_MAR5         0xD     /* Multicast Address Register 5      */
+#define        DP_MAR6         0xE     /* Multicast Address Register 6      */
+#define        DP_MAR7         0xF     /* 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_NOP      0x00    /* DMA: No Operation                 */
+#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_DM_ABORT    0x20    /* DMA: Abort 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                   */
+#define CR_PS_T1       0xC0    /* Test Mode Register Map            */
+
+/* Bits in dp_isr */
+#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 iEnable           */
+#define IMR_PTXE       0x02    /* Packet Transmitted iEnable        */
+#define IMR_RXEE       0x04    /* Receive Error iEnable             */
+#define IMR_TXEE       0x08    /* Transmit Error iEnable            */
+#define IMR_OVWE       0x10    /* Overwrite Warning iEnable         */
+#define IMR_CNTE       0x20    /* Counter Overflow iEnable          */
+#define IMR_RDCE       0x40    /* DMA Complete iEnable              */
+
+/* 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
+                                * Called Loopback Select (LS) in 
+                                * later manuals. Should be set.     */
+#define DCR_AR         0x10    /* Autoinitialize Remote             */
+#define DCR_FTS                0x60    /* Fifo Threshold Select             */
+#define DCR_2BYTES     0x00    /* 2 bytes                           */
+#define DCR_4BYTES     0x40    /* 4 bytes                           */
+#define DCR_8BYTES     0x20    /* 8 bytes                           */
+#define DCR_12BYTES    0x60    /* 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 Disable             */
+#define TCR_OFST       0x10    /* Collision Offset Enable (be nice) */
+
+/* Bits in dp_tsr */
+#define TSR_PTX                0x01    /* Packet Transmitted (without error)*/
+#define TSR_DFR                0x02    /* Transmit Deferred, reserved in
+                                * later manuals.                    */
+#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 tp_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                 */
+#define RSR_DFR                0x80    /* In later manuals: Deferring       */
+
+
+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;
+
+#define DP_PAGESIZE    256
+
+/* 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))
+
+/* Software interface to the dp8390 driver */
+
+struct dpeth;
+struct iovec_dat;
+_PROTOTYPE( typedef void (*dp_initf_t), (struct dpeth *dep)            );
+_PROTOTYPE( typedef void (*dp_stopf_t), (struct dpeth *dep)            );
+_PROTOTYPE( typedef void (*dp_user2nicf_t), (struct dpeth *dep,
+                       struct iovec_dat *iovp, vir_bytes offset,
+                       int nic_addr, vir_bytes count)                  );
+_PROTOTYPE( typedef void (*dp_nic2userf_t), (struct dpeth *dep,
+                       int nic_addr, struct iovec_dat *iovp,
+                       vir_bytes offset, vir_bytes count)              );
+#if 0
+_PROTOTYPE( typedef void (*dp_getheaderf_t), (struct dpeth *dep,
+                       int page, struct dp_rcvhdr *h, u16_t *eth_type) );
+#endif
+_PROTOTYPE( typedef void (*dp_getblock_t), (struct dpeth *dep,
+               int page, size_t offset, size_t size, void *dst)        );
+
+/* iovectors are handled IOVEC_NR entries at a time. */
+#define IOVEC_NR       16
+
+typedef int irq_hook_t;
+
+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;
+
+#define SENDQ_NR       2       /* Maximum size of the send queue */
+#define SENDQ_PAGES    6       /* 6 * DP_PAGESIZE >= 1514 bytes */
+
+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.
+        */
+       port_t de_base_port;
+       phys_bytes de_linmem;
+       int de_irq;
+       int de_int_pending;
+       irq_hook_t de_hook;
+       dp_initf_t de_initf; 
+       dp_stopf_t de_stopf; 
+       int de_prog_IO;
+       char de_name[sizeof("dp8390#n")];
+
+       /* The initf function fills the following fields. Only cards that do
+        * programmed I/O fill in the de_pata_port field.
+        * In addition, the init routine has to fill in the sendq data
+        * structures.
+        */
+       ether_addr_t de_address;
+       port_t de_dp8390_port;
+       port_t de_data_port;
+       int de_16bit;
+       int de_ramsize;
+       int de_offset_page;
+       int de_startpage;
+       int de_stoppage;
+
+#if ENABLE_PCI
+       /* PCI config */
+       char de_pci;                    /* TRUE iff PCI device */
+       u8_t de_pcibus; 
+       u8_t de_pcidev; 
+       u8_t de_pcifunc;        
+#endif
+
+       /* 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 */
+
+       /* Fields for internal use by the dp8390 driver. */
+       int de_flags;
+       int de_mode;
+       eth_stat_t de_stat;
+       iovec_dat_t de_read_iovec;
+       iovec_dat_t de_write_iovec;
+       iovec_dat_t de_tmp_iovec;
+       vir_bytes de_read_s;
+       int de_client;
+       message de_sendmsg;
+       dp_user2nicf_t de_user2nicf; 
+       dp_nic2userf_t de_nic2userf; 
+       dp_getblock_t de_getblockf; 
+} dpeth_t;
+
+#define DEI_DEFAULT    0x8000
+
+#define DEF_EMPTY      0x000
+#define DEF_PACK_SEND  0x001
+#define DEF_PACK_RECV  0x002
+#define DEF_SEND_AVAIL 0x004
+#define DEF_READING    0x010
+#define DEF_PROMISC    0x040
+#define DEF_MULTI      0x080
+#define DEF_BROAD      0x100
+#define DEF_ENABLED    0x200
+#define DEF_STOPPED    0x400
+
+#define DEM_DISABLED   0x0
+#define DEM_SINK       0x1
+#define DEM_ENABLED    0x2
+
+#if !__minix_vmd
+#define debug          0       /* Standard Minix lacks debug variable */
+#endif
+
+/*
+ * $PchId: dp8390.h,v 1.10 2005/02/10 17:26:06 philip Exp $
+ */
diff --git a/drivers/dp8390/local.h b/drivers/dp8390/local.h
new file mode 100644 (file)
index 0000000..21b1596
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+local.h
+*/
+
+#define ENABLE_WDETH 1
+#define ENABLE_NE2000 1
+#define ENABLE_3C503 1
+#define ENABLE_PCI 1
+
+struct dpeth;
+
+/* 3c503.c */
+_PROTOTYPE( int el2_probe, (struct dpeth* dep)                         );
+
+/* dp8390.c */
+_PROTOTYPE( u8_t inb, (port_t port)                                    );
+_PROTOTYPE( u16_t inw, (port_t port)                                   );
+_PROTOTYPE( void outb, (port_t port, u8_t v)                           );
+_PROTOTYPE( void outw, (port_t port, u16_t v)                          );
+
+/* ne2000.c */
+_PROTOTYPE( int ne_probe, (struct dpeth *dep)                          );
+_PROTOTYPE( void ne_init, (struct dpeth *dep)                          );
+
+/* rtl8029.c */
+_PROTOTYPE( int rtl_probe, (struct dpeth *dep)                         );
+
+/* wdeth.c */
+_PROTOTYPE( int wdeth_probe, (struct dpeth* dep)                               );
+
diff --git a/drivers/dp8390/ne2000.c b/drivers/dp8390/ne2000.c
new file mode 100644 (file)
index 0000000..ddac235
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ne2000.c
+
+Driver for the ne2000 ethernet cards. This file contains only the ne2000
+specific code, the rest is in dp8390.c
+
+Created:       March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
+*/
+
+#include "../drivers.h"
+
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#if __minix_vmd
+#include "config.h"
+#endif
+
+#include "local.h"
+#include "dp8390.h"
+#include "ne2000.h"
+
+#if ENABLE_NE2000
+
+#define N 100
+
+#define MILLIS_TO_TICKS(m)  (((m)*HZ/1000)+1)
+
+_PROTOTYPE( typedef int (*testf_t), (dpeth_t *dep, int pos, u8_t *pat) );
+
+u8_t   pat0[]= { 0x00, 0x00, 0x00, 0x00 };
+u8_t   pat1[]= { 0xFF, 0xFF, 0xFF, 0xFF };
+u8_t   pat2[]= { 0xA5, 0x5A, 0x69, 0x96 };
+u8_t   pat3[]= { 0x96, 0x69, 0x5A, 0xA5 };
+
+_PROTOTYPE( static int test_8, (dpeth_t *dep, int pos, u8_t *pat)      );
+_PROTOTYPE( static int test_16, (dpeth_t *dep, int pos, u8_t *pat)     );
+_PROTOTYPE( static void ne_stop, (dpeth_t *dep)                                );
+_PROTOTYPE( static void milli_delay, (unsigned long millis)            );
+
+/*===========================================================================*
+ *                             ne_probe                                     *
+ *===========================================================================*/
+int ne_probe(dep)
+dpeth_t *dep;
+{
+       int byte;
+       int i;
+       int loc1, loc2;
+       testf_t f;
+
+       dep->de_dp8390_port= dep->de_base_port + NE_DP8390;
+
+       /* We probe for an ne1000 or an ne2000 by testing whether the
+        * on board is reachable through the dp8390. Note that the
+        * ne1000 is an 8bit card and has a memory region distict from
+        * the 16bit ne2000
+        */
+
+       for (dep->de_16bit= 0; dep->de_16bit < 2; dep->de_16bit++)
+       {
+               /* Reset the ethernet card */
+               byte= inb_ne(dep, NE_RESET);
+               milli_delay(2);
+               outb_ne(dep, NE_RESET, byte);
+               milli_delay(2);
+
+               /* Reset the dp8390 */
+               outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
+               for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
+                       ; /* Do nothing */
+
+               /* Check if the dp8390 is really there */
+               if ((inb_reg0(dep, DP_CR) & (CR_STP|CR_DM_ABORT)) !=
+                       (CR_STP|CR_DM_ABORT))
+               {
+                       return 0;
+               }
+
+               /* Disable the receiver and init TCR and DCR. */
+               outb_reg0(dep, DP_RCR, RCR_MON);
+               outb_reg0(dep, DP_TCR, TCR_NORMAL);
+               if (dep->de_16bit)
+               {
+                       outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES |
+                               DCR_BMS);
+               }
+               else
+               {
+                       outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES |
+                               DCR_BMS);
+               }
+
+               if (dep->de_16bit)
+               {
+                       loc1= NE2000_START;
+                       loc2= NE2000_START + NE2000_SIZE - 4;
+                       f= test_16;
+               }
+               else
+               {
+                       loc1= NE1000_START;
+                       loc2= NE1000_START + NE1000_SIZE - 4;
+                       f= test_8;
+               }
+               if (f(dep, loc1, pat0) && f(dep, loc1, pat1) &&
+                       f(dep, loc1, pat2) && f(dep, loc1, pat3) &&
+                       f(dep, loc2, pat0) && f(dep, loc2, pat1) &&
+                       f(dep, loc2, pat2) && f(dep, loc2, pat3))
+               {
+                       /* We don't need a memory segment */
+                       dep->de_linmem= 0;
+                       if (!dep->de_pci)
+                               dep->de_initf= ne_init;
+                       dep->de_stopf= ne_stop;
+                       dep->de_prog_IO= 1;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+
+/*===========================================================================*
+ *                             ne_init                                      *
+ *===========================================================================*/
+void ne_init(dep)
+dpeth_t *dep;
+{
+       int i;
+       int word, sendq_nr;
+
+       /* Setup a transfer to get the ethernet address. */
+       if (dep->de_16bit)
+               outb_reg0(dep, DP_RBCR0, 6*2);
+       else
+               outb_reg0(dep, DP_RBCR0, 6);
+       outb_reg0(dep, DP_RBCR1, 0);
+       outb_reg0(dep, DP_RSAR0, 0);
+       outb_reg0(dep, DP_RSAR1, 0);
+       outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+
+       for (i= 0; i<6; i++)
+       {
+               if (dep->de_16bit)
+               {
+                       word= inw_ne(dep, NE_DATA);
+                       dep->de_address.ea_addr[i]= word;
+               }
+               else
+               {
+                       dep->de_address.ea_addr[i] = inb_ne(dep, NE_DATA);
+               }
+       }
+       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;
+       }
+
+       /* 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= dep->de_offset_page +
+                       i*SENDQ_PAGES;  
+       }
+
+       dep->de_startpage= dep->de_offset_page + i*SENDQ_PAGES;
+       dep->de_stoppage= dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE;
+
+       /* Can't override the default IRQ. */
+       dep->de_irq &= ~DEI_DEFAULT;
+
+       if (!debug)
+       {
+               printf("%s: NE%d000 at %X:%d\n",
+                       dep->de_name, dep->de_16bit ? 2 : 1,
+                       dep->de_base_port, dep->de_irq);
+       }
+       else
+       {
+               printf("%s: Novell NE%d000 ethernet card at I/O address "
+                       "0x%X, memory size 0x%X, irq %d\n",
+                       dep->de_name, dep->de_16bit ? 2 : 1,
+                       dep->de_base_port, dep->de_ramsize, dep->de_irq);
+       }
+}
+
+
+/*===========================================================================*
+ *                             test_8                                       *
+ *===========================================================================*/
+static int test_8(dep, pos, pat)
+dpeth_t *dep;
+int pos;
+u8_t *pat;
+{
+       u8_t buf[4];
+       int i;
+       int r;
+
+       outb_reg0(dep, DP_ISR, 0xFF);
+
+       /* Setup a transfer to put the pattern. */
+       outb_reg0(dep, DP_RBCR0, 4);
+       outb_reg0(dep, DP_RBCR1, 0);
+       outb_reg0(dep, DP_RSAR0, pos & 0xFF);
+       outb_reg0(dep, DP_RSAR1, pos >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
+
+       for (i= 0; i<4; i++)
+               outb_ne(dep, NE_DATA, pat[i]);
+
+       for (i= 0; i<N; i++)
+       {
+               if (inb_reg0(dep, DP_ISR) & ISR_RDC)
+                       break;
+       }
+       if (i == N)
+       {
+               if (debug)
+               {
+                       printf("%s: NE1000 remote DMA test failed\n",
+                               dep->de_name);
+               }
+               return 0;
+       }
+
+       outb_reg0(dep, DP_RBCR0, 4);
+       outb_reg0(dep, DP_RBCR1, 0);
+       outb_reg0(dep, DP_RSAR0, pos & 0xFF);
+       outb_reg0(dep, DP_RSAR1, pos >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+
+       for (i= 0; i<4; i++)
+               buf[i]= inb_ne(dep, NE_DATA);
+
+       r= (memcmp(buf, pat, 4) == 0);
+       return r;
+}
+
+
+/*===========================================================================*
+ *                             test_16                                      *
+ *===========================================================================*/
+static int test_16(dep, pos, pat)
+dpeth_t *dep;
+int pos;
+u8_t *pat;
+{
+       u8_t buf[4];
+       int i;
+       int r;
+
+       outb_reg0(dep, DP_ISR, 0xFF);
+
+       /* Setup a transfer to put the pattern. */
+       outb_reg0(dep, DP_RBCR0, 4);
+       outb_reg0(dep, DP_RBCR1, 0);
+       outb_reg0(dep, DP_RSAR0, pos & 0xFF);
+       outb_reg0(dep, DP_RSAR1, pos >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
+
+       for (i= 0; i<4; i += 2)
+       {
+               outw_ne(dep, NE_DATA, *(u16_t *)(pat+i));
+       }
+
+       for (i= 0; i<N; i++)
+       {
+               if (inb_reg0(dep, DP_ISR) & ISR_RDC)
+                       break;
+       }
+       if (i == N)
+       {
+               if (debug)
+               {
+                       printf("%s: NE2000 remote DMA test failed\n",
+                               dep->de_name);
+               }
+               return 0;
+       }
+
+       outb_reg0(dep, DP_RBCR0, 4);
+       outb_reg0(dep, DP_RBCR1, 0);
+       outb_reg0(dep, DP_RSAR0, pos & 0xFF);
+       outb_reg0(dep, DP_RSAR1, pos >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+
+       for (i= 0; i<4; i += 2)
+       {
+               *(u16_t *)(buf+i)= inw_ne(dep, NE_DATA);
+       }
+
+       r= (memcmp(buf, pat, 4) == 0);
+       return r;
+}
+
+
+/*===========================================================================*
+ *                             ne_stop                                      *
+ *===========================================================================*/
+static void ne_stop(dep)
+dpeth_t *dep;
+{
+       int byte;
+
+       /* Reset the ethernet card */
+       byte= inb_ne(dep, NE_RESET);
+       milli_delay(2);
+       outb_ne(dep, NE_RESET, byte);
+}
+
+static void milli_delay(unsigned long millis)
+{
+       tickdelay(MILLIS_TO_TICKS(millis));
+}
+
+#endif /* ENABLE_NE2000 */
+
+/*
+ * $PchId: ne2000.c,v 1.10 2004/08/03 12:03:00 philip Exp $
+ */
diff --git a/drivers/dp8390/ne2000.h b/drivers/dp8390/ne2000.h
new file mode 100644 (file)
index 0000000..d2e358f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ne2000.h
+
+Created:       March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
+*/
+
+#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 */
+
+/*
+ * $PchId: ne2000.h,v 1.4 2004/08/03 12:03:20 philip Exp $
+ */
diff --git a/drivers/dp8390/rtl8029.c b/drivers/dp8390/rtl8029.c
new file mode 100644 (file)
index 0000000..bb76b2f
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+rtl8029.c
+
+Initialization of PCI DP8390-based ethernet cards
+
+Created:       April 2000 by Philip Homburg <philip@f-mnx.phicoh.com>
+*/
+
+#include "../drivers.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+
+#include "assert.h"
+#include "../libpci/pci.h"
+
+#include "local.h"
+#include "dp8390.h"
+#include "rtl8029.h"
+
+#if ENABLE_PCI
+
+#define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)
+
+PRIVATE struct pcitab
+{
+       u16_t vid;
+       u16_t did;
+       int checkclass;
+} pcitab[]=
+{
+       { 0x10ec, 0x8029, 0 },          /* Realtek RTL8029 */
+
+       { 0x0000, 0x0000, 0 }
+};
+
+_PROTOTYPE( static void rtl_init, (struct dpeth *dep)                  );
+_PROTOTYPE( static u16_t get_ee_word, (dpeth_t *dep, int a)            );
+_PROTOTYPE( static void ee_wen, (dpeth_t *dep)                         );
+_PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, U16_t w)    );
+_PROTOTYPE( static void ee_wds, (dpeth_t *dep)                         );
+_PROTOTYPE( static void micro_delay, (unsigned long usecs)             );
+
+PUBLIC int rtl_probe(dep)
+struct dpeth *dep;
+{
+       int i, r, devind, just_one;
+       u16_t vid, did;
+       u32_t bar;
+       u8_t ilr;
+       char *dname;
+
+       pci_init();
+
+       if ((dep->de_pcibus | dep->de_pcidev | dep->de_pcifunc) != 0)
+       {
+               /* Look for specific PCI device */
+               r= pci_find_dev(dep->de_pcibus, dep->de_pcidev,
+                       dep->de_pcifunc, &devind);
+               if (r == 0)
+               {
+                       printf("%s: no PCI found at %d.%d.%d\n",
+                               dep->de_name, dep->de_pcibus,
+                               dep->de_pcidev, dep->de_pcifunc);
+                       return 0;
+               }
+               pci_ids(devind, &vid, &did);
+               just_one= TRUE;
+       }
+       else
+       {
+               r= pci_first_dev(&devind, &vid, &did);
+               if (r == 0)
+                       return 0;
+               just_one= FALSE;
+       }
+
+       for(;;)
+       {
+               for (i= 0; pcitab[i].vid != 0; i++)
+               {
+                       if (pcitab[i].vid != vid)
+                               continue;
+                       if (pcitab[i].did != did)
+                               continue;
+                       if (pcitab[i].checkclass)
+                       {
+                               panic("",
+                               "rtl_probe: class check not implemented",
+                                       NO_NUM);
+                       }
+                       break;
+               }
+               if (pcitab[i].vid != 0)
+                       break;
+
+               if (just_one)
+               {
+                       printf(
+               "%s: wrong PCI device (%04X/%04X) found at %d.%d.%d\n",
+                               dep->de_name, vid, did,
+                               dep->de_pcibus,
+                               dep->de_pcidev, dep->de_pcifunc);
+                       return 0;
+               }
+
+               r= pci_next_dev(&devind, &vid, &did);
+               if (!r)
+                       return 0;
+       }
+
+       dname= pci_dev_name(vid, did);
+       if (!dname)
+               dname= "unknown device";
+       printf("%s: %s (%04X/%04X) at %s\n",
+               dep->de_name, dname, vid, did, pci_slot_name(devind));
+       pci_reserve(devind);
+       /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
+       bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
+       if ((bar & 0x3ff) >= 0x100-32 || bar < 0x400)
+               panic("", "base address is not properly configured", NO_NUM);
+       dep->de_base_port= bar;
+
+       ilr= pci_attr_r8(devind, PCI_ILR);
+       dep->de_irq= ilr;
+       if (debug)
+       {
+               printf("%s: using I/O address 0x%lx, IRQ %d\n",
+                       dep->de_name, (unsigned long)bar, ilr);
+       }
+       dep->de_initf= rtl_init;
+
+       return TRUE;
+}
+
+static void rtl_init(dep)
+dpeth_t *dep;
+{
+       u8_t reg_a, reg_b, cr, config0, config2, config3;
+       int i;
+
+#if DEBUG
+       printf("rtl_init called\n");
+#endif
+       ne_init(dep);
+
+       /* ID */
+       outb_reg0(dep, DP_CR, CR_PS_P0);
+       reg_a = inb_reg0(dep, DP_DUM1);
+       reg_b = inb_reg0(dep, DP_DUM2);
+
+#if DEBUG
+       printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
+#endif
+
+       outb_reg0(dep, DP_CR, CR_PS_P3);
+       config0 = inb_reg3(dep, 3);
+       config2 = inb_reg3(dep, 5);
+       config3 = inb_reg3(dep, 6);
+       outb_reg0(dep, DP_CR, CR_PS_P0);
+
+#if DEBUG
+       printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
+               config0, config2, config3);
+#endif
+
+       if (getenv("RTL8029FD"))
+       {
+               printf("rtl_init: setting full-duplex mode\n");
+               outb_reg0(dep, DP_CR, CR_PS_P3);
+
+               cr= inb_reg3(dep, 1);
+               outb_reg3(dep, 1, cr | 0xc0);
+
+               outb_reg3(dep, 6, config3 | 0x40);
+               config3 = inb_reg3(dep, 6);
+
+               config2= inb_reg3(dep, 5);
+               outb_reg3(dep, 5, config2 | 0x20);
+               config2= inb_reg3(dep, 5);
+
+               outb_reg3(dep, 1, cr);
+
+               outb_reg0(dep, DP_CR, CR_PS_P0);
+
+#if DEBUG
+               printf("rtl_init: config 2 = %x\n", config2);
+               printf("rtl_init: config 3 = %x\n", config3);
+#endif
+       }
+
+#if DEBUG
+       for (i= 0; i<64; i++)
+               printf("%x ", get_ee_word(dep, i));
+       printf("\n");
+#endif
+
+       if (getenv("RTL8029MN"))
+       {
+               ee_wen(dep);
+
+               set_ee_word(dep, 0x78/2, 0x10ec);
+               set_ee_word(dep, 0x7A/2, 0x8029);
+               set_ee_word(dep, 0x7C/2, 0x10ec);
+               set_ee_word(dep, 0x7E/2, 0x8029);
+
+               ee_wds(dep);
+
+               assert(get_ee_word(dep, 0x78/2) == 0x10ec);
+               assert(get_ee_word(dep, 0x7A/2) == 0x8029);
+               assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
+               assert(get_ee_word(dep, 0x7E/2) == 0x8029);
+       }
+
+       if (getenv("RTL8029XXX"))
+       {
+               ee_wen(dep);
+
+               set_ee_word(dep, 0x76/2, 0x8029);
+
+               ee_wds(dep);
+
+               assert(get_ee_word(dep, 0x76/2) == 0x8029);
+       }
+}
+
+static u16_t get_ee_word(dep, a)
+dpeth_t *dep;
+int a;
+{
+       int b, i, cmd;
+       u16_t w;
+
+       outb_reg0(dep, DP_CR, CR_PS_P3);        /* Bank 3 */
+
+       /* Switch to 9346 mode and enable CS */
+       outb_reg3(dep, 1, 0x80 | 0x8);
+
+       cmd= 0x180 | (a & 0x3f);        /* 1 1 0 a5 a4 a3 a2 a1 a0 */
+       for (i= 8; i >= 0; i--)
+       {
+               b= (cmd & (1 << i));
+               b= (b ? 2 : 0);
+
+               /* Cmd goes out on the rising edge of the clock */
+               outb_reg3(dep, 1, 0x80 | 0x8 | b);
+               outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
+       }
+       outb_reg3(dep, 1, 0x80 | 0x8);  /* End of cmd */
+
+       w= 0;
+       for (i= 0; i<16; i++)
+       {
+               w <<= 1;
+
+               /* Data is shifted out on the rising edge. Read at the
+                * falling edge.
+                */
+               outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
+               outb_reg3(dep, 1, 0x80 | 0x8 | b);
+               b= inb_reg3(dep, 1);
+               w |= (b & 1);
+       }
+
+       outb_reg3(dep, 1, 0x80);                /* drop CS */
+       outb_reg3(dep, 1, 0x00);                /* back to normal */
+       outb_reg0(dep, DP_CR, CR_PS_P0);        /* back to bank 0 */
+
+       return w;
+}
+
+static void ee_wen(dep)
+dpeth_t *dep;
+{
+       int b, i, cmd;
+
+       outb_reg0(dep, DP_CR, CR_PS_P3);        /* Bank 3 */
+
+       /* Switch to 9346 mode and enable CS */
+       outb_reg3(dep, 1, 0x80 | 0x8);
+
+       cmd= 0x130;             /* 1 0 0 1 1 x x x x */
+       for (i= 8; i >= 0; i--)
+       {
+               b= (cmd & (1 << i));
+               b= (b ? 2 : 0);
+
+               /* Cmd goes out on the rising edge of the clock */
+               outb_reg3(dep, 1, 0x80 | 0x8 | b);
+               outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
+       }
+       outb_reg3(dep, 1, 0x80 | 0x8);  /* End of cmd */
+       outb_reg3(dep, 1, 0x80);        /* Drop CS */
+       micro_delay(1);                 /* Is this required? */
+}
+
+static void set_ee_word(dep, a, w)
+dpeth_t *dep;
+int a;
+u16_t w;
+{
+       int b, i, cmd;
+
+       outb_reg3(dep, 1, 0x80 | 0x8);          /* Set CS */
+
+       cmd= 0x140 | (a & 0x3f);                /* 1 0 1 a5 a4 a3 a2 a1 a0 */
+       for (i= 8; i >= 0; i--)
+       {
+               b= (cmd & (1 << i));
+               b= (b ? 2 : 0);
+
+               /* Cmd goes out on the rising edge of the clock */
+               outb_reg3(dep, 1, 0x80 | 0x8 | b);
+               outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
+       }
+       for (i= 15; i >= 0; i--)
+       {
+               b= (w & (1 << i));
+               b= (b ? 2 : 0);
+
+               /* Cmd goes out on the rising edge of the clock */
+               outb_reg3(dep, 1, 0x80 | 0x8 | b);
+               outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
+       }
+       outb_reg3(dep, 1, 0x80 | 0x8);  /* End of data */
+       outb_reg3(dep, 1, 0x80);        /* Drop CS */
+       micro_delay(1);                 /* Is this required? */
+       outb_reg3(dep, 1, 0x80 | 0x8);          /* Set CS */
+       for (i= 0; i<10000; i++)
+       {
+               if (inb_reg3(dep, 1) & 1)
+                       break;
+               micro_delay(1);
+       }
+       if (!(inb_reg3(dep, 1) & 1))
+               panic("", "set_ee_word: device remains busy", NO_NUM);
+}
+
+static void ee_wds(dep)
+dpeth_t *dep;
+{
+       int b, i, cmd;
+
+       outb_reg0(dep, DP_CR, CR_PS_P3);        /* Bank 3 */
+
+       /* Switch to 9346 mode and enable CS */
+       outb_reg3(dep, 1, 0x80 | 0x8);
+
+       cmd= 0x100;             /* 1 0 0 0 0 x x x x */
+       for (i= 8; i >= 0; i--)
+       {
+               b= (cmd & (1 << i));
+               b= (b ? 2 : 0);
+
+               /* Cmd goes out on the rising edge of the clock */
+               outb_reg3(dep, 1, 0x80 | 0x8 | b);
+               outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
+       }
+       outb_reg3(dep, 1, 0x80 | 0x8);  /* End of cmd */
+       outb_reg3(dep, 1, 0x80);        /* Drop CS */
+       outb_reg3(dep, 1, 0x00);                /* back to normal */
+       outb_reg0(dep, DP_CR, CR_PS_P0);        /* back to bank 0 */
+}
+
+static void micro_delay(unsigned long usecs)
+{
+       tickdelay(MICROS_TO_TICKS(usecs));
+}
+
+#endif /* ENABLE_PCI */
+
+/*
+ * $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $
+ */
diff --git a/drivers/dp8390/rtl8029.h b/drivers/dp8390/rtl8029.h
new file mode 100644 (file)
index 0000000..0e6554a
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+rtl8029.h
+
+Created:       Sep 2003 by Philip Homburg <philip@f-mnx.phicoh.com>
+*/
+
+/* Bits in dp_cr */
+#define CR_PS_P3       0xC0    /* Register Page 3                   */
+
+#define inb_reg3(dep, reg)     (inb (dep->de_dp8390_port+reg))
+#define outb_reg3(dep, reg, data) (outb(dep->de_dp8390_port+reg, data))
+
+/*
+ * $PchId: rtl8029.h,v 1.3 2004/08/03 15:11:06 philip Exp $
+ */
diff --git a/drivers/dp8390/wdeth.c b/drivers/dp8390/wdeth.c
new file mode 100644 (file)
index 0000000..fa176c3
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+wdeth.c
+
+Created:       March 14, 1994 by Philip Homburg
+*/
+
+#include "../drivers.h"
+
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#include "assert.h"
+
+#include "local.h"
+#include "dp8390.h"
+#include "wdeth.h"
+
+#if ENABLE_WDETH
+
+#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 int we_int_table[8]= { 9, 3, 5, 7, 10, 11, 15, 4 };
+static 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 0;       /* 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 0;       /* No ethernet board at this address */
+
+       dep->de_initf= we_init;
+       dep->de_stopf= we_stop;
+       dep->de_prog_IO= 0;
+       return 1;
+}
+
+
+/*===========================================================================*
+ *                             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;
+
+       assert(dep->de_mode == DEM_ENABLED);
+       assert(!(dep->de_flags & DEF_ENABLED));
+
+       dep->de_address.ea_addr[0] = inb_we(dep, EPL_EA0);
+       dep->de_address.ea_addr[1] = inb_we(dep, EPL_EA1);
+       dep->de_address.ea_addr[2] = inb_we(dep, EPL_EA2);
+       dep->de_address.ea_addr[3] = inb_we(dep, EPL_EA3);
+       dep->de_address.ea_addr[4] = inb_we(dep, EPL_EA4);
+       dep->de_address.ea_addr[5] = inb_we(dep, EPL_EA5);
+
+       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];
+#if DEBUG
+ { printf("%s: encoded irq= %d\n", dep->de_name, int_nr); }
+#endif
+               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];
+#if DEBUG
+ { printf("%s: encoded irq= %d\n", dep->de_name, int_nr); }
+#endif
+               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;
+
+       if (!debug)
+       {
+               printf("%s: WD80%d3 at %X:%d:%lX\n",
+                       dep->de_name, we_type & WET_BRD_16BIT ? 1 : 0,
+                       dep->de_base_port, dep->de_irq, dep->de_linmem);
+       }
+       else
+       {
+               printf("%s: Western Digital %s%s card %s%s at I/O "
+                       "address 0x%X, memory address 0x%lX, "
+                       "memory size 0x%X, irq %d\n",
+                       dep->de_name,
+                       we_type & WET_BRD_16BIT ? "16-bit " : "", 
+                       we_type & WET_ETHERNET ? "Ethernet" : 
+                       we_type & WET_STARLAN ? "Starlan" : "Network",
+                       we_type & WET_INTERF_CHIP ? "with an interface chip " : "",
+                       we_type & WET_SLT_16BIT ? "in a 16-bit slot " : "",
+                       dep->de_base_port, dep->de_linmem, dep->de_ramsize,
+                       dep->de_irq);
+       }
+
+       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;
+}
+
+
+/*===========================================================================*
+ *                             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);
+}
+
+
+/*===========================================================================*
+ *                             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);
+#if DEBUG
+               printf("%s: tlb= 0x%x\n", dep->de_name, tlb);
+#endif
+               return tlb == E_TLB_EB || tlb == E_TLB_E ||
+                       tlb == E_TLB_SMCE || tlb == E_TLB_SMC8216T ||
+                       tlb == E_TLB_SMC8216C;
+       }
+       outb_we(dep, EPL_ICR, icr);
+       return (icr & E_ICR_16BIT);
+}
+
+
+/*===========================================================================*
+ *                             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_SMC8216T || tlb == E_TLB_SMC8216C;
+}
+
+#endif /* ENABLE_WDETH */
+
+/*
+ * $PchId: wdeth.c,v 1.10 2003/09/10 19:31:50 philip Exp $
+ */
diff --git a/drivers/dp8390/wdeth.h b/drivers/dp8390/wdeth.h
new file mode 100644 (file)
index 0000000..ca2d5f3
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+wdeth.h
+
+Created:       before Dec 28, 1992 by Philip Homburg
+*/
+
+#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_SMC8216T 0x2A            /* SMC 8216 T */
+#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 */
+
+/*
+ * $PchId: wdeth.h,v 1.6 2003/09/10 19:29:52 philip Exp $
+ */
index 79a00bd54e6027dc3c852b68c0da38f30d78365c..564193ef4cb91f186e3fbee41ba7f482c3d4a7bc 100644 (file)
 
 _PROTOTYPE( int get_mon_param, (char *key, char *value, int max_size)  );
 _PROTOTYPE( int env_prefix, (char *env, char *prefix)                  );
+_PROTOTYPE( int env_prefix_x, (int argc, char *argv[],
+                                        char *env, char *prefix)        );
 _PROTOTYPE( void env_panic, (char *key)                                        );
 _PROTOTYPE( int env_parse, (char *env, char *fmt, int field, long *param,
                                long min, long max)                     );
+_PROTOTYPE( int env_parse_x, (int argc, char *argv[], char *env,
+       char *fmt, int field, long *param, long min, long max)          );
+
 
 #define fkey_map(fkeys, sfkeys) fkey_ctl(FKEY_MAP, (fkeys), (sfkeys))
 #define fkey_unmap(fkeys, sfkeys) fkey_ctl(FKEY_UNMAP, (fkeys), (sfkeys))
index 8979957a58ddb0f771d0026bd1ab9e48987f30fc..fd9f5939391716eee18014e333a4c7f37f456aff 100644 (file)
@@ -12,6 +12,21 @@ char *fmt;           /* template to parse it with */
 int field;             /* field number of value to return */
 long *param;           /* address of parameter to get */
 long min, max;         /* minimum and maximum values for the parameter */
+{
+       return env_parse_x(0, NULL, env, fmt, field, param, min, max);
+}
+
+/*=========================================================================*
+ *                             env_parse_x                                *
+ *=========================================================================*/
+PUBLIC int env_parse_x(argc, argv, env, fmt, field, param, min, max)
+int argc;
+char *argv[];
+char *env;             /* environment variable to inspect */
+char *fmt;             /* template to parse it with */
+int field;             /* field number of value to return */
+long *param;           /* address of parameter to get */
+long min, max;         /* minimum and maximum values for the parameter */
 {
 /* Parse an environment variable setting, something like "DPETH0=300:3".
  * Panic if the parsing fails.  Return EP_UNSET if the environment variable
@@ -29,9 +44,27 @@ long min, max;               /* minimum and maximum values for the parameter */
   char value[EP_BUF_SIZE];
   char PUNCT[] = ":,;.";
   long newpar;
-  int s, i = 0, radix, r;
+  int s, i, radix, r, keylen;
+
+  keylen= strlen(env);
+  for (i= 0; i<argc; i++)
+  {
+       if (strncmp(argv[i], env, keylen) != 0)
+               continue;
+       if (strlen(argv[i]) <= keylen)
+               continue;
+       if (argv[i][keylen] != '=')
+               continue;
+       val= argv[i]+keylen+1;
+       if (strlen(val)+1 > EP_BUF_SIZE)
+       {
+             printf("WARNING: env_parse() failed: argument too long\n");
+             return(EP_EGETKENV);
+       }
+       strcpy(value, val);
+  }
 
-  if ((s=get_mon_param(env, value, sizeof(value))) != 0) { 
+  if (i >= argc && (s=get_mon_param(env, value, sizeof(value))) != 0) { 
       if (s == ESRCH) return(EP_UNSET);                /* only error allowed */ 
       printf("WARNING: get_mon_param() failed in env_parse(): %d\n",s);
       return(EP_EGETKENV);
@@ -40,6 +73,7 @@ long min, max;                /* minimum and maximum values for the parameter */
   if (strcmp(val, "off") == 0) return(EP_OFF);
   if (strcmp(val, "on") == 0) return(EP_ON);
 
+  i = 0;
   r = EP_ON;
   for (;;) {
        while (*val == ' ') val++;      /* skip spaces */
index 791854ff2d3e4d8ddf893d15c47fd57a7526ea26..9f1e0deb9e7b276c20a290b9d97501e956da3000 100644 (file)
@@ -8,16 +8,49 @@
 PUBLIC int env_prefix(env, prefix)
 char *env;             /* environment variable to inspect */
 char *prefix;          /* prefix to test for */
+{
+       return env_prefix_x(0, NULL, env, prefix);
+}
+
+
+/*=========================================================================*
+ *                             env_prefix_x                               *
+ *=========================================================================*/
+PUBLIC int env_prefix_x(argc, argv, env, prefix)
+int argc;
+char *argv[];
+char *env;             /* environment variable to inspect */
+char *prefix;          /* prefix to test for */
 {
 /* An environment setting may be prefixed by a word, usually "pci".  
  * Return TRUE if a given prefix is used.
  */
   char value[EP_BUF_SIZE];
   char punct[] = ":,;.";
-  int s;
+  int i, s, keylen;
+  char *val;
   size_t n;
 
-  if ((s = get_mon_param(env, value, sizeof(value))) != 0) {
+  keylen= strlen(env);
+  for (i= 0; i<argc; i++)
+  {
+       printf("env_prefix_x: argv[%d] = '%s'\n", i, argv[i]);
+       if (strncmp(argv[i], env, keylen) != 0)
+               continue;
+       if (strlen(argv[i]) <= keylen)
+               continue;
+       if (argv[i][keylen] != '=')
+               continue;
+       val= argv[i]+keylen+1;
+       if (strlen(val)+1 > EP_BUF_SIZE)
+       {
+             printf("WARNING: env_parse() failed: argument too long\n");
+             return(EP_EGETKENV);
+       }
+       strcpy(value, val);
+  }
+
+  if (i >= argc && (s = get_mon_param(env, value, sizeof(value))) != 0) {
        if (s != ESRCH)         /* only error allowed */
        printf("WARNING: get_mon_param() failed in env_prefix(): %d\n", s);     
   }