From: Philip Homburg Date: Fri, 5 Aug 2005 09:53:08 +0000 (+0000) Subject: Added dp8390 driver. Additional env_parse functions that take argc and argv. X-Git-Tag: v3.1.0~444 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/cppcheck-error.log?a=commitdiff_plain;h=db5a8bb2b8c72749e625cb9e959d34a8ea140286;p=minix.git Added dp8390 driver. Additional env_parse functions that take argc and argv. --- diff --git a/drivers/Makefile b/drivers/Makefile index ea9199725..eaefc09b1 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -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 index 000000000..d1f317dfb --- /dev/null +++ b/drivers/dp8390/3c503.c @@ -0,0 +1,201 @@ +/* + * 3c503.c A shared memory driver for Etherlink II board. + * + * Created: Dec. 20, 1996 by G. Falzoni + * + * 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 +#include + +#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 index 000000000..cd9ed46b5 --- /dev/null +++ b/drivers/dp8390/3c503.h @@ -0,0 +1,64 @@ +/* + * 3c503.h A shared memory driver for Etherlink II board. + * + * Created: Dec. 20, 1996 by G. Falzoni + */ + +#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 index 000000000..e633e85d4 --- /dev/null +++ b/drivers/dp8390/Makefile @@ -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 index 000000000..b6b91f9bf --- /dev/null +++ b/drivers/dp8390/dp8390.c @@ -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 + * + * Modified Mar 10 1994 by Philip Homburg + * Become a generic dp8390 driver. + * + * Modified Dec 20 1996 by G. Falzoni + * Added support for 3c503 boards. + */ + +#include "../drivers.h" + +#include +#include +#include +#include +#include +#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; ide_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]; ide_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]; ide_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; ide_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; ide_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; ide_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; ide_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), ð_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 index 000000000..24bdcd8a1 --- /dev/null +++ b/drivers/dp8390/dp8390.h @@ -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 index 000000000..21b1596c4 --- /dev/null +++ b/drivers/dp8390/local.h @@ -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 index 000000000..ddac2358d --- /dev/null +++ b/drivers/dp8390/ne2000.c @@ -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 +*/ + +#include "../drivers.h" + +#include +#include +#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; ide_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; ide_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; ide_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 index 000000000..d2e358f28 --- /dev/null +++ b/drivers/dp8390/ne2000.h @@ -0,0 +1,28 @@ +/* +ne2000.h + +Created: March 15, 1994 by Philip Homburg +*/ + +#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 index 000000000..bb76b2f2d --- /dev/null +++ b/drivers/dp8390/rtl8029.c @@ -0,0 +1,376 @@ +/* +rtl8029.c + +Initialization of PCI DP8390-based ethernet cards + +Created: April 2000 by Philip Homburg +*/ + +#include "../drivers.h" + +#include +#include +#include +#include + +#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 index 000000000..0e6554a7d --- /dev/null +++ b/drivers/dp8390/rtl8029.h @@ -0,0 +1,15 @@ +/* +rtl8029.h + +Created: Sep 2003 by Philip Homburg +*/ + +/* 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 index 000000000..fa176c3c7 --- /dev/null +++ b/drivers/dp8390/wdeth.c @@ -0,0 +1,369 @@ +/* +wdeth.c + +Created: March 14, 1994 by Philip Homburg +*/ + +#include "../drivers.h" + +#include +#include +#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; ide_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 index 000000000..ca2d5f316 --- /dev/null +++ b/drivers/dp8390/wdeth.h @@ -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 $ + */ diff --git a/include/minix/sysutil.h b/include/minix/sysutil.h index 79a00bd54..564193ef4 100644 --- a/include/minix/sysutil.h +++ b/include/minix/sysutil.h @@ -31,9 +31,14 @@ _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)) diff --git a/lib/sysutil/env_parse.c b/lib/sysutil/env_parse.c index 8979957a5..fd9f59393 100644 --- a/lib/sysutil/env_parse.c +++ b/lib/sysutil/env_parse.c @@ -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 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 */ diff --git a/lib/sysutil/env_prefix.c b/lib/sysutil/env_prefix.c index 791854ff2..9f1e0deb9 100644 --- a/lib/sysutil/env_prefix.c +++ b/lib/sysutil/env_prefix.c @@ -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 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); }