diff --git a/src/device.c b/src/device.c index 09f522867..8f3e153bc 100644 --- a/src/device.c +++ b/src/device.c @@ -423,8 +423,9 @@ device_get_name(const device_t *d, int bus, char *name) fbus = strstr(tname, sbus); if (fbus == tname) strcat(name, tname + strlen(sbus) + 1); - /* Special case to not strip the "oPCI" from "Ensoniq AudioPCI". */ - else if ((fbus == NULL) || (*(fbus - 1) == 'o')) + /* Special case to not strip the "oPCI" from "Ensoniq AudioPCI" or + the "-ISA" from "AMD PCnet-ISA". */ + else if ((fbus == NULL) || (*(fbus - 1) == 'o') || (*(fbus - 1) == '-')) strcat(name, tname); else { strncat(name, tname, fbus - tname - 1); diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 74018cf4d..939b24df5 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -85,6 +85,7 @@ enum { typedef struct _isapnp_device_ { uint8_t number; uint8_t regs[256]; + uint8_t mem_upperlimit, irq_types, io_16bit; struct _isapnp_device_ *next; } isapnp_device_t; @@ -116,26 +117,28 @@ typedef struct { static void -isapnp_device_config_changed(isapnp_t *dev) +isapnp_device_config_changed(isapnp_card_t *card, isapnp_device_t *ld) { /* Ignore device if it hasn't signed up for configuration changes. */ - if (!dev->current_ld_card->config_changed) + if (!card->config_changed) return; /* Populate config structure, performing endianness conversion as needed. */ - isapnp_card_t *card = dev->current_ld_card; - isapnp_device_t *ld = dev->current_ld; card->config.activate = ld->regs[0x30] & 0x01; uint8_t i, reg_base; for (i = 0; i < 4; i++) { reg_base = 0x40 + (8 * i); card->config.mem[i].base = (ld->regs[reg_base] << 16) | (ld->regs[reg_base + 1] << 8); card->config.mem[i].size = (ld->regs[reg_base + 3] << 16) | (ld->regs[reg_base + 4] << 8); + if (ld->regs[reg_base + 2] & 0x01) /* upper limit */ + card->config.mem[i].size -= card->config.mem[i].base; } for (i = 0; i < 4; i++) { reg_base = (i == 0) ? 0x76 : (0x80 + (16 * i)); card->config.mem32[i].base = (ld->regs[reg_base] << 24) | (ld->regs[reg_base + 1] << 16) | (ld->regs[reg_base + 2] << 8) | ld->regs[reg_base + 3]; card->config.mem32[i].size = (ld->regs[reg_base + 5] << 24) | (ld->regs[reg_base + 6] << 16) | (ld->regs[reg_base + 7] << 8) | ld->regs[reg_base + 8]; + if (ld->regs[reg_base + 4] & 0x01) /* upper limit */ + card->config.mem32[i].size -= card->config.mem32[i].base; } for (i = 0; i < 8; i++) { reg_base = 0x60 + (2 * i); @@ -157,6 +160,36 @@ isapnp_device_config_changed(isapnp_t *dev) } +static void +isapnp_reset_ld_regs(isapnp_device_t *ld) +{ + memset(ld->regs, 0, sizeof(ld->regs)); + + /* DMA disable uses a non-zero value. */ + ld->regs[0x74] = ld->regs[0x75] = ISAPNP_DMA_DISABLED; + + /* Set the upper limit bit on memory ranges which require it. */ + uint8_t i; + for (i = 0; i < 4; i++) + ld->regs[0x42 + (8 * i)] |= !!(ld->mem_upperlimit & (1 << i)); + ld->regs[0x7a] |= !!(ld->mem_upperlimit & (1 << 4)); + for (i = 1; i < 4; i++) + ld->regs[0x84 + (16 * i)] |= !!(ld->mem_upperlimit & (1 << (4 + i))); + + /* Set the default IRQ type bits. */ + for (i = 0; i < 2; i++) { + if (ld->irq_types & (0x1 << (4 * i))) + ld->regs[0x70 + (2 * i)] = 0x02; + else if (ld->irq_types & (0x2 << (4 * i))) + ld->regs[0x70 + (2 * i)] = 0x00; + else if (ld->irq_types & (0x4 << (4 * i))) + ld->regs[0x70 + (2 * i)] = 0x03; + else if (ld->irq_types & (0x8 << (4 * i))) + ld->regs[0x70 + (2 * i)] = 0x01; + } +} + + static uint8_t isapnp_read_rangecheck(uint16_t addr, void *priv) { @@ -278,6 +311,8 @@ isapnp_read_data(uint16_t addr, void *priv) ret = card->read_vendor_reg(0, dev->reg, card->priv); break; + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: @@ -359,7 +394,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) isapnp_t *dev = (isapnp_t *) priv; isapnp_card_t *card; isapnp_device_t *ld; - uint16_t io_addr; + uint16_t io_addr, reset_cards = 0; isapnp_log("ISAPnP: write_data(%02X)\n", val); @@ -378,18 +413,21 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) while (card) { ld = card->first_ld; while (ld) { - memset(ld->regs, 0, sizeof(ld->regs)); - dev->current_ld = ld; - dev->current_ld_card = card; - isapnp_device_config_changed(dev); + if (card->state != PNP_STATE_WAIT_FOR_KEY) { + isapnp_reset_ld_regs(ld); + isapnp_device_config_changed(card, ld); + reset_cards++; + } ld = ld->next; } card = card->next; } - dev->current_ld = NULL; - dev->current_ld_card = NULL; - dev->isolated_card = NULL; + if (reset_cards != 0) { + dev->current_ld = NULL; + dev->current_ld_card = NULL; + dev->isolated_card = NULL; + } } if (val & 0x02) { isapnp_log("ISAPnP: Return to WAIT_FOR_KEY\n"); @@ -460,26 +498,8 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) ld = ld->next; } - if (!ld) { - isapnp_log("ISAPnP: Creating CSN %02X device %02X\n", card->csn, val); - - ld = (isapnp_device_t *) malloc(sizeof(isapnp_device_t)); - memset(ld, 0, sizeof(isapnp_device_t)); - - ld->number = val; - - dev->current_ld_card = card; - dev->current_ld = ld; - - if (!card->first_ld) { - card->first_ld = ld; - } else { - ld = card->first_ld; - while (ld->next) - ld = ld->next; - ld->next = dev->current_ld; - } - } + if (!ld) + fatal("ISAPnP: CSN %02X has no device %02X\n", card->csn, val); break; @@ -489,7 +509,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) isapnp_log("ISAPnP: Activate CSN %02X device %02X\n", dev->current_ld_card->csn, dev->current_ld->number); dev->current_ld->regs[dev->reg] = val & 0x01; - isapnp_device_config_changed(dev); + isapnp_device_config_changed(dev->current_ld_card, dev->current_ld); break; @@ -525,6 +545,8 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) card->write_vendor_reg(0, dev->reg, val, card->priv); break; + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: @@ -536,11 +558,40 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) break; default: - if (dev->reg >= 0x38) { + if (dev->reg >= 0x40) { CHECK_CURRENT_LD(); isapnp_log("ISAPnP: Write %02X to register %02X on CSN %02X device %02X\n", val, dev->reg, dev->current_ld_card->csn, dev->current_ld->number); + + switch (dev->reg) { + case 0x42: case 0x4a: case 0x52: case 0x5a: + case 0x7a: case 0x84: case 0x94: case 0xa4: + /* read-only memory range length / upper limit bit */ + val = (val & 0xfe) | (dev->current_ld->regs[dev->reg] & 0x01); + break; + + case 0x60: case 0x62: case 0x64: case 0x66: case 0x68: case 0x6a: case 0x6c: case 0x6e: + /* discard upper address bits if this I/O range can only decode 10-bit */ + if (!(dev->current_ld->io_16bit & (1 << ((dev->reg >> 1) & 0x07)))) + val &= 0x07; + break; + + case 0x71: case 0x73: + /* limit IRQ types to supported ones */ + if ((val & 0x01) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x0c : 0xc0))) /* level, not supported = force edge */ + val &= ~0x01; + else if (!(val & 0x01) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x03 : 0x30))) /* edge, not supported = force level */ + val |= 0x01; + + if ((val & 0x02) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x05 : 0x50))) /* high, not supported = force low */ + val &= ~0x02; + else if (!(val & 0x02) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x0a : 0xa0))) /* low, not supported = force high */ + val |= 0x02; + + break; + } + dev->current_ld->regs[dev->reg] = val; - isapnp_device_config_changed(dev); + isapnp_device_config_changed(dev->current_ld_card, dev->current_ld); } break; } @@ -604,14 +655,6 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, card->rom = rom; card->rom_size = rom_size; - - /* Populate descriptor checksum in ROM. */ - uint16_t checksum_offset = card->rom_size - 1; - card->rom[checksum_offset] = 0x00; - for (uint16_t i = 9; i < checksum_offset; i++) - card->rom[checksum_offset] += card->rom[i]; - card->rom[checksum_offset] = -card->rom[checksum_offset]; - card->priv = priv; card->config_changed = config_changed; card->csn_changed = csn_changed; @@ -621,12 +664,198 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, if (!dev->first_card) { dev->first_card = card; } else { - isapnp_card_t *current_card = dev->first_card; - while (current_card->next) - current_card = current_card->next; - current_card->next = card; + isapnp_card_t *prev_card = dev->first_card; + while (prev_card->next) + prev_card = prev_card->next; + prev_card->next = card; } + /* Parse resources in ROM to allocate logical devices, + and determine the state of read-only register bits. */ +#ifdef ENABLE_ISAPNP_LOG + uint16_t vendor = (card->rom[0] << 8) | card->rom[1]; + isapnp_log("ISAPnP: Parsing ROM resources for card %c%c%c%02X%02X (serial %08X)\n", '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[2], card->rom[3], (card->rom[7] << 24) | (card->rom[6] << 16) | (card->rom[5] << 8) | card->rom[4]); +#endif + uint16_t i = 9, j; + uint8_t ldn = 0, res, in_df = 0; + uint8_t irq = 0, io = 0, mem_range = 0, mem_range_32 = 0, irq_df = 0, io_df = 0, mem_range_df = 0, mem_range_32_df = 0; + uint32_t len; + isapnp_device_t *ld = NULL, *prev_ld = NULL; + + while (i < card->rom_size) { + if (card->rom[i] & 0x80) { /* large resource */ + res = card->rom[i] & 0x7f; + len = (card->rom[i + 2] << 8) | card->rom[i + 1]; + + switch (res) { + case 0x01: /* memory range */ + case 0x05: /* 32-bit memory range */ + if (res == 0x01) { + if (mem_range > 3) + fatal("ISAPnP: Memory descriptor overflow (%d)\n", mem_range); + + isapnp_log("ISAPnP: >>%s Memory range %d uses upper limit = ", in_df ? ">" : "", mem_range); + res = 1 << mem_range; + mem_range++; + } else { + if (mem_range_32 > 3) + fatal("ISAPnP: 32-bit memory descriptor overflow (%d)\n", mem_range_32); + + isapnp_log("ISAPnP: >>%s 32-bit memory range %d uses upper limit = ", in_df ? ">" : "", mem_range_32); + res = 1 << (4 + mem_range_32); + mem_range_32++; + } + + if (card->rom[i + 3] & 0x4) { + isapnp_log("yes\n"); + ld->mem_upperlimit |= res; + } else { + isapnp_log("no\n"); + ld->mem_upperlimit &= ~res; + } + + break; + +#ifdef ENABLE_ISAPNP_LOG + case 0x02: /* ANSI identifier */ + res = card->rom[i + 3 + len]; + card->rom[i + 3 + len] = '\0'; + isapnp_log("ISAPnP: >%s ANSI identifier: \"%s\"\n", ldn ? ">" : "", &card->rom[i + 3]); + card->rom[i + 3 + len] = res; + break; + + default: + isapnp_log("ISAPnP: >%s%s Large resource %02X (length %d)\n", ldn ? ">" : "", in_df ? ">" : "", res, (card->rom[i + 2] << 8) | card->rom[i + 1]); + break; +#endif + } + + i += 3; /* header */ + } else { /* small resource */ + res = (card->rom[i] >> 3) & 0x0f; + len = card->rom[i] & 0x07; + + switch (res) { + case 0x02: +#ifdef ENABLE_ISAPNP_LOG + vendor = (card->rom[i + 1] << 8) | card->rom[i + 2]; + isapnp_log("ISAPnP: > Logical device %02X: %c%c%c%02X%02X\n", ldn, '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[i + 3], card->rom[i + 4]); +#endif + + /* We're done with the previous logical device. */ + if (ld) { + prev_ld = ld; + isapnp_reset_ld_regs(ld); + } + + /* Create logical device. */ + ld = (isapnp_device_t *) malloc(sizeof(isapnp_device_t)); + memset(ld, 0, sizeof(isapnp_device_t)); + + ld->number = ldn++; + + if (prev_ld) + prev_ld->next = ld; + else + card->first_ld = ld; + + /* Start the position counts over. */ + irq = io = mem_range = mem_range_32 = irq_df = io_df = mem_range_df = mem_range_32_df = 0; + + break; + +#ifdef ENABLE_ISAPNP_LOG + case 0x03: /* compatible device ID */ + vendor = (card->rom[i + 1] << 8) | card->rom[i + 2]; + isapnp_log("ISAPnP: >> Compatible device ID: %c%c%c%02X%02X\n", '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[i + 3], card->rom[i + 4]); + break; +#endif + + case 0x04: /* IRQ */ + if (irq > 1) + fatal("ISAPnP: IRQ descriptor overflow (%d)\n", irq); + + if (len == 2) /* default */ + res = 0x01; /* high true edge sensitive */ + else /* specific */ + res = card->rom[i + 3] & 0x0f; + + isapnp_log("ISAPnP: >>%s IRQ index %d interrupt types = %01X\n", in_df ? ">" : "", irq, res); + + ld->irq_types &= ~(0x0f << (4 * irq)); + ld->irq_types |= res << (4 * irq); + + irq++; + + break; + + case 0x06: /* start dependent function */ + isapnp_log("ISAPnP: >> Start dependent function: %s\n", (((len == 0) || (card->rom[i + 1] == 1)) ? "acceptable" : ((card->rom[i + 1] == 0) ? "good" : ((card->rom[i + 1] == 2) ? "sub-optimal" : "unknown priority")))); + + if (in_df) { + /* We're in a dependent function and this is the next one starting. + Walk positions back to the saved values. */ + irq = irq_df; + io = io_df; + mem_range = mem_range_df; + mem_range_32 = mem_range_32_df; + } else { + /* Save current positions to restore at the next DF. */ + irq_df = irq; + io_df = io; + mem_range_df = mem_range; + mem_range_32_df = mem_range_32; + in_df = 1; + } + + break; + + case 0x07: /* end dependent function */ + isapnp_log("ISAPnP: >> End dependent function\n"); + in_df = 0; + break; + + case 0x08: /* I/O port */ + if (io > 7) + fatal("ISAPnP: I/O descriptor overflow (%d)\n", io); + + isapnp_log("ISAPnP: >>%s I/O range %d %d-bit decode\n", in_df ? ">" : "", io, (card->rom[i + 1] & 0x01) ? 16 : 10); + + if (card->rom[i + 1] & 0x01) + ld->io_16bit |= 1 << io; + else + ld->io_16bit &= ~(1 << io); + + io++; + + break; + + case 0x0f: /* end tag */ + /* Calculate checksum. */ + res = 0x00; + for (j = 9; j <= i; j++) + res += card->rom[j]; + card->rom[i + 1] = -res; + + isapnp_log("ISAPnP: End card resources (checksum %02X)\n", card->rom[i + 1]); + break; + +#ifdef ENABLE_ISAPNP_LOG + default: + isapnp_log("ISAPnP: >%s%s Small resource %02X (length %d)\n", ldn ? ">" : "", in_df ? ">" : "", res, card->rom[i] & 0x07); + break; +#endif + } + + i++; /* header */ + } + i += len; /* specified length */ + } + + /* We're done with the last logical device. */ + if (ld) + isapnp_reset_ld_regs(ld); + return card; } diff --git a/src/include/86box/net_pcnet.h b/src/include/86box/net_pcnet.h index cab123c83..651a62198 100644 --- a/src/include/86box/net_pcnet.h +++ b/src/include/86box/net_pcnet.h @@ -24,14 +24,16 @@ enum { DEV_AM79C960 = 1, /* PCnet-ISA (ISA, 10 Mbps, NE2100/NE1500T compatible) */ DEV_AM79C960_EB = 2, /* PCnet-ISA (ISA, 10 Mbps, Racal InterLan EtherBlaster compatible) */ DEV_AM79C960_VLB = 3, /* PCnet-VLB (VLB, 10 Mbps, NE2100/NE1500T compatible) */ - DEV_AM79C970A = 4, /* PCnet-PCI II (PCI, 10 Mbps) */ - DEV_AM79C973 = 5 /* PCnet-FAST III (PCI, 10/100 Mbps) */ + DEV_AM79C961 = 4, /* PCnet-ISA+ (ISA, 10 Mbps, NE2100/NE1500T compatible, Plug and Play) */ + DEV_AM79C970A = 5, /* PCnet-PCI II (PCI, 10 Mbps) */ + DEV_AM79C973 = 6 /* PCnet-FAST III (PCI, 10/100 Mbps) */ }; extern const device_t pcnet_am79c960_device; extern const device_t pcnet_am79c960_eb_device; extern const device_t pcnet_am79c960_vlb_device; +extern const device_t pcnet_am79c961_device; extern const device_t pcnet_am79c970a_device; extern const device_t pcnet_am79c973_device; diff --git a/src/include/86box/scsi_aha154x.h b/src/include/86box/scsi_aha154x.h index e7b3d62c0..ed9002ae7 100644 --- a/src/include/86box/scsi_aha154x.h +++ b/src/include/86box/scsi_aha154x.h @@ -5,6 +5,7 @@ extern const device_t aha154xa_device; extern const device_t aha154xb_device; extern const device_t aha154xc_device; extern const device_t aha154xcf_device; +extern const device_t aha154xcp_device; extern const device_t aha1640_device; extern void aha_device_reset(void *p); diff --git a/src/include/86box/scsi_x54x.h b/src/include/86box/scsi_x54x.h index 6c8164902..5cf541c24 100644 --- a/src/include/86box/scsi_x54x.h +++ b/src/include/86box/scsi_x54x.h @@ -367,6 +367,7 @@ typedef struct { #define X54X_LBA_BIOS 4 #define X54X_INT_GEOM_WRITABLE 8 #define X54X_MBX_24BIT 16 +#define X54X_ISAPNP 32 typedef struct { /* 32 bytes */ @@ -401,7 +402,8 @@ typedef struct { CmdBuf[128], DataBuf[65536], shadow_ram[128], - dma_buffer[128]; + dma_buffer[128], + cmd_33_buf[4096]; /* 16 bytes */ char *fw_rev; /* The 4 bytes of the revision command information + 2 extra bytes for BusLogic */ @@ -415,7 +417,11 @@ typedef struct { rom_ioaddr, /* offset in BIOS of I/O addr */ rom_shram, /* index to shared RAM */ rom_shramsz, /* size of shared RAM */ - rom_fwhigh; /* offset in BIOS of ver ID */ + rom_fwhigh, /* offset in BIOS of ver ID */ + pnp_len, /* length of the PnP ROM */ + pnp_offset, /* offset in the microcode ROM of the PnP ROM */ + cmd_33_len, /* length of the SCSISelect code decompressor program */ + cmd_33_offset; /* offset in the microcode ROM of the SCSISelect code decompressor program */ /* 16 + 20 + 52 = 88 bytes */ volatile int @@ -445,6 +451,7 @@ typedef struct { /* 8 bytes */ wchar_t *bios_path, /* path to BIOS image file */ + *mcode_path, /* path to microcode image file, needed by the AHA-1542CP */ *nvr_path; /* path to NVR image file */ /* 56 bytes */ diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 221696acc..3bb2a6496 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -126,6 +126,8 @@ typedef struct sb_t int pos; uint8_t pos_regs[8]; + + uint16_t opl_pnp_addr; } sb_t; extern void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p); diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index d655e78c8..64814221c 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -68,13 +68,6 @@ #include <86box/isapnp.h> -enum { - PNP_PHASE_WAIT_FOR_KEY = 0, - PNP_PHASE_CONFIG, - PNP_PHASE_ISOLATION, - PNP_PHASE_SLEEP -}; - /* ROM BIOS file paths. */ #define ROM_PATH_NE1000 L"roms/network/ne1000/ne1000.rom" #define ROM_PATH_NE2000 L"roms/network/ne2000/ne2000.rom" @@ -82,13 +75,25 @@ enum { #define ROM_PATH_RTL8029 L"roms/network/rtl8029as/rtl8029as.rom" /* PCI info. */ -#define PNP_VENDID 0x4a8c /* Realtek, Inc */ #define PCI_VENDID 0x10ec /* Realtek, Inc */ -#define PNP_DEVID 0x8019 /* RTL8029AS */ #define PCI_DEVID 0x8029 /* RTL8029AS */ #define PCI_REGSIZE 256 /* size of PCI space */ +static uint8_t rtl8019as_pnp_rom[] = { + 0x4a, 0x8c, 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, /* RTL8019, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ + 0x82, 0x22, 0x00, 'R', 'E', 'A', 'L', 'T', 'E', 'K', ' ', 'P', 'L', 'U', 'G', ' ', '&', ' ', 'P', 'L', 'A', 'Y', ' ', 'E', 'T', 'H', 'E', 'R', 'N', 'E', 'T', ' ', 'C', 'A', 'R', 'D', 0x00, /* ANSI identifier */ + + 0x16, 0x4a, 0x8c, 0x80, 0x19, 0x02, 0x00, /* logical device RTL8019 */ + 0x1c, 0x41, 0xd0, 0x80, 0xd6, /* compatible device PNP80D6 */ + 0x47, 0x00, 0x20, 0x02, 0x80, 0x03, 0x20, 0x20, /* I/O 0x220-0x380, decodes 10-bit, 32-byte alignment, 32 addresses */ + 0x23, 0x38, 0x9e, 0x01, /* IRQ 3/4/5/9/10/11/12/15, high true edge sensitive */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; + + typedef struct { dp8390_t *dp8390; const char *name; @@ -108,7 +113,6 @@ typedef struct { void *pnp_card; uint8_t pnp_activate; uint8_t pnp_csnsav; - uint64_t pnp_id; uint8_t maclocal[6]; /* configured MAC (local) address */ /* RTL8019AS/RTL8029AS registers */ @@ -933,8 +937,6 @@ nic_init(const device_t *info) #ifdef ENABLE_NIC_LOG int i; #endif - char *ansi_id = "REALTEK PLUG & PLAY ETHERNET CARD"; - uint64_t *eeprom_pnp_id; /* Get the desired debug level. */ #ifdef ENABLE_NIC_LOG @@ -1111,10 +1113,6 @@ nic_init(const device_t *info) /* Add device to the PCI bus, keep its slot number. */ dev->card = pci_add_card(PCI_ADD_NORMAL, nic_pci_read, nic_pci_write, dev); - } else { - dev->pnp_id = PNP_DEVID; - dev->pnp_id <<= 32LL; - dev->pnp_id |= PNP_VENDID; } /* Initialize the RTL8029 EEPROM. */ @@ -1128,63 +1126,15 @@ nic_init(const device_t *info) dev->eeprom[0x7E] = (PCI_DEVID&0xff); dev->eeprom[0x77] = dev->eeprom[0x7B] = - dev->eeprom[0x7F] = (dev->board == NE2K_RTL8019AS) ? (PNP_DEVID>>8) : (PCI_DEVID>>8); + dev->eeprom[0x7F] = (PCI_DEVID>>8); dev->eeprom[0x78] = dev->eeprom[0x7C] = (PCI_VENDID&0xff); dev->eeprom[0x79] = dev->eeprom[0x7D] = (PCI_VENDID>>8); } else { - eeprom_pnp_id = (uint64_t *) &dev->eeprom[0x12]; - *eeprom_pnp_id = dev->pnp_id; + memcpy(&dev->eeprom[0x12], rtl8019as_pnp_rom, sizeof(rtl8019as_pnp_rom)); - /* TAG: Plug and Play Version Number. */ - dev->eeprom[0x1B] = 0x0A; /* Item byte */ - dev->eeprom[0x1C] = 0x10; /* PnP version */ - dev->eeprom[0x1D] = 0x10; /* Vendor version */ - - /* TAG: ANSI Identifier String. */ - dev->eeprom[0x1E] = 0x82; /* Item byte */ - dev->eeprom[0x1F] = 0x22; /* Length bits 7-0 */ - dev->eeprom[0x20] = 0x00; /* Length bits 15-8 */ - memcpy(&dev->eeprom[0x21], ansi_id, 0x22); - - /* TAG: Logical Device ID. */ - dev->eeprom[0x43] = 0x16; /* Item byte */ - dev->eeprom[0x44] = 0x4A; /* Logical device ID0 */ - dev->eeprom[0x45] = 0x8C; /* Logical device ID1 */ - dev->eeprom[0x46] = 0x80; /* Logical device ID2 */ - dev->eeprom[0x47] = 0x19; /* Logical device ID3 */ - dev->eeprom[0x48] = 0x02; /* Flag0 (02=BROM/disabled) */ - dev->eeprom[0x49] = 0x00; /* Flag 1 */ - - /* TAG: Compatible Device ID (NE2000) */ - dev->eeprom[0x4A] = 0x1C; /* Item byte */ - dev->eeprom[0x4B] = 0x41; /* Compatible ID0 */ - dev->eeprom[0x4C] = 0xD0; /* Compatible ID1 */ - dev->eeprom[0x4D] = 0x80; /* Compatible ID2 */ - dev->eeprom[0x4E] = 0xD6; /* Compatible ID3 */ - - /* TAG: I/O Format */ - dev->eeprom[0x4F] = 0x47; /* Item byte */ - dev->eeprom[0x50] = 0x00; /* I/O information */ - dev->eeprom[0x51] = 0x20; /* Min. I/O base bits 7-0 */ - dev->eeprom[0x52] = 0x02; /* Min. I/O base bits 15-8 */ - dev->eeprom[0x53] = 0x80; /* Max. I/O base bits 7-0 */ - dev->eeprom[0x54] = 0x03; /* Max. I/O base bits 15-8 */ - dev->eeprom[0x55] = 0x20; /* Base alignment */ - dev->eeprom[0x56] = 0x20; /* Range length */ - - /* TAG: IRQ Format. */ - dev->eeprom[0x57] = 0x23; /* Item byte */ - dev->eeprom[0x58] = 0x38; /* IRQ mask bits 7-0 */ - dev->eeprom[0x59] = 0x9E; /* IRQ mask bits 15-8 */ - dev->eeprom[0x5A] = 0x01; /* IRQ information */ - - /* TAG: END Tag */ - dev->eeprom[0x5B] = 0x79; /* Item byte */ - /* Checksum is filled in by isapnp_add_card */ - - dev->pnp_card = isapnp_add_card(&dev->eeprom[0x12], 75, 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(&dev->eeprom[0x12], sizeof(rtl8019as_pnp_rom), nic_pnp_config_changed, nic_pnp_csn_changed, nic_pnp_read_vendor_reg, nic_pnp_write_vendor_reg, dev); } } diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index 40d2dec6e..66c77f8fd 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -40,6 +40,7 @@ #include <86box/pic.h> #include <86box/random.h> #include <86box/device.h> +#include <86box/isapnp.h> #include <86box/network.h> #include <86box/net_pcnet.h> #include <86box/bswap.h> @@ -80,7 +81,7 @@ typedef struct RTNETETHERHDR #define BCR_LED1 5 #define BCR_LED2 6 #define BCR_LED3 7 -#define BCR_RESERVED8 8 +#define BCR_SWCONFIG 8 #define BCR_FDC 9 /* 10 - 15 = reserved */ #define BCR_IOBASEL 16 /* Reserved */ @@ -189,6 +190,21 @@ typedef struct RTNETETHERHDR #define PHYSADDR(S,A) ((A) | (S)->GCUpperPhys) +static const uint8_t am79c961_pnp_rom[] = { + 0x04, 0x96, 0x55, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* ADV55AA, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x00, /* PnP version 1.0, vendor version 0.0 */ + 0x82, 0x1c, 0x00, 'A', 'M', 'D', ' ', 'E', 't', 'h', 'e', 'r', 'n', 'e', 't', ' ', 'N', 'e', 't', 'w', 'o', 'r', 'k', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r', /* ANSI identifier */ + + 0x16, 0x04, 0x96, 0x55, 0xaa, 0x00, 0xbd, /* logical device ADV55AA, supports vendor-specific registers 0x38/0x3A/0x3B/0x3C/0x3D/0x3F */ + 0x1c, 0x41, 0xd0, 0x82, 0x8c, /* compatible device PNP828C */ + 0x47, 0x00, 0x00, 0x02, 0xe0, 0x03, 0x20, 0x18, /* I/O 0x200-0x3E0, decodes 10-bit, 32-byte alignment, 24 addresses */ + 0x2a, 0xe8, 0x02, /* DMA 3/5/6/7, compatibility, no count by word, no count by byte, not bus master, 16-bit only */ + 0x23, 0x38, 0x9e, 0x09, /* IRQ 3/4/5/9/10/11/12/15, low true level sensitive, high true edge sensitive */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; + + typedef struct { mem_mapping_t mmio_mapping; const char *name; @@ -211,7 +227,7 @@ typedef struct { uint32_t GCRDRA; /** Address of the TX descriptor table (ring). Loaded at init. */ uint32_t GCTDRA; - uint8_t aPROM[16]; + uint8_t aPROM[256]; uint16_t aCSR[CSR_MAX_REG]; uint16_t aBCR[BCR_MAX_RAP]; uint16_t aMII[MII_MAX_REG]; @@ -885,6 +901,7 @@ pcnetSoftReset(nic_t *dev) case DEV_AM79C960: case DEV_AM79C960_EB: case DEV_AM79C960_VLB: + case DEV_AM79C961: dev->aCSR[88] = 0x3003; dev->aCSR[89] = 0x0262; break; @@ -1750,10 +1767,6 @@ pcnetHardReset(nic_t *dev) dev->aBCR[BCR_LED1] = 0x0084; dev->aBCR[BCR_LED2] = 0x0088; dev->aBCR[BCR_LED3] = 0x0090; - - /* For ISA PnP cards, BCR8 reports IRQ/DMA (e.g. 0x0035 means IRQ 3, DMA 5). */ - if (dev->is_isa) - dev->aBCR[8] = dev->dma_channel | (dev->base_irq << 4); dev->aBCR[BCR_FDC] = 0x0000; dev->aBCR[BCR_BSBC] = 0x9001; @@ -2227,6 +2240,14 @@ pcnet_bcr_readw(nic_t *dev, uint16_t rap) } else val = 0xffff; break; + + case BCR_SWCONFIG: + if (dev->board == DEV_AM79C961) + val = ((dev->base_irq & 0x0f) << 4) | (dev->dma_channel & 0x07); + else + val = 0xffff; + break; + default: val = rap < BCR_MAX_RAP ? dev->aBCR[rap] : 0; break; @@ -2745,6 +2766,65 @@ pcnet_pci_read(int func, int addr, void *p) return(0); } +static void +pcnet_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + if (ld) + return; + + nic_t *dev = (nic_t *) priv; + + dev->base_address = 0; + dev->base_irq = 0; + dev->dma_channel = -1; + + if (dev->base_address) { + pcnet_ioremove(dev, dev->base_address, 0x20); + dev->base_address = 0; + } + + if (config->activate) { + dev->base_address = config->io[0].base; + if (dev->base_address != ISAPNP_IO_DISABLED) + pcnet_ioset(dev, dev->base_address, 0x20); + + dev->base_irq = config->irq[0].irq; + dev->dma_channel = config->dma[0].dma; + if (dev->dma_channel == ISAPNP_DMA_DISABLED) + dev->dma_channel = -1; + + /* Update PnP register mirrors in ROM. */ + dev->aPROM[32] = dev->base_address >> 8; + dev->aPROM[33] = dev->base_address; + dev->aPROM[34] = dev->base_irq; + dev->aPROM[35] = (config->irq[0].level << 1) | config->irq[0].type; + dev->aPROM[36] = (dev->dma_channel == -1) ? ISAPNP_DMA_DISABLED : dev->dma_channel; + } +} + +static uint8_t +pcnet_pnp_read_vendor_reg(uint8_t ld, uint8_t reg, void *priv) +{ + nic_t *dev = (nic_t *) priv; + + if (!ld && (reg == 0xf0)) + return dev->aPROM[50]; + else + return 0x00; +} + +static void +pcnet_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv) +{ + if (ld) + return; + + nic_t *dev = (nic_t *) priv; + + if (reg == 0xf0) + dev->aPROM[50] = val & 0x1f; +} + /** * Takes down the link temporarily if it's current status is up. * @@ -2942,6 +3022,8 @@ pcnet_init(const device_t *info) dev->aPROM[9] = 0x11; else if (dev->is_vlb) dev->aPROM[9] = 0x10; + else if (dev->board == DEV_AM79C961) + dev->aPROM[9] = 0x01; else dev->aPROM[9] = 0x00; @@ -2981,6 +3063,18 @@ pcnet_init(const device_t *info) /* Add device to the PCI bus, keep its slot number. */ dev->card = pci_add_card(PCI_ADD_NORMAL, pcnet_pci_read, pcnet_pci_write, dev); + } else if (dev->board == DEV_AM79C961) { + dev->dma_channel = -1; + + /* Weird secondary checksum. The datasheet isn't clear on what + role it might play with the PnP register mirrors before it. */ + for (c = 0, checksum = 0; c < 54; c++) + checksum += dev->aPROM[c]; + + dev->aPROM[51] = checksum; + + memcpy(&dev->aPROM[0x40], am79c961_pnp_rom, sizeof(am79c961_pnp_rom)); + isapnp_add_card(&dev->aPROM[0x40], sizeof(am79c961_pnp_rom), pcnet_pnp_config_changed, NULL, pcnet_pnp_read_vendor_reg, pcnet_pnp_write_vendor_reg, dev); } else { dev->base_address = device_get_config_hex16("base"); dev->base_irq = device_get_config_int("irq"); @@ -3164,7 +3258,7 @@ static const device_config_t pcnet_vlb_config[] = }; const device_t pcnet_am79c960_device = { - "AMD Am79c960 (PCnet-ISA) ", + "AMD PCnet-ISA ", DEVICE_AT | DEVICE_ISA, DEV_AM79C960, pcnet_init, pcnet_close, NULL, @@ -3173,7 +3267,7 @@ const device_t pcnet_am79c960_device = { }; const device_t pcnet_am79c960_eb_device = { - "AMD Am79c960EB (PCnet-ISA) ", + "Racal Interlan EtherBlaster", DEVICE_AT | DEVICE_ISA, DEV_AM79C960_EB, pcnet_init, pcnet_close, NULL, @@ -3182,7 +3276,7 @@ const device_t pcnet_am79c960_eb_device = { }; const device_t pcnet_am79c960_vlb_device = { - "AMD Am79c960 (PCnet-VL) ", + "AMD PCnet-VL", DEVICE_VLB, DEV_AM79C960_VLB, pcnet_init, pcnet_close, NULL, @@ -3190,8 +3284,17 @@ const device_t pcnet_am79c960_vlb_device = { pcnet_vlb_config }; +const device_t pcnet_am79c961_device = { + "AMD PCnet-ISA+", + DEVICE_AT | DEVICE_ISA, + DEV_AM79C961, + pcnet_init, pcnet_close, NULL, + { NULL }, NULL, NULL, + pcnet_pci_config +}; + const device_t pcnet_am79c970a_device = { - "AMD Am79c970a (PCnet-PCI II)", + "AMD PCnet-PCI II", DEVICE_PCI, DEV_AM79C970A, pcnet_init, pcnet_close, NULL, @@ -3200,7 +3303,7 @@ const device_t pcnet_am79c970a_device = { }; const device_t pcnet_am79c973_device = { - "AMD Am79c973 (PCnet-FAST)", + "AMD PCnet-FAST III", DEVICE_PCI, DEV_AM79C973, pcnet_init, pcnet_close, NULL, diff --git a/src/network/network.c b/src/network/network.c index be7006b43..b545b08ca 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -73,6 +73,7 @@ static netcard_t net_cards[] = { { "none", NULL, NULL }, { "3c503", &threec503_device, NULL }, { "pcnetisa", &pcnet_am79c960_device, NULL }, + { "pcnetisaplus", &pcnet_am79c961_device, NULL }, { "ne1k", &ne1000_device, NULL }, { "ne2k", &ne2000_device, NULL }, { "pcnetracal", &pcnet_am79c960_eb_device, NULL }, diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index 06439cfdd..bbf728431 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -61,6 +61,7 @@ static SCSI_CARD scsi_cards[] = { { "aha154xb", &aha154xb_device, }, { "aha154xc", &aha154xc_device, }, { "aha154xcf", &aha154xcf_device, }, + { "aha154xcp", &aha154xcp_device, }, { "bt542b", &buslogic_542b_1991_device, }, { "bt542bh", &buslogic_device, }, { "bt545s", &buslogic_545s_device, }, diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 8e4bf93be..17498735a 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -38,6 +38,7 @@ #include <86box/plat.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/isapnp.h> #include <86box/scsi.h> #include <86box/scsi_aha154x.h> #include <86box/scsi_x54x.h> @@ -70,6 +71,8 @@ uint16_t aha_ports[] = { 0x0130, 0x0134, 0x0000, 0x0000 }; +static uint8_t *aha1542cp_pnp_rom = NULL; + #pragma pack(push,1) typedef struct { @@ -189,7 +192,7 @@ aha154x_eeprom(x54x_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint r = 0; aha_eeprom_save(dev); - + if (dev->type == AHA_154xCF) { if (dev->fdc_address > 0) { fdc_remove(dev->fdc); @@ -309,6 +312,12 @@ aha_param_len(void *p) case CMD_MBENABLE: return 2; + case 0x39: + return 3; + + case 0x40: + return 2; + default: return 0; } @@ -409,17 +418,47 @@ aha_cmds(void *p) } break; - case 0x2C: /* AHA-1542CP sends this */ - dev->DataBuf[0] = 0x00; + case 0x2C: /* Detect termination status */ + /* Bits 7,6 are termination status and must be 1,0 for the BIOS to work. */ + dev->DataBuf[0] = 0x40; dev->DataReplyLeft = 1; break; - case 0x33: /* AHA-1542CP sends this */ + case 0x2D: /* ???? - Returns two bytes according to the microcode */ dev->DataBuf[0] = 0x00; - dev->DataBuf[1] = 0x00; - dev->DataBuf[2] = 0x00; - dev->DataBuf[3] = 0x00; - dev->DataReplyLeft = 256; + dev->DataBuf[0] = 0x00; + dev->DataReplyLeft = 2; + break; + + case 0x33: /* Send the SCSISelect code decompressor program */ + if (dev->cmd_33_len == 0x0000) { + /* If we are on a controller without this command, return invalid command. */ + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + + /* We have to send (decompressor program length + 2 bytes of little endian size). */ + dev->DataReplyLeft = dev->cmd_33_len + 2; + memset(dev->DataBuf, 0x00, dev->DataReplyLeft); + dev->DataBuf[0] = dev->cmd_33_len & 0xff; + dev->DataBuf[1] = (dev->cmd_33_len >> 8) & 0xff; + memcpy(&(dev->DataBuf[2]), dev->cmd_33_buf, dev->cmd_33_len); + break; + + case 0x39: /* Receive 3 bytes: address high, address low, byte to write to that address. */ + /* Since we are not running the actual microcode, just log the received values + (if logging is enabled) and break. */ + aha_log("aha_cmds(): Command 0x39: %02X -> %02X%02X\n", + dev->CmdBuf[2], dev->CmdBuf[0], dev->CmdBuf[1]); + break; + + case 0x40: /* Receive 2 bytes: address high, address low, then return one byte from that + address. */ + aha_log("aha_cmds(): Command 0x40: %02X%02X\n", + dev->CmdBuf[0], dev->CmdBuf[1]); + dev->DataReplyLeft = 1; + dev->DataBuf[0] = 0xff; break; default: @@ -597,6 +636,94 @@ aha_mca_feedb(void *priv) } +static void +aha_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + x54x_t *dev = (x54x_t *) priv; + int i; + + switch (ld) { + case 0: + if (dev->Base) { + x54x_io_remove(dev, dev->Base, 4); + dev->Base = 0; + } + + dev->Irq = 0; + dev->DmaChannel = ISAPNP_DMA_DISABLED; + dev->rom_addr = 0; + + mem_mapping_disable(&dev->bios.mapping); + + if (config->activate) { + dev->Base = config->io[0].base; + if (dev->Base != ISAPNP_IO_DISABLED) + x54x_io_set(dev, dev->Base, 4); + + /* + * Patch the ROM BIOS image for stuff Adaptec deliberately + * made hard to understand. Well, maybe not, maybe it was + * their way of handling issues like these at the time.. + * + * Patch 1: emulate the I/O ADDR SW setting by patching a + * byte in the BIOS that indicates the I/O ADDR + * switch setting on the board. + */ + if (dev->rom_ioaddr != 0x0000) { + /* Look up the I/O address in the table. */ + for (i=0; i<8; i++) + if (aha_ports[i] == dev->Base) break; + if (i == 8) { + aha_log("%s: invalid I/O address %04x selected!\n", + dev->name, dev->Base); + return; + } + dev->bios.rom[dev->rom_ioaddr] = (uint8_t)i; + /* Negation of the DIP switches to satify the checksum. */ + dev->bios.rom[dev->rom_ioaddr + 1] = (uint8_t)((i ^ 0xff) + 1); + } + + dev->Irq = config->irq[0].irq; + dev->DmaChannel = config->dma[0].dma; + + dev->nvr[1] = (dev->Irq - 9) | (dev->DmaChannel << 4); + aha_eeprom_save(dev); + + dev->rom_addr = config->mem[0].base; + if (dev->rom_addr) { + mem_mapping_enable(&dev->bios.mapping); + aha_log("SCSI BIOS set to: %08X-%08X\n", dev->rom_addr, dev->rom_addr + config->mem[0].size - 1); + mem_mapping_set_addr(&dev->bios.mapping, dev->rom_addr, config->mem[0].size); + } + } + + break; + +#ifdef AHA1542CP_FDC + case 1: + if (dev->fdc_address) { + fdc_remove(dev->fdc); + dev->fdc_address = 0; + } + + fdc_set_irq(dev->fdc, 0); + fdc_set_dma_ch(dev->fdc, ISAPNP_DMA_DISABLED); + + if (config->activate) { + dev->fdc_address = config->io[0].base; + if (dev->fdc_address != ISAPNP_IO_DISABLED) + fdc_set_base(dev->fdc, dev->fdc_address); + + fdc_set_irq(dev->fdc, config->irq[0].irq); + fdc_set_dma_ch(dev->fdc, config->dma[0].dma); + } + + break; +#endif + } +} + + /* Initialize the board's ROM BIOS. */ static void aha_setbios(x54x_t *dev) @@ -705,6 +832,68 @@ aha_setbios(x54x_t *dev) } +/* Get the SCSISelect code decompressor program from the microcode rom for the + AHA-1542CP. */ +static void +aha_setmcode(x54x_t *dev) +{ + uint32_t temp; + FILE *f; + + /* Only if this device has a BIOS ROM. */ + if (dev->mcode_path == NULL) return; + + /* Open the microcode image file and make sure it exists. */ + aha_log("%s: loading microcode from '%ls'\n", dev->name, dev->bios_path); + if ((f = rom_fopen(dev->mcode_path, L"rb")) == NULL) { + aha_log("%s: microcode ROM not found!\n", dev->name); + return; + } + + /* + * Manually load and process the ROM image. + * + * We *could* use the system "rom_init" function here, but for + * this special case, we can't: we may need WRITE access to the + * memory later on. + */ + (void)fseek(f, 0L, SEEK_END); + temp = ftell(f); + (void)fseek(f, 0L, SEEK_SET); + + if (temp < (dev->cmd_33_offset + dev->cmd_33_len - 1)) { + aha_log("%s: microcode ROM size invalid!\n", dev->name); + (void)fclose(f); + return; + } + + /* Allocate the buffer and then read the real PnP ROM into it. */ + if (aha1542cp_pnp_rom != NULL) { + free(aha1542cp_pnp_rom); + aha1542cp_pnp_rom = NULL; + } + aha1542cp_pnp_rom = (uint8_t *) malloc(dev->pnp_len + 7); + fseek(f, dev->pnp_offset, SEEK_SET); + (void)fread(aha1542cp_pnp_rom, dev->pnp_len, 1, f); + memset(&(aha1542cp_pnp_rom[4]), 0x00, 5); + fseek(f, dev->pnp_offset + 4, SEEK_SET); + (void)fread(&(aha1542cp_pnp_rom[9]), dev->pnp_len - 4, 1, f); + /* Even the real AHA-1542CP microcode seem to be flipping bit + 4 to not erroneously indicate there is a range length. */ + aha1542cp_pnp_rom[0x87] |= 0x04; + /* Insert the terminator and the checksum byte that will later + be filled in by the isapnp code. */ + aha1542cp_pnp_rom[dev->pnp_len + 5] = 0x79; + aha1542cp_pnp_rom[dev->pnp_len + 6] = 0x00; + + /* Load the SCSISelect decompression code. */ + fseek(f, dev->cmd_33_offset, SEEK_SET); + (void)fread(dev->cmd_33_buf, dev->cmd_33_len, 1, f); + + (void)fclose(f); +} + + static void aha_initnvr(x54x_t *dev) { @@ -755,6 +944,18 @@ aha_setnvr(x54x_t *dev) } +void +aha1542cp_close(void *priv) +{ + if (aha1542cp_pnp_rom != NULL) { + free(aha1542cp_pnp_rom); + aha1542cp_pnp_rom = NULL; + } + + x54x_close(priv); +} + + /* General initialization routine for all boards. */ static void * aha_init(const device_t *info) @@ -791,6 +992,11 @@ aha_init(const device_t *info) dev->ven_cmds = aha_cmds; dev->get_ven_data = aha_setup_data; + dev->mcode_path = NULL; + dev->cmd_33_len = 0x0000; + dev->cmd_33_offset = 0x0000; + memset(dev->cmd_33_buf, 0x00, 4096); + strcpy(dev->vendor, "Adaptec"); /* Perform per-board initialization. */ @@ -851,7 +1057,7 @@ aha_init(const device_t *info) dev->rom_shramsz = 128; /* size of shadow RAM */ dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ - dev->flags |= X54X_CDROM_BOOT; + dev->flags |= X54X_CDROM_BOOT; dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ @@ -863,16 +1069,31 @@ aha_init(const device_t *info) case AHA_154xCP: strcpy(dev->name, "AHA-154xCP"); dev->bios_path = L"roms/scsi/adaptec/aha1542cp102.bin"; - dev->nvr_path = L"aha1540cp.nvr"; + dev->mcode_path = L"roms/scsi/adaptec/908301-00_f_mcode_17c9.u12"; + dev->nvr_path = L"aha1542cp.nvr"; dev->fw_rev = "F001"; dev->rom_shram = 0x3F80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0055; /* firmware version (hi/lo) */ + dev->flags |= X54X_CDROM_BOOT; + dev->flags |= X54X_ISAPNP; dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ - dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->pnp_len = 0x00be; /* length of the PnP ROM */ + dev->pnp_offset = 0x533d; /* offset of the PnP ROM in the microcode ROM */ + dev->cmd_33_len = 0x06dc; /* length of the SCSISelect code expansion routine returned by + SCSI controller command 0x33 */ + dev->cmd_33_offset = 0x7000; /* offset of the SCSISelect code expansion routine in the + microcode ROM */ + aha_setmcode(dev); + if (aha1542cp_pnp_rom) + isapnp_add_card(aha1542cp_pnp_rom, dev->pnp_len + 7, aha_pnp_config_changed, NULL, NULL, NULL, dev); +#ifdef AHA1542CP_FDC + dev->fdc = device_add(&fdc_at_device); +#endif break; case AHA_1640: @@ -900,7 +1121,7 @@ aha_init(const device_t *info) /* Initialize the device. */ x54x_device_reset(dev); - if (!(dev->bus & DEVICE_MCA)) { + if (!(dev->bus & DEVICE_MCA) && !(dev->flags & X54X_ISAPNP)) { /* Register our address space. */ x54x_io_set(dev, dev->Base, 4); @@ -1297,6 +1518,15 @@ const device_t aha154xcf_device = { aha_154xcf_config }; +const device_t aha154xcp_device = { + "Adaptec AHA-154xCP", + DEVICE_ISA | DEVICE_AT, + AHA_154xCP, + aha_init, aha1542cp_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + const device_t aha1640_device = { "Adaptec AHA-1640", DEVICE_MCA, diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index a3e8d2f0d..5a00930aa 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -92,6 +92,8 @@ x54x_irq(x54x_t *dev, int set) else pci_clear_irq(dev->pci_slot, PCI_INTA); } else { + x54x_log("%sing IRQ %i\n", set ? "Rais" : "Lower", irq); + if (set) { if (dev->interrupt_type) int_type = dev->interrupt_type(dev); @@ -961,7 +963,7 @@ x54x_scsi_cmd(x54x_t *dev) else dev->callback_sub_phase = 2; - x54x_log("scsi_devices[%02i].Status = %02X\n", id, sd->status); + x54x_log("scsi_devices[%02i].Status = %02X\n", req->TargetID, sd->status); } @@ -1310,7 +1312,7 @@ x54x_cmd_callback(void *priv) period = (1000000.0 / dev->ha_bps) * ((double) dev->temp_period); timer_on(&dev->timer, dev->media_period + period + 10.0, 0); - x54x_log("Temporary period: %lf us (%" PRIi64 " periods)\n", dev->timer.period, dev->temp_period); + // x54x_log("Temporary period: %lf us (%" PRIi64 " periods)\n", dev->timer.period, dev->temp_period); } @@ -1371,6 +1373,13 @@ x54x_in(uint16_t port, void *priv) break; } +#ifdef ENABLE_X54X_LOG + if (port == 0x0332) + x54x_log("x54x_in(): %04X, %02X, %08X\n", port, ret, dev->DataReplyLeft); + else + x54x_log("x54x_in(): %04X, %02X\n", port, ret); +#endif + return(ret); } diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 6b04254a0..ffc736132 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -74,10 +74,10 @@ static const int sb_pro_mcv_irqs[4] = {7, 5, 3, 3}; static uint8_t sb_16_pnp_rom[] = { 0x0e, 0x8c, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0028, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ - 0x82, 0x11, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x53, 0x42, 0x31, 0x36, 0x20, 0x50, 0x6e, 0x50, /* ANSI identifier "Creative SB16 PnP" */ + 0x82, 0x11, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', '1', '6', ' ', 'P', 'n', 'P', /* ANSI identifier */ 0x15, 0x0e, 0x8c, 0x00, 0x31, 0x00, /* logical device CTL0031 */ - 0x82, 0x05, 0x00, 0x41, 0x75, 0x64, 0x69, 0x6f, /* ANSI identifier "Audio" */ + 0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */ 0x30, /* start dependent functions, acceptable */ 0x22, 0xa0, 0x04, /* IRQ 5/7/10 */ 0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */ @@ -86,18 +86,19 @@ static uint8_t sb_16_pnp_rom[] = { 0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */ 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */ 0x38, /* end dependent functions */ + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ }; static uint8_t sb_awe32_pnp_rom[] = { 0x0e, 0x8c, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL009C, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ - 0x82, 0x11, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x53, 0x42, 0x33, 0x32, 0x20, 0x50, 0x6e, 0x50, /* ANSI identifier "Creative SB32 PnP" */ + 0x82, 0x11, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', '3', '2', ' ', 'P', 'n', 'P', /* ANSI identifier */ - 0x16, 0x0e, 0x8c, 0x00, 0x41, 0x00, 0xa9, /* logical device CTL0041, supports vendor-specific registers 0x38/0x3a/0x3c/0x3f */ - 0x82, 0x05, 0x00, 0x41, 0x75, 0x64, 0x69, 0x6f, /* ANSI identifier "Audio" */ + 0x16, 0x0e, 0x8c, 0x00, 0x41, 0x00, 0xa9, /* logical device CTL0041, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */ + 0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */ 0x31, 0x00, /* start dependent functions, preferred */ 0x22, 0x20, 0x00, /* IRQ 5 */ - 0x2a, 0x01, 0x0c, /* DMA 1, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x2a, 0x02, 0x0c, /* DMA 1, compatibility, no count by word, count by byte, is bus master, 8-bit only */ 0x2a, 0x20, 0x16, /* DMA 5, compatibility, count by word, no count by byte, is bus master, 16-bit only */ 0x47, 0x01, 0x20, 0x02, 0x20, 0x02, 0x01, 0x10, /* I/O 0x220, decodes 16-bit, 1-byte alignment, 16 addresses */ 0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x01, 0x02, /* I/O 0x330, decodes 16-bit, 1-byte alignment, 2 addresses */ @@ -144,8 +145,8 @@ static uint8_t sb_awe32_pnp_rom[] = { 0x47, 0x01, 0x88, 0x03, 0x94, 0x03, 0x04, 0x04, /* I/O 0x388-0x394, decodes 16-bit, 4-byte alignment, 4 addresses */ 0x38, /* end dependent functions */ - 0x16, 0x0e, 0x8c, 0x00, 0x21, 0x00, 0xa9, /* logical device CTL0021, supports vendor-specific registers 0x38/0x3a/0x3c/0x3f */ - 0x82, 0x09, 0x00, 0x57, 0x61, 0x76, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, /* ANSI identifier "WaveTable" */ + 0x16, 0x0e, 0x8c, 0x00, 0x21, 0x00, 0xa9, /* logical device CTL0021, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */ + 0x82, 0x09, 0x00, 'W', 'a', 'v', 'e', 'T', 'a', 'b', 'l', 'e', /* ANSI identifier */ 0x31, 0x00, /* start dependent functions, preferred */ 0x47, 0x01, 0x20, 0x06, 0x20, 0x06, 0x01, 0x04, /* I/O 0x620, decodes 16-bit, 1-byte alignment, 4 addresses */ 0x30, /* start dependent functions, acceptable */ @@ -1131,15 +1132,20 @@ sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) opl3_write, NULL, NULL, &sb->opl); io_removehandler(addr + 8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); io_removehandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb); + addr = sb->opl_pnp_addr; + if (addr) { + sb->opl_pnp_addr = 0; + io_removehandler(addr, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + } + sb_dsp_setaddr(&sb->dsp, 0); sb_dsp_setirq(&sb->dsp, 0); - sb_dsp_setdma8(&sb->dsp, 0); - sb_dsp_setdma16(&sb->dsp, 0); + sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED); + sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED); mpu401_change_addr(sb->mpu, 0); @@ -1161,9 +1167,11 @@ sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) mpu401_change_addr(sb->mpu, addr); addr = config->io[2].base; - if (addr != ISAPNP_IO_DISABLED) - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, + if (addr != ISAPNP_IO_DISABLED) { + sb->opl_pnp_addr = addr; + io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + } val = config->irq[0].irq; if (val != ISAPNP_IRQ_DISABLED)