From d56df03a530348985919333c5599bbdf95670b19 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 19 Oct 2018 00:37:25 +0200 Subject: [PATCH] Ported the WinPcap thread's packet sanity checks to the SLiRP thread - SLiRP is now more stable; Unified all three NIC families' DP8390 chip implementations in net_dp8390.c/h; Some fixes for the WD8013EBT NIC; Network status bar icon updating is now done at WinPcap/SLiRP handler level, not at the NIC level anymore. --- src/network/net_3c503.c | 997 ++----------------------- src/network/net_dp8390.c | 1068 ++++++++++++++++++++++++++- src/network/net_dp8390.h | 63 +- src/network/net_ne2000.c | 1356 ++++------------------------------ src/network/net_pcap.c | 29 +- src/network/net_slirp.c | 54 +- src/network/net_wd8003.c | 1507 +++++++++----------------------------- src/network/network.c | 14 +- 8 files changed, 1737 insertions(+), 3351 deletions(-) diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index 61fd1f96c..aca87f0cf 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -8,7 +8,7 @@ * Implementation of the following network controllers: * - 3Com Etherlink II 3c503 (ISA 8-bit). * - * Version: @(#)net_3c503.c 1.0.1 2018/10/02 + * Version: @(#)net_3c503.c 1.0.2 2018/10/17 * * Based on @(#)3c503.cpp Carl (MAME) * @@ -55,20 +55,18 @@ #include "../mem.h" #include "../random.h" #include "../device.h" -#include "../ui.h" #include "network.h" #include "net_dp8390.h" #include "net_3c503.h" #include "bswap.h" typedef struct { - dp8390_t dp8390; + dp8390_t *dp8390; mem_mapping_t ram_mapping; uint32_t base_address; int base_irq; uint32_t bios_addr; uint8_t maclocal[6]; /* configured MAC (local) address */ - uint8_t prom[32]; struct { uint8_t pstr; @@ -89,19 +87,14 @@ typedef struct { int dma_channel; } threec503_t; -static void threec503_rx(void *, uint8_t *, int); -static void threec503_tx(threec503_t *, uint32_t); - #ifdef ENABLE_3COM503_LOG int threec503_do_log = ENABLE_3COM503_LOG; -#endif static void threec503_log(const char *fmt, ...) { -#ifdef ENABLE_3COM503_LOG va_list ap; if (threec503_do_log) { @@ -109,13 +102,17 @@ threec503_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define threec503_log(fmt, ...) +#endif static void -threec503_interrupt(threec503_t *dev, int set) +threec503_interrupt(void *priv, int set) { + threec503_t *dev = (threec503_t *) priv; + switch (dev->base_irq) { case 2: dev->regs.idcfr = 0x10; @@ -149,7 +146,7 @@ threec503_ram_write(uint32_t addr, uint8_t val, void *priv) if ((addr & 0x3fff) >= 0x2000) return; - dev->dp8390.mem[addr & 0x1fff] = val; + dev->dp8390->mem[addr & 0x1fff] = val; } @@ -161,7 +158,7 @@ threec503_ram_read(uint32_t addr, void *priv) if ((addr & 0x3fff) >= 0x2000) return 0xff; - return dev->dp8390.mem[addr & 0x1fff]; + return dev->dp8390->mem[addr & 0x1fff]; } @@ -189,746 +186,16 @@ static void threec503_reset(void *priv) { threec503_t *dev = (threec503_t *)priv; - int i; +#ifdef ENABLE_3COM503_LOG threec503_log("3Com503: reset\n"); +#endif - /* Initialize the MAC address area by doubling the physical address */ - dev->prom[0] = dev->dp8390.physaddr[0]; - dev->prom[1] = dev->dp8390.physaddr[1]; - dev->prom[2] = dev->dp8390.physaddr[2]; - dev->prom[3] = dev->dp8390.physaddr[3]; - dev->prom[4] = dev->dp8390.physaddr[4]; - dev->prom[5] = dev->dp8390.physaddr[5]; - - /* ne1k signature */ - for (i=6; i<16; i++) - dev->prom[i] = 0x57; - - /* Zero out registers and memory */ - memset(&dev->dp8390.CR, 0x00, sizeof(dev->dp8390.CR) ); - memset(&dev->dp8390.ISR, 0x00, sizeof(dev->dp8390.ISR)); - memset(&dev->dp8390.IMR, 0x00, sizeof(dev->dp8390.IMR)); - memset(&dev->dp8390.DCR, 0x00, sizeof(dev->dp8390.DCR)); - memset(&dev->dp8390.TCR, 0x00, sizeof(dev->dp8390.TCR)); - memset(&dev->dp8390.TSR, 0x00, sizeof(dev->dp8390.TSR)); - memset(&dev->dp8390.RSR, 0x00, sizeof(dev->dp8390.RSR)); - dev->dp8390.tx_timer_active = 0; - dev->dp8390.local_dma = 0; - dev->dp8390.page_start = 0; - dev->dp8390.page_stop = 0; - dev->dp8390.bound_ptr = 0; - dev->dp8390.tx_page_start = 0; - dev->dp8390.num_coll = 0; - dev->dp8390.tx_bytes = 0; - dev->dp8390.fifo = 0; - dev->dp8390.remote_dma = 0; - dev->dp8390.remote_start = 0; - dev->dp8390.remote_bytes = 0; - dev->dp8390.tallycnt_0 = 0; - dev->dp8390.tallycnt_1 = 0; - dev->dp8390.tallycnt_2 = 0; - - dev->dp8390.curr_page = 0; - - dev->dp8390.rempkt_ptr = 0; - dev->dp8390.localpkt_ptr = 0; - dev->dp8390.address_cnt = 0; - - memset(&dev->dp8390.mem, 0x00, sizeof(dev->dp8390.mem)); - - /* Set power-up conditions */ - dev->dp8390.CR.stop = 1; - dev->dp8390.CR.rdma_cmd = 4; - dev->dp8390.ISR.reset = 1; - dev->dp8390.DCR.longaddr = 1; + dp8390_reset(dev->dp8390); memset(&dev->regs, 0, sizeof(dev->regs)); dev->regs.ctrl = 0x0a; - - threec503_interrupt(dev, 0); -} - - -/* - * Access the 32K private RAM. - * - * The NE2000 memory is accessed through the data port of the - * ASIC (offset 0) after setting up a remote-DMA transfer. - * Both byte and word accesses are allowed. - * The first 16 bytes contains the MAC address at even locations, - * and there is 16K of buffer memory starting at 16K. - */ -static uint32_t -threec503_chipmem_read(threec503_t *dev, uint32_t addr, unsigned int len) -{ - uint32_t retval = 0; - - if (addr <= 15) { - retval = dev->prom[addr % 16]; - if (len == 2) - retval |= (dev->prom[(addr + 1) % 16] << 8); - return(retval); - } - - if ((addr >= DP8390_WORD_MEMSTART) && (addr < DP8390_WORD_MEMEND)) { - retval = dev->dp8390.mem[addr - DP8390_WORD_MEMSTART]; - if (len == 2) - retval |= (dev->dp8390.mem[addr - DP8390_WORD_MEMSTART + 1] << 8); - return(retval); - } - - threec503_log("3Com503: out-of-bounds chipmem read, %04X\n", addr); - return(0xff); -} - - -static void -threec503_chipmem_write(threec503_t *dev, uint32_t addr, uint32_t val, unsigned len) -{ - if ((addr >= DP8390_WORD_MEMSTART) && (addr < DP8390_WORD_MEMEND)) { - dev->dp8390.mem[addr-DP8390_WORD_MEMSTART] = val & 0xff; - if (len == 2) - dev->dp8390.mem[addr-DP8390_WORD_MEMSTART+1] = val >> 8; - } else - threec503_log("3Com503: out-of-bounds chipmem write, %04X\n", addr); -} - - -/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ -static uint32_t -threec503_page0_read(threec503_t *dev, uint32_t off, unsigned int len) -{ - uint8_t retval = 0; - - if (len > 1) { - /* encountered with win98 hardware probe */ - threec503_log("3Com503: bad length! Page0 read from register 0x%02x, len=%u\n", - off, len); - return(retval); - } - - switch(off) { - case 0x01: /* CLDA0 */ - retval = (dev->dp8390.local_dma & 0xff); - break; - - case 0x02: /* CLDA1 */ - retval = (dev->dp8390.local_dma >> 8); - break; - - case 0x03: /* BNRY */ - retval = dev->dp8390.bound_ptr; - break; - - case 0x04: /* TSR */ - retval = ((dev->dp8390.TSR.ow_coll << 7) | - (dev->dp8390.TSR.cd_hbeat << 6) | - (dev->dp8390.TSR.fifo_ur << 5) | - (dev->dp8390.TSR.no_carrier << 4) | - (dev->dp8390.TSR.aborted << 3) | - (dev->dp8390.TSR.collided << 2) | - (dev->dp8390.TSR.tx_ok)); - break; - - case 0x05: /* NCR */ - retval = dev->dp8390.num_coll; - break; - - case 0x06: /* FIFO */ - /* reading FIFO is only valid in loopback mode */ - threec503_log("3Com503: reading FIFO not supported yet\n"); - retval = dev->dp8390.fifo; - break; - - case 0x07: /* ISR */ - retval = ((dev->dp8390.ISR.reset << 7) | - (dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - break; - - case 0x08: /* CRDA0 */ - retval = (dev->dp8390.remote_dma & 0xff); - break; - - case 0x09: /* CRDA1 */ - retval = (dev->dp8390.remote_dma >> 8); - break; - - case 0x0a: /* reserved / RTL8029ID0 */ - threec503_log("3Com503: reserved Page0 read - 0x0a\n"); - retval = 0xff; - break; - - case 0x0b: /* reserved / RTL8029ID1 */ - threec503_log("3Com503: reserved Page0 read - 0x0b\n"); - retval = 0xff; - break; - - case 0x0c: /* RSR */ - retval = ((dev->dp8390.RSR.deferred << 7) | - (dev->dp8390.RSR.rx_disabled << 6) | - (dev->dp8390.RSR.rx_mbit << 5) | - (dev->dp8390.RSR.rx_missed << 4) | - (dev->dp8390.RSR.fifo_or << 3) | - (dev->dp8390.RSR.bad_falign << 2) | - (dev->dp8390.RSR.bad_crc << 1) | - (dev->dp8390.RSR.rx_ok)); - break; - - case 0x0d: /* CNTR0 */ - retval = dev->dp8390.tallycnt_0; - break; - - case 0x0e: /* CNTR1 */ - retval = dev->dp8390.tallycnt_1; - break; - - case 0x0f: /* CNTR2 */ - retval = dev->dp8390.tallycnt_2; - break; - - default: - threec503_log("3Com503: Page0 register 0x%02x out of range\n", - off); - break; - } - - threec503_log("3Com503: Page0 read from register 0x%02x, value=0x%02x\n", - off, retval); - - return(retval); -} - - -static void -threec503_page0_write(threec503_t *dev, uint32_t off, uint32_t val, unsigned len) -{ - uint8_t val2; - - /* It appears to be a common practice to use outw on page0 regs... */ - - /* break up outw into two outb's */ - if (len == 2) { - threec503_page0_write(dev, off, (val & 0xff), 1); - if (off < 0x0f) - threec503_page0_write(dev, off+1, ((val>>8)&0xff), 1); - return; - } - - threec503_log("3Com503: Page0 write to register 0x%02x, value=0x%02x\n", - off, val); - - switch(off) { - case 0x01: /* PSTART */ - dev->dp8390.page_start = val; - break; - - case 0x02: /* PSTOP */ - dev->dp8390.page_stop = val; - break; - - case 0x03: /* BNRY */ - dev->dp8390.bound_ptr = val; - break; - - case 0x04: /* TPSR */ - dev->dp8390.tx_page_start = val; - break; - - case 0x05: /* TBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.tx_bytes &= 0xff00; - dev->dp8390.tx_bytes |= (val & 0xff); - break; - - case 0x06: /* TBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.tx_bytes &= 0x00ff; - dev->dp8390.tx_bytes |= ((val & 0xff) << 8); - break; - - case 0x07: /* ISR */ - val &= 0x7f; /* clear RST bit - status-only bit */ - /* All other values are cleared iff the ISR bit is 1 */ - dev->dp8390.ISR.pkt_rx &= !((int)((val & 0x01) == 0x01)); - dev->dp8390.ISR.pkt_tx &= !((int)((val & 0x02) == 0x02)); - dev->dp8390.ISR.rx_err &= !((int)((val & 0x04) == 0x04)); - dev->dp8390.ISR.tx_err &= !((int)((val & 0x08) == 0x08)); - dev->dp8390.ISR.overwrite &= !((int)((val & 0x10) == 0x10)); - dev->dp8390.ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20)); - dev->dp8390.ISR.rdma_done &= !((int)((val & 0x40) == 0x40)); - val = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - val &= ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - if (val == 0x00) - threec503_interrupt(dev, 0); - break; - - case 0x08: /* RSAR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_start &= 0xff00; - dev->dp8390.remote_start |= (val & 0xff); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x09: /* RSAR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_start &= 0x00ff; - dev->dp8390.remote_start |= ((val & 0xff) << 8); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x0a: /* RBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_bytes &= 0xff00; - dev->dp8390.remote_bytes |= (val & 0xff); - break; - - case 0x0b: /* RBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_bytes &= 0x00ff; - dev->dp8390.remote_bytes |= ((val & 0xff) << 8); - break; - - case 0x0c: /* RCR */ - /* Check if the reserved bits are set */ - if (val & 0xc0) { - threec503_log("3Com503: RCR write, reserved bits set\n"); - } - - /* Set all other bit-fields */ - dev->dp8390.RCR.errors_ok = ((val & 0x01) == 0x01); - dev->dp8390.RCR.runts_ok = ((val & 0x02) == 0x02); - dev->dp8390.RCR.broadcast = ((val & 0x04) == 0x04); - dev->dp8390.RCR.multicast = ((val & 0x08) == 0x08); - dev->dp8390.RCR.promisc = ((val & 0x10) == 0x10); - dev->dp8390.RCR.monitor = ((val & 0x20) == 0x20); - - /* Monitor bit is a little suspicious... */ - if (val & 0x20) threec503_log("3Com503: RCR write, monitor bit set!\n"); - break; - - case 0x0d: /* TCR */ - /* Check reserved bits */ - if (val & 0xe0) threec503_log("3Com503: TCR write, reserved bits set\n"); - - /* Test loop mode (not supported) */ - if (val & 0x06) { - dev->dp8390.TCR.loop_cntl = (val & 0x6) >> 1; - threec503_log("3Com503: TCR write, loop mode %d not supported\n", - dev->dp8390.TCR.loop_cntl); - } else { - dev->dp8390.TCR.loop_cntl = 0; - } - - /* Inhibit-CRC not supported. */ - if (val & 0x01) threec503_log( - "3Com503: TCR write, inhibit-CRC not supported\n"); - - /* Auto-transmit disable very suspicious */ - if (val & 0x08) threec503_log( - "3Com503: TCR write, auto transmit disable not supported\n"); - - /* Allow collision-offset to be set, although not used */ - dev->dp8390.TCR.coll_prio = ((val & 0x08) == 0x08); - break; - - case 0x0e: /* DCR */ - /* the loopback mode is not suppported yet */ - if (! (val & 0x08)) threec503_log( - "3Com503: DCR write, loopback mode selected\n"); - - /* It is questionable to set longaddr and auto_rx, since - * they are not supported on the NE2000. Print a warning - * and continue. */ - if (val & 0x04) - threec503_log("3Com503: DCR write - LAS set ???\n"); - if (val & 0x10) - threec503_log("3Com503: DCR write - AR set ???\n"); - - /* Set other values. */ - dev->dp8390.DCR.wdsize = ((val & 0x01) == 0x01); - dev->dp8390.DCR.endian = ((val & 0x02) == 0x02); - dev->dp8390.DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ - dev->dp8390.DCR.loop = ((val & 0x08) == 0x08); - dev->dp8390.DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ - dev->dp8390.DCR.fifo_size = (val & 0x50) >> 5; - break; - - case 0x0f: /* IMR */ - /* Check for reserved bit */ - if (val & 0x80) - threec503_log("3Com503: IMR write, reserved bit set\n"); - - /* Set other values */ - dev->dp8390.IMR.rx_inte = ((val & 0x01) == 0x01); - dev->dp8390.IMR.tx_inte = ((val & 0x02) == 0x02); - dev->dp8390.IMR.rxerr_inte = ((val & 0x04) == 0x04); - dev->dp8390.IMR.txerr_inte = ((val & 0x08) == 0x08); - dev->dp8390.IMR.overw_inte = ((val & 0x10) == 0x10); - dev->dp8390.IMR.cofl_inte = ((val & 0x20) == 0x20); - dev->dp8390.IMR.rdma_inte = ((val & 0x40) == 0x40); - val2 = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - if (((val & val2) & 0x7f) == 0) - threec503_interrupt(dev, 0); - else - threec503_interrupt(dev, 1); - break; - - default: - threec503_log("3Com503: Page0 write, bad register 0x%02x\n", - off); - break; - } -} - - -/* Handle reads/writes to the first page of the DS8390 register file. */ -static uint32_t -threec503_page1_read(threec503_t *dev, uint32_t off, unsigned int len) -{ - threec503_log("3Com503: Page1 read from register 0x%02x, len=%u\n", - off, len); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - return(dev->dp8390.physaddr[off - 1]); - - case 0x07: /* CURR */ - threec503_log("3Com503: returning current page: 0x%02x\n", - (dev->dp8390.curr_page)); - return(dev->dp8390.curr_page); - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - return(dev->dp8390.mchash[off - 8]); - - default: - threec503_log("3Com503: Page1 read register 0x%02x out of range\n", - off); - return(0); - } -} - - -static void -threec503_page1_write(threec503_t *dev, uint32_t off, uint32_t val, unsigned len) -{ - threec503_log("3Com503: Page1 write to register 0x%02x, len=%u, value=0x%04x\n", - off, len, val); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - dev->dp8390.physaddr[off - 1] = val; - if (off == 6) threec503_log( - "3Com503: physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], - dev->dp8390.physaddr[2], dev->dp8390.physaddr[3], - dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); - break; - - case 0x07: /* CURR */ - dev->dp8390.curr_page = val; - break; - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - dev->dp8390.mchash[off - 8] = val; - break; - - default: - threec503_log("3Com503: Page1 write register 0x%02x out of range\n", - off); - break; - } -} - - -/* Handle reads/writes to the second page of the DS8390 register file. */ -static uint32_t -threec503_page2_read(threec503_t *dev, uint32_t off, unsigned int len) -{ - threec503_log("3Com503: Page2 read from register 0x%02x, len=%u\n", - off, len); - - switch(off) { - case 0x01: /* PSTART */ - return(dev->dp8390.page_start); - - case 0x02: /* PSTOP */ - return(dev->dp8390.page_stop); - - case 0x03: /* Remote Next-packet pointer */ - return(dev->dp8390.rempkt_ptr); - - case 0x04: /* TPSR */ - return(dev->dp8390.tx_page_start); - - case 0x05: /* Local Next-packet pointer */ - return(dev->dp8390.localpkt_ptr); - - case 0x06: /* Address counter (upper) */ - return(dev->dp8390.address_cnt >> 8); - - case 0x07: /* Address counter (lower) */ - return(dev->dp8390.address_cnt & 0xff); - - case 0x08: /* Reserved */ - case 0x09: - case 0x0a: - case 0x0b: - threec503_log("3Com503: reserved Page2 read - register 0x%02x\n", - off); - return(0xff); - - case 0x0c: /* RCR */ - return ((dev->dp8390.RCR.monitor << 5) | - (dev->dp8390.RCR.promisc << 4) | - (dev->dp8390.RCR.multicast << 3) | - (dev->dp8390.RCR.broadcast << 2) | - (dev->dp8390.RCR.runts_ok << 1) | - (dev->dp8390.RCR.errors_ok)); - - case 0x0d: /* TCR */ - return ((dev->dp8390.TCR.coll_prio << 4) | - (dev->dp8390.TCR.ext_stoptx << 3) | - ((dev->dp8390.TCR.loop_cntl & 0x3) << 1) | - (dev->dp8390.TCR.crc_disable)); - - case 0x0e: /* DCR */ - return (((dev->dp8390.DCR.fifo_size & 0x3) << 5) | - (dev->dp8390.DCR.auto_rx << 4) | - (dev->dp8390.DCR.loop << 3) | - (dev->dp8390.DCR.longaddr << 2) | - (dev->dp8390.DCR.endian << 1) | - (dev->dp8390.DCR.wdsize)); - - case 0x0f: /* IMR */ - return ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - - default: - threec503_log("3Com503: Page2 register 0x%02x out of range\n", - off); - break; - } - - return(0); -} - - -static void -threec503_page2_write(threec503_t *dev, uint32_t off, uint32_t val, unsigned len) -{ - /* Maybe all writes here should be BX_PANIC()'d, since they - affect internal operation, but let them through for now - and print a warning. */ - threec503_log("3Com503: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", - off, len, val); - switch(off) { - case 0x01: /* CLDA0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.local_dma &= 0xff00; - dev->dp8390.local_dma |= (val & 0xff); - break; - - case 0x02: /* CLDA1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.local_dma &= 0x00ff; - dev->dp8390.local_dma |= ((val & 0xff) << 8); - break; - - case 0x03: /* Remote Next-pkt pointer */ - dev->dp8390.rempkt_ptr = val; - break; - - case 0x04: - threec503_log("page 2 write to reserved register 0x04\n"); - break; - - case 0x05: /* Local Next-packet pointer */ - dev->dp8390.localpkt_ptr = val; - break; - - case 0x06: /* Address counter (upper) */ - /* Clear out high byte and re-insert */ - dev->dp8390.address_cnt &= 0x00ff; - dev->dp8390.address_cnt |= ((val & 0xff) << 8); - break; - - case 0x07: /* Address counter (lower) */ - /* Clear out low byte and re-insert */ - dev->dp8390.address_cnt &= 0xff00; - dev->dp8390.address_cnt |= (val & 0xff); - break; - - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - threec503_log("3Com503: Page2 write to reserved register 0x%02x\n", - off); - break; - - default: - threec503_log("3Com503: Page2 write, illegal register 0x%02x\n", - off); - break; - } -} - - -/* Routines for handling reads/writes to the Command Register. */ -static uint32_t -threec503_read_cr(threec503_t *dev) -{ - uint32_t retval; - - retval = (((dev->dp8390.CR.pgsel & 0x03) << 6) | - ((dev->dp8390.CR.rdma_cmd & 0x07) << 3) | - (dev->dp8390.CR.tx_packet << 2) | - (dev->dp8390.CR.start << 1) | - (dev->dp8390.CR.stop)); - threec503_log("3Com503: read CR returns 0x%02x\n", retval); - - return(retval); -} - - -static void -threec503_write_cr(threec503_t *dev, uint32_t val) -{ - threec503_log("3Com503: wrote 0x%02x to CR\n", val); - - /* Validate remote-DMA */ - if ((val & 0x38) == 0x00) { - threec503_log("3Com503: CR write - invalid rDMA value 0\n"); - val |= 0x20; /* dma_cmd == 4 is a safe default */ - } - - /* Check for s/w reset */ - if (val & 0x01) { - dev->dp8390.ISR.reset = 1; - dev->dp8390.CR.stop = 1; - } else - dev->dp8390.CR.stop = 0; - - dev->dp8390.CR.rdma_cmd = (val & 0x38) >> 3; - - /* If start command issued, the RST bit in the ISR */ - /* must be cleared */ - if ((val & 0x02) && !dev->dp8390.CR.start) - dev->dp8390.ISR.reset = 0; - - dev->dp8390.CR.start = ((val & 0x02) == 0x02); - dev->dp8390.CR.pgsel = (val & 0xc0) >> 6; - - /* Check for send-packet command */ - if (dev->dp8390.CR.rdma_cmd == 3) { - /* Set up DMA read from receive ring */ - dev->dp8390.remote_start = dev->dp8390.remote_dma = dev->dp8390.bound_ptr * 256; - dev->dp8390.remote_bytes = (uint16_t) threec503_chipmem_read(dev, dev->dp8390.bound_ptr * 256 + 2, 2); - threec503_log("3Com503: sending buffer %x length %d\n", - dev->dp8390.remote_start, dev->dp8390.remote_bytes); - } - - /* Check for start-tx */ - if ((val & 0x04) && dev->dp8390.TCR.loop_cntl) { - if (dev->dp8390.TCR.loop_cntl != 1) { - threec503_log("3Com503: loop mode %d not supported\n", - dev->dp8390.TCR.loop_cntl); - } else { - threec503_rx(dev, - &dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], - dev->dp8390.tx_bytes); - } - } else if (val & 0x04) { - if (dev->dp8390.CR.stop || (!dev->dp8390.CR.start)) { - if (dev->dp8390.tx_bytes == 0) /* njh@bandsman.co.uk */ - return; /* Solaris9 probe */ - threec503_log("3Com503: CR write - tx start, dev in reset\n"); - } - - if (dev->dp8390.tx_bytes == 0) - threec503_log("3Com503: CR write - tx start, tx bytes == 0\n"); - - /* Send the packet to the system driver */ - dev->dp8390.CR.tx_packet = 1; - network_tx(&dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], - dev->dp8390.tx_bytes); - - /* some more debug */ - if (dev->dp8390.tx_timer_active) - threec503_log("3Com503: CR write, tx timer still active\n"); - - threec503_tx(dev, val); - } - - /* Linux probes for an interrupt by setting up a remote-DMA read - * of 0 bytes with remote-DMA completion interrupts enabled. - * Detect this here */ - if (dev->dp8390.CR.rdma_cmd == 0x01 && dev->dp8390.CR.start && dev->dp8390.remote_bytes == 0) { - dev->dp8390.ISR.rdma_done = 1; - if (dev->dp8390.IMR.rdma_inte) { - threec503_interrupt(dev, 1); - threec503_interrupt(dev, 0); - } - } } @@ -943,18 +210,18 @@ threec503_nic_lo_read(uint16_t addr, void *priv) case 0x00: threec503_log("Read offset=%04x\n", off); if (off == 0x00) - retval = threec503_read_cr(dev); - else switch(dev->dp8390.CR.pgsel) { + retval = dp8390_read_cr(dev->dp8390); + else switch(dev->dp8390->CR.pgsel) { case 0x00: - retval = threec503_page0_read(dev, off, 1); + retval = dp8390_page0_read(dev->dp8390, off, 1); break; case 0x01: - retval = threec503_page1_read(dev, off, 1); + retval = dp8390_page1_read(dev->dp8390, off, 1); break; case 0x02: - retval = threec503_page2_read(dev, off, 1); + retval = dp8390_page2_read(dev->dp8390, off, 1); break; case 0x03: @@ -964,11 +231,11 @@ threec503_nic_lo_read(uint16_t addr, void *priv) break; case 0x01: - retval = dev->prom[off]; + retval = dev->dp8390->macaddr[off]; break; case 0x02: - retval = dev->prom[off + 0x10]; + retval = dev->dp8390->macaddr[off + 0x10]; break; case 0x03: @@ -993,18 +260,18 @@ threec503_nic_lo_write(uint16_t addr, uint8_t val, void *priv) page being selected by the PS0,PS1 registers in the command register */ if (off == 0x00) - threec503_write_cr(dev, val); - else switch(dev->dp8390.CR.pgsel) { + dp8390_write_cr(dev->dp8390, val); + else switch(dev->dp8390->CR.pgsel) { case 0x00: - threec503_page0_write(dev, off, val, 1); + dp8390_page0_write(dev->dp8390, off, val, 1); break; case 0x01: - threec503_page1_write(dev, off, val, 1); + dp8390_page1_write(dev->dp8390, off, val, 1); break; case 0x02: - threec503_page2_write(dev, off, val, 1); + dp8390_page2_write(dev->dp8390, off, val, 1); break; case 0x03: @@ -1134,7 +401,7 @@ threec503_nic_hi_read(uint16_t addr, void *priv) threec503_set_drq(dev); - return threec503_chipmem_read(dev, dev->regs.da++, 1); + return dp8390_chipmem_read(dev->dp8390, dev->regs.da++, 1); } return 0; @@ -1190,7 +457,7 @@ threec503_nic_hi_write(uint16_t addr, uint8_t val, void *priv) case 0x06: if (val & 1) { threec503_reset(dev); - dev->dp8390.ISR.reset = 1; + dev->dp8390->ISR.reset = 1; dev->regs.ctrl = 0x0b; return; } @@ -1264,25 +531,12 @@ threec503_nic_hi_write(uint16_t addr, uint8_t val, void *priv) threec503_set_drq(dev); - threec503_chipmem_write(dev, dev->regs.da++, val, 1); + dp8390_chipmem_write(dev->dp8390, dev->regs.da++, val, 1); break; } } -static void -threec503_nic_ioremove(threec503_t *dev, uint16_t addr) -{ - io_removehandler(addr, 0x10, - threec503_nic_lo_read, NULL, NULL, - threec503_nic_lo_write, NULL, NULL, dev); - - io_removehandler(addr+0x400, 0x10, - threec503_nic_hi_read, NULL, NULL, - threec503_nic_hi_write, NULL, NULL, dev); -} - - static void threec503_nic_ioset(threec503_t *dev, uint16_t addr) { @@ -1296,174 +550,6 @@ threec503_nic_ioset(threec503_t *dev, uint16_t addr) } -static void -threec503_tx(threec503_t *dev, uint32_t val) -{ - dev->dp8390.CR.tx_packet = 0; - dev->dp8390.TSR.tx_ok = 1; - dev->dp8390.ISR.pkt_tx = 1; - - /* Generate an interrupt if not masked */ - if (dev->dp8390.IMR.tx_inte) - threec503_interrupt(dev, 1); - dev->dp8390.tx_timer_active = 0; -} - - -/* - * Called by the platform-specific code when an Ethernet frame - * has been received. The destination address is tested to see - * if it should be accepted, and if the RX ring has enough room, - * it is copied into it and the receive process is updated. - */ -static void -threec503_rx(void *priv, uint8_t *buf, int io_len) -{ - static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; - threec503_t *dev = (threec503_t *)priv; - uint8_t pkthdr[4]; - uint8_t *startptr; - int rx_pages, avail; - int idx, nextpage; - int endbytes; - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 1); - - if (io_len != 60) - threec503_log("3Com503: rx_frame with length %d\n", io_len); - - if ((dev->dp8390.CR.stop != 0) || (dev->dp8390.page_start == 0)) return; - - /* - * Add the pkt header + CRC to the length, and work - * out how many 256-byte pages the frame would occupy. - */ - rx_pages = (io_len + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; - if (dev->dp8390.curr_page < dev->dp8390.bound_ptr) { - avail = dev->dp8390.bound_ptr - dev->dp8390.curr_page; - } else { - avail = (dev->dp8390.page_stop - dev->dp8390.page_start) - - (dev->dp8390.curr_page - dev->dp8390.bound_ptr); - } - - /* - * Avoid getting into a buffer overflow condition by - * not attempting to do partial receives. The emulation - * to handle this condition seems particularly painful. - */ - if ((avail < rx_pages) -#if NE2K_NEVER_FULL_RING - || (avail == rx_pages) -#endif - ) { - threec503_log("3Com503: no space\n"); - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - if ((io_len < 40/*60*/) && !dev->dp8390.RCR.runts_ok) { - threec503_log("3Com503: rejected small packet, length %d\n", io_len); - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Some computers don't care... */ - if (io_len < 60) - io_len = 60; - - threec503_log("3Com503: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", - buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], - io_len); - - /* Do address filtering if not in promiscuous mode. */ - if (! dev->dp8390.RCR.promisc) { - /* If this is a broadcast frame.. */ - if (! memcmp(buf, bcast_addr, 6)) { - /* Broadcast not enabled, we're done. */ - if (! dev->dp8390.RCR.broadcast) { - threec503_log("3Com503: RX BC disabled\n"); - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* If this is a multicast frame.. */ - else if (buf[0] & 0x01) { - /* Multicast not enabled, we're done. */ - if (! dev->dp8390.RCR.multicast) { -#if 1 - threec503_log("3Com503: RX MC disabled\n"); -#endif - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Are we listening to this multicast address? */ - idx = mcast_index(buf); - if (! (dev->dp8390.mchash[idx>>3] & (1<<(idx&0x7)))) { - threec503_log("3Com503: RX MC not listed\n"); - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* Unicast, must be for us.. */ - else if (memcmp(buf, dev->dp8390.physaddr, 6)) return; - } else - threec503_log("3Com503: RX promiscuous receive\n"); - - nextpage = dev->dp8390.curr_page + rx_pages; - if (nextpage >= dev->dp8390.page_stop) - nextpage -= (dev->dp8390.page_stop - dev->dp8390.page_start); - - /* Set up packet header. */ - pkthdr[0] = 0x01; /* RXOK - packet is OK */ - if (buf[0] & 0x01) - pkthdr[0] |= 0x20; /* MULTICAST packet */ - pkthdr[1] = nextpage; /* ptr to next packet */ - pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ - pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ - threec503_log("3Com503: RX pkthdr [%02x %02x %02x %02x]\n", - pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); - - /* Copy into buffer, update curpage, and signal interrupt if config'd */ - startptr = &dev->dp8390.mem[(dev->dp8390.curr_page * 256) - DP8390_WORD_MEMSTART]; - memcpy(startptr, pkthdr, sizeof(pkthdr)); - if ((nextpage > dev->dp8390.curr_page) || - ((dev->dp8390.curr_page + rx_pages) == dev->dp8390.page_stop)) { - memcpy(startptr+sizeof(pkthdr), buf, io_len); - } else { - endbytes = (dev->dp8390.page_stop - dev->dp8390.curr_page) * 256; - memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); - startptr = &dev->dp8390.mem[(dev->dp8390.page_start * 256) - DP8390_WORD_MEMSTART]; - memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); - } - dev->dp8390.curr_page = nextpage; - - dev->dp8390.RSR.rx_ok = 1; - dev->dp8390.RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; - dev->dp8390.ISR.pkt_rx = 1; - - if (dev->dp8390.IMR.rx_inte) - threec503_interrupt(dev, 1); - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); -} - - static void * threec503_nic_init(const device_t *info) { @@ -1480,7 +566,7 @@ threec503_nic_init(const device_t *info) dev->base_irq = device_get_config_int("irq"); dev->dma_channel = device_get_config_int("dma"); dev->bios_addr = device_get_config_hex20("bios_addr"); - + /* See if we have a local MAC address configured. */ mac = device_get_config_mac("mac", -1); @@ -1505,19 +591,22 @@ threec503_nic_init(const device_t *info) dev->maclocal[4] = (mac>>8) & 0xff; dev->maclocal[5] = (mac & 0xff); } - memcpy(dev->dp8390.physaddr, dev->maclocal, sizeof(dev->maclocal)); + + dev->dp8390 = device_add(&dp8390_device); + dev->dp8390->priv = dev; + dev->dp8390->interrupt = threec503_interrupt; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CHECK_CR | DP8390_FLAG_CLEAR_IRQ); + + memcpy(dev->dp8390->physaddr, dev->maclocal, sizeof(dev->maclocal)); threec503_log("I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", dev->base_address, dev->base_irq, - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], dev->dp8390.physaddr[2], - dev->dp8390.physaddr[3], dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); + dev->dp8390->physaddr[0], dev->dp8390->physaddr[1], dev->dp8390->physaddr[2], + dev->dp8390->physaddr[3], dev->dp8390->physaddr[4], dev->dp8390->physaddr[5]); /* Reset the board. */ threec503_reset(dev); - /* Attach ourselves to the network module. */ - network_attach(dev, dev->dp8390.physaddr, threec503_rx); - /* Map this system into the memory map. */ mem_mapping_add(&dev->ram_mapping, dev->bios_addr, 0x4000, threec503_ram_read, NULL, NULL, @@ -1525,6 +614,9 @@ threec503_nic_init(const device_t *info) NULL, MEM_MAPPING_EXTERNAL, dev); mem_mapping_disable(&dev->ram_mapping); + /* Attach ourselves to the network module. */ + network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx); + return(dev); } @@ -1533,13 +625,10 @@ static void threec503_nic_close(void *priv) { threec503_t *dev = (threec503_t *)priv; - - /* Make sure the platform layer is shut down. */ - network_close(); - - threec503_nic_ioremove(dev, dev->base_address); +#ifdef ENABLE_3COM503_LOG threec503_log("3Com503: closed\n"); +#endif free(dev); } diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index ee24ecd1e..e645d5b3d 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -1,3 +1,20 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the DP8390 Network Interface Controller used by + * the WD family, NE1000/NE2000 family, and 3Com 3C503 NIC's. + * + * Version: @(#)net_dp8390.c 1.0.0 2018/10/17 + * + * Authors: Miran Grca, + * Bochs project, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Bochs project. + */ #include #include #include @@ -6,12 +23,40 @@ #include #include #define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "network.h" +#include "net_dp8390.h" + + +static void dp8390_tx(dp8390_t *dev, uint32_t val); +void dp8390_rx(void *priv, uint8_t *buf, int io_len); + + +#ifdef ENABLE_DP8390_LOG +int dp8390_do_log = ENABLE_DP8390_LOG; + +static void +dp8390_log(const char *fmt, ...) +{ + va_list ap; + + if (dp8390_do_log >= lvl) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define dp8390_log(lvl, fmt, ...) +#endif + /* * Return the 6-bit index into the multicast * table. Stolen unashamedly from FreeBSD's if_ed.c */ -int +static int mcast_index(const void *dst) { #define POLYNOMIAL 0x04c11db6 @@ -33,3 +78,1024 @@ mcast_index(const void *dst) return(crc >> 26); #undef POLYNOMIAL } + + +/* + * Access the 32K private RAM. + * + * The NE2000 memory is accessed through the data port of the + * ASIC (offset 0) after setting up a remote-DMA transfer. + * Both byte and word accesses are allowed. + * The first 16 bytes contain the MAC address at even locations, + * and there is 16K of buffer memory starting at 16K. + */ +uint32_t +dp8390_chipmem_read(dp8390_t *dev, uint32_t addr, unsigned int len) +{ + int i; + uint32_t retval = 0; + +#ifdef ENABLE_DP8390_LOG + if ((len > 1) && (addr & (len - 1)) + dp3890_log("DP8390: unaligned chipmem word read\n"); +#endif + + dp8390_log("DP8390: Chipmem Read Address=%04x\n", addr); + + /* ROM'd MAC address */ + for (i = 0; i < len; i++) { + if (addr < dev->macaddr_size) + retval |= ((uint32_t) dev->macaddr[addr & (dev->macaddr_size - 1)]) << (i << 3); + else if ((addr >= dev->mem_start) && (addr < dev->mem_end) && !(dev->flags & DP8390_FLAG_NO_CHIPMEM)) + retval |= (uint32_t) (dev->mem[addr - dev->mem_start]) << (i << 3); + else { + dp8390_log("DP8390: out-of-bounds chipmem read, %04X\n", addr); + retval |= 0xff << (i << 3); + } + addr++; + } + + return(retval); +} + + +void +dp8390_chipmem_write(dp8390_t *dev, uint32_t addr, uint32_t val, unsigned len) +{ + int i; + + if (dev->flags & DP8390_FLAG_NO_CHIPMEM) + return; + +#ifdef ENABLE_DP8390_LOG + if ((len > 1) && (addr & (len - 1)) + dp8390_log("DP8390: unaligned chipmem word write\n"); +#endif + + dp8390_log("DP8390: Chipmem Write Address=%04x\n", addr); + + for (i = 0; i < len; i++) { + if ((addr < dev->mem_start) || (addr >= dev->mem_end)) { + dp8390_log("DP8390: out-of-bounds chipmem write, %04X\n", addr); + return; + } + + dev->mem[addr - dev->mem_start] = val & 0xff; + val >>= 8; + addr++; + } +} + + +/* Routines for handling reads/writes to the Command Register. */ +uint32_t +dp8390_read_cr(dp8390_t *dev) +{ + uint32_t retval; + + retval = (((dev->CR.pgsel & 0x03) << 6) | + ((dev->CR.rdma_cmd & 0x07) << 3) | + (dev->CR.tx_packet << 2) | + (dev->CR.start << 1) | + (dev->CR.stop)); + dp8390_log("DP8390: read CR returns 0x%02x\n", retval); + + return(retval); +} + + +void +dp8390_write_cr(dp8390_t *dev, uint32_t val) +{ + dp8390_log("DP8390: wrote 0x%02x to CR\n", val); + + /* Validate remote-DMA */ + if ((val & 0x38) == 0x00) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: CR write - invalid rDMA value 0\n"); +#endif + val |= 0x20; /* dma_cmd == 4 is a safe default */ + } + + /* Check for s/w reset */ + if (val & 0x01) { + dev->ISR.reset = 1; + dev->CR.stop = 1; + } else { + dev->CR.stop = 0; + } + + dev->CR.rdma_cmd = (val & 0x38) >> 3; + + /* If start command issued, the RST bit in the ISR */ + /* must be cleared */ + if ((val & 0x02) && !dev->CR.start) + dev->ISR.reset = 0; + + dev->CR.start = ((val & 0x02) == 0x02); + dev->CR.pgsel = (val & 0xc0) >> 6; + + /* Check for send-packet command */ + if (dev->CR.rdma_cmd == 3) { + /* Set up DMA read from receive ring */ + dev->remote_start = dev->remote_dma = dev->bound_ptr * 256; + dev->remote_bytes = (uint16_t) dp8390_chipmem_read(dev, dev->bound_ptr * 256 + 2, 2); + dp8390_log("DP8390: sending buffer #x%x length %d\n", + dev->dp8390.remote_start, dev->dp8390.remote_bytes); + } + + /* Check for start-tx */ + if ((val & 0x04) && dev->TCR.loop_cntl) { + if (dev->TCR.loop_cntl) { + dp8390_rx(dev, &dev->mem[(dev->tx_page_start * 256) - dev->mem_start], + dev->tx_bytes); + } + } else if (val & 0x04) { + if (dev->CR.stop || (!dev->CR.start && (dev->flags & DP8390_FLAG_CHECK_CR))) { + if (dev->tx_bytes == 0) /* njh@bandsman.co.uk */ + return; /* Solaris9 probe */ +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: CR write - tx start, dev in reset\n"); +#endif + } + +#ifdef ENABLE_DP8390_LOG + if (dev->tx_bytes == 0) + dp8390_log("DP8390: CR write - tx start, tx bytes == 0\n"); +#endif + + /* Send the packet to the system driver */ + dev->CR.tx_packet = 1; + + network_tx(&dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes); + + /* some more debug */ +#ifdef ENABLE_DP8390_LOG + if (dev->tx_timer_active) + dp8390_log("DP8390: CR write, tx timer still active\n"); +#endif + + dp8390_tx(dev, val); + } + + /* Linux probes for an interrupt by setting up a remote-DMA read + * of 0 bytes with remote-DMA completion interrupts enabled. + * Detect this here */ + if ((dev->CR.rdma_cmd == 0x01) && dev->CR.start && + (dev->remote_bytes == 0)) { + dev->ISR.rdma_done = 1; + if (dev->IMR.rdma_inte && dev->interrupt) { + dev->interrupt(dev->priv, 1); + if (dev->flags & DP8390_FLAG_CLEAR_IRQ) + dev->interrupt(dev->priv, 0); + } + } +} + + +static void +dp8390_tx(dp8390_t *dev, uint32_t val) +{ + dev->CR.tx_packet = 0; + dev->TSR.tx_ok = 1; + dev->ISR.pkt_tx = 1; + + /* Generate an interrupt if not masked */ + if (dev->IMR.tx_inte && dev->interrupt) + dev->interrupt(dev->priv, 1); + dev->tx_timer_active = 0; +} + + +/* + * Called by the platform-specific code when an Ethernet frame + * has been received. The destination address is tested to see + * if it should be accepted, and if the RX ring has enough room, + * it is copied into it and the receive process is updated. + */ +void +dp8390_rx(void *priv, uint8_t *buf, int io_len) +{ + dp8390_t *dev = (dp8390_t *)priv; + static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; + uint8_t pkthdr[4]; + uint8_t *startptr; + int pages, avail; + int idx, nextpage; + int endbytes; + + if (io_len != 60) + dp8390_log("%s: rx_frame with length %d\n", dev->name, io_len); + + if ((dev->CR.stop != 0) || (dev->page_start == 0)) return; + + /* + * Add the pkt header + CRC to the length, and work + * out how many 256-byte pages the frame would occupy. + */ + pages = (io_len + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; + if (dev->curr_page < dev->bound_ptr) { + avail = dev->bound_ptr - dev->curr_page; + } else { + avail = (dev->page_stop - dev->page_start) - + (dev->curr_page - dev->bound_ptr); + } + + /* + * Avoid getting into a buffer overflow condition by + * not attempting to do partial receives. The emulation + * to handle this condition seems particularly painful. + */ + if ((avail < pages) +#if DP8390_NEVER_FULL_RING + || (avail == pages) +#endif + ) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: no space\n"); +#endif + + return; + } + + if ((io_len < 40/*60*/) && !dev->RCR.runts_ok) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: rejected small packet, length %d\n", io_len); +#endif + + return; + } + + /* Some computers don't care... */ + if (io_len < 60) + io_len = 60; + + dp8390_log("DP8390: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", + buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + io_len); + + /* Do address filtering if not in promiscuous mode. */ + if (! dev->RCR.promisc) { + /* If this is a broadcast frame.. */ + if (! memcmp(buf, bcast_addr, 6)) { + /* Broadcast not enabled, we're done. */ + if (! dev->RCR.broadcast) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: RX BC disabled\n"); +#endif + return; + } + } + + /* If this is a multicast frame.. */ + else if (buf[0] & 0x01) { + /* Multicast not enabled, we're done. */ + if (! dev->RCR.multicast) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: RX MC disabled\n"); +#endif + return; + } + + /* Are we listening to this multicast address? */ + idx = mcast_index(buf); + if (! (dev->mchash[idx>>3] & (1<<(idx&0x7)))) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: RX MC not listed\n"); +#endif + return; + } + } + + /* Unicast, must be for us.. */ + else if (memcmp(buf, dev->physaddr, 6)) return; + } else { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: RX promiscuous receive\n"); +#endif + } + + nextpage = dev->curr_page + pages; + if (nextpage >= dev->page_stop) + nextpage -= (dev->page_stop - dev->page_start); + + /* Set up packet header. */ + pkthdr[0] = 0x01; /* RXOK - packet is OK */ + if (buf[0] & 0x01) + pkthdr[0] |= 0x20; /* MULTICAST packet */ + pkthdr[1] = nextpage; /* ptr to next packet */ + pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ + pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ + dp8390_log("DP8390: RX pkthdr [%02x %02x %02x %02x]\n", + pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); + + /* Copy into buffer, update curpage, and signal interrupt if config'd */ + startptr = &dev->mem[(dev->curr_page * 256) - dev->mem_start]; + memcpy(startptr, pkthdr, sizeof(pkthdr)); + if ((nextpage > dev->curr_page) || + ((dev->curr_page + pages) == dev->page_stop)) { + memcpy(startptr+sizeof(pkthdr), buf, io_len); + } else { + endbytes = (dev->page_stop - dev->curr_page) * 256; + memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); + startptr = &dev->mem[(dev->page_start * 256) - dev->mem_start]; + memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); + } + dev->curr_page = nextpage; + + dev->RSR.rx_ok = 1; + dev->RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; + dev->ISR.pkt_rx = 1; + + if (dev->IMR.rx_inte && dev->interrupt) + dev->interrupt(dev->priv, 1); +} + + +/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ +uint32_t +dp8390_page0_read(dp8390_t *dev, uint32_t off, unsigned int len) +{ + uint8_t retval = 0; + + if (len > 1) { + /* encountered with win98 hardware probe */ + dp8390_log("DP8390: bad length! Page0 read from register 0x%02x, len=%u\n", + off, len); + return(retval); + } + + switch(off) { + case 0x01: /* CLDA0 */ + retval = (dev->local_dma & 0xff); + break; + + case 0x02: /* CLDA1 */ + retval = (dev->local_dma >> 8); + break; + + case 0x03: /* BNRY */ + retval = dev->bound_ptr; + break; + + case 0x04: /* TSR */ + retval = ((dev->TSR.ow_coll << 7) | + (dev->TSR.cd_hbeat << 6) | + (dev->TSR.fifo_ur << 5) | + (dev->TSR.no_carrier << 4) | + (dev->TSR.aborted << 3) | + (dev->TSR.collided << 2) | + (dev->TSR.tx_ok)); + break; + + case 0x05: /* NCR */ + retval = dev->num_coll; + break; + + case 0x06: /* FIFO */ + /* reading FIFO is only valid in loopback mode */ +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: reading FIFO not supported yet\n"); +#endif + retval = dev->fifo; + break; + + case 0x07: /* ISR */ + retval = ((dev->ISR.reset << 7) | + (dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + break; + + case 0x08: /* CRDA0 */ + retval = (dev->remote_dma & 0xff); + break; + + case 0x09: /* CRDA1 */ + retval = (dev->remote_dma >> 8); + break; + + case 0x0a: /* reserved / RTL8029ID0 */ + retval = dev->id0; + break; + + case 0x0b: /* reserved / RTL8029ID1 */ + retval = dev->id1; + break; + + case 0x0c: /* RSR */ + retval = ((dev->RSR.deferred << 7) | + (dev->RSR.rx_disabled << 6) | + (dev->RSR.rx_mbit << 5) | + (dev->RSR.rx_missed << 4) | + (dev->RSR.fifo_or << 3) | + (dev->RSR.bad_falign << 2) | + (dev->RSR.bad_crc << 1) | + (dev->RSR.rx_ok)); + break; + + case 0x0d: /* CNTR0 */ + retval = dev->tallycnt_0; + break; + + case 0x0e: /* CNTR1 */ + retval = dev->tallycnt_1; + break; + + case 0x0f: /* CNTR2 */ + retval = dev->tallycnt_2; + break; + + default: + dp8390_log("DP8390: Page0 register 0x%02x out of range\n", off); + break; + } + + dp8390_log("DP8390: Page0 read from register 0x%02x, value=0x%02x\n", off, + retval); + + return(retval); +} + + +void +dp8390_page0_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + uint8_t val2; + + dp8390_log("DP839: Page0 write to register 0x%02x, value=0x%02x\n", + off, val); + + switch(off) { + case 0x01: /* PSTART */ + dev->page_start = val; + break; + + case 0x02: /* PSTOP */ + dev->page_stop = val; + break; + + case 0x03: /* BNRY */ + dev->bound_ptr = val; + break; + + case 0x04: /* TPSR */ + dev->tx_page_start = val; + break; + + case 0x05: /* TBCR0 */ + /* Clear out low byte and re-insert */ + dev->tx_bytes &= 0xff00; + dev->tx_bytes |= (val & 0xff); + break; + + case 0x06: /* TBCR1 */ + /* Clear out high byte and re-insert */ + dev->tx_bytes &= 0x00ff; + dev->tx_bytes |= ((val & 0xff) << 8); + break; + + case 0x07: /* ISR */ + val &= 0x7f; /* clear RST bit - status-only bit */ + /* All other values are cleared iff the ISR bit is 1 */ + dev->ISR.pkt_rx &= !((int)((val & 0x01) == 0x01)); + dev->ISR.pkt_tx &= !((int)((val & 0x02) == 0x02)); + dev->ISR.rx_err &= !((int)((val & 0x04) == 0x04)); + dev->ISR.tx_err &= !((int)((val & 0x08) == 0x08)); + dev->ISR.overwrite &= !((int)((val & 0x10) == 0x10)); + dev->ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20)); + dev->ISR.rdma_done &= !((int)((val & 0x40) == 0x40)); + val = ((dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + val &= ((dev->IMR.rdma_inte << 6) | + (dev->IMR.cofl_inte << 5) | + (dev->IMR.overw_inte << 4) | + (dev->IMR.txerr_inte << 3) | + (dev->IMR.rxerr_inte << 2) | + (dev->IMR.tx_inte << 1) | + (dev->IMR.rx_inte)); + if ((val == 0x00) && dev->interrupt) + dev->interrupt(dev->priv, 0); + break; + + case 0x08: /* RSAR0 */ + /* Clear out low byte and re-insert */ + dev->remote_start &= 0xff00; + dev->remote_start |= (val & 0xff); + dev->remote_dma = dev->remote_start; + break; + + case 0x09: /* RSAR1 */ + /* Clear out high byte and re-insert */ + dev->remote_start &= 0x00ff; + dev->remote_start |= ((val & 0xff) << 8); + dev->remote_dma = dev->remote_start; + break; + + case 0x0a: /* RBCR0 */ + /* Clear out low byte and re-insert */ + dev->remote_bytes &= 0xff00; + dev->remote_bytes |= (val & 0xff); + break; + + case 0x0b: /* RBCR1 */ + /* Clear out high byte and re-insert */ + dev->remote_bytes &= 0x00ff; + dev->remote_bytes |= ((val & 0xff) << 8); + break; + + case 0x0c: /* RCR */ + /* Check if the reserved bits are set */ +#ifdef ENABLE_DP8390_LOG + if (val & 0xc0) + dp8390_log("DP8390: RCR write, reserved bits set\n"); +#endif + + /* Set all other bit-fields */ + dev->RCR.errors_ok = ((val & 0x01) == 0x01); + dev->RCR.runts_ok = ((val & 0x02) == 0x02); + dev->RCR.broadcast = ((val & 0x04) == 0x04); + dev->RCR.multicast = ((val & 0x08) == 0x08); + dev->RCR.promisc = ((val & 0x10) == 0x10); + dev->RCR.monitor = ((val & 0x20) == 0x20); + + /* Monitor bit is a little suspicious... */ +#ifdef ENABLE_DP8390_LOG + if (val & 0x20) + dp8390_log("DP8390: RCR write, monitor bit set!\n"); +#endif + break; + + case 0x0d: /* TCR */ + /* Check reserved bits */ +#ifdef ENABLE_DP8390_LOG + if (val & 0xe0) + dp8390_log("DP8390: TCR write, reserved bits set\n"); +#endif + + /* Test loop mode (not supported) */ + if (val & 0x06) { + dev->TCR.loop_cntl = (val & 0x6) >> 1; + dp8390_log("DP8390: TCR write, loop mode %d not supported\n", + dev->TCR.loop_cntl); + } else + dev->TCR.loop_cntl = 0; + + /* Inhibit-CRC not supported. */ +#ifdef ENABLE_DP8390_LOG + if (val & 0x01) + dp8390_log("DP8390: TCR write, inhibit-CRC not supported\n"); +#endif + + /* Auto-transmit disable very suspicious */ +#ifdef ENABLE_DP8390_LOG + if (val & 0x08) + dp8390_log("DP8390: TCR write, auto transmit disable not supported\n"); +#endif + + /* Allow collision-offset to be set, although not used */ + dev->TCR.coll_prio = ((val & 0x08) == 0x08); + break; + + case 0x0e: /* DCR */ + /* the loopback mode is not suppported yet */ +#ifdef ENABLE_DP8390_LOG + if (! (val & 0x08)) + dp8390_log("DP8390: DCR write, loopback mode selected\n"); +#endif + + /* It is questionable to set longaddr and auto_rx, since + * they are not supported on the NE2000. Print a warning + * and continue. */ +#ifdef ENABLE_DP8390_LOG + if (val & 0x04) + dp8390_log("DP8390: DCR write - LAS set ???\n"); + if (val & 0x10) + dp8390_log("DP8390: DCR write - AR set ???\n"); +#endif + + /* Set other values. */ + dev->DCR.wdsize = ((val & 0x01) == 0x01); + dev->DCR.endian = ((val & 0x02) == 0x02); + dev->DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ + dev->DCR.loop = ((val & 0x08) == 0x08); + dev->DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ + dev->DCR.fifo_size = (val & 0x50) >> 5; + break; + + case 0x0f: /* IMR */ + /* Check for reserved bit */ +#ifdef ENABLE_DP8390_LOG + if (val & 0x80) + dp8390_log("DP8390: IMR write, reserved bit set\n"); +#endif + + /* Set other values */ + dev->IMR.rx_inte = ((val & 0x01) == 0x01); + dev->IMR.tx_inte = ((val & 0x02) == 0x02); + dev->IMR.rxerr_inte = ((val & 0x04) == 0x04); + dev->IMR.txerr_inte = ((val & 0x08) == 0x08); + dev->IMR.overw_inte = ((val & 0x10) == 0x10); + dev->IMR.cofl_inte = ((val & 0x20) == 0x20); + dev->IMR.rdma_inte = ((val & 0x40) == 0x40); + val2 = ((dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + if (dev->interrupt) { + if (((val & val2) & 0x7f) == 0) + dev->interrupt(dev->priv, 0); + else + dev->interrupt(dev->priv, 1); + } + break; + + default: + dp8390_log("DP8390: Page0 write, bad register 0x%02x\n", off); + break; + } +} + + +/* Handle reads/writes to the first page of the DS8390 register file. */ +uint32_t +dp8390_page1_read(dp8390_t *dev, uint32_t off, unsigned int len) +{ + dp8390_log("DP8390: Page1 read from register 0x%02x, len=%u\n", + off, len); + + switch(off) { + case 0x01: /* PAR0-5 */ + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + return(dev->physaddr[off - 1]); + + case 0x07: /* CURR */ + dp8390_log("DP8390: returning current page: 0x%02x\n", + (dev->curr_page)); + return(dev->curr_page); + + case 0x08: /* MAR0-7 */ + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + return(dev->mchash[off - 8]); + + default: + dp8390_log("DP8390: Page1 read register 0x%02x out of range\n", + off); + return(0); + } +} + + +void +dp8390_page1_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + dp8390_log("DP8390: Page1 write to register 0x%02x, len=%u, value=0x%04x\n", + off, len, val); + + switch(off) { + case 0x01: /* PAR0-5 */ + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + dev->physaddr[off - 1] = val; + if (off == 6) + dp8390_log("DP8390: Physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->dp8390->physaddr[0], dev->dp8390.physaddr[1], + dev->dp8390->physaddr[2], dev->dp8390.physaddr[3], + dev->dp8390->physaddr[4], dev->dp8390.physaddr[5]); + break; + + case 0x07: /* CURR */ + dev->curr_page = val; + break; + + case 0x08: /* MAR0-7 */ + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + dev->mchash[off - 8] = val; + break; + + default: + dp8390_log("DP8390: Page1 write register 0x%02x out of range\n", + off); + break; + } +} + + +/* Handle reads/writes to the second page of the DS8390 register file. */ +uint32_t +dp8390_page2_read(dp8390_t *dev, uint32_t off, unsigned int len) +{ + dp8390_log("DP8390: Page2 read from register 0x%02x, len=%u\n", + off, len); + + switch(off) { + case 0x01: /* PSTART */ + return(dev->page_start); + + case 0x02: /* PSTOP */ + return(dev->page_stop); + + case 0x03: /* Remote Next-packet pointer */ + return(dev->rempkt_ptr); + + case 0x04: /* TPSR */ + return(dev->tx_page_start); + + case 0x05: /* Local Next-packet pointer */ + return(dev->localpkt_ptr); + + case 0x06: /* Address counter (upper) */ + return(dev->address_cnt >> 8); + + case 0x07: /* Address counter (lower) */ + return(dev->address_cnt & 0xff); + + case 0x08: /* Reserved */ + case 0x09: + case 0x0a: + case 0x0b: + dp8390_log("DP8390: reserved Page2 read - register 0x%02x\n", + off); + return(0xff); + + case 0x0c: /* RCR */ + return ((dev->RCR.monitor << 5) | + (dev->RCR.promisc << 4) | + (dev->RCR.multicast << 3) | + (dev->RCR.broadcast << 2) | + (dev->RCR.runts_ok << 1) | + (dev->RCR.errors_ok)); + + case 0x0d: /* TCR */ + return ((dev->TCR.coll_prio << 4) | + (dev->TCR.ext_stoptx << 3) | + ((dev->TCR.loop_cntl & 0x3) << 1) | + (dev->TCR.crc_disable)); + + case 0x0e: /* DCR */ + return (((dev->DCR.fifo_size & 0x3) << 5) | + (dev->DCR.auto_rx << 4) | + (dev->DCR.loop << 3) | + (dev->DCR.longaddr << 2) | + (dev->DCR.endian << 1) | + (dev->DCR.wdsize)); + + case 0x0f: /* IMR */ + return ((dev->IMR.rdma_inte << 6) | + (dev->IMR.cofl_inte << 5) | + (dev->IMR.overw_inte << 4) | + (dev->IMR.txerr_inte << 3) | + (dev->IMR.rxerr_inte << 2) | + (dev->IMR.tx_inte << 1) | + (dev->IMR.rx_inte)); + + default: + dp8390_log("DP8390: Page2 register 0x%02x out of range\n", + off); + break; + } + + return(0); +} + + +void +dp8390_page2_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len) +{ +/* Maybe all writes here should be BX_PANIC()'d, since they + affect internal operation, but let them through for now + and print a warning. */ + dp8390_log("DP8390: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", + off, len, val); + + switch(off) { + case 0x01: /* CLDA0 */ + /* Clear out low byte and re-insert */ + dev->local_dma &= 0xff00; + dev->local_dma |= (val & 0xff); + break; + + case 0x02: /* CLDA1 */ + /* Clear out high byte and re-insert */ + dev->local_dma &= 0x00ff; + dev->local_dma |= ((val & 0xff) << 8); + break; + + case 0x03: /* Remote Next-pkt pointer */ + dev->rempkt_ptr = val; + break; + + case 0x04: +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: Page 2 write to reserved register 0x04\n"); +#endif + break; + + case 0x05: /* Local Next-packet pointer */ + dev->localpkt_ptr = val; + break; + + case 0x06: /* Address counter (upper) */ + /* Clear out high byte and re-insert */ + dev->address_cnt &= 0x00ff; + dev->address_cnt |= ((val & 0xff) << 8); + break; + + case 0x07: /* Address counter (lower) */ + /* Clear out low byte and re-insert */ + dev->address_cnt &= 0xff00; + dev->address_cnt |= (val & 0xff); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + dp8390_log("DP8390: Page2 write to reserved register 0x%02x\n", + off); + break; + + default: + dp8390_log("DP8390: Page2 write, illegal register 0x%02x\n", + off); + break; + } +} + + +void +dp8390_set_defaults(dp8390_t *dev, uint8_t flags) +{ + if (flags & DP8390_FLAG_DWORD_MEM) { + dev->mem_size = DP8390_DWORD_MEMSIZ; + dev->mem_start = DP8390_DWORD_MEMSTART; + dev->mem_end = DP8390_DWORD_MEMEND; + dev->macaddr_size = 32; + } else { + dev->mem_size = DP8390_WORD_MEMSIZ; + dev->mem_start = DP8390_WORD_MEMSTART; + dev->mem_end = DP8390_WORD_MEMEND; + dev->macaddr_size = 16; + } + + if (flags & DP8390_FLAG_NO_CHIPMEM) + dev->mem_start = 0; + + dev->flags = flags; +} + + +void +dp8390_set_id(dp8390_t *dev, uint8_t id0, uint8_t id1) +{ + dev->id0 = id0; + dev->id1 = id1; +} + + +void +dp8390_reset(dp8390_t *dev) +{ + int i, max, shift = 0; + + if (dev->flags & DP8390_FLAG_DWORD_MEM) + shift = 1; + + max = 16 << shift; + + /* Initialize the MAC address area by doubling the physical address */ + for (i = 0; i < max; i++) { + if (i < (6 << shift)) + dev->macaddr[i] = dev->physaddr[i >> shift]; + else /* Signature */ + dev->macaddr[i] = 0x57; + } + + /* Zero out registers and memory */ + memset(&dev->CR, 0x00, sizeof(dev->CR) ); + memset(&dev->ISR, 0x00, sizeof(dev->ISR)); + memset(&dev->IMR, 0x00, sizeof(dev->IMR)); + memset(&dev->DCR, 0x00, sizeof(dev->DCR)); + memset(&dev->TCR, 0x00, sizeof(dev->TCR)); + memset(&dev->TSR, 0x00, sizeof(dev->TSR)); + memset(&dev->RSR, 0x00, sizeof(dev->RSR)); + dev->tx_timer_active = 0; + dev->local_dma = 0; + dev->page_start = 0; + dev->page_stop = 0; + dev->bound_ptr = 0; + dev->tx_page_start = 0; + dev->num_coll = 0; + dev->tx_bytes = 0; + dev->fifo = 0; + dev->remote_dma = 0; + dev->remote_start = 0; + + dev->remote_bytes = 0; + + dev->tallycnt_0 = 0; + dev->tallycnt_1 = 0; + dev->tallycnt_2 = 0; + + dev->curr_page = 0; + + dev->rempkt_ptr = 0; + dev->localpkt_ptr = 0; + dev->address_cnt = 0; + + memset(&dev->mem, 0x00, sizeof(dev->mem)); + + /* Set power-up conditions */ + dev->CR.stop = 1; + dev->CR.rdma_cmd = 4; + dev->ISR.reset = 1; + dev->DCR.longaddr = 1; + + if (dev->interrupt) + dev->interrupt(dev->priv, 0); +} + + +void +dp8390_soft_reset(dp8390_t *dev) +{ + memset(&(dev->ISR), 0x00, sizeof(dev->ISR)); + dev->ISR.reset = 1; +} + + +static void * +dp8390_init(const device_t *info) +{ + dp8390_t *dp8390 = (dp8390_t *) malloc(sizeof(dp8390_t)); + memset(dp8390, 0, sizeof(dp8390_t)); + + /* Set values assuming WORD and only the clear IRQ flag - + - the NIC can then call dp8390_set_defaults() again to + change that. */ + dp8390_set_defaults(dp8390, DP8390_FLAG_CLEAR_IRQ); + + /* Set the two registers some NIC's use as ID bytes, + to their default values of 0xFF. */ + dp8390_set_id(dp8390, 0xff, 0xff); + + return dp8390; +} + + +static void +dp8390_close(void *priv) +{ + dp8390_t *dp8390 = (dp8390_t *) priv; + + /* Make sure the platform layer is shut down. */ + network_close(); + + if (dp8390) + free(dp8390); +} + + +const device_t dp8390_device = +{ + "DP8390 Network Interface Controller", + 0, 0, + dp8390_init, dp8390_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/network/net_dp8390.h b/src/network/net_dp8390.h index 16b2d0188..75dd9ed10 100644 --- a/src/network/net_dp8390.h +++ b/src/network/net_dp8390.h @@ -1,3 +1,21 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Header of the emulation of the DP8390 Network Interface + * Controller used by the WD family, NE1000/NE2000 family, and + * 3Com 3C503 NIC's. + * + * Version: @(#)net_dp8390.h 1.0.0 2018/10/17 + * + * Authors: Miran Grca, + * Bochs project, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Bochs project. + */ #ifndef NET_DP8390_H # define NET_DP8390_H @@ -13,6 +31,11 @@ #define DP8390_WORD_MEMSTART (8*1024) #define DP8390_WORD_MEMEND (DP8390_WORD_MEMSTART+DP8390_WORD_MEMSIZ) +#define DP8390_FLAG_DWORD_MEM 0x01 +#define DP8390_FLAG_CHECK_CR 0x02 +#define DP8390_FLAG_CLEAR_IRQ 0x04 +#define DP8390_FLAG_NO_CHIPMEM 0x08 + typedef struct { /* Page 0 */ @@ -147,12 +170,46 @@ typedef struct { /* Novell ASIC state */ uint8_t mem[DP8390_DWORD_MEMSIZ]; /* on-chip packet memory */ - + + uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */ + uint8_t macaddr_size, /* Defaults to 16 but can be 32 */ + flags, /* Flags affecting some behaviors. */ + id0, /* 0x50 for the Realtek NIC's, otherwise + 0xFF. */ + id1; /* 0x70 for the RTL8019AS, 0x43 for the + RTL8029AS, otherwise 0xFF. */ + int mem_size, mem_start, mem_end; + int tx_timer_index; int tx_timer_active; - + + void *priv; + + void (*interrupt)(void *priv, int set); } dp8390_t; -extern int mcast_index(const void *dst); +extern const device_t dp8390_device; + + +extern uint32_t dp8390_chipmem_read(dp8390_t *dev, uint32_t addr, unsigned int len); +extern void dp8390_chipmem_write(dp8390_t *dev, uint32_t addr, uint32_t val, unsigned len); + +extern uint32_t dp8390_read_cr(dp8390_t *dev); +extern void dp8390_write_cr(dp8390_t *dev, uint32_t val); + +extern void dp8390_rx(void *priv, uint8_t *buf, int io_len); + +extern uint32_t dp8390_page0_read(dp8390_t *dev, uint32_t off, unsigned int len); +extern void dp8390_page0_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len); +extern uint32_t dp8390_page1_read(dp8390_t *dev, uint32_t off, unsigned int len); +extern void dp8390_page1_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len); +extern uint32_t dp8390_page2_read(dp8390_t *dev, uint32_t off, unsigned int len); +extern void dp8390_page2_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len); + +extern void dp8390_set_defaults(dp8390_t *dev, uint8_t flags); +extern void dp8390_set_id(dp8390_t *dev, uint8_t id0, uint8_t id1); +extern void dp8390_reset(dp8390_t *dev); +extern void dp8390_soft_reset(dp8390_t *dev); + #endif /*NET_DP8390_H*/ diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index c5c049443..a21587112 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -13,7 +13,7 @@ * - Realtek RTL8019AS (ISA 16-bit, PnP); * - Realtek RTL8029AS (PCI). * - * Version: @(#)net_ne2000.c 1.0.9 2018/10/02 + * Version: @(#)net_ne2000.c 1.0.10 2018/10/17 * * Based on @(#)ne2k.cc v1.56.2.1 2004/02/02 22:37:22 cbothamy * @@ -61,7 +61,6 @@ #include "../pic.h" #include "../random.h" #include "../device.h" -#include "../ui.h" #include "network.h" #include "net_dp8390.h" #include "net_ne2000.h" @@ -96,25 +95,23 @@ uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE, typedef struct { - dp8390_t dp8390; - uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */ + dp8390_t *dp8390; + const char *name; int board; int is_pci, is_mca, is_8bit; - const char *name; uint32_t base_address; int base_irq; uint32_t bios_addr, bios_size, bios_mask; + int card; /* PCI card slot */ + int has_bios, pad; uint8_t pnp_regs[256]; uint8_t pnp_res_data[256]; bar_t pci_bar[2]; uint8_t pci_regs[PCI_REGSIZE]; - uint8_t maclocal[6]; /* configured MAC (local) address */ uint8_t eeprom[128]; /* for RTL8029AS */ rom_t bios_rom; - int card; /* PCI card slot */ - int has_bios; uint8_t pnp_phase; uint8_t pnp_magic_count; uint8_t pnp_address; @@ -123,33 +120,30 @@ typedef struct { uint8_t pnp_activate; uint8_t pnp_io_check; uint8_t pnp_csnsav; - uint16_t pnp_read; - uint64_t pnp_id; uint8_t pnp_id_checksum; uint8_t pnp_serial_read_pos; uint8_t pnp_serial_read_pair; uint8_t pnp_serial_read; + uint8_t maclocal[6]; /* configured MAC (local) address */ + uint16_t pnp_read; + uint64_t pnp_id; /* RTL8019AS/RTL8029AS registers */ uint8_t config0, config2, config3; uint8_t _9346cr; - - /* POS registers, MCA boards only */ - uint8_t pos_regs[8]; + uint32_t pad0; + + /* POS registers, MCA boards only */ + uint8_t pos_regs[8]; } nic_t; -static void nic_rx(void *, uint8_t *, int); -static void nic_tx(nic_t *, uint32_t); - #ifdef ENABLE_NIC_LOG int nic_do_log = ENABLE_NIC_LOG; -#endif static void nelog(int lvl, const char *fmt, ...) { -#ifdef ENABLE_NIC_LOG va_list ap; if (nic_do_log >= lvl) { @@ -157,13 +151,17 @@ nelog(int lvl, const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define nelog(lvl, fmt, ...) +#endif static void -nic_interrupt(nic_t *dev, int set) +nic_interrupt(void *priv, int set) { + nic_t *dev = (nic_t *) priv; + if (dev->is_pci) { if (set) pci_set_irq(dev->card, PCI_INTA); @@ -183,86 +181,10 @@ static void nic_reset(void *priv) { nic_t *dev = (nic_t *)priv; - int i; nelog(1, "%s: reset\n", dev->name); - if (dev->board == NE2K_NE1000) - { - /* Initialize the MAC address area by doubling the physical address */ - dev->macaddr[0] = dev->dp8390.physaddr[0]; - dev->macaddr[1] = dev->dp8390.physaddr[1]; - dev->macaddr[2] = dev->dp8390.physaddr[2]; - dev->macaddr[3] = dev->dp8390.physaddr[3]; - dev->macaddr[4] = dev->dp8390.physaddr[4]; - dev->macaddr[5] = dev->dp8390.physaddr[5]; - - /* ne1k signature */ - for (i=6; i<16; i++) - dev->macaddr[i] = 0x57; - } - else - { - /* Initialize the MAC address area by doubling the physical address */ - dev->macaddr[0] = dev->dp8390.physaddr[0]; - dev->macaddr[1] = dev->dp8390.physaddr[0]; - dev->macaddr[2] = dev->dp8390.physaddr[1]; - dev->macaddr[3] = dev->dp8390.physaddr[1]; - dev->macaddr[4] = dev->dp8390.physaddr[2]; - dev->macaddr[5] = dev->dp8390.physaddr[2]; - dev->macaddr[6] = dev->dp8390.physaddr[3]; - dev->macaddr[7] = dev->dp8390.physaddr[3]; - dev->macaddr[8] = dev->dp8390.physaddr[4]; - dev->macaddr[9] = dev->dp8390.physaddr[4]; - dev->macaddr[10] = dev->dp8390.physaddr[5]; - dev->macaddr[11] = dev->dp8390.physaddr[5]; - - /* ne2k signature */ - for (i=12; i<32; i++) - dev->macaddr[i] = 0x57; - } - - /* Zero out registers and memory */ - memset(&dev->dp8390.CR, 0x00, sizeof(dev->dp8390.CR) ); - memset(&dev->dp8390.ISR, 0x00, sizeof(dev->dp8390.ISR)); - memset(&dev->dp8390.IMR, 0x00, sizeof(dev->dp8390.IMR)); - memset(&dev->dp8390.DCR, 0x00, sizeof(dev->dp8390.DCR)); - memset(&dev->dp8390.TCR, 0x00, sizeof(dev->dp8390.TCR)); - memset(&dev->dp8390.TSR, 0x00, sizeof(dev->dp8390.TSR)); - memset(&dev->dp8390.RSR, 0x00, sizeof(dev->dp8390.RSR)); - dev->dp8390.tx_timer_active = 0; - dev->dp8390.local_dma = 0; - dev->dp8390.page_start = 0; - dev->dp8390.page_stop = 0; - dev->dp8390.bound_ptr = 0; - dev->dp8390.tx_page_start = 0; - dev->dp8390.num_coll = 0; - dev->dp8390.tx_bytes = 0; - dev->dp8390.fifo = 0; - dev->dp8390.remote_dma = 0; - dev->dp8390.remote_start = 0; - - dev->dp8390.remote_bytes = 0; - - dev->dp8390.tallycnt_0 = 0; - dev->dp8390.tallycnt_1 = 0; - dev->dp8390.tallycnt_2 = 0; - - dev->dp8390.curr_page = 0; - - dev->dp8390.rempkt_ptr = 0; - dev->dp8390.localpkt_ptr = 0; - dev->dp8390.address_cnt = 0; - - memset(&dev->dp8390.mem, 0x00, sizeof(dev->dp8390.mem)); - - /* Set power-up conditions */ - dev->dp8390.CR.stop = 1; - dev->dp8390.CR.rdma_cmd = 4; - dev->dp8390.ISR.reset = 1; - dev->dp8390.DCR.longaddr = 1; - - nic_interrupt(dev, 0); + dp8390_reset(dev->dp8390); } @@ -271,123 +193,7 @@ nic_soft_reset(void *priv) { nic_t *dev = (nic_t *)priv; - memset(&(dev->dp8390.ISR), 0x00, sizeof(dev->dp8390.ISR)); - dev->dp8390.ISR.reset = 1; -} - - -/* - * Access the 32K private RAM. - * - * The NE2000 memory is accessed through the data port of the - * ASIC (offset 0) after setting up a remote-DMA transfer. - * Both byte and word accesses are allowed. - * The first 16 bytes contain the MAC address at even locations, - * and there is 16K of buffer memory starting at 16K. - */ -static uint32_t -chipmem_read(nic_t *dev, uint32_t addr, unsigned int len) -{ - uint32_t retval = 0; - - if ((len == 2) && (addr & 0x1)) { - nelog(3, "%s: unaligned chipmem word read\n", dev->name); - } - - nelog(3, "Chipmem Read Address=%04x\n", addr); - - /* ROM'd MAC address */ - if (dev->board != NE2K_NE1000) { - if (addr <= 31) { - retval = dev->macaddr[addr % 32]; - if ((len == 2) || (len == 4)) { - retval |= (dev->macaddr[(addr + 1) % 32] << 8); - } - if (len == 4) { - retval |= (dev->macaddr[(addr + 2) % 32] << 16); - retval |= (dev->macaddr[(addr + 3) % 32] << 24); - } - return(retval); - } - - if ((addr >= DP8390_DWORD_MEMSTART) && (addr < DP8390_DWORD_MEMEND)) { - retval = dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART]; - if ((len == 2) || (len == 4)) { - retval |= (dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART + 1] << 8); - } - if (len == 4) { - retval |= (dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART + 2] << 16); - retval |= (dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART + 3] << 24); - } - return(retval); - } - } else { - if (addr <= 15) { - retval = dev->macaddr[addr % 16]; - if (len == 2) { - retval |= (dev->macaddr[(addr + 1) % 16] << 8); - } - return(retval); - } - - if ((addr >= DP8390_WORD_MEMSTART) && (addr < DP8390_WORD_MEMEND)) { - retval = dev->dp8390.mem[addr - DP8390_WORD_MEMSTART]; - if (len == 2) { - retval |= (dev->dp8390.mem[addr - DP8390_WORD_MEMSTART + 1] << 8); - } - return(retval); - } - } - - nelog(3, "%s: out-of-bounds chipmem read, %04X\n", dev->name, addr); - - if (dev->is_pci) { - return(0xff); - } else { - switch(len) { - case 1: - return(0xff); - case 2: - return(0xffff); - } - } - - return(0xffff); -} - - -static void -chipmem_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) -{ - if ((len == 2) && (addr & 0x1)) { - nelog(3, "%s: unaligned chipmem word write\n", dev->name); - } - - nelog(3, "Chipmem Write Address=%04x\n", addr); - - if (dev->board != NE2K_NE1000) { - if ((addr >= DP8390_DWORD_MEMSTART) && (addr < DP8390_DWORD_MEMEND)) { - dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART] = val & 0xff; - if ((len == 2) || (len == 4)) { - dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART+1] = val >> 8; - } - if (len == 4) { - dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART+2] = val >> 16; - dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART+3] = val >> 24; - } - } else { - nelog(3, "%s: out-of-bounds chipmem write, %04X\n", dev->name, addr); - } - } else { - if ((addr >= DP8390_WORD_MEMSTART) && (addr < DP8390_WORD_MEMEND)) { - dev->dp8390.mem[addr-DP8390_WORD_MEMSTART] = val & 0xff; - if (len == 2) { - dev->dp8390.mem[addr-DP8390_WORD_MEMSTART+1] = val >> 8; - } - } else { - nelog(3, "%s: out-of-bounds chipmem write, %04X\n", dev->name, addr); - } - } + dp8390_soft_reset(dev->dp8390); } @@ -414,43 +220,43 @@ asic_read(nic_t *dev, uint32_t off, unsigned int len) /* A read remote-DMA command must have been issued, and the source-address and length registers must have been initialised. */ - if (len > dev->dp8390.remote_bytes) { + if (len > dev->dp8390->remote_bytes) { nelog(3, "%s: DMA read underrun iolen=%d remote_bytes=%d\n", - dev->name, len, dev->dp8390.remote_bytes); + dev->name, len, dev->dp8390->remote_bytes); } nelog(3, "%s: DMA read: addr=%4x remote_bytes=%d\n", - dev->name, dev->dp8390.remote_dma,dev->dp8390.remote_bytes); - retval = chipmem_read(dev, dev->dp8390.remote_dma, len); + dev->name, dev->dp8390->remote_dma,dev->dp8390->remote_bytes); + retval = dp8390_chipmem_read(dev->dp8390, dev->dp8390->remote_dma, len); /* The 8390 bumps the address and decreases the byte count by the selected word size after every access, not by the amount of data requested by the host (io_len). */ if (len == 4) { - dev->dp8390.remote_dma += len; + dev->dp8390->remote_dma += len; } else { - dev->dp8390.remote_dma += (dev->dp8390.DCR.wdsize + 1); + dev->dp8390->remote_dma += (dev->dp8390->DCR.wdsize + 1); } - if (dev->dp8390.remote_dma == dev->dp8390.page_stop << 8) { - dev->dp8390.remote_dma = dev->dp8390.page_start << 8; + if (dev->dp8390->remote_dma == dev->dp8390->page_stop << 8) { + dev->dp8390->remote_dma = dev->dp8390->page_start << 8; } /* keep s.remote_bytes from underflowing */ - if (dev->dp8390.remote_bytes > dev->dp8390.DCR.wdsize) { + if (dev->dp8390->remote_bytes > dev->dp8390->DCR.wdsize) { if (len == 4) { - dev->dp8390.remote_bytes -= len; + dev->dp8390->remote_bytes -= len; } else { - dev->dp8390.remote_bytes -= (dev->dp8390.DCR.wdsize + 1); + dev->dp8390->remote_bytes -= (dev->dp8390->DCR.wdsize + 1); } } else { - dev->dp8390.remote_bytes = 0; + dev->dp8390->remote_bytes = 0; } /* If all bytes have been written, signal remote-DMA complete */ - if (dev->dp8390.remote_bytes == 0) { - dev->dp8390.ISR.rdma_done = 1; - if (dev->dp8390.IMR.rdma_inte) + if (dev->dp8390->remote_bytes == 0) { + dev->dp8390->ISR.rdma_done = 1; + if (dev->dp8390->IMR.rdma_inte) nic_interrupt(dev, 1); } break; @@ -476,35 +282,35 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) switch(off) { case 0x00: /* Data register - see asic_read for a description */ - if ((len > 1) && (dev->dp8390.DCR.wdsize == 0)) { + if ((len > 1) && (dev->dp8390->DCR.wdsize == 0)) { nelog(3, "%s: DMA write length %d on byte mode operation\n", dev->name, len); break; } - if (dev->dp8390.remote_bytes == 0) + if (dev->dp8390->remote_bytes == 0) nelog(3, "%s: DMA write, byte count 0\n", dev->name); - chipmem_write(dev, dev->dp8390.remote_dma, val, len); + dp8390_chipmem_write(dev->dp8390, dev->dp8390->remote_dma, val, len); if (len == 4) - dev->dp8390.remote_dma += len; - else - dev->dp8390.remote_dma += (dev->dp8390.DCR.wdsize + 1); + dev->dp8390->remote_dma += len; + else + dev->dp8390->remote_dma += (dev->dp8390->DCR.wdsize + 1); - if (dev->dp8390.remote_dma == dev->dp8390.page_stop << 8) - dev->dp8390.remote_dma = dev->dp8390.page_start << 8; + if (dev->dp8390->remote_dma == dev->dp8390->page_stop << 8) + dev->dp8390->remote_dma = dev->dp8390->page_start << 8; if (len == 4) - dev->dp8390.remote_bytes -= len; - else - dev->dp8390.remote_bytes -= (dev->dp8390.DCR.wdsize + 1); + dev->dp8390->remote_bytes -= len; + else + dev->dp8390->remote_bytes -= (dev->dp8390->DCR.wdsize + 1); - if (dev->dp8390.remote_bytes > DP8390_DWORD_MEMSIZ) - dev->dp8390.remote_bytes = 0; + if (dev->dp8390->remote_bytes > DP8390_DWORD_MEMSIZ) + dev->dp8390->remote_bytes = 0; /* If all bytes have been written, signal remote-DMA complete */ - if (dev->dp8390.remote_bytes == 0) { - dev->dp8390.ISR.rdma_done = 1; - if (dev->dp8390.IMR.rdma_inte) + if (dev->dp8390->remote_bytes == 0) { + dev->dp8390->ISR.rdma_done = 1; + if (dev->dp8390->IMR.rdma_inte) nic_interrupt(dev, 1); } break; @@ -521,550 +327,6 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) } -/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ -static uint32_t -page0_read(nic_t *dev, uint32_t off, unsigned int len) -{ - uint8_t retval = 0; - - if (len > 1) { - /* encountered with win98 hardware probe */ - nelog(3, "%s: bad length! Page0 read from register 0x%02x, len=%u\n", - dev->name, off, len); - return(retval); - } - - switch(off) { - case 0x01: /* CLDA0 */ - retval = (dev->dp8390.local_dma & 0xff); - break; - - case 0x02: /* CLDA1 */ - retval = (dev->dp8390.local_dma >> 8); - break; - - case 0x03: /* BNRY */ - retval = dev->dp8390.bound_ptr; - break; - - case 0x04: /* TSR */ - retval = ((dev->dp8390.TSR.ow_coll << 7) | - (dev->dp8390.TSR.cd_hbeat << 6) | - (dev->dp8390.TSR.fifo_ur << 5) | - (dev->dp8390.TSR.no_carrier << 4) | - (dev->dp8390.TSR.aborted << 3) | - (dev->dp8390.TSR.collided << 2) | - (dev->dp8390.TSR.tx_ok)); - break; - - case 0x05: /* NCR */ - retval = dev->dp8390.num_coll; - break; - - case 0x06: /* FIFO */ - /* reading FIFO is only valid in loopback mode */ - nelog(3, "%s: reading FIFO not supported yet\n", dev->name); - retval = dev->dp8390.fifo; - break; - - case 0x07: /* ISR */ - retval = ((dev->dp8390.ISR.reset << 7) | - (dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - break; - - case 0x08: /* CRDA0 */ - retval = (dev->dp8390.remote_dma & 0xff); - break; - - case 0x09: /* CRDA1 */ - retval = (dev->dp8390.remote_dma >> 8); - break; - - case 0x0a: /* reserved / RTL8029ID0 */ - if (dev->board == NE2K_RTL8019AS) { - retval = 0x50; - } else if (dev->board == NE2K_RTL8029AS) { - retval = 0x50; - } else { - nelog(3, "%s: reserved Page0 read - 0x0a\n", dev->name); - retval = 0xff; - } - break; - - case 0x0b: /* reserved / RTL8029ID1 */ - if (dev->board == NE2K_RTL8019AS) { - retval = 0x70; - } else if (dev->board == NE2K_RTL8029AS) { - retval = 0x43; - } else { - nelog(3, "%s: reserved Page0 read - 0x0b\n", dev->name); - retval = 0xff; - } - break; - - case 0x0c: /* RSR */ - retval = ((dev->dp8390.RSR.deferred << 7) | - (dev->dp8390.RSR.rx_disabled << 6) | - (dev->dp8390.RSR.rx_mbit << 5) | - (dev->dp8390.RSR.rx_missed << 4) | - (dev->dp8390.RSR.fifo_or << 3) | - (dev->dp8390.RSR.bad_falign << 2) | - (dev->dp8390.RSR.bad_crc << 1) | - (dev->dp8390.RSR.rx_ok)); - break; - - case 0x0d: /* CNTR0 */ - retval = dev->dp8390.tallycnt_0; - break; - - case 0x0e: /* CNTR1 */ - retval = dev->dp8390.tallycnt_1; - break; - - case 0x0f: /* CNTR2 */ - retval = dev->dp8390.tallycnt_2; - break; - - default: - nelog(3, "%s: Page0 register 0x%02x out of range\n", - dev->name, off); - break; - } - - nelog(3, "%s: Page0 read from register 0x%02x, value=0x%02x\n", - dev->name, off, retval); - - return(retval); -} - - -static void -page0_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) -{ - uint8_t val2; - - nelog(3, "%s: Page0 write to register 0x%02x, value=0x%02x\n", - dev->name, off, val); - - switch(off) { - case 0x01: /* PSTART */ - dev->dp8390.page_start = val; - break; - - case 0x02: /* PSTOP */ - dev->dp8390.page_stop = val; - break; - - case 0x03: /* BNRY */ - dev->dp8390.bound_ptr = val; - break; - - case 0x04: /* TPSR */ - dev->dp8390.tx_page_start = val; - break; - - case 0x05: /* TBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.tx_bytes &= 0xff00; - dev->dp8390.tx_bytes |= (val & 0xff); - break; - - case 0x06: /* TBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.tx_bytes &= 0x00ff; - dev->dp8390.tx_bytes |= ((val & 0xff) << 8); - break; - - case 0x07: /* ISR */ - val &= 0x7f; /* clear RST bit - status-only bit */ - /* All other values are cleared iff the ISR bit is 1 */ - dev->dp8390.ISR.pkt_rx &= !((int)((val & 0x01) == 0x01)); - dev->dp8390.ISR.pkt_tx &= !((int)((val & 0x02) == 0x02)); - dev->dp8390.ISR.rx_err &= !((int)((val & 0x04) == 0x04)); - dev->dp8390.ISR.tx_err &= !((int)((val & 0x08) == 0x08)); - dev->dp8390.ISR.overwrite &= !((int)((val & 0x10) == 0x10)); - dev->dp8390.ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20)); - dev->dp8390.ISR.rdma_done &= !((int)((val & 0x40) == 0x40)); - val = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - val &= ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - if (val == 0x00) - nic_interrupt(dev, 0); - break; - - case 0x08: /* RSAR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_start &= 0xff00; - dev->dp8390.remote_start |= (val & 0xff); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x09: /* RSAR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_start &= 0x00ff; - dev->dp8390.remote_start |= ((val & 0xff) << 8); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x0a: /* RBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_bytes &= 0xff00; - dev->dp8390.remote_bytes |= (val & 0xff); - break; - - case 0x0b: /* RBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_bytes &= 0x00ff; - dev->dp8390.remote_bytes |= ((val & 0xff) << 8); - break; - - case 0x0c: /* RCR */ - /* Check if the reserved bits are set */ - if (val & 0xc0) { - nelog(3, "%s: RCR write, reserved bits set\n", - dev->name); - } - - /* Set all other bit-fields */ - dev->dp8390.RCR.errors_ok = ((val & 0x01) == 0x01); - dev->dp8390.RCR.runts_ok = ((val & 0x02) == 0x02); - dev->dp8390.RCR.broadcast = ((val & 0x04) == 0x04); - dev->dp8390.RCR.multicast = ((val & 0x08) == 0x08); - dev->dp8390.RCR.promisc = ((val & 0x10) == 0x10); - dev->dp8390.RCR.monitor = ((val & 0x20) == 0x20); - - /* Monitor bit is a little suspicious... */ - if (val & 0x20) nelog(3, "%s: RCR write, monitor bit set!\n", - dev->name); - break; - - case 0x0d: /* TCR */ - /* Check reserved bits */ - if (val & 0xe0) nelog(3, "%s: TCR write, reserved bits set\n", - dev->name); - - /* Test loop mode (not supported) */ - if (val & 0x06) { - dev->dp8390.TCR.loop_cntl = (val & 0x6) >> 1; - nelog(3, "%s: TCR write, loop mode %d not supported\n", - dev->name, dev->dp8390.TCR.loop_cntl); - } else { - dev->dp8390.TCR.loop_cntl = 0; - } - - /* Inhibit-CRC not supported. */ - if (val & 0x01) nelog(3, - "%s: TCR write, inhibit-CRC not supported\n",dev->name); - - /* Auto-transmit disable very suspicious */ - if (val & 0x08) nelog(3, - "%s: TCR write, auto transmit disable not supported\n", - dev->name); - - /* Allow collision-offset to be set, although not used */ - dev->dp8390.TCR.coll_prio = ((val & 0x08) == 0x08); - break; - - case 0x0e: /* DCR */ - /* the loopback mode is not suppported yet */ - if (! (val & 0x08)) nelog(3, - "%s: DCR write, loopback mode selected\n", dev->name); - - /* It is questionable to set longaddr and auto_rx, since - * they are not supported on the NE2000. Print a warning - * and continue. */ - if (val & 0x04) - nelog(3, "%s: DCR write - LAS set ???\n", dev->name); - if (val & 0x10) - nelog(3, "%s: DCR write - AR set ???\n", dev->name); - - /* Set other values. */ - dev->dp8390.DCR.wdsize = ((val & 0x01) == 0x01); - dev->dp8390.DCR.endian = ((val & 0x02) == 0x02); - dev->dp8390.DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ - dev->dp8390.DCR.loop = ((val & 0x08) == 0x08); - dev->dp8390.DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ - dev->dp8390.DCR.fifo_size = (val & 0x50) >> 5; - break; - - case 0x0f: /* IMR */ - /* Check for reserved bit */ - if (val & 0x80) - nelog(3, "%s: IMR write, reserved bit set\n",dev->name); - - /* Set other values */ - dev->dp8390.IMR.rx_inte = ((val & 0x01) == 0x01); - dev->dp8390.IMR.tx_inte = ((val & 0x02) == 0x02); - dev->dp8390.IMR.rxerr_inte = ((val & 0x04) == 0x04); - dev->dp8390.IMR.txerr_inte = ((val & 0x08) == 0x08); - dev->dp8390.IMR.overw_inte = ((val & 0x10) == 0x10); - dev->dp8390.IMR.cofl_inte = ((val & 0x20) == 0x20); - dev->dp8390.IMR.rdma_inte = ((val & 0x40) == 0x40); - val2 = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - if (((val & val2) & 0x7f) == 0) - nic_interrupt(dev, 0); - else - nic_interrupt(dev, 1); - break; - - default: - nelog(3, "%s: Page0 write, bad register 0x%02x\n", - dev->name, off); - break; - } -} - - -/* Handle reads/writes to the first page of the DS8390 register file. */ -static uint32_t -page1_read(nic_t *dev, uint32_t off, unsigned int len) -{ - nelog(3, "%s: Page1 read from register 0x%02x, len=%u\n", - dev->name, off, len); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - return(dev->dp8390.physaddr[off - 1]); - - case 0x07: /* CURR */ - nelog(3, "%s: returning current page: 0x%02x\n", - dev->name, (dev->dp8390.curr_page)); - return(dev->dp8390.curr_page); - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - return(dev->dp8390.mchash[off - 8]); - - default: - nelog(3, "%s: Page1 read register 0x%02x out of range\n", - dev->name, off); - return(0); - } -} - - -static void -page1_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) -{ - nelog(3, "%s: Page1 write to register 0x%02x, len=%u, value=0x%04x\n", - dev->name, off, len, val); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - dev->dp8390.physaddr[off - 1] = val; - if (off == 6) nelog(3, - "%s: physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], - dev->dp8390.physaddr[2], dev->dp8390.physaddr[3], - dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); - break; - - case 0x07: /* CURR */ - dev->dp8390.curr_page = val; - break; - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - dev->dp8390.mchash[off - 8] = val; - break; - - default: - nelog(3, "%s: Page1 write register 0x%02x out of range\n", - dev->name, off); - break; - } -} - - -/* Handle reads/writes to the second page of the DS8390 register file. */ -static uint32_t -page2_read(nic_t *dev, uint32_t off, unsigned int len) -{ - nelog(3, "%s: Page2 read from register 0x%02x, len=%u\n", - dev->name, off, len); - - switch(off) { - case 0x01: /* PSTART */ - return(dev->dp8390.page_start); - - case 0x02: /* PSTOP */ - return(dev->dp8390.page_stop); - - case 0x03: /* Remote Next-packet pointer */ - return(dev->dp8390.rempkt_ptr); - - case 0x04: /* TPSR */ - return(dev->dp8390.tx_page_start); - - case 0x05: /* Local Next-packet pointer */ - return(dev->dp8390.localpkt_ptr); - - case 0x06: /* Address counter (upper) */ - return(dev->dp8390.address_cnt >> 8); - - case 0x07: /* Address counter (lower) */ - return(dev->dp8390.address_cnt & 0xff); - - case 0x08: /* Reserved */ - case 0x09: - case 0x0a: - case 0x0b: - nelog(3, "%s: reserved Page2 read - register 0x%02x\n", - dev->name, off); - return(0xff); - - case 0x0c: /* RCR */ - return ((dev->dp8390.RCR.monitor << 5) | - (dev->dp8390.RCR.promisc << 4) | - (dev->dp8390.RCR.multicast << 3) | - (dev->dp8390.RCR.broadcast << 2) | - (dev->dp8390.RCR.runts_ok << 1) | - (dev->dp8390.RCR.errors_ok)); - - case 0x0d: /* TCR */ - return ((dev->dp8390.TCR.coll_prio << 4) | - (dev->dp8390.TCR.ext_stoptx << 3) | - ((dev->dp8390.TCR.loop_cntl & 0x3) << 1) | - (dev->dp8390.TCR.crc_disable)); - - case 0x0e: /* DCR */ - return (((dev->dp8390.DCR.fifo_size & 0x3) << 5) | - (dev->dp8390.DCR.auto_rx << 4) | - (dev->dp8390.DCR.loop << 3) | - (dev->dp8390.DCR.longaddr << 2) | - (dev->dp8390.DCR.endian << 1) | - (dev->dp8390.DCR.wdsize)); - - case 0x0f: /* IMR */ - return ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - - default: - nelog(3, "%s: Page2 register 0x%02x out of range\n", - dev->name, off); - break; - } - - return(0); -} - - -static void -page2_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) -{ -/* Maybe all writes here should be BX_PANIC()'d, since they - affect internal operation, but let them through for now - and print a warning. */ - nelog(3, "%s: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", - dev->name, off, len, val); - switch(off) { - case 0x01: /* CLDA0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.local_dma &= 0xff00; - dev->dp8390.local_dma |= (val & 0xff); - break; - - case 0x02: /* CLDA1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.local_dma &= 0x00ff; - dev->dp8390.local_dma |= ((val & 0xff) << 8); - break; - - case 0x03: /* Remote Next-pkt pointer */ - dev->dp8390.rempkt_ptr = val; - break; - - case 0x04: - nelog(3, "page 2 write to reserved register 0x04\n"); - break; - - case 0x05: /* Local Next-packet pointer */ - dev->dp8390.localpkt_ptr = val; - break; - - case 0x06: /* Address counter (upper) */ - /* Clear out high byte and re-insert */ - dev->dp8390.address_cnt &= 0x00ff; - dev->dp8390.address_cnt |= ((val & 0xff) << 8); - break; - - case 0x07: /* Address counter (lower) */ - /* Clear out low byte and re-insert */ - dev->dp8390.address_cnt &= 0xff00; - dev->dp8390.address_cnt |= (val & 0xff); - break; - - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - nelog(3, "%s: Page2 write to reserved register 0x%02x\n", - dev->name, off); - break; - - default: - nelog(3, "%s: Page2 write, illegal register 0x%02x\n", - dev->name, off); - break; - } -} - - /* Writes to this page are illegal. */ static uint32_t page3_read(nic_t *dev, uint32_t off, unsigned int len) @@ -1133,119 +395,6 @@ page3_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) } -/* Routines for handling reads/writes to the Command Register. */ -static uint32_t -read_cr(nic_t *dev) -{ - uint32_t retval; - - retval = (((dev->dp8390.CR.pgsel & 0x03) << 6) | - ((dev->dp8390.CR.rdma_cmd & 0x07) << 3) | - (dev->dp8390.CR.tx_packet << 2) | - (dev->dp8390.CR.start << 1) | - (dev->dp8390.CR.stop)); - nelog(3, "%s: read CR returns 0x%02x\n", dev->name, retval); - - return(retval); -} - - -static void -write_cr(nic_t *dev, uint32_t val) -{ - nelog(3, "%s: wrote 0x%02x to CR\n", dev->name, val); - - /* Validate remote-DMA */ - if ((val & 0x38) == 0x00) { - nelog(3, "%s: CR write - invalid rDMA value 0\n", dev->name); - val |= 0x20; /* dma_cmd == 4 is a safe default */ - } - - /* Check for s/w reset */ - if (val & 0x01) { - dev->dp8390.ISR.reset = 1; - dev->dp8390.CR.stop = 1; - } else { - dev->dp8390.CR.stop = 0; - } - - dev->dp8390.CR.rdma_cmd = (val & 0x38) >> 3; - - /* If start command issued, the RST bit in the ISR */ - /* must be cleared */ - if ((val & 0x02) && !dev->dp8390.CR.start) - dev->dp8390.ISR.reset = 0; - - dev->dp8390.CR.start = ((val & 0x02) == 0x02); - dev->dp8390.CR.pgsel = (val & 0xc0) >> 6; - - /* Check for send-packet command */ - if (dev->dp8390.CR.rdma_cmd == 3) { - /* Set up DMA read from receive ring */ - dev->dp8390.remote_start = dev->dp8390.remote_dma = dev->dp8390.bound_ptr * 256; - dev->dp8390.remote_bytes = (uint16_t) chipmem_read(dev, dev->dp8390.bound_ptr * 256 + 2, 2); - nelog(3, "%s: sending buffer #x%x length %d\n", - dev->name, dev->dp8390.remote_start, dev->dp8390.remote_bytes); - } - - /* Check for start-tx */ - if ((val & 0x04) && dev->dp8390.TCR.loop_cntl) { - if (dev->dp8390.TCR.loop_cntl != 1) { - nelog(3, "%s: loop mode %d not supported\n", - dev->name, dev->dp8390.TCR.loop_cntl); - } else { - if (dev->board >= NE2K_NE2000) { - nic_rx(dev, - &dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_DWORD_MEMSTART], - dev->dp8390.tx_bytes); - } else { - nic_rx(dev, - &dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], - dev->dp8390.tx_bytes); - } - } - } else if (val & 0x04) { - if (dev->dp8390.CR.stop || (!dev->dp8390.CR.start && (dev->board < NE2K_RTL8019AS))) { - if (dev->dp8390.tx_bytes == 0) /* njh@bandsman.co.uk */ { - return; /* Solaris9 probe */ - } - nelog(3, "%s: CR write - tx start, dev in reset\n", dev->name); - } - - if (dev->dp8390.tx_bytes == 0) - nelog(3, "%s: CR write - tx start, tx bytes == 0\n", dev->name); - - /* Send the packet to the system driver */ - dev->dp8390.CR.tx_packet = 1; - if (dev->board >= NE2K_NE2000) { - network_tx(&dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_DWORD_MEMSTART], - dev->dp8390.tx_bytes); - } else { - network_tx(&dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], - dev->dp8390.tx_bytes); - } - - /* some more debug */ - if (dev->dp8390.tx_timer_active) - nelog(3, "%s: CR write, tx timer still active\n", dev->name); - - nic_tx(dev, val); - } - - /* Linux probes for an interrupt by setting up a remote-DMA read - * of 0 bytes with remote-DMA completion interrupts enabled. - * Detect this here */ - if (dev->dp8390.CR.rdma_cmd == 0x01 && dev->dp8390.CR.start && dev->dp8390.remote_bytes == 0) { - dev->dp8390.ISR.rdma_done = 1; - if (dev->dp8390.IMR.rdma_inte) { - nic_interrupt(dev, 1); - if (!dev->is_pci) - nic_interrupt(dev, 0); - } - } -} - - static uint32_t nic_read(nic_t *dev, uint32_t addr, unsigned len) { @@ -1254,33 +403,29 @@ nic_read(nic_t *dev, uint32_t addr, unsigned len) nelog(3, "%s: read addr %x, len %d\n", dev->name, addr, len); - if (off >= 0x10) { - retval = asic_read(dev, off - 0x10, len); - } else if (off == 0x00) { - retval = read_cr(dev); - } else switch(dev->dp8390.CR.pgsel) { + if (off >= 0x10) + retval = asic_read(dev, off - 0x10, len); + else if (off == 0x00) + retval = dp8390_read_cr(dev->dp8390); + else switch(dev->dp8390->CR.pgsel) { case 0x00: - retval = page0_read(dev, off, len); + retval = dp8390_page0_read(dev->dp8390, off, len); break; - case 0x01: - retval = page1_read(dev, off, len); + retval = dp8390_page1_read(dev->dp8390, off, len); break; - case 0x02: - retval = page2_read(dev, off, len); + retval = dp8390_page2_read(dev->dp8390, off, len); break; - case 0x03: retval = page3_read(dev, off, len); break; - default: nelog(3, "%s: unknown value of pgsel in read - %d\n", - dev->name, dev->dp8390.CR.pgsel); + dev->name, dev->dp8390->CR.pgsel); break; - } - + } + return(retval); } @@ -1295,12 +440,7 @@ nic_readb(uint16_t addr, void *priv) static uint16_t nic_readw(uint16_t addr, void *priv) { - nic_t *dev = (nic_t *)priv; - - if (dev->dp8390.DCR.wdsize & 1) - return(nic_read(dev, addr, 2)); - else - return(nic_read(dev, addr, 1)); + return(nic_read((nic_t *)priv, addr, 2)); } @@ -1318,34 +458,30 @@ nic_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) nelog(3, "%s: write addr %x, value %x len %d\n", dev->name, addr, val, len); - /* The high 16 bytes of i/o space are for the ne2000 asic - - the low 16 bytes are for the DS8390, with the current - page being selected by the PS0,PS1 registers in the - command register */ - if (off >= 0x10) { - asic_write(dev, off - 0x10, val, len); - } else if (off == 0x00) { - write_cr(dev, val); - } else switch(dev->dp8390.CR.pgsel) { + /* The high 16 bytes of i/o space are for the ne2000 asic - + the low 16 bytes are for the DS8390, with the current + page being selected by the PS0,PS1 registers in the + command register */ + if (off >= 0x10) + asic_write(dev, off - 0x10, val, len); + else if (off == 0x00) + dp8390_write_cr(dev->dp8390, val); + else switch(dev->dp8390->CR.pgsel) { case 0x00: - page0_write(dev, off, val, len); + dp8390_page0_write(dev->dp8390, off, val, len); break; - case 0x01: - page1_write(dev, off, val, len); + dp8390_page1_write(dev->dp8390, off, val, len); break; - case 0x02: - page2_write(dev, off, val, len); + dp8390_page2_write(dev->dp8390, off, val, len); break; - case 0x03: page3_write(dev, off, val, len); break; - default: nelog(3, "%s: unknown value of pgsel in write - %d\n", - dev->name, dev->dp8390.CR.pgsel); + dev->name, dev->dp8390->CR.pgsel); break; } } @@ -1361,12 +497,7 @@ nic_writeb(uint16_t addr, uint8_t val, void *priv) static void nic_writew(uint16_t addr, uint16_t val, void *priv) { - nic_t *dev = (nic_t *)priv; - - if (dev->dp8390.DCR.wdsize & 1) - nic_write(dev, addr, val, 2); - else - nic_write(dev, addr, val, 1); + nic_write((nic_t *)priv, addr, val, 2); } @@ -1830,21 +961,6 @@ nic_pci_read(int func, int addr, void *priv) ret = dev->pci_regs[addr]; break; -#if 0 - case 0x0C: /* (reserved) */ - ret = dev->pci_regs[addr]; - break; - - case 0x0D: /* PCI_LTR */ - case 0x0E: /* PCI_HTR */ - ret = dev->pci_regs[addr]; - break; - - case 0x0F: /* (reserved) */ - ret = dev->pci_regs[addr]; - break; -#endif - case 0x10: /* PCI_BAR 7:5 */ ret = (dev->pci_bar[0].addr_regs[0] & 0xe0) | 0x01; break; @@ -1915,32 +1031,9 @@ nic_pci_write(int func, int addr, uint8_t val, void *priv) nic_ioset(dev, dev->base_address); } } -#if 0 - if (val & PCI_COMMAND_MEMORY) { - ... - } -#endif dev->pci_regs[addr] = val & 0x03; break; -#if 0 - case 0x0C: /* (reserved) */ - dev->pci_regs[addr] = val; - break; - - case 0x0D: /* PCI_LTR */ - dev->pci_regs[addr] = val; - break; - - case 0x0E: /* PCI_HTR */ - dev->pci_regs[addr] = val; - break; - - case 0x0F: /* (reserved) */ - dev->pci_regs[addr] = val; - break; -#endif - case 0x10: /* PCI_BAR */ val &= 0xe0; /* 0xe0 acc to RTL DS */ val |= 0x01; /* re-enable IOIN bit */ @@ -1991,182 +1084,6 @@ nic_pci_write(int func, int addr, uint8_t val, void *priv) } -static void -nic_tx(nic_t *dev, uint32_t val) -{ - dev->dp8390.CR.tx_packet = 0; - dev->dp8390.TSR.tx_ok = 1; - dev->dp8390.ISR.pkt_tx = 1; - - /* Generate an interrupt if not masked */ - if (dev->dp8390.IMR.tx_inte) - nic_interrupt(dev, 1); - dev->dp8390.tx_timer_active = 0; -} - - -/* - * Called by the platform-specific code when an Ethernet frame - * has been received. The destination address is tested to see - * if it should be accepted, and if the RX ring has enough room, - * it is copied into it and the receive process is updated. - */ -static void -nic_rx(void *priv, uint8_t *buf, int io_len) -{ - static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; - nic_t *dev = (nic_t *)priv; - uint8_t pkthdr[4]; - uint8_t *startptr; - int pages, avail; - int idx, nextpage; - int endbytes; - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 1); - - if (io_len != 60) - nelog(2, "%s: rx_frame with length %d\n", dev->name, io_len); - - if ((dev->dp8390.CR.stop != 0) || (dev->dp8390.page_start == 0)) return; - - /* - * Add the pkt header + CRC to the length, and work - * out how many 256-byte pages the frame would occupy. - */ - pages = (io_len + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; - if (dev->dp8390.curr_page < dev->dp8390.bound_ptr) { - avail = dev->dp8390.bound_ptr - dev->dp8390.curr_page; - } else { - avail = (dev->dp8390.page_stop - dev->dp8390.page_start) - - (dev->dp8390.curr_page - dev->dp8390.bound_ptr); - } - - /* - * Avoid getting into a buffer overflow condition by - * not attempting to do partial receives. The emulation - * to handle this condition seems particularly painful. - */ - if ((avail < pages) -#if NE2K_NEVER_FULL_RING - || (avail == pages) -#endif - ) { - nelog(1, "%s: no space\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - if ((io_len < 40/*60*/) && !dev->dp8390.RCR.runts_ok) { - nelog(1, "%s: rejected small packet, length %d\n", dev->name, io_len); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Some computers don't care... */ - if (io_len < 60) - io_len = 60; - - nelog(2, "%s: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", - dev->name, - buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], - io_len); - - /* Do address filtering if not in promiscuous mode. */ - if (! dev->dp8390.RCR.promisc) { - /* If this is a broadcast frame.. */ - if (! memcmp(buf, bcast_addr, 6)) { - /* Broadcast not enabled, we're done. */ - if (! dev->dp8390.RCR.broadcast) { - nelog(2, "%s: RX BC disabled\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* If this is a multicast frame.. */ - else if (buf[0] & 0x01) { - /* Multicast not enabled, we're done. */ - if (! dev->dp8390.RCR.multicast) { -#if 1 - nelog(2, "%s: RX MC disabled\n", dev->name); -#endif - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Are we listening to this multicast address? */ - idx = mcast_index(buf); - if (! (dev->dp8390.mchash[idx>>3] & (1<<(idx&0x7)))) { - nelog(2, "%s: RX MC not listed\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* Unicast, must be for us.. */ - else if (memcmp(buf, dev->dp8390.physaddr, 6)) return; - } else { - nelog(2, "%s: RX promiscuous receive\n", dev->name); - } - - nextpage = dev->dp8390.curr_page + pages; - if (nextpage >= dev->dp8390.page_stop) - nextpage -= (dev->dp8390.page_stop - dev->dp8390.page_start); - - /* Set up packet header. */ - pkthdr[0] = 0x01; /* RXOK - packet is OK */ - if (buf[0] & 0x01) - pkthdr[0] |= 0x20; /* MULTICAST packet */ - pkthdr[1] = nextpage; /* ptr to next packet */ - pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ - pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ - nelog(2, "%s: RX pkthdr [%02x %02x %02x %02x]\n", - dev->name, pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); - - /* Copy into buffer, update curpage, and signal interrupt if config'd */ - if (dev->board >= NE2K_NE2000) - startptr = &dev->dp8390.mem[(dev->dp8390.curr_page * 256) - DP8390_DWORD_MEMSTART]; - else - startptr = &dev->dp8390.mem[(dev->dp8390.curr_page * 256) - DP8390_WORD_MEMSTART]; - memcpy(startptr, pkthdr, sizeof(pkthdr)); - if ((nextpage > dev->dp8390.curr_page) || - ((dev->dp8390.curr_page + pages) == dev->dp8390.page_stop)) { - memcpy(startptr+sizeof(pkthdr), buf, io_len); - } else { - endbytes = (dev->dp8390.page_stop - dev->dp8390.curr_page) * 256; - memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); - if (dev->board >= NE2K_NE2000) - startptr = &dev->dp8390.mem[(dev->dp8390.page_start * 256) - DP8390_DWORD_MEMSTART]; - else - startptr = &dev->dp8390.mem[(dev->dp8390.page_start * 256) - DP8390_WORD_MEMSTART]; - memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); - } - dev->dp8390.curr_page = nextpage; - - dev->dp8390.RSR.rx_ok = 1; - dev->dp8390.RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; - dev->dp8390.ISR.pkt_rx = 1; - - if (dev->dp8390.IMR.rx_inte) - nic_interrupt(dev, 1); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); -} - - static void nic_rom_init(nic_t *dev, wchar_t *s) { @@ -2221,8 +1138,8 @@ static void nic_mca_write(int port, uint8_t val, void *priv) { nic_t *dev = (nic_t *)priv; - uint16_t base[] = MCA_611F_IO_PORTS; - int8_t irq[] = MCA_611F_IRQS; + uint16_t base[] = MCA_611F_IO_PORTS; + int8_t irq[] = MCA_611F_IRQS; /* MCA does not write registers below 0x0100. */ if (port < 0x0102) return; @@ -2287,36 +1204,6 @@ nic_init(const device_t *info) dev->name = info->name; dev->board = info->local; rom = NULL; - switch(dev->board) { - case NE2K_NE1000: - dev->is_8bit = 1; - /*FALLTHROUGH*/ - - case NE2K_NE2000: - dev->maclocal[0] = 0x00; /* 00:00:D8 (Novell OID) */ - dev->maclocal[1] = 0x00; - dev->maclocal[2] = 0xD8; - rom = (dev->board == NE2K_NE1000) ? NULL : ROM_PATH_NE2000; - break; - - case NE2K_ETHERNEXT_MC: - dev->maclocal[0] = 0x00; /* 00:00:D8 (Networth Inc. OID) */ - dev->maclocal[1] = 0x00; - dev->maclocal[2] = 0x79; - dev->pos_regs[0] = 0x1F; - dev->pos_regs[1] = 0x61; - rom = NULL; - break; - - case NE2K_RTL8019AS: - case NE2K_RTL8029AS: - dev->is_pci = (dev->board == NE2K_RTL8029AS) ? 1 : 0; - dev->maclocal[0] = 0x00; /* 00:E0:4C (Realtek OID) */ - dev->maclocal[1] = 0xE0; - dev->maclocal[2] = 0x4C; - rom = (dev->board == NE2K_RTL8019AS) ? ROM_PATH_RTL8019 : ROM_PATH_RTL8029; - break; - } if (dev->board >= NE2K_RTL8019AS) { dev->base_address = 0x340; @@ -2348,16 +1235,6 @@ nic_init(const device_t *info) /* See if we have a local MAC address configured. */ mac = device_get_config_mac("mac", -1); - /* - * Make this device known to the I/O system. - * PnP and PCI devices start with address spaces inactive. - */ - if (dev->board < NE2K_RTL8019AS && dev->board != NE2K_ETHERNEXT_MC) - nic_ioset(dev, dev->base_address); - - /* Set up our BIOS ROM space, if any. */ - nic_rom_init(dev, rom); - /* Set up our BIA. */ if (mac & 0xff000000) { /* Generate new local MAC. */ @@ -2373,12 +1250,68 @@ nic_init(const device_t *info) dev->maclocal[4] = (mac>>8) & 0xff; dev->maclocal[5] = (mac & 0xff); } - memcpy(dev->dp8390.physaddr, dev->maclocal, sizeof(dev->maclocal)); + + dev->dp8390 = device_add(&dp8390_device); + dev->dp8390->priv = dev; + dev->dp8390->interrupt = nic_interrupt; + + memcpy(dev->dp8390->physaddr, dev->maclocal, sizeof(dev->maclocal)); nelog(2, "%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, dev->base_address, dev->base_irq, - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], dev->dp8390.physaddr[2], - dev->dp8390.physaddr[3], dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); + dev->dp8390->physaddr[0], dev->dp8390->physaddr[1], dev->dp8390->physaddr[2], + dev->dp8390->physaddr[3], dev->dp8390->physaddr[4], dev->dp8390->physaddr[5]); + + switch(dev->board) { + case NE2K_NE1000: + dev->is_8bit = 1; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CHECK_CR | DP8390_FLAG_CLEAR_IRQ); + /*FALLTHROUGH*/ + + case NE2K_NE2000: + dev->maclocal[0] = 0x00; /* 00:00:D8 (Novell OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0xD8; + rom = (dev->board == NE2K_NE1000) ? NULL : ROM_PATH_NE2000; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_DWORD_MEM | DP8390_FLAG_CHECK_CR | + DP8390_FLAG_CLEAR_IRQ); + break; + + case NE2K_ETHERNEXT_MC: + dev->maclocal[0] = 0x00; /* 00:00:D8 (Networth Inc. OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0x79; + dev->pos_regs[0] = 0x1F; + dev->pos_regs[1] = 0x61; + rom = NULL; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_DWORD_MEM | DP8390_FLAG_CHECK_CR | + DP8390_FLAG_CLEAR_IRQ); + break; + + case NE2K_RTL8019AS: + case NE2K_RTL8029AS: + dev->is_pci = (dev->board == NE2K_RTL8029AS) ? 1 : 0; + dev->maclocal[0] = 0x00; /* 00:E0:4C (Realtek OID) */ + dev->maclocal[1] = 0xE0; + dev->maclocal[2] = 0x4C; + rom = (dev->board == NE2K_RTL8019AS) ? ROM_PATH_RTL8019 : ROM_PATH_RTL8029; + if (dev->is_pci) + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_DWORD_MEM); + else + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_DWORD_MEM | DP8390_FLAG_CLEAR_IRQ); + dp8390_set_id(dev->dp8390, 0x50, (dev->board == NE2K_RTL8019AS) ? 0x70 : 0x43); + break; + } + + /* + * Make this device known to the I/O system. + * PnP and PCI devices start with address spaces inactive. + */ + if (dev->board < NE2K_RTL8019AS && dev->board != NE2K_ETHERNEXT_MC) + nic_ioset(dev, dev->base_address); + + /* Set up our BIOS ROM space, if any. */ + nic_rom_init(dev, rom); if (dev->board >= NE2K_RTL8019AS) { if (dev->is_pci) { @@ -2513,12 +1446,12 @@ nic_init(const device_t *info) } } - if (dev->board != NE2K_ETHERNEXT_MC) - /* Reset the board. */ - nic_reset(dev); + if (dev->board != NE2K_ETHERNEXT_MC) + /* Reset the board. */ + nic_reset(dev); /* Attach ourselves to the network module. */ - network_attach(dev, dev->dp8390.physaddr, nic_rx); + network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx); nelog(1, "%s: %s attached IO=0x%X IRQ=%d\n", dev->name, dev->is_pci?"PCI":"ISA", dev->base_address, dev->base_irq); @@ -2532,11 +1465,6 @@ nic_close(void *priv) { nic_t *dev = (nic_t *)priv; - /* Make sure the platform layer is shut down. */ - network_close(); - - nic_ioremove(dev, dev->base_address); - nelog(1, "%s: closed\n", dev->name); free(dev); diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index ea19e97a1..ba04a14ae 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -8,7 +8,7 @@ * * Handle WinPcap library processing. * - * Version: @(#)net_pcap.c 1.0.5 2018/10/02 + * Version: @(#)net_pcap.c 1.0.6 2018/10/17 * * Author: Fred N. van Kempen, * @@ -55,6 +55,7 @@ #include "../device.h" #include "../plat.h" #include "../plat_dynld.h" +#include "../ui.h" #include "network.h" @@ -138,22 +139,22 @@ static dllimp_t pcap_imports[] = { #ifdef ENABLE_PCAP_LOG int pcap_do_log = ENABLE_PCAP_LOG; -#endif static void -pcap_log(const char *format, ...) +pcap_log(const char *fmt, ...) { -#ifdef ENABLE_PCAP_LOG va_list ap; if (pcap_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define pcap_log(fmt, ...) +#endif /* Handle the receiving of frames from the channel. */ @@ -186,6 +187,8 @@ poll_thread(void *arg) /* Wait for the next packet to arrive. */ data = (uint8_t *)f_pcap_next((void *)pcap, &h); if (data != NULL) { + ui_sb_update_icon(SB_NETWORK, 1); + /* Received MAC. */ mac_cmp32[0] = *(uint32_t *)(data+6); mac_cmp16[0] = *(uint16_t *)(data+10); @@ -204,8 +207,10 @@ poll_thread(void *arg) } /* If we did not get anything, wait a while. */ - if (data == NULL) + if (data == NULL) { + ui_sb_update_icon(SB_NETWORK, 0); thread_wait_event(evt, 10); + } /* Release ownership of the device. */ network_wait(0); @@ -319,6 +324,8 @@ net_pcap_close(void) { void *pc; + ui_sb_update_icon(SB_NETWORK, 0); + if (pcap == NULL) return; pcap_log("PCAP: closing.\n"); @@ -374,6 +381,8 @@ net_pcap_reset(const netcard_t *card, uint8_t *mac) char filter_exp[255]; struct bpf_program fp; + ui_sb_update_icon(SB_NETWORK, 0); + /* Open a PCAP live channel. */ if ((pcap = f_pcap_open_live(network_host, /* interface name */ 1518, /* max packet size */ @@ -422,9 +431,13 @@ net_pcap_in(uint8_t *bufp, int len) { if (pcap == NULL) return; + ui_sb_update_icon(SB_NETWORK, 1); + network_busy(1); f_pcap_sendpacket((void *)pcap, bufp, len); network_busy(0); + + ui_sb_update_icon(SB_NETWORK, 0); } diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 41ca07b70..bd7781726 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -8,7 +8,7 @@ * * Handle SLiRP library processing. * - * Version: @(#)net_slirp.c 1.0.4 2018/10/02 + * Version: @(#)net_slirp.c 1.0.5 2018/10/17 * * Author: Fred N. van Kempen, * @@ -56,6 +56,7 @@ #include "../86box.h" #include "../device.h" #include "../plat.h" +#include "../ui.h" #include "network.h" @@ -67,22 +68,22 @@ static event_t *poll_state; #ifdef ENABLE_SLIRP_LOG int slirp_do_log = ENABLE_SLIRP_LOG; -#endif static void -slirp_log(const char *format, ...) +slirp_log(const char *fmt, ...) { -#ifdef ENABLE_SLIRP_LOG va_list ap; if (slirp_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define slirp_log(fmt, ...) +#endif static void @@ -116,10 +117,14 @@ slirp_tic(void) /* Handle the receiving of frames. */ static void -poll_thread(UNUSED(void *arg)) +poll_thread(void *arg) { + uint8_t *mac = (uint8_t *)arg; struct queuepacket *qp; + uint32_t mac_cmp32[2]; + uint16_t mac_cmp16[2]; event_t *evt; + int data_valid = 0; slirp_log("SLiRP: polling started.\n"); thread_set_event(poll_state); @@ -141,18 +146,37 @@ poll_thread(UNUSED(void *arg)) if (slirpq == NULL) break; /* Wait for the next packet to arrive. */ + data_valid = 0; + if (QueuePeek(slirpq) != 0) { /* Grab a packet from the queue. */ + ui_sb_update_icon(SB_NETWORK, 1); + qp = QueueDelete(slirpq); slirp_log("SLiRP: inQ:%d got a %dbyte packet @%08lx\n", QueuePeek(slirpq), qp->len, qp); - poll_card->rx(poll_card->priv, (uint8_t *)qp->data, qp->len); + /* Received MAC. */ + mac_cmp32[0] = *(uint32_t *)(((uint8_t *)qp->data)+6); + mac_cmp16[0] = *(uint16_t *)(((uint8_t *)qp->data)+10); + + /* Local MAC. */ + mac_cmp32[1] = *(uint32_t *)mac; + mac_cmp16[1] = *(uint16_t *)(mac+4); + if ((mac_cmp32[0] != mac_cmp32[1]) || + (mac_cmp16[0] != mac_cmp16[1])) { + + poll_card->rx(poll_card->priv, (uint8_t *)qp->data, qp->len); + data_valid = 1; + } /* Done with this one. */ free(qp); - } else { - /* If we did not get anything, wait a while. */ + } + + /* If we did not get anything, wait a while. */ + if (!data_valid) { + ui_sb_update_icon(SB_NETWORK, 0); thread_wait_event(evt, 10); } @@ -194,6 +218,8 @@ net_slirp_init(void) int net_slirp_reset(const netcard_t *card, uint8_t *mac) { + ui_sb_update_icon(SB_NETWORK, 0); + /* Save the callback info. */ poll_card = card; @@ -211,6 +237,8 @@ net_slirp_close(void) { queueADT sl; + ui_sb_update_icon(SB_NETWORK, 0); + if (slirpq == NULL) return; slirp_log("SLiRP: closing.\n"); @@ -245,11 +273,15 @@ net_slirp_in(uint8_t *pkt, int pkt_len) { if (slirpq == NULL) return; + ui_sb_update_icon(SB_NETWORK, 1); + network_busy(1); slirp_input((const uint8_t *)pkt, pkt_len); network_busy(0); + + ui_sb_update_icon(SB_NETWORK, 0); } diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index 0cc0ae533..cedb4f873 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -11,7 +11,7 @@ * - SMC/WD 8013EBT (ISA 16-bit); * - SMC/WD 8013EP/A (MCA). * - * Version: @(#)net_wd8003.c 1.0.1 2018/10/02 + * Version: @(#)net_wd8003.c 1.0.2 2018/10/17 * * Authors: Fred N. van Kempen, * TheCollector1995, @@ -57,7 +57,6 @@ #include "../pic.h" #include "../random.h" #include "../device.h" -#include "../ui.h" #include "network.h" #include "net_dp8390.h" #include "net_wd8003.h" @@ -83,310 +82,212 @@ #define WE_TYPE_WD8013EBP 0x2c typedef struct { - dp8390_t dp8390; - mem_mapping_t ram_mapping; - uint32_t ram_addr, ram_size; - uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */ + dp8390_t *dp8390; + mem_mapping_t ram_mapping; + uint32_t ram_addr, ram_size; uint8_t maclocal[6]; /* configured MAC (local) address */ + uint8_t bit16, pad; int board; const char *name; uint32_t base_address; int base_irq; - - /* POS registers, MCA boards only */ - uint8_t pos_regs[8]; - - /* Memory for WD cards*/ - uint8_t reg1; - uint8_t reg5; - uint8_t if_chip; - uint8_t board_chip; + + /* POS registers, MCA boards only */ + uint8_t pos_regs[8]; + + /* Memory for WD cards*/ + uint8_t reg0, reg1, + reg4, reg5, + if_chip, board_chip; } wd_t; -static void wd_rx(void *, uint8_t *, int); -static void wd_tx(wd_t *, uint32_t); #ifdef ENABLE_WD_LOG int wd_do_log = ENABLE_WD_LOG; -#endif static void -wdlog(int lvl, const char *fmt, ...) +wdlog(const char *fmt, ...) { -#ifdef ENABLE_WD_LOG va_list ap; - if (wd_do_log >= lvl) { + if (wd_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define wdlog(fmt, ...) +#endif + + +static const int we_int_table[8] = {9, 3, 5, 7, 10, 11, 15, 4}; + static void -wd_interrupt(wd_t *dev, int set) +wd_interrupt(void *priv, int set) { - if (set) - picint(1<base_irq); - else - picintc(1<base_irq); + wd_t *dev = (wd_t *) priv; + + if (dev->reg4 & 0x80) + return; + + if (set) + picint(1 << dev->base_irq); + else + picintc(1 << dev->base_irq); } + /* reset - restore state to power-up, cancelling all i/o */ static void wd_reset(void *priv) { wd_t *dev = (wd_t *)priv; - wdlog(1, "%s: reset\n", dev->name); + wdlog("%s: reset\n", dev->name); - /* Initialize the MAC address area by doubling the physical address */ - dev->macaddr[0] = dev->dp8390.physaddr[0]; - dev->macaddr[1] = dev->dp8390.physaddr[1]; - dev->macaddr[2] = dev->dp8390.physaddr[2]; - dev->macaddr[3] = dev->dp8390.physaddr[3]; - dev->macaddr[4] = dev->dp8390.physaddr[4]; - dev->macaddr[5] = dev->dp8390.physaddr[5]; - - /* Zero out registers and memory */ - memset(&dev->dp8390.CR, 0x00, sizeof(dev->dp8390.CR) ); - memset(&dev->dp8390.ISR, 0x00, sizeof(dev->dp8390.ISR)); - memset(&dev->dp8390.IMR, 0x00, sizeof(dev->dp8390.IMR)); - memset(&dev->dp8390.DCR, 0x00, sizeof(dev->dp8390.DCR)); - memset(&dev->dp8390.TCR, 0x00, sizeof(dev->dp8390.TCR)); - memset(&dev->dp8390.TSR, 0x00, sizeof(dev->dp8390.TSR)); - memset(&dev->dp8390.RSR, 0x00, sizeof(dev->dp8390.RSR)); - dev->dp8390.tx_timer_active = 0; - dev->dp8390.local_dma = 0; - dev->dp8390.page_start = 0; - dev->dp8390.page_stop = 0; - dev->dp8390.bound_ptr = 0; - dev->dp8390.tx_page_start = 0; - dev->dp8390.num_coll = 0; - dev->dp8390.tx_bytes = 0; - dev->dp8390.fifo = 0; - dev->dp8390.remote_dma = 0; - dev->dp8390.remote_start = 0; - - dev->dp8390.remote_bytes = 0; - - dev->dp8390.tallycnt_0 = 0; - dev->dp8390.tallycnt_1 = 0; - dev->dp8390.tallycnt_2 = 0; - - dev->dp8390.curr_page = 0; - - dev->dp8390.rempkt_ptr = 0; - dev->dp8390.localpkt_ptr = 0; - dev->dp8390.address_cnt = 0; - - memset(&dev->dp8390.mem, 0x00, sizeof(dev->dp8390.mem)); - - /* Set power-up conditions */ - dev->dp8390.CR.stop = 1; - dev->dp8390.CR.rdma_cmd = 4; - dev->dp8390.ISR.reset = 1; - dev->dp8390.DCR.longaddr = 1; - - wd_interrupt(dev, 0); + dp8390_reset(dev->dp8390); } -static uint32_t -wd_chipmem_read(wd_t *dev, uint32_t addr, unsigned int len) + +static void +wd_soft_reset(void *priv) { - uint32_t retval = 0; + wd_t *dev = (wd_t *)priv; - if ((len == 2) && (addr & 0x1)) { - wdlog(3, "%s: unaligned chipmem word read\n", dev->name); - } - - /* ROM'd MAC address */ - if (dev->board == WD8003E) - { - if (addr <= 15) { - retval = dev->macaddr[addr % 16]; - if (len == 2) { - retval |= (dev->macaddr[(addr + 1) % 16] << 8); - } - return(retval); - } - } - - return(0xff); + dp8390_soft_reset(dev->dp8390); } + static uint32_t wd_ram_read(uint32_t addr, unsigned len, void *priv) { - wd_t *dev = (wd_t *)priv; - uint32_t ret; - - if ((addr & 0x3fff) >= 0x2000) - { - if (len == 2) - return 0xffff; - else if (len == 1) - return 0xff; - else - return 0xffffffff; - } - - ret = dev->dp8390.mem[addr & 0x1fff]; - if (len == 2 || len == 4) - ret |= dev->dp8390.mem[(addr+1) & 0x1fff] << 8; - if (len == 4) { - ret |= dev->dp8390.mem[(addr+2) & 0x1fff] << 16; - ret |= dev->dp8390.mem[(addr+3) & 0x1fff] << 24; - } - - return ret; + wd_t *dev = (wd_t *)priv; + uint32_t ret; + uint16_t ram_mask = dev->ram_size - 1; + + ret = dev->dp8390->mem[addr & ram_mask]; + + if (len == 2) + ret |= dev->dp8390->mem[(addr + 1) & ram_mask] << 8; + + return ret; } + static uint8_t wd_ram_readb(uint32_t addr, void *priv) { - wd_t *dev = (wd_t *)priv; - - return wd_ram_read(addr, 1, dev); + wd_t *dev = (wd_t *)priv; + + return wd_ram_read(addr, 1, dev); } + static uint16_t wd_ram_readw(uint32_t addr, void *priv) { - wd_t *dev = (wd_t *)priv; - - return wd_ram_read(addr, 2, dev); + wd_t *dev = (wd_t *)priv; + + return wd_ram_read(addr, 2, dev); } -static uint32_t -wd_ram_readl(uint32_t addr, void *priv) -{ - wd_t *dev = (wd_t *)priv; - - return wd_ram_read(addr, 4, dev); -} static void wd_ram_write(uint32_t addr, uint32_t val, unsigned len, void *priv) { - wd_t *dev = (wd_t *)priv; + wd_t *dev = (wd_t *)priv; + uint16_t ram_mask = dev->ram_size - 1; - if ((addr & 0x3fff) >= 0x2000) - return; + dev->dp8390->mem[addr & ram_mask] = val & 0xff; - dev->dp8390.mem[addr & 0x1fff] = val & 0xff; - if (len == 2 || len == 4) - dev->dp8390.mem[(addr+1) & 0x1fff] = val >> 8; - if (len == 4) { - dev->dp8390.mem[(addr+2) & 0x1fff] = val >> 16; - dev->dp8390.mem[(addr+3) & 0x1fff] = val >> 24; - } + if (len == 2) + dev->dp8390->mem[(addr + 1) & ram_mask] = val >> 8; } + static void wd_ram_writeb(uint32_t addr, uint8_t val, void *priv) { - wd_t *dev = (wd_t *)priv; + wd_t *dev = (wd_t *)priv; - wd_ram_write(addr, val, 1, dev); + wd_ram_write(addr, val, 1, dev); } + static void wd_ram_writew(uint32_t addr, uint16_t val, void *priv) { - wd_t *dev = (wd_t *)priv; + wd_t *dev = (wd_t *)priv; - wd_ram_write(addr, val, 2, dev); + wd_ram_write(addr, val, 2, dev); } -static void -wd_ram_writel(uint32_t addr, uint32_t val, void *priv) -{ - wd_t *dev = (wd_t *)priv; - - wd_ram_write(addr, val, 4, dev); -} static uint32_t wd_smc_read(wd_t *dev, uint32_t off) { uint32_t retval = 0; - uint32_t checksum = 0; - + uint32_t checksum = 0; + + if (dev->board == WD8003E) { + if ((off >= 0x01) && (off <= 0x06)) + off += 0x07; /* On the WD8003E, ports 00-06 shadow ports 08-0D. */ + else if (off == 0x07) + off = 0x0f; /* Port 07 shadows port 0F (checksum). */ + } + switch(off) { case 0x00: + if (dev->board == WD8013EBT) + retval = dev->reg0; break; case 0x01: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[0]; - if (dev->board == WD8013EPA) - retval = dev->reg1; - break; - - case 0x02: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[1]; - break; - - case 0x03: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[2]; + retval = dev->reg1; break; case 0x04: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[3]; + if (dev->board == WD8013EBT) + retval = dev->reg4; break; - + case 0x05: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[4]; - if (dev->board == WD8013EPA) - retval = dev->reg5; + retval = dev->reg5; break; - case 0x06: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[5]; - break; - case 0x07: - if (dev->board == WD8013EPA) - { - if (dev->if_chip != 0x35 && dev->if_chip != 0x3A) - { + if (dev->board == WD8013EPA) { + if ((dev->if_chip != 0x35) && (dev->if_chip != 0x3A)) retval = 0; - break; - } - - retval = dev->if_chip; + else + retval = dev->if_chip; } break; - + case 0x08: - retval = dev->dp8390.physaddr[0]; + retval = dev->dp8390->physaddr[0]; break; case 0x09: - retval = dev->dp8390.physaddr[1]; + retval = dev->dp8390->physaddr[1]; break; case 0x0a: - retval = dev->dp8390.physaddr[2]; + retval = dev->dp8390->physaddr[2]; break; case 0x0b: - retval = dev->dp8390.physaddr[3]; + retval = dev->dp8390->physaddr[3]; break; case 0x0c: - retval = dev->dp8390.physaddr[4]; + retval = dev->dp8390->physaddr[4]; break; case 0x0d: - retval = dev->dp8390.physaddr[5]; + retval = dev->dp8390->physaddr[5]; break; case 0x0e: @@ -394,53 +295,85 @@ wd_smc_read(wd_t *dev, uint32_t off) break; case 0x0f: - { /*This has to return the byte that adds up to 0xFF*/ - checksum = (dev->dp8390.physaddr[0] + dev->dp8390.physaddr[1] + dev->dp8390.physaddr[2] + - dev->dp8390.physaddr[3] + dev->dp8390.physaddr[4] + dev->dp8390.physaddr[5] + + checksum = (dev->dp8390->physaddr[0] + dev->dp8390->physaddr[1] + dev->dp8390->physaddr[2] + + dev->dp8390->physaddr[3] + dev->dp8390->physaddr[4] + dev->dp8390->physaddr[5] + dev->board_chip); retval = 0xff - (checksum & 0xff); - } break; } - wdlog(2, "%s: ASIC read addr=0x%02x, value=0x%04x\n", + wdlog("%s: ASIC read addr=0x%02x, value=0x%04x\n", dev->name, (unsigned)off, (unsigned) retval); - + return(retval); } + +static void +wd_set_irq(wd_t *dev) +{ + uint8_t irq; + + irq = (dev->reg4 & 0x60) >> 5; + irq |= (dev->reg1 & 0x04); + + dev->base_irq = we_int_table[irq]; +} + + static void wd_smc_write(wd_t *dev, uint32_t off, uint32_t val) { - wdlog(2, "%s: ASIC write addr=0x%02x, value=0x%04x\n", - dev->name, (unsigned)off, (unsigned) val); + wdlog("%s: ASIC write addr=0x%02x, value=0x%04x\n", + dev->name, (unsigned)off, (unsigned) val); switch(off) { case 0x00: /* WD Control register */ + dev->reg0 = val; + if (val & 0x80) - { - dev->dp8390.ISR.reset = 1; - return; - } - - mem_mapping_disable(&dev->ram_mapping); - + wd_soft_reset(dev); + if (val & 0x40) - { mem_mapping_enable(&dev->ram_mapping); - } + else + mem_mapping_disable(&dev->ram_mapping); break; case 0x01: - dev->reg1 = val; + if (dev->board == WD8003E) + break; + + dev->reg1 &= 0x60; + dev->reg1 |= (val & ~0x60); + if (!dev->bit16) + dev->reg1 &= ~0x01; + + if (dev->board == WD8013EBT) { + wd_set_irq(dev); + + dev->ram_size = (dev->reg1 & 0x08) ? 0x8000 : 0x4000; + + mem_mapping_set_addr(&dev->ram_mapping, dev->ram_addr, dev->ram_size); + if (!(dev->reg0 & 0x40)) + mem_mapping_disable(&dev->ram_mapping); + } break; case 0x04: + if (dev->board != WD8013EBT) + break; + + dev->reg4 = val; + wd_set_irq(dev); break; case 0x05: + if (dev->board == WD8003E) + break; + dev->reg5 = val; break; @@ -449,897 +382,145 @@ wd_smc_write(wd_t *dev, uint32_t off, uint32_t val) case 0x07: dev->if_chip = val; - break; + break; - default: /* this is invalid, but happens under win95 device detection */ - wdlog(3, "%s: ASIC write invalid address %04x, ignoring\n", - dev->name, (unsigned)off); + default: + /* This is invalid, but happens under win95 device detection: + maybe some clone cards implement writing for some other + registers? */ + wdlog("%s: ASIC write invalid address %04x, ignoring\n", + dev->name, (unsigned)off); break; } } -/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ static uint8_t -page0_read(wd_t *dev, uint32_t off) +wd_read(uint16_t addr, void *priv, int len) { + wd_t *dev = (wd_t *)priv; + uint8_t retval = 0; + int off = addr - dev->base_address; - switch(off) { - case 0x01: /* CLDA0 */ - retval = (dev->dp8390.local_dma & 0xff); - break; + wdlog("%s: read addr %x\n", dev->name, addr); - case 0x02: /* CLDA1 */ - retval = (dev->dp8390.local_dma >> 8); - break; - - case 0x03: /* BNRY */ - retval = dev->dp8390.bound_ptr; - break; - - case 0x04: /* TSR */ - retval = ((dev->dp8390.TSR.ow_coll << 7) | - (dev->dp8390.TSR.cd_hbeat << 6) | - (dev->dp8390.TSR.fifo_ur << 5) | - (dev->dp8390.TSR.no_carrier << 4) | - (dev->dp8390.TSR.aborted << 3) | - (dev->dp8390.TSR.collided << 2) | - (dev->dp8390.TSR.tx_ok)); - break; - - case 0x05: /* NCR */ - retval = dev->dp8390.num_coll; - break; - - case 0x06: /* FIFO */ - /* reading FIFO is only valid in loopback mode */ - wdlog(3, "%s: reading FIFO not supported yet\n", dev->name); - retval = dev->dp8390.fifo; - break; - - case 0x07: /* ISR */ - retval = ((dev->dp8390.ISR.reset << 7) | - (dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - break; - - case 0x08: /* CRDA0 */ - retval = (dev->dp8390.remote_dma & 0xff); - break; - - case 0x09: /* CRDA1 */ - retval = (dev->dp8390.remote_dma >> 8); - break; - - case 0x0a: /* reserved / RTL8029ID0 */ - wdlog(3, "%s: reserved Page0 read - 0x0a\n", dev->name); - retval = 0xff; - break; - - case 0x0b: /* reserved / RTL8029ID1 */ - wdlog(3, "%s: reserved Page0 read - 0x0b\n", dev->name); - retval = 0xff; - break; - - case 0x0c: /* RSR */ - retval = ((dev->dp8390.RSR.deferred << 7) | - (dev->dp8390.RSR.rx_disabled << 6) | - (dev->dp8390.RSR.rx_mbit << 5) | - (dev->dp8390.RSR.rx_missed << 4) | - (dev->dp8390.RSR.fifo_or << 3) | - (dev->dp8390.RSR.bad_falign << 2) | - (dev->dp8390.RSR.bad_crc << 1) | - (dev->dp8390.RSR.rx_ok)); - break; - - case 0x0d: /* CNTR0 */ - retval = dev->dp8390.tallycnt_0; - break; - - case 0x0e: /* CNTR1 */ - retval = dev->dp8390.tallycnt_1; - break; - - case 0x0f: /* CNTR2 */ - retval = dev->dp8390.tallycnt_2; - break; - - default: - wdlog(3, "%s: Page0 register 0x%02x out of range\n", - dev->name, off); - break; + if (off == 0x10) + retval = dp8390_read_cr(dev->dp8390); + else if ((off >= 0x00) && (off <= 0x0f)) + retval = wd_smc_read(dev, off); + else { + switch(dev->dp8390->CR.pgsel) { + case 0x00: + retval = dp8390_page0_read(dev->dp8390, off - 0x10, len); + break; + case 0x01: + retval = dp8390_page1_read(dev->dp8390, off - 0x10, len); + break; + case 0x02: + retval = dp8390_page2_read(dev->dp8390, off - 0x10, len); + break; + default: + wdlog("%s: unknown value of pgsel in read - %d\n", + dev->name, dev->dp8390->CR.pgsel); + break; + } } - wdlog(3, "%s: Page0 read from register 0x%02x, value=0x%02x\n", - dev->name, off, retval); - return(retval); } -static void -page0_write(wd_t *dev, uint32_t off, uint8_t val) -{ - uint8_t val2; - - wdlog(3, "%s: Page0 write to register 0x%02x, value=0x%02x\n", - dev->name, off, val); - - switch(off) { - case 0x01: /* PSTART */ - dev->dp8390.page_start = val; - break; - - case 0x02: /* PSTOP */ - dev->dp8390.page_stop = val; - break; - - case 0x03: /* BNRY */ - dev->dp8390.bound_ptr = val; - break; - - case 0x04: /* TPSR */ - dev->dp8390.tx_page_start = val; - break; - - case 0x05: /* TBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.tx_bytes &= 0xff00; - dev->dp8390.tx_bytes |= (val & 0xff); - break; - - case 0x06: /* TBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.tx_bytes &= 0x00ff; - dev->dp8390.tx_bytes |= ((val & 0xff) << 8); - break; - - case 0x07: /* ISR */ - val &= 0x7f; /* clear RST bit - status-only bit */ - /* All other values are cleared iff the ISR bit is 1 */ - dev->dp8390.ISR.pkt_rx &= !((int)((val & 0x01) == 0x01)); - dev->dp8390.ISR.pkt_tx &= !((int)((val & 0x02) == 0x02)); - dev->dp8390.ISR.rx_err &= !((int)((val & 0x04) == 0x04)); - dev->dp8390.ISR.tx_err &= !((int)((val & 0x08) == 0x08)); - dev->dp8390.ISR.overwrite &= !((int)((val & 0x10) == 0x10)); - dev->dp8390.ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20)); - dev->dp8390.ISR.rdma_done &= !((int)((val & 0x40) == 0x40)); - val = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - val &= ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - if (val == 0x00) - wd_interrupt(dev, 0); - break; - - case 0x08: /* RSAR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_start &= 0xff00; - dev->dp8390.remote_start |= (val & 0xff); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x09: /* RSAR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_start &= 0x00ff; - dev->dp8390.remote_start |= ((val & 0xff) << 8); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x0a: /* RBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_bytes &= 0xff00; - dev->dp8390.remote_bytes |= (val & 0xff); - break; - - case 0x0b: /* RBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_bytes &= 0x00ff; - dev->dp8390.remote_bytes |= ((val & 0xff) << 8); - break; - - case 0x0c: /* RCR */ - /* Check if the reserved bits are set */ - if (val & 0xc0) { - wdlog(3, "%s: RCR write, reserved bits set\n", - dev->name); - } - - /* Set all other bit-fields */ - dev->dp8390.RCR.errors_ok = ((val & 0x01) == 0x01); - dev->dp8390.RCR.runts_ok = ((val & 0x02) == 0x02); - dev->dp8390.RCR.broadcast = ((val & 0x04) == 0x04); - dev->dp8390.RCR.multicast = ((val & 0x08) == 0x08); - dev->dp8390.RCR.promisc = ((val & 0x10) == 0x10); - dev->dp8390.RCR.monitor = ((val & 0x20) == 0x20); - - /* Monitor bit is a little suspicious... */ - if (val & 0x20) wdlog(3, "%s: RCR write, monitor bit set!\n", - dev->name); - break; - - case 0x0d: /* TCR */ - /* Check reserved bits */ - if (val & 0xe0) wdlog(3, "%s: TCR write, reserved bits set\n", - dev->name); - - /* Test loop mode (not supported) */ - if (val & 0x06) { - dev->dp8390.TCR.loop_cntl = (val & 0x6) >> 1; - wdlog(3, "%s: TCR write, loop mode %d not supported\n", - dev->name, dev->dp8390.TCR.loop_cntl); - } - else { - dev->dp8390.TCR.loop_cntl = 0; - } - - /* Inhibit-CRC not supported. */ - if (val & 0x01) wdlog(3, - "%s: TCR write, inhibit-CRC not supported\n",dev->name); - - /* Auto-transmit disable very suspicious */ - if (val & 0x08) - { - wdlog(3, - "%s: TCR write, auto transmit disable not supported\n", - dev->name); - } - - /* Allow collision-offset to be set, although not used */ - dev->dp8390.TCR.coll_prio = ((val & 0x08) == 0x08); - break; - - case 0x0e: /* DCR */ - /* the loopback mode is not suppported yet */ - if (! (val & 0x08)) wdlog(3, - "%s: DCR write, loopback mode selected\n", dev->name); - - /* It is questionable to set longaddr and auto_rx, since - * they are not supported on the NE2000. Print a warning - * and continue. */ - if (val & 0x04) - wdlog(3, "%s: DCR write - LAS set ???\n", dev->name); - if (val & 0x10) - wdlog(3, "%s: DCR write - AR set ???\n", dev->name); - - /* Set other values. */ - dev->dp8390.DCR.wdsize = ((val & 0x01) == 0x01); - dev->dp8390.DCR.endian = ((val & 0x02) == 0x02); - dev->dp8390.DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ - dev->dp8390.DCR.loop = ((val & 0x08) == 0x08); - dev->dp8390.DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ - dev->dp8390.DCR.fifo_size = (val & 0x50) >> 5; - break; - - case 0x0f: /* IMR */ - /* Check for reserved bit */ - if (val & 0x80) - wdlog(3, "%s: IMR write, reserved bit set\n",dev->name); - - /* Set other values */ - dev->dp8390.IMR.rx_inte = ((val & 0x01) == 0x01); - dev->dp8390.IMR.tx_inte = ((val & 0x02) == 0x02); - dev->dp8390.IMR.rxerr_inte = ((val & 0x04) == 0x04); - dev->dp8390.IMR.txerr_inte = ((val & 0x08) == 0x08); - dev->dp8390.IMR.overw_inte = ((val & 0x10) == 0x10); - dev->dp8390.IMR.cofl_inte = ((val & 0x20) == 0x20); - dev->dp8390.IMR.rdma_inte = ((val & 0x40) == 0x40); - val2 = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - if (((val & val2) & 0x7f) == 0) - wd_interrupt(dev, 0); - else - wd_interrupt(dev, 1); - break; - - default: - wdlog(3, "%s: Page0 write, bad register 0x%02x\n", - dev->name, off); - break; - } -} - -/* Handle reads/writes to the first page of the DS8390 register file. */ -static uint8_t -page1_read(wd_t *dev, uint32_t off) -{ - wdlog(3, "%s: Page1 read from register 0x%02x\n", - dev->name, off); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - return(dev->dp8390.physaddr[off - 1]); - - case 0x07: /* CURR */ - wdlog(3, "%s: returning current page: 0x%02x\n", - dev->name, (dev->dp8390.curr_page)); - return(dev->dp8390.curr_page); - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - return(dev->dp8390.mchash[off - 8]); - - default: - wdlog(3, "%s: Page1 read register 0x%02x out of range\n", - dev->name, off); - return(0); - } -} - - -static void -page1_write(wd_t *dev, uint32_t off, uint8_t val) -{ - wdlog(3, "%s: Page1 write to register 0x%02x, value=0x%04x\n", - dev->name, off, val); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - dev->dp8390.physaddr[off - 1] = val; - if (off == 6) wdlog(3, - "%s: physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], - dev->dp8390.physaddr[2], dev->dp8390.physaddr[3], - dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); - break; - - case 0x07: /* CURR */ - dev->dp8390.curr_page = val; - break; - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - dev->dp8390.mchash[off - 8] = val; - break; - - default: - wdlog(3, "%s: Page1 write register 0x%02x out of range\n", - dev->name, off); - break; - } -} - -/* Handle reads/writes to the second page of the DS8390 register file. */ -static uint8_t -page2_read(wd_t *dev, uint32_t off) -{ - wdlog(3, "%s: Page2 read from register 0x%02x\n", - dev->name, off); - - switch(off) { - case 0x01: /* PSTART */ - return(dev->dp8390.page_start); - - case 0x02: /* PSTOP */ - return(dev->dp8390.page_stop); - - case 0x03: /* Remote Next-packet pointer */ - return(dev->dp8390.rempkt_ptr); - - case 0x04: /* TPSR */ - return(dev->dp8390.tx_page_start); - - case 0x05: /* Local Next-packet pointer */ - return(dev->dp8390.localpkt_ptr); - - case 0x06: /* Address counter (upper) */ - return(dev->dp8390.address_cnt >> 8); - - case 0x07: /* Address counter (lower) */ - return(dev->dp8390.address_cnt & 0xff); - - case 0x08: /* Reserved */ - case 0x09: - case 0x0a: - case 0x0b: - wdlog(3, "%s: reserved Page2 read - register 0x%02x\n", - dev->name, off); - return(0xff); - - case 0x0c: /* RCR */ - return ((dev->dp8390.RCR.monitor << 5) | - (dev->dp8390.RCR.promisc << 4) | - (dev->dp8390.RCR.multicast << 3) | - (dev->dp8390.RCR.broadcast << 2) | - (dev->dp8390.RCR.runts_ok << 1) | - (dev->dp8390.RCR.errors_ok)); - - case 0x0d: /* TCR */ - return ((dev->dp8390.TCR.coll_prio << 4) | - (dev->dp8390.TCR.ext_stoptx << 3) | - ((dev->dp8390.TCR.loop_cntl & 0x3) << 1) | - (dev->dp8390.TCR.crc_disable)); - - case 0x0e: /* DCR */ - return (((dev->dp8390.DCR.fifo_size & 0x3) << 5) | - (dev->dp8390.DCR.auto_rx << 4) | - (dev->dp8390.DCR.loop << 3) | - (dev->dp8390.DCR.longaddr << 2) | - (dev->dp8390.DCR.endian << 1) | - (dev->dp8390.DCR.wdsize)); - - case 0x0f: /* IMR */ - return ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - - default: - wdlog(3, "%s: Page2 register 0x%02x out of range\n", - dev->name, off); - break; - } - - return(0); -} - -#if 0 -static void -page2_write(wd_t *dev, uint32_t off, uint8_t val) -{ -/* Maybe all writes here should be BX_PANIC()'d, since they - affect internal operation, but let them through for now - and print a warning. */ - wdlog(3, "%s: Page2 write to register 0x%02x, value=0x%04x\n", - dev->name, off, val); - switch(off) { - case 0x01: /* CLDA0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.local_dma &= 0xff00; - dev->dp8390.local_dma |= (val & 0xff); - break; - - case 0x02: /* CLDA1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.local_dma &= 0x00ff; - dev->dp8390.local_dma |= ((val & 0xff) << 8); - break; - - case 0x03: /* Remote Next-pkt pointer */ - dev->dp8390.rempkt_ptr = val; - break; - - case 0x04: - wdlog(3, "page 2 write to reserved register 0x04\n"); - break; - - case 0x05: /* Local Next-packet pointer */ - dev->dp8390.localpkt_ptr = val; - break; - - case 0x06: /* Address counter (upper) */ - /* Clear out high byte and re-insert */ - dev->dp8390.address_cnt &= 0x00ff; - dev->dp8390.address_cnt |= ((val & 0xff) << 8); - break; - - case 0x07: /* Address counter (lower) */ - /* Clear out low byte and re-insert */ - dev->dp8390.address_cnt &= 0xff00; - dev->dp8390.address_cnt |= (val & 0xff); - break; - - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - wdlog(3, "%s: Page2 write to reserved register 0x%02x\n", - dev->name, off); - break; - - default: - wdlog(3, "%s: Page2 write, illegal register 0x%02x\n", - dev->name, off); - break; - } -} -#endif - -/* Routines for handling reads/writes to the Command Register. */ -static uint8_t -read_cr(wd_t *dev) -{ - uint32_t retval; - - retval = (((dev->dp8390.CR.pgsel & 0x03) << 6) | - ((dev->dp8390.CR.rdma_cmd & 0x07) << 3) | - (dev->dp8390.CR.tx_packet << 2) | - (dev->dp8390.CR.start << 1) | - (dev->dp8390.CR.stop)); - wdlog(3, "%s: read CR returns 0x%02x\n", dev->name, retval); - - return(retval); -} - -static void -write_cr(wd_t *dev, uint8_t val) -{ - wdlog(3, "%s: wrote 0x%02x to CR\n", dev->name, val); - - /* Validate remote-DMA */ - if ((val & 0x38) == 0x00) { - wdlog(3, "%s: CR write - invalid rDMA value 0\n", dev->name); - val |= 0x20; /* dma_cmd == 4 is a safe default */ - } - - /* Check for s/w reset */ - if (val & 0x01) { - dev->dp8390.ISR.reset = 1; - dev->dp8390.CR.stop = 1; - } else { - dev->dp8390.CR.stop = 0; - } - - dev->dp8390.CR.rdma_cmd = (val & 0x38) >> 3; - - /* If start command issued, the RST bit in the ISR */ - /* must be cleared */ - if ((val & 0x02) && !dev->dp8390.CR.start) - dev->dp8390.ISR.reset = 0; - - dev->dp8390.CR.start = ((val & 0x02) == 0x02); - dev->dp8390.CR.pgsel = (val & 0xc0) >> 6; - - /* Check for send-packet command */ - if (dev->dp8390.CR.rdma_cmd == 3) { - /* Set up DMA read from receive ring */ - dev->dp8390.remote_start = dev->dp8390.remote_dma = dev->dp8390.bound_ptr * 256; - dev->dp8390.remote_bytes = (uint16_t) wd_chipmem_read(dev, dev->dp8390.bound_ptr * 256 + 2, 2); - wdlog(2, "%s: sending buffer #x%x length %d\n", - dev->name, dev->dp8390.remote_start, dev->dp8390.remote_bytes); - } - - /* Check for start-tx */ - if ((val & 0x04) && dev->dp8390.TCR.loop_cntl) { - if (dev->dp8390.TCR.loop_cntl) { - wd_rx(dev, &dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], - dev->dp8390.tx_bytes); - } - } else if (val & 0x04) { - if (dev->dp8390.CR.stop) { - if (dev->dp8390.tx_bytes == 0) /* njh@bandsman.co.uk */ { - return; /* Solaris9 probe */ - } - wdlog(3, "%s: CR write - tx start, dev in reset\n", dev->name); - } - - if (dev->dp8390.tx_bytes == 0) - wdlog(3, "%s: CR write - tx start, tx bytes == 0\n", dev->name); - - /* Send the packet to the system driver */ - dev->dp8390.CR.tx_packet = 1; - - network_tx(dev->dp8390.mem, dev->dp8390.tx_bytes); - - wd_tx(dev, val); - } - - /* Linux probes for an interrupt by setting up a remote-DMA read - * of 0 bytes with remote-DMA completion interrupts enabled. - * Detect this here */ - if (dev->dp8390.CR.rdma_cmd == 0x01 && dev->dp8390.CR.start && dev->dp8390.remote_bytes == 0) { - dev->dp8390.ISR.rdma_done = 1; - if (dev->dp8390.IMR.rdma_inte) { - wd_interrupt(dev, 1); - wd_interrupt(dev, 0); - } - } -} - static uint8_t wd_readb(uint16_t addr, void *priv) { - wd_t *dev = (wd_t *)priv; - - uint8_t retval = 0; + wd_t *dev = (wd_t *) priv; + + return(wd_read(addr, dev, 1)); +} + + +static uint16_t +wd_readw(uint16_t addr, void *priv) +{ + wd_t *dev = (wd_t *) priv; + + return(wd_read(addr, dev, 2)); +} + + +static void +wd_write(uint16_t addr, uint8_t val, void *priv, unsigned int len) +{ + wd_t *dev = (wd_t *)priv; int off = addr - dev->base_address; - wdlog(3, "%s: read addr %x\n", dev->name, addr); + wdlog("%s: write addr %x, value %x\n", dev->name, addr, val); - if (off == 0x10) - { - retval = read_cr(dev); - } - else if (off >= 0x00 && off <= 0x0f) - { - retval = wd_smc_read(dev, off); - } - else - { - switch(dev->dp8390.CR.pgsel) { + if (off == 0x10) + dp8390_write_cr(dev->dp8390, val); + else if ((off >= 0x00) && (off <= 0x0f)) + wd_smc_write(dev, off, val); + else { + switch(dev->dp8390->CR.pgsel) { case 0x00: - retval = page0_read(dev, off - 0x10); + dp8390_page0_write(dev->dp8390, off - 0x10, val, len); break; - case 0x01: - retval = page1_read(dev, off - 0x10); + dp8390_page1_write(dev->dp8390, off - 0x10, val, len); break; - - case 0x02: - retval = page2_read(dev, off - 0x10); - break; - default: - wdlog(3, "%s: unknown value of pgsel in read - %d\n", - dev->name, dev->dp8390.CR.pgsel); + wdlog("%s: unknown value of pgsel in write - %d\n", + dev->name, dev->dp8390->CR.pgsel); break; - } - } - - return(retval); + } + } } static void wd_writeb(uint16_t addr, uint8_t val, void *priv) { - wd_t *dev = (wd_t *)priv; - int off = addr - dev->base_address; - - wdlog(3, "%s: write addr %x, value %x\n", dev->name, addr, val); - - if (off == 0x10) - { - write_cr(dev, val); - } - else if (off >= 0x00 && off <= 0x0f) - { - wd_smc_write(dev, off, val); - } - else - { - switch(dev->dp8390.CR.pgsel) { - case 0x00: - page0_write(dev, off - 0x10, val); - break; - - case 0x01: - page1_write(dev, off - 0x10, val); - break; - - default: - wdlog(3, "%s: unknown value of pgsel in write - %d\n", - dev->name, dev->dp8390.CR.pgsel); - break; - } - } + wd_write(addr, val, priv, 1); } -static void wd_ioset(wd_t *dev, uint16_t addr); -static void wd_ioremove(wd_t *dev, uint16_t addr); static void -wd_ioset(wd_t *dev, uint16_t addr) +wd_writew(uint16_t addr, uint16_t val, void *priv) +{ + wd_write(addr, val & 0xff, priv, 2); +} + + +static void +wd_io_set(wd_t *dev, uint16_t addr) { + if (dev->bit16) { io_sethandler(addr, 0x20, - wd_readb, NULL, NULL, - wd_writeb, NULL, NULL, dev); + wd_readb, wd_readw, NULL, + wd_writeb, wd_writew, NULL, dev); + } else { + io_sethandler(addr, 0x20, + wd_readb, NULL, NULL, + wd_writeb, NULL, NULL, dev); + } } + static void -wd_ioremove(wd_t *dev, uint16_t addr) +wd_io_remove(wd_t *dev, uint16_t addr) { + if (dev->bit16) { + io_removehandler(addr, 0x20, + wd_readb, wd_readw, NULL, + wd_writeb, wd_writew, NULL, dev); + } else { io_removehandler(addr, 0x20, wd_readb, NULL, NULL, wd_writeb, NULL, NULL, dev); + } } -/* - * Called by the platform-specific code when an Ethernet frame - * has been received. The destination address is tested to see - * if it should be accepted, and if the RX ring has enough room, - * it is copied into it and the receive process is updated. - */ -static void -wd_rx(void *priv, uint8_t *buf, int io_len) -{ - static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; - wd_t *dev = (wd_t *)priv; - uint8_t pkthdr[4]; - uint8_t *startptr; - int pages, avail; - int idx, nextpage; - int endbytes; - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 1); - - if (io_len != 60) - wdlog(2, "%s: rx_frame with length %d\n", dev->name, io_len); - - if ((dev->dp8390.CR.stop != 0) || (dev->dp8390.page_start == 0)) return; - - /* - * Add the pkt header + CRC to the length, and work - * out how many 256-byte pages the frame would occupy. - */ - pages = (io_len + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; - if (dev->dp8390.curr_page < dev->dp8390.bound_ptr) { - avail = dev->dp8390.bound_ptr - dev->dp8390.curr_page; - } else { - avail = (dev->dp8390.page_stop - dev->dp8390.page_start) - - (dev->dp8390.curr_page - dev->dp8390.bound_ptr); - } - - /* - * Avoid getting into a buffer overflow condition by - * not attempting to do partial receives. The emulation - * to handle this condition seems particularly painful. - */ - if ((avail < pages) -#if NE2K_NEVER_FULL_RING - || (avail == pages) -#endif - ) { - wdlog(1, "%s: no space\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - if ((io_len < 40/*60*/) && !dev->dp8390.RCR.runts_ok) { - wdlog(1, "%s: rejected small packet, length %d\n", dev->name, io_len); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Some computers don't care... */ - if (io_len < 60) - io_len = 60; - - wdlog(2, "%s: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", - dev->name, - buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], - io_len); - - /* Do address filtering if not in promiscuous mode. */ - if (! dev->dp8390.RCR.promisc) { - /* If this is a broadcast frame.. */ - if (! memcmp(buf, bcast_addr, 6)) { - /* Broadcast not enabled, we're done. */ - if (! dev->dp8390.RCR.broadcast) { - wdlog(2, "%s: RX BC disabled\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* If this is a multicast frame.. */ - else if (buf[0] & 0x01) { - /* Multicast not enabled, we're done. */ - if (! dev->dp8390.RCR.multicast) { -#if 1 - wdlog(2, "%s: RX MC disabled\n", dev->name); -#endif - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Are we listening to this multicast address? */ - idx = mcast_index(buf); - if (! (dev->dp8390.mchash[idx>>3] & (1<<(idx&0x7)))) { - wdlog(2, "%s: RX MC not listed\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* Unicast, must be for us.. */ - else if (memcmp(buf, dev->dp8390.physaddr, 6)) return; - } else { - wdlog(2, "%s: RX promiscuous receive\n", dev->name); - } - - nextpage = dev->dp8390.curr_page + pages; - if (nextpage >= dev->dp8390.page_stop) - nextpage -= (dev->dp8390.page_stop - dev->dp8390.page_start); - - /* Set up packet header. */ - pkthdr[0] = 0x01; /* RXOK - packet is OK */ - pkthdr[1] = nextpage; /* ptr to next packet */ - pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ - pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ - wdlog(2, "%s: RX pkthdr [%02x %02x %02x %02x]\n", - dev->name, pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); - - /* Copy into buffer, update curpage, and signal interrupt if config'd */ - startptr = dev->dp8390.mem + (dev->dp8390.curr_page * 256); - memcpy(startptr, pkthdr, sizeof(pkthdr)); - if ((nextpage > dev->dp8390.curr_page) || - ((dev->dp8390.curr_page + pages) == dev->dp8390.page_stop)) { - memcpy(startptr+sizeof(pkthdr), buf, io_len); - } else { - endbytes = (dev->dp8390.page_stop - dev->dp8390.curr_page) * 256; - memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); - startptr = dev->dp8390.mem + (dev->dp8390.page_start * 256); - memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); - } - dev->dp8390.curr_page = nextpage; - - dev->dp8390.RSR.rx_ok = 1; - dev->dp8390.RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; - dev->dp8390.ISR.pkt_rx = 1; - - if (dev->dp8390.IMR.rx_inte) - wd_interrupt(dev, 1); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); -} - -static void -wd_tx(wd_t *dev, uint32_t val) -{ - dev->dp8390.CR.tx_packet = 0; - dev->dp8390.TSR.tx_ok = 1; - dev->dp8390.ISR.pkt_tx = 1; - - /* Generate an interrupt if not masked */ - if (dev->dp8390.IMR.tx_inte) - wd_interrupt(dev, 1); - dev->dp8390.tx_timer_active = 0; -} static uint8_t wd_mca_read(int port, void *priv) @@ -1349,14 +530,15 @@ wd_mca_read(int port, void *priv) return(dev->pos_regs[port & 7]); } -#define MCA_61C8_IRQS { 3, 4, 10, 15 } + +#define MCA_61C8_IRQS { 3, 4, 10, 14 } + static void wd_mca_write(int port, uint8_t val, void *priv) { wd_t *dev = (wd_t *)priv; - int8_t irq[4] = MCA_61C8_IRQS; - uint32_t ram_size = 0; + int8_t irq[4] = MCA_61C8_IRQS; /* MCA does not write registers below 0x0100. */ if (port < 0x0102) return; @@ -1364,16 +546,6 @@ wd_mca_write(int port, uint8_t val, void *priv) /* Save the MCA register value. */ dev->pos_regs[port & 7] = val; - wd_ioremove(dev, dev->base_address); - - dev->base_address = 0x800 + (((dev->pos_regs[2] & 0xf0) >> 4) * 0x1000); - - dev->ram_addr = 0xC0000 + ((dev->pos_regs[3] & 0x0f) * 0x2000) + ((dev->pos_regs[3] & 0x80) ? 0xF00000 : 0); - - dev->base_irq = irq[(dev->pos_regs[5] & 0x0c) >> 2]; - - ram_size = (dev->pos_regs[3] & 0x10) ? 0x4000 : 0x2000; - /* * The PS/2 Model 80 BIOS always enables a card if it finds one, * even if no resources were assigned yet (because we only added @@ -1381,35 +553,46 @@ wd_mca_write(int port, uint8_t val, void *priv) * * So, remove current address, if any. */ + wd_io_remove(dev, dev->base_address); + + dev->base_address = 0x800 + ((dev->pos_regs[2] & 0xf0) << 8); + + dev->ram_addr = (dev->pos_regs[3] & 0x0f); + dev->ram_addr <<= 13; + dev->ram_addr |= 0xC0000; + if (dev->pos_regs[3] & 0x80) { + dev->ram_size = 0x4000; + dev->ram_addr |= 0xF00000; + } else { + if (dev->pos_regs[3] & 0x10) + dev->ram_size = 0x2000; + else + dev->ram_size = 0x4000; + } + + dev->base_irq = irq[(dev->pos_regs[5] & 0x0c) >> 2]; /* Initialize the device if fully configured. */ if (dev->pos_regs[2] & 0x01) { /* Card enabled; register (new) I/O handler. */ - - wd_ioset(dev, dev->base_address); - - wd_reset(dev); - - mem_mapping_add(&dev->ram_mapping, dev->ram_addr, ram_size, - wd_ram_readb, wd_ram_readw, wd_ram_readl, - wd_ram_writeb, wd_ram_writew, wd_ram_writel, - NULL, MEM_MAPPING_EXTERNAL, dev); - - mem_mapping_disable(&dev->ram_mapping); - - wdlog(1, "%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, - dev->base_address, dev->base_irq, dev->ram_addr); + wd_io_set(dev, dev->base_address); + + mem_mapping_set_addr(&dev->ram_mapping, dev->ram_addr, dev->ram_size); + mem_mapping_disable(&dev->ram_mapping); + + wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, + dev->base_address, dev->base_irq, dev->ram_addr); } } + static void * wd_init(const device_t *info) { uint32_t mac; wd_t *dev; -#ifdef ENABLE_NIC_LOG int i; -#endif + uint8_t irq; /* Get the desired debug level. */ #ifdef ENABLE_NIC_LOG @@ -1421,51 +604,14 @@ wd_init(const device_t *info) memset(dev, 0x00, sizeof(wd_t)); dev->name = info->name; dev->board = info->local; - - switch(dev->board) { - case WD8003E: - dev->board_chip = WE_TYPE_WD8003E; - dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ - dev->maclocal[1] = 0x00; - dev->maclocal[2] = 0xC0; - break; - - case WD8013EBT: - dev->board_chip = WE_TYPE_WD8013EBT; - dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ - dev->maclocal[1] = 0x00; - dev->maclocal[2] = 0xC0; - break; - case WD8013EPA: - dev->board_chip = WE_TYPE_WD8013EP | 0x80; - dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ - dev->maclocal[1] = 0x00; - dev->maclocal[2] = 0xC0; - dev->pos_regs[0] = 0xC8; - dev->pos_regs[1] = 0x61; - break; - } - - if (dev->board != WD8013EPA) { - dev->base_address = device_get_config_hex16("base"); - dev->base_irq = device_get_config_int("irq"); - dev->ram_addr = device_get_config_hex20("ram_addr"); - } - else { - mca_add(wd_mca_read, wd_mca_write, dev); - } + dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0xC0; /* See if we have a local MAC address configured. */ mac = device_get_config_mac("mac", -1); - /* - * Make this device known to the I/O system. - * PnP and PCI devices start with address spaces inactive. - */ - if (dev->board != WD8013EPA) - wd_ioset(dev, dev->base_address); - /* Set up our BIA. */ if (mac & 0xff000000) { /* Generate new local MAC. */ @@ -1481,32 +627,87 @@ wd_init(const device_t *info) dev->maclocal[4] = (mac>>8) & 0xff; dev->maclocal[5] = (mac & 0xff); } - memcpy(dev->dp8390.physaddr, dev->maclocal, sizeof(dev->maclocal)); - wdlog(0, "%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, dev->base_address, dev->base_irq, - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], dev->dp8390.physaddr[2], - dev->dp8390.physaddr[3], dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); + if (dev->board == WD8013EPA) + mca_add(wd_mca_read, wd_mca_write, dev); + else { + dev->base_address = device_get_config_hex16("base"); + dev->base_irq = device_get_config_int("irq"); + dev->ram_addr = device_get_config_hex20("ram_addr"); + } + + dev->dp8390 = device_add(&dp8390_device); + dev->dp8390->priv = dev; + dev->dp8390->interrupt = wd_interrupt; + + switch(dev->board) { + case WD8003E: + dev->board_chip = WE_TYPE_WD8003E; + dev->ram_size = 0x2000; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CLEAR_IRQ | DP8390_FLAG_NO_CHIPMEM); + break; + + case WD8013EBT: + dev->board_chip = WE_TYPE_WD8013EBT; + dev->ram_size = 0x4000; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CLEAR_IRQ | DP8390_FLAG_NO_CHIPMEM); + irq = 255; + for (i = 0; i < 8; i++) { + if (we_int_table[i] == dev->base_irq) + irq = i; + } + if (irq != 255) { + dev->reg4 = (irq & 0x03) << 5; + dev->reg1 = irq & 0x04; + } + + dev->bit16 = 1; + break; + + case WD8013EPA: + dev->board_chip = WE_TYPE_WD8013EP | 0x80; + dev->ram_size = 0x4000; + dev->pos_regs[0] = 0xC8; + dev->pos_regs[1] = 0x61; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CLEAR_IRQ | DP8390_FLAG_NO_CHIPMEM); + dev->bit16 = 1; + break; + } + + if (dev->base_address) + wd_io_set(dev, dev->base_address); + + memcpy(dev->dp8390->physaddr, dev->maclocal, sizeof(dev->maclocal)); + + wdlog("%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, dev->base_address, dev->base_irq, + dev->dp8390->physaddr[0], dev->dp8390->physaddr[1], dev->dp8390->physaddr[2], + dev->dp8390->physaddr[3], dev->dp8390->physaddr[4], dev->dp8390->physaddr[5]); /* Reset the board. */ - if (dev->board != WD8013EPA) - wd_reset(dev); + wd_reset(dev); + + /* Map this system into the memory map. */ + if (dev->bit16) { + mem_mapping_add(&dev->ram_mapping, dev->ram_addr, dev->ram_size, + wd_ram_readb, wd_ram_readw, NULL, + wd_ram_writeb, wd_ram_writew, NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + } else { + mem_mapping_add(&dev->ram_mapping, dev->ram_addr, dev->ram_size, + wd_ram_readb, NULL, NULL, + wd_ram_writeb, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + } + mem_mapping_disable(&dev->ram_mapping); /* Attach ourselves to the network module. */ - network_attach(dev, dev->dp8390.physaddr, wd_rx); - - /* Map this system into the memory map. */ - if (dev->board != WD8013EPA) - { - mem_mapping_add(&dev->ram_mapping, dev->ram_addr, 0x4000, - wd_ram_readb, NULL, NULL, - wd_ram_writeb, NULL, NULL, - NULL, MEM_MAPPING_EXTERNAL, dev); - mem_mapping_disable(&dev->ram_mapping); - - wdlog(1, "%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, - dev->base_address, dev->base_irq, dev->ram_addr); - } + network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx); + + if (dev->board != WD8013EPA) { + wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, + dev->base_address, dev->base_irq, dev->ram_addr); + } return(dev); } @@ -1517,16 +718,12 @@ wd_close(void *priv) { wd_t *dev = (wd_t *)priv; - /* Make sure the platform layer is shut down. */ - network_close(); - - wd_ioremove(dev, dev->base_address); - - wdlog(1, "%s: closed\n", dev->name); + wdlog("%s: closed\n", dev->name); free(dev); } + static const device_config_t wd8003_config[] = { { @@ -1629,10 +826,10 @@ static const device_config_t wd8013_config[] = "irq", "IRQ", CONFIG_SELECTION, "", 3, { { - "IRQ 2", 2 + "IRQ 3", 3 }, { - "IRQ 3", 3 + "IRQ 4", 4 }, { "IRQ 5", 5 @@ -1640,6 +837,9 @@ static const device_config_t wd8013_config[] = { "IRQ 7", 7 }, + { + "IRQ 9", 9 + }, { "IRQ 10", 10 }, @@ -1698,6 +898,7 @@ static const device_config_t mca_mac_config[] = } }; + const device_t wd8003e_device = { "Western Digital WD8003E", DEVICE_ISA, diff --git a/src/network/network.c b/src/network/network.c index 025d9ee66..6f31476fc 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -12,7 +12,7 @@ * it should be malloc'ed and then linked to the NETCARD def. * Will be done later. * - * Version: @(#)network.c 1.0.7 2018/08/11 + * Version: @(#)network.c 1.0.8 2018/10/17 * * Author: Fred N. van Kempen, * @@ -116,22 +116,22 @@ static struct { #ifdef ENABLE_NETWORK_LOG int network_do_log = ENABLE_NETWORK_LOG; -#endif static void -network_log(const char *format, ...) +network_log(const char *fmt, ...) { -#ifdef ENABLE_NETWORK_LOG va_list ap; if (network_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define network_log(fmt, ...) +#endif void