From 01c410479b57b9fdcbc7fbd68b00ac9aec8766a3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 24 Sep 2025 15:16:59 +0200 Subject: [PATCH] RTL8019AS and ISA PnP fixes: fixes PNPODI.COM. RTL8019AS now detects the card but thinks there's an IRQ conflict. --- src/device/isapnp.c | 60 ++++++++- src/include/86box/isapnp.h | 30 +++-- src/mem/nmc93cxx.c | 1 + src/network/net_dp8390.c | 2 +- src/network/net_ne2000.c | 256 +++++++++++++++++++++++++++++-------- 5 files changed, 274 insertions(+), 75 deletions(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 64f6a1d5f..675d9adf7 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -25,6 +25,7 @@ #include <86box/io.h> #include <86box/isapnp.h> #include <86box/plat_unused.h> +#include "cpu.h" #define CHECK_CURRENT_LD() \ if (!ld) { \ @@ -42,6 +43,11 @@ const uint8_t isapnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61, 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1, 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; +/* Required for the RTL8019AS. */ +const uint8_t isapnp_init_key2[32] = { 0xDA, 0x6D, 0x36, 0x1B, 0x8D, 0x46, 0x23, 0x91, + 0x48, 0xA4, 0xD2, 0x69, 0x34, 0x9A, 0x4D, 0x26, + 0x13, 0x89, 0x44, 0xA2, 0x51, 0x28, 0x94, 0xCA, + 0x65, 0x32, 0x19, 0x0C, 0x86, 0x43, 0xA1, 0x50 }; static const device_t isapnp_device; #ifdef ENABLE_ISAPNP_LOG @@ -85,11 +91,13 @@ typedef struct _isapnp_card_ { uint8_t enable; uint8_t state; uint8_t csn; + uint8_t csnsav; uint8_t ld; uint8_t id_checksum; uint8_t serial_read; uint8_t serial_read_pair; uint8_t serial_read_pos; + uint8_t is_rt; uint8_t *rom; uint16_t rom_pos; uint16_t rom_size; @@ -109,6 +117,7 @@ typedef struct _isapnp_card_ { typedef struct { uint8_t in_isolation; + uint8_t using_key2; uint8_t reg; uint8_t key_pos : 5; uint16_t read_data_addr; @@ -166,7 +175,7 @@ isapnp_device_config_changed(isapnp_card_t *card, isapnp_device_t *ld) } for (uint8_t i = 0; i < 8; i++) { reg_base = 0x60 + (2 * i); - if (ld->regs[0x31] & 0x02) + if (!(ld->regs[0x30] & 0x01) && (ld->regs[0x31] & 0x02)) card->config.io[i].base = 0; /* let us handle I/O range check reads */ else card->config.io[i].base = (ld->regs[reg_base] << 8) | ld->regs[reg_base + 1]; @@ -288,7 +297,7 @@ isapnp_read_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uint case 0x01: /* Serial Isolation */ card = dev->first_card; while (card) { - if (card->enable && card->rom && (card->state == PNP_STATE_ISOLATION)) + if (card->enable && (card->rom != NULL) && (card->state == PNP_STATE_ISOLATION)) break; card = card->next; } @@ -374,6 +383,7 @@ vendor_defined: default: if (reg >= 0x30) { + CHECK_CURRENT_CARD(); CHECK_CURRENT_LD(); isapnp_log("ISAPnP: Read register %02X from CSN %02X device %02X\n", reg, card->csn, ld->number); ret = ld->regs[reg]; @@ -397,7 +407,8 @@ isapnp_read_data(UNUSED(uint16_t addr), void *priv) card = card->next; } - isapnp_log("ISAPnP: read_data() => "); + // isapnp_log("ISAPnP: read_data() => "); + isapnp_log("[%04X:%08X] ISAPnP: read_data() => ", CS, cpu_state.pc); return isapnp_read_common(dev, card, dev->current_ld, dev->reg); } @@ -432,12 +443,14 @@ isapnp_write_addr(UNUSED(uint16_t addr), uint8_t val, void *priv) if (card->state == PNP_STATE_WAIT_FOR_KEY) { /* checking only the first card should be fine */ /* Check written value against LFSR key. */ - if (val == isapnp_init_key[dev->key_pos]) { + if ((val == isapnp_init_key[dev->key_pos]) || (val == isapnp_init_key2[dev->key_pos])) { + dev->using_key2 = (val == isapnp_init_key2[dev->key_pos]); dev->key_pos++; if (!dev->key_pos) { isapnp_log("ISAPnP: Key unlocked, putting cards to SLEEP\n"); while (card) { - if (card->enable && (card->enable != ISAPNP_CARD_NO_KEY) && (card->state == PNP_STATE_WAIT_FOR_KEY)) + int is_rt = (!dev->using_key2 || card->is_rt); + if (card->enable && is_rt && (card->enable != ISAPNP_CARD_NO_KEY) && (card->state == PNP_STATE_WAIT_FOR_KEY)) card->state = PNP_STATE_SLEEP; card = card->next; } @@ -493,6 +506,7 @@ isapnp_write_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uin card->state = PNP_STATE_WAIT_FOR_KEY; card = card->next; } + dev->key_pos = 0; } if (val & 0x04) { isapnp_log("ISAPnP: Reset CSN\n"); @@ -566,6 +580,20 @@ isapnp_write_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uin ld->regs[reg] = val & 0x01; isapnp_device_config_changed(card, ld); + for (uint8_t i = 0; i < 8; i++) { + if (!ld->io_len[i]) + continue; + + io_addr = (ld->regs[0x60 + (2 * i)] << 8) | ld->regs[0x61 + (2 * i)]; + if (val & 0x01) { + if (ld->regs[0x31] & 0x02) + io_removehandler(io_addr, ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, ld); + } else { + if (ld->regs[0x31] & 0x02) + io_sethandler(io_addr, ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, ld); + } + } + break; case 0x31: /* I/O Range Check */ @@ -578,7 +606,7 @@ isapnp_write_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uin io_addr = (ld->regs[0x60 + (2 * i)] << 8) | ld->regs[0x61 + (2 * i)]; if (ld->regs[reg] & 0x02) io_removehandler(io_addr, ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, ld); - if (val & 0x02) + if ((val & 0x02) && !(ld->regs[0x30] & 0x01)) io_sethandler(io_addr, ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, ld); } @@ -601,6 +629,7 @@ vendor_defined: default: if (reg >= 0x40) { + CHECK_CURRENT_CARD(); CHECK_CURRENT_LD(); isapnp_log("ISAPnP: Write %02X to register %02X on CSN %02X device %02X\n", val, reg, card->csn, ld->number); @@ -670,7 +699,8 @@ isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv) } } - isapnp_log("ISAPnP: write_data(%02X) => ", val); + // isapnp_log("ISAPnP: write_data(%02X) => ", val); + isapnp_log("[%04X:%08X] ISAPnP: write_data(%02X) => ", CS, cpu_state.pc, val); isapnp_write_common(dev, card, dev->current_ld, dev->reg, val); } @@ -1163,6 +1193,22 @@ isapnp_read_reg(void *priv, uint8_t ldn, uint8_t reg) return isapnp_read_common(device_get_priv(&isapnp_device), card, ld, reg); } +void +isapnp_set_rt(void *priv, uint8_t is_rt) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + + card->is_rt = is_rt; +} + +uint8_t * +isapnp_get_csnsav(void *priv) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + + return &card->csnsav; +} + void isapnp_write_reg(void *priv, uint8_t ldn, uint8_t reg, uint8_t val) { diff --git a/src/include/86box/isapnp.h b/src/include/86box/isapnp.h index 6f7eb1185..2ffbd2d66 100644 --- a/src/include/86box/isapnp.h +++ b/src/include/86box/isapnp.h @@ -57,19 +57,21 @@ typedef struct isapnp_device_config_t { extern const uint8_t isapnp_init_key[32]; -void *isapnp_add_card(uint8_t *rom, uint16_t rom_size, - void (*config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv), - void (*csn_changed)(uint8_t csn, void *priv), - uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv), - void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv), - void *priv); -void isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size); -void isapnp_enable_card(void *priv, uint8_t enable); -void isapnp_set_csn(void *priv, uint8_t csn); -uint8_t isapnp_read_reg(void *priv, uint8_t ldn, uint8_t reg); -void isapnp_write_reg(void *priv, uint8_t ldn, uint8_t reg, uint8_t val); -void isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config); -void isapnp_reset_card(void *priv); -void isapnp_reset_device(void *priv, uint8_t ld); +extern void *isapnp_add_card(uint8_t *rom, uint16_t rom_size, + void (*config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv), + void (*csn_changed)(uint8_t csn, void *priv), + uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv), + void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv), + void *priv); +extern void isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size); +extern void isapnp_enable_card(void *priv, uint8_t enable); +extern void isapnp_set_csn(void *priv, uint8_t csn); +extern uint8_t isapnp_read_reg(void *priv, uint8_t ldn, uint8_t reg); +extern void isapnp_write_reg(void *priv, uint8_t ldn, uint8_t reg, uint8_t val); +extern void isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config); +extern void isapnp_reset_card(void *priv); +extern void isapnp_reset_device(void *priv, uint8_t ld); +extern void isapnp_set_rt(void *priv, uint8_t is_rt); +extern uint8_t *isapnp_get_csnsav(void *priv); #endif /*EMU_ISAPNP_H*/ diff --git a/src/mem/nmc93cxx.c b/src/mem/nmc93cxx.c index 17d97591e..a0d24b872 100644 --- a/src/mem/nmc93cxx.c +++ b/src/mem/nmc93cxx.c @@ -29,6 +29,7 @@ #include <86box/nmc93cxx.h> #include <86box/plat_unused.h> +#define ENABLE_NMC93CXX_EEPROM_LOG 3 #ifdef ENABLE_NMC93CXX_EEPROM_LOG int nmc93cxx_eeprom_do_log = ENABLE_NMC93CXX_EEPROM_LOG; diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index 7f3490877..0bf3e9d3b 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -514,7 +514,7 @@ dp8390_page0_write(dp8390_t *dev, uint32_t off, uint32_t val, UNUSED(unsigned le { uint8_t val2; - dp8390_log("DP839: Page0 write to register 0x%02x, value=0x%02x\n", + dp8390_log("DP8390: Page0 write to register 0x%02x, value=0x%02x\n", off, val); switch (off) { diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 0ce0190ac..d7e4e28a0 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -65,6 +65,7 @@ #include <86box/network.h> #include <86box/net_dp8390.h> #include <86box/net_ne2000.h> +#include <86box/nmc93cxx.h> #include <86box/isapnp.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> @@ -85,25 +86,26 @@ typedef struct nic_t { const char *name; - uint8_t pnp_csnsav; uint8_t pci_slot; uint8_t irq_state; - uint8_t pad; + uint8_t csnsav; /* RTL8019AS/RTL8029AS registers */ uint8_t config0; + uint8_t config1; uint8_t config2; uint8_t config3; uint8_t _9346cr; uint8_t pci_regs[PCI_REGSIZE]; - uint8_t eeprom[128]; /* for RTL8029AS */ uint8_t maclocal[6]; /* configured MAC (local) address */ /* POS registers, MCA boards only */ uint8_t pos_regs[8]; + uint8_t eeprom_data[128]; + int board; int is_pci; int is_mca; @@ -121,6 +123,9 @@ typedef struct nic_t { rom_t bios_rom; void *pnp_card; + uint8_t *pnp_csnsav; + + nmc93cxx_eeprom_t *eeprom; } nic_t; #ifdef ENABLE_NE2K_LOG @@ -144,7 +149,11 @@ nelog(int lvl, const char *fmt, ...) static void nic_interrupt(void *priv, int set) { - nic_t *dev = (nic_t *) priv; + nic_t *dev = (nic_t *) priv; + int enabled = 1; + + if (dev->board == NE2K_RTL8019AS_PNP) + enabled = dev->config1 & 0x80; if (dev->is_pci) { if (set) @@ -152,9 +161,12 @@ nic_interrupt(void *priv, int set) else pci_clear_irq(dev->pci_slot, PCI_INTA, &dev->irq_state); } else { - if (set) - picint(1 << dev->base_irq); - else + if (enabled && (dev->base_irq != 0x02)) { + if (set) + picint(1 << dev->base_irq); + else + picintc(1 << dev->base_irq); + } else if (dev->base_irq != 0x02) picintc(1 << dev->base_irq); } } @@ -236,6 +248,7 @@ asic_read(nic_t *dev, uint32_t off, unsigned int len) /* If all bytes have been written, signal remote-DMA complete */ if (dev->dp8390->remote_bytes == 0) { + nelog(3, "%s: DMA read: done (%i)\n", dev->name, dev->dp8390->IMR.rdma_inte); dev->dp8390->ISR.rdma_done = 1; if (dev->dp8390->IMR.rdma_inte) nic_interrupt(dev, 1); @@ -262,6 +275,11 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) dev->name, (unsigned) off, (unsigned) val); switch (off) { + default: /* this is invalid, but happens under win95 device detection */ + nelog(3, "%s: ASIC write invalid address %04x, ignoring\n", + dev->name, (unsigned) off); + break; + case 0x00: /* Data register - see asic_read for a description */ if ((len > 1) && (dev->dp8390->DCR.wdsize == 0)) { nelog(3, "%s: DMA write length %d on byte mode operation\n", @@ -299,11 +317,6 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) case 0x0f: /* Reset register */ /* end of reset pulse */ break; - - default: /* this is invalid, but happens under win95 device detection */ - nelog(3, "%s: ASIC write invalid address %04x, ignoring\n", - dev->name, (unsigned) off); - break; } } @@ -311,59 +324,137 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) static uint32_t page3_read(nic_t *dev, uint32_t off, UNUSED(unsigned int len)) { + uint8_t ret = 0x00; + if (dev->board >= NE2K_RTL8019AS_PNP) switch (off) { - case 0x1: /* 9346CR */ - return (dev->_9346cr); + default: + break; - case 0x3: /* CONFIG0 */ - return 0x00; /* Cable not BNC */ + case 0x1: /* 9346CR */ + ret = (dev->_9346cr & 0xfe); + + if (((ret & 0xc0) == 0x80) && nmc93cxx_eeprom_read(dev->eeprom)) + ret |= 0x01; + break; + + case 0x3: /* CONFIG0 */ + if (dev->board == NE2K_RTL8019AS_PNP) + ret = (dev->config0 & 0xc0) | 0x10; /* Cable not BNC */ + else + ret = 0x00; /* Cable not BNC */ + break; + + case 0x4: /* CONFIG1 */ + if (dev->board == NE2K_RTL8019AS_PNP) + ret = dev->config1; + break; case 0x5: /* CONFIG2 */ - return (dev->config2 & 0xe0); + if (dev->board == NE2K_RTL8019AS_PNP) + ret = dev->config2; + else + ret = (dev->config2 & 0xe0); + break; case 0x6: /* CONFIG3 */ - return (dev->config3 & 0x46); + if (dev->board == NE2K_RTL8019AS_PNP) + ret = dev->config3; + else + ret = (dev->config3 & 0x46); + break; case 0x8: /* CSNSAV */ - return ((dev->board == NE2K_RTL8019AS_PNP) ? dev->pnp_csnsav : 0x00); + ret = ((dev->board == NE2K_RTL8019AS_PNP) ? *dev->pnp_csnsav : 0x00); + break; + + case 0xb: /* INTR */ + if (dev->board == NE2K_RTL8019AS_PNP) { + ret = (pic2.irr & 0x02) ? 0x01 : 0x00; + ret |= (pic.irr & 0x08) ? 0x02 : 0x00; + ret |= (pic.irr & 0x10) ? 0x04 : 0x00; + ret |= (pic.irr & 0x20) ? 0x08 : 0x00; + ret |= (pic2.irr & 0x04) ? 0x10 : 0x00; + ret |= (pic2.irr & 0x08) ? 0x20 : 0x00; + ret |= (pic2.irr & 0x10) ? 0x40 : 0x00; + ret |= (pic2.irr & 0x80) ? 0x80 : 0x00; + } + break; + + case 0xd: /* CONFIG4 */ + if (dev->board == NE2K_RTL8019AS_PNP) { + uint8_t *data = (uint8_t *) nmc93cxx_eeprom_data(dev->eeprom); + ret = data[0x03]; + } + break; case 0xe: /* 8029ASID0 */ if (dev->board == NE2K_RTL8029AS) - return 0x29; + ret = 0x29; break; case 0xf: /* 8029ASID1 */ if (dev->board == NE2K_RTL8029AS) - return 0x80; - break; - - default: + ret = 0x80; break; } - nelog(3, "%s: Page3 read register 0x%02x attempted\n", dev->name, off); - return 0x00; + nelog(3, "%s: Page3 read register 0x%02x, value=0x%04x\n", dev->name, off, ret); + return ret; } static void page3_write(nic_t *dev, uint32_t off, uint32_t val, UNUSED(unsigned len)) { + int cfg_write_enable = ((dev->_9346cr & 0xc0) == 0xc0); + if (dev->board >= NE2K_RTL8019AS_PNP) { - nelog(3, "%s: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", + nelog(3, "%s: Page3 write to register 0x%02x, len=%u, value=0x%04x\n", dev->name, off, len, val); switch (off) { case 0x01: /* 9346CR */ dev->_9346cr = (val & 0xfe); + if ((val & 0xc0) == 0x80) + nmc93cxx_eeprom_write(dev->eeprom, !!(val & 0x08), !!(val & 0x04), !!(val & 0x02)); + else if ((val & 0xc0) == 0x40) { + uint8_t *data = (uint8_t *) nmc93cxx_eeprom_data(dev->eeprom); + + data[0x00] = 0x80; + data[0x01] = 0x00; + data[0x02] = 0x80; + data[0x03] = 0x00; + + dev->_9346cr = 0x21; + } + break; + + case 0x03: /* CONFIG0 */ + if (cfg_write_enable && (dev->board == NE2K_RTL8019AS_PNP)) + dev->config0 = (val & 0xc0); + break; + + case 0x04: /* CONFIG1 */ + if (cfg_write_enable && (dev->board == NE2K_RTL8019AS_PNP)) + dev->config1 = (dev->config1 & 0x7f) | (val & 0x80); break; case 0x05: /* CONFIG2 */ - dev->config2 = (val & 0xe0); + if (cfg_write_enable) { + if (dev->board == NE2K_RTL8019AS_PNP) + dev->config2 = val; + else + dev->config2 = (val & 0xe0); + } break; case 0x06: /* CONFIG3 */ - dev->config3 = (val & 0x46); + if (cfg_write_enable) { + if (dev->board == NE2K_RTL8019AS_PNP) + dev->config3 = val; + else + dev->config3 = (val & 0x46); + } break; case 0x09: /* HLTCLK */ @@ -491,6 +582,10 @@ static void nic_ioremove(nic_t *dev, uint16_t addr); static void nic_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) { + uint8_t irq_map[16] = { 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x50, 0x60, 0x00, 0x00, 0x70 }; + uint8_t ios = 0x00; + if (ld) return; @@ -502,10 +597,22 @@ nic_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) } dev->base_address = config->io[0].base; - dev->base_irq = config->irq[0].irq; - if (config->activate && (dev->base_address != ISAPNP_IO_DISABLED)) + nic_interrupt(dev, 0); + dev->base_irq = config->irq[0].irq; + if ((dev->base_irq >= 0x00) && (dev->base_irq <= 0x0f)) + dev->config1 = (dev->config1 & 0x8f) | irq_map[dev->base_irq]; + else + dev->config1 = (dev->config1 & 0x8f); + + if (config->activate && (dev->base_address != ISAPNP_IO_DISABLED)) { nic_ioset(dev, dev->base_address); + ios |= (dev->base_address & 0x0100) ? 0x00 : 0x04; + ios |= (dev->base_address & 0x0080) ? 0x08 : 0x00; + ios |= (dev->base_address & 0x0040) ? 0x02 : 0x00; + ios |= (dev->base_address & 0x0020) ? 0x01 : 0x00; + dev->config1 = (dev->config1 & 0xf0) | ios; + } } static void @@ -513,7 +620,7 @@ nic_pnp_csn_changed(uint8_t csn, void *priv) { nic_t *dev = (nic_t *) priv; - dev->pnp_csnsav = csn; + *dev->pnp_csnsav = csn; } static uint8_t @@ -525,17 +632,21 @@ nic_pnp_read_vendor_reg(uint8_t ld, uint8_t reg, void *priv) const nic_t *dev = (nic_t *) priv; switch (reg) { - case 0xF0: - return dev->config0; + case 0xf0: /* CONFIG0 */ + return 0x00; /* Cable not BNC */ - case 0xF2: + case 0xf1: /* CONFIG1 */ + return dev->config1; + break; + + case 0xf2: /* CONFIG2 */ return dev->config2; - case 0xF3: + case 0xf3: /* CONFIG3 */ return dev->config3; - case 0xF5: - return dev->pnp_csnsav; + case 0xf5: + return *dev->pnp_csnsav; default: break; @@ -550,9 +661,9 @@ nic_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv) nic_t *dev = (nic_t *) priv; if ((ld == 0) && (reg == 0xf6) && (val & 0x04)) { - uint8_t csn = dev->pnp_csnsav; + uint8_t csn = *dev->pnp_csnsav; isapnp_set_csn(dev->pnp_card, 0); - dev->pnp_csnsav = csn; + *dev->pnp_csnsav = csn; } } @@ -913,6 +1024,7 @@ nic_init(const device_t *info) char *rom = NULL; nic_t *dev; int set_oui = 0; + int use_nvr = 0; dev = calloc(1, sizeof(nic_t)); dev->name = info->name; @@ -1144,26 +1256,33 @@ nic_init(const device_t *info) } /* Initialize the RTL80x9 EEPROM. */ - memset(dev->eeprom, 0x00, sizeof(dev->eeprom)); + memset(dev->eeprom_data, 0x00, sizeof(dev->eeprom_data)); if (dev->board == NE2K_RTL8029AS) { - memcpy(&dev->eeprom[0x02], dev->maclocal, 6); + dev->eeprom_data[0x00] = 0x00; + dev->eeprom_data[0x01] = 0x00; - dev->eeprom[0x76] = dev->eeprom[0x7A] = dev->eeprom[0x7E] = (PCI_DEVID & 0xff); - dev->eeprom[0x77] = dev->eeprom[0x7B] = dev->eeprom[0x7F] = (PCI_DEVID >> 8); - dev->eeprom[0x78] = dev->eeprom[0x7C] = (PCI_VENDID & 0xff); - dev->eeprom[0x79] = dev->eeprom[0x7D] = (PCI_VENDID >> 8); + memcpy(&dev->eeprom_data[0x02], dev->maclocal, 6); + + dev->eeprom_data[0x76] = dev->eeprom_data[0x7a] = dev->eeprom_data[0x7e] = (PCI_DEVID & 0xff); + dev->eeprom_data[0x77] = dev->eeprom_data[0x7b] = dev->eeprom_data[0x7f] = (PCI_DEVID >> 8); + dev->eeprom_data[0x78] = dev->eeprom_data[0x7c] = (PCI_VENDID & 0xff); + dev->eeprom_data[0x79] = dev->eeprom_data[0x7d] = (PCI_VENDID >> 8); + + use_nvr = 1; } else { const char *pnp_rom_file = NULL; int pnp_rom_len = 0x4a; switch (dev->board) { case NE2K_RTL8019AS_PNP: pnp_rom_file = "roms/network/rtl8019as/RTL8019A.BIN"; + use_nvr = 1; break; case NE2K_DE220P: pnp_rom_file = "roms/network/de220p/dlk2201a.bin"; - pnp_rom_len = 0x43; + pnp_rom_len = 0x43; + use_nvr = 1; break; default: @@ -1174,8 +1293,8 @@ nic_init(const device_t *info) if (pnp_rom_file) { FILE *fp = rom_fopen(pnp_rom_file, "rb"); if (fp) { - if (fread(&dev->eeprom[0x12], 1, pnp_rom_len, fp) == pnp_rom_len) - pnp_rom = &dev->eeprom[0x12]; + if (fread(&dev->eeprom_data[0x12], 1, pnp_rom_len, fp) == pnp_rom_len) + pnp_rom = &dev->eeprom_data[0x12]; fclose(fp); } } @@ -1183,10 +1302,22 @@ nic_init(const device_t *info) switch (info->local) { case NE2K_RTL8019AS_PNP: case NE2K_DE220P: - dev->pnp_card = isapnp_add_card(pnp_rom, pnp_rom_len, - nic_pnp_config_changed, nic_pnp_csn_changed, - nic_pnp_read_vendor_reg, nic_pnp_write_vendor_reg, - dev); + dev->pnp_card = isapnp_add_card(pnp_rom, pnp_rom_len, + nic_pnp_config_changed, nic_pnp_csn_changed, + nic_pnp_read_vendor_reg, nic_pnp_write_vendor_reg, + dev); + dev->pnp_csnsav = isapnp_get_csnsav(dev->pnp_card); + dev->config0 = 0x00; + dev->config1 = 0x80; + dev->config2 = 0x00; + dev->config3 = 0x80; + isapnp_set_rt(dev->pnp_card, 1); + + dev->eeprom_data[0x00] = 0x80; + dev->eeprom_data[0x01] = 0x00; + dev->eeprom_data[0x02] = 0x80; + dev->eeprom_data[0x03] = 0x01; + memcpy(&dev->eeprom_data[0x04], dev->maclocal, 6); break; default: @@ -1195,6 +1326,25 @@ nic_init(const device_t *info) } } + if (use_nvr) { + nmc93cxx_eeprom_params_t params; + char filename[1024] = { 0 }; + + params.nwords = 64; + params.default_content = (uint16_t *) dev->eeprom_data; + params.filename = filename; + int inst = device_get_instance(); + snprintf(filename, sizeof(filename), "nmc93cxx_eeprom_%s_%d.nvr", info->internal_name, inst); + dev->eeprom = device_add_inst_params(&nmc93cxx_device, inst, ¶ms); + if (dev->eeprom == NULL) { + free(dev); + return NULL; + } + } + + if (dev->pnp_csnsav == NULL) + dev->pnp_csnsav = &dev->csnsav; + if (dev->board != NE2K_ETHERNEXT_MC) /* Reset the board. */ nic_reset(dev);