From 6fb31016f6f9b6e3a8bebdb3ca0ecc01777182b9 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 19 Mar 2021 16:32:08 -0300 Subject: [PATCH 1/4] FW-6400GX has no ISA slots --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d11de8e41..d4292ece0 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -410,7 +410,7 @@ const machine_t machines[] = { /* Slot 2 machines */ /* 440GX */ { "[i440GX] Gigabyte GA-6GXU", "6gxu", MACHINE_TYPE_SLOT2, CPU_PKG_SLOT2, 0, 100000000, 133333333, 1800, 3500, 4.0, 6.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2097152,16384, 511, machine_at_6gxu_init, NULL }, - { "[i440GX] Freeway FW-6400GX", "fw6400gx", MACHINE_TYPE_SLOT2, CPU_PKG_SLOT2, 0, 100000000, 150000000, 1800, 3500, 3.0, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2080768,16384, 511, machine_at_fw6400gx_init, NULL }, + { "[i440GX] Freeway FW-6400GX", "fw6400gx", MACHINE_TYPE_SLOT2, CPU_PKG_SLOT2, 0, 100000000, 150000000, 1800, 3500, 3.0, 8.0, (MACHINE_AGP & ~MACHINE_AT) | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2080768,16384, 511, machine_at_fw6400gx_init, NULL }, { "[i440GX] SuperMicro Super S2DGE", "s2dge", MACHINE_TYPE_SLOT2, CPU_PKG_SLOT2, 0, 66666667, 100000000, 1800, 3500, 3.0, 7.5, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 16384,2097152,16384, 511, machine_at_s2dge_init, NULL }, /* PGA370 machines */ From b3389937279f30ec8b87a120d899d1132179f597 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 20 Mar 2021 01:21:02 -0300 Subject: [PATCH 2/4] Add ISAPnP framework --- src/device/CMakeLists.txt | 2 +- src/device/isapnp.c | 618 +++++++++++++++++++++++++++++++++++++ src/include/86box/isapnp.h | 58 ++++ src/win/Makefile.mingw | 2 +- 4 files changed, 678 insertions(+), 2 deletions(-) create mode 100644 src/device/isapnp.c create mode 100644 src/include/86box/isapnp.h diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index 85339108a..f09051ac9 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -15,7 +15,7 @@ add_library(dev OBJECT bugger.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c - postcard.c serial.c vpc2007.c clock_ics9xxx.c i2c.c i2c_gpio.c + postcard.c serial.c vpc2007.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c smbus_piix4.c keyboard.c keyboard_xt.c keyboard_at.c mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c) diff --git a/src/device/isapnp.c b/src/device/isapnp.c new file mode 100644 index 000000000..9b8ab6923 --- /dev/null +++ b/src/device/isapnp.c @@ -0,0 +1,618 @@ +/* + * 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. + * + * This file is part of the 86Box distribution. + * + * Implementation of ISA Plug and Play. + * + * + * + * Author: Miran Grca, + * RichardG, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2021 RichardG. + */ + +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/isapnp.h> + + +#define CHECK_CURRENT_LD() if (!dev->current_ld) { \ + isapnp_log("ISAPnP: No logical device selected\n"); \ + break; \ + } + +#define CHECK_CURRENT_CARD() do { \ + card = dev->first_card; \ + while (card) { \ + if (card->state == PNP_STATE_CONFIG) \ + break; \ + card = card->next; \ + } \ + if (!card) { \ + isapnp_log("ISAPnP: No card in CONFIG state\n"); \ + break; \ + } \ + } while (0); + + +static const uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE, + 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61, + 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1, + 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; +static const device_t isapnp_device; + + +#ifdef ENABLE_ISAPNP_LOG +int isapnp_do_log = ENABLE_ISAPNP_LOG; + + +static void +isapnp_log(const char *fmt, ...) +{ + va_list ap; + + if (isapnp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define isapnp_log(fmt, ...) +#endif + + +enum { + PNP_STATE_WAIT_FOR_KEY = 0, + PNP_STATE_CONFIG, + PNP_STATE_ISOLATION, + PNP_STATE_SLEEP +}; + +typedef struct _isapnp_device_ { + uint8_t number; + uint8_t regs[256]; + + struct _isapnp_device_ *next; +} isapnp_device_t; + +typedef struct _isapnp_card_ { + uint8_t state, csn, id_checksum, serial_read, serial_read_pair, serial_read_pos, *rom; + uint16_t rom_pos, rom_size; + void *priv; + + /* ISAPnP memory and I/O addresses are awkwardly big endian, so we populate this + structure whenever something on some device changes, and pass it on instead. */ + isapnp_device_config_t config; + 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); + + isapnp_device_t *first_ld; + struct _isapnp_card_ *next; +} isapnp_card_t; + +typedef struct { + uint8_t reg, key_pos: 5; + uint16_t read_data_addr; + + isapnp_card_t *first_card, *isolated_card, *current_ld_card; + isapnp_device_t *current_ld; +} isapnp_t; + + +static void +isapnp_device_config_changed(isapnp_t *dev) +{ + /* Ignore device if it hasn't signed up for configuration changes. */ + if (!dev->current_ld_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); + } + 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]; + } + for (i = 0; i < 8; i++) { + reg_base = 0x60 + (2 * i); + card->config.io[i].base = (ld->regs[reg_base] << 8) | ld->regs[reg_base + 1]; + } + for (i = 0; i < 2; i++) { + reg_base = 0x70 + (2 * i); + card->config.irq[i].irq = ld->regs[reg_base]; + card->config.irq[i].level = ld->regs[reg_base + 1] & 0x02; + card->config.irq[i].type = ld->regs[reg_base + 1] & 0x01; + } + for (i = 0; i < 2; i++) { + reg_base = 0x74 + i; + card->config.dma[i].dma = ld->regs[reg_base]; + } + + /* Signal the configuration change. */ + card->config_changed(ld->number, &card->config, card->priv); +} + + +static uint8_t +isapnp_read_rangecheck(uint16_t addr, void *priv) +{ + isapnp_device_t *dev = (isapnp_device_t *) priv; + return (dev->regs[0x31] & 0x01) ? 0x55 : 0xaa; +} + + +static uint8_t +isapnp_read_data(uint16_t addr, void *priv) +{ + isapnp_t *dev = (isapnp_t *) priv; + uint8_t ret = 0xff, bit, next_shift; + isapnp_card_t *card; + + switch (dev->reg) { + case 0x01: /* Serial Isolation */ + card = dev->first_card; + while (card) { + if (card->state == PNP_STATE_ISOLATION) + break; + card = card->next; + } + dev->isolated_card = card; + + if (card) { + if (card->serial_read_pair) { /* second byte (aa/00) */ + card->serial_read <<= 1; + if (!card->serial_read_pos) + card->rom_pos = 0x09; + } else { /* first byte (55/00) */ + if (card->serial_read_pos < 64) { /* reading 64-bit vendor/serial */ + bit = (card->rom[card->serial_read_pos >> 3] >> (card->serial_read_pos & 0x7)) & 0x01; + next_shift = (!!(card->id_checksum & 0x02) ^ !!(card->id_checksum & 0x01) ^ bit) & 0x01; + card->id_checksum >>= 1; + card->id_checksum |= (next_shift << 7); + } else { /* reading 8-bit checksum */ + if (card->serial_read_pos == 64) /* populate ID checksum in ROM */ + card->rom[0x08] = card->id_checksum; + bit = (card->id_checksum >> (card->serial_read_pos & 0x7)) & 0x01; + } + isapnp_log("ISAPnP: Read bit %d of byte %02X (%02X) = %d\n", card->serial_read_pos & 0x7, card->serial_read_pos >> 3, card->rom[card->serial_read_pos >> 3], bit); + card->serial_read = bit ? 0x55 : 0x00; + card->serial_read_pos = (card->serial_read_pos + 1) % 72; + } + card->serial_read_pair ^= 1; + ret = card->serial_read; + } + + break; + + case 0x04: /* Resource Data */ + CHECK_CURRENT_CARD(); + + isapnp_log("ISAPnP: Read resource data index %02X (%02X) from CSN %02X\n", card->rom_pos, card->rom[card->rom_pos], card->csn); + if (card->rom_pos >= card->rom_size) + ret = 0xff; + else + ret = card->rom[card->rom_pos++]; + + break; + + case 0x05: /* Status */ + ret = 0x00; + CHECK_CURRENT_CARD(); + + isapnp_log("ISAPnP: Query status for CSN %02X\n", card->csn); + ret = 0x01; + + break; + + case 0x06: /* Card Select Number */ + ret = 0x00; + CHECK_CURRENT_CARD(); + + isapnp_log("ISAPnP: Query CSN %02X\n", card->csn); + ret = card->csn; + + break; + + case 0x07: /* Logical Device Number */ + ret = 0x00; + CHECK_CURRENT_LD(); + + isapnp_log("ISAPnP: Query LDN for CSN %02X device %02X\n", dev->current_ld_card->csn, dev->current_ld->number); + ret = dev->current_ld->number; + + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + CHECK_CURRENT_CARD(); + isapnp_log("ISAPnP: Read vendor-defined register %02X from CSN %02X\n", dev->reg, card->csn); + if (card->read_vendor_reg) + ret = card->read_vendor_reg(0, dev->reg, card->priv); + break; + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: + CHECK_CURRENT_LD(); + isapnp_log("ISAPnP: Read vendor-defined register %02X from CSN %02X device %02X\n", dev->reg, dev->current_ld_card->csn, dev->current_ld->number); + if (dev->current_ld_card->read_vendor_reg) + ret = dev->current_ld_card->read_vendor_reg(dev->current_ld->number, dev->reg, dev->current_ld_card->priv); + break; + + default: + if (dev->reg >= 0x30) { + CHECK_CURRENT_LD(); + isapnp_log("ISAPnP: Read register %02X from CSN %02X device %02X\n", dev->reg, dev->current_ld_card->csn, dev->current_ld->number); + ret = dev->current_ld->regs[dev->reg]; + } + break; + } + + isapnp_log("ISAPnP: read_data(%02X) = %02X\n", dev->reg, ret); + + return ret; +} + + +static void +isapnp_set_read_data(uint16_t addr, isapnp_t *dev) +{ + /* Remove existing READ_DATA port if set. */ + if (dev->read_data_addr) { + io_removehandler(dev->read_data_addr, 1, isapnp_read_data, NULL, NULL, NULL, NULL, NULL, dev); + dev->read_data_addr = 0; + } + + /* Set new READ_DATA port if within range. */ + if ((addr >= 0x203) && (addr <= 0x3ff)) { + dev->read_data_addr = addr; + io_sethandler(dev->read_data_addr, 1, isapnp_read_data, NULL, NULL, NULL, NULL, NULL, dev); + } +} + + +static void +isapnp_write_addr(uint16_t addr, uint8_t val, void *priv) +{ + isapnp_t *dev = (isapnp_t *) priv; + isapnp_card_t *card = dev->first_card; + + isapnp_log("ISAPnP: write_addr(%02X)\n", val); + + if (!card) /* don't do anything if we have no PnP cards */ + return; + + if (card->state == PNP_STATE_WAIT_FOR_KEY) { /* checking only the first card should be fine */ + /* Check written value against LFSR key. */ + if (val == pnp_init_key[dev->key_pos]) { + dev->key_pos++; + if (!dev->key_pos) { + isapnp_log("ISAPnP: Key unlocked, putting cards to SLEEP\n"); + while (card) { + if (card->state == PNP_STATE_WAIT_FOR_KEY) + card->state = PNP_STATE_SLEEP; + card = card->next; + } + } + } else { + dev->key_pos = 0; + } + } else { + /* Nobody waiting for key, set register address. */ + dev->reg = val; + } +} + + +static void +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; + + isapnp_log("ISAPnP: write_data(%02X)\n", val); + + switch (dev->reg) { + case 0x00: /* Set RD_DATA Port */ + isapnp_set_read_data((val << 2) | 3, dev); + isapnp_log("ISAPnP: Read data port set to %04X\n", dev->read_data_addr); + break; + + case 0x02: /* Config Control */ + if (val & 0x01) { + isapnp_log("ISAPnP: Reset\n"); + isapnp_set_read_data(0, dev); + + card = dev->first_card; + 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); + ld = ld->next; + } + card = card->next; + } + + 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"); + card = dev->first_card; + while (card) { + card->state = PNP_STATE_WAIT_FOR_KEY; + card = card->next; + } + } + if (val & 0x04) { + isapnp_log("ISAPnP: Reset CSN\n"); + card = dev->first_card; + while (card) { + card->csn = 0; + if (card->csn_changed) + card->csn_changed(card->csn, card->priv); + card = card->next; + } + } + break; + + case 0x03: /* Wake[CSN] */ + isapnp_log("ISAPnP: Wake[%02X]\n", val); + card = dev->first_card; + while (card) { + if (card->csn == val) { + card->rom_pos = 0; + card->id_checksum = pnp_init_key[0]; + if (card->state == PNP_STATE_SLEEP) + card->state = (val == 0) ? PNP_STATE_ISOLATION : PNP_STATE_CONFIG; + } else { + card->state = PNP_STATE_SLEEP; + } + + card = card->next; + } + break; + + case 0x06: /* Card Select Number */ + if (dev->isolated_card) { + isapnp_log("ISAPnP: Set CSN %02X\n", val); + dev->isolated_card->csn = val; + if (dev->isolated_card->csn_changed) + dev->isolated_card->csn_changed(dev->isolated_card->csn, dev->isolated_card->priv); + dev->isolated_card->state = PNP_STATE_CONFIG; + dev->isolated_card = NULL; + } else { + isapnp_log("ISAPnP: Set CSN %02X but no card is isolated\n", val); + } + break; + + case 0x07: /* Logical Device Number */ + CHECK_CURRENT_CARD(); + + ld = card->first_ld; + while (ld) { + if (ld->number == val) { + isapnp_log("ISAPnP: Select CSN %02X device %02X\n", card->csn, val); + dev->current_ld_card = card; + dev->current_ld = ld; + break; + } + 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; + } + } + + break; + + case 0x30: /* Activate */ + CHECK_CURRENT_LD(); + + 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); + + break; + + case 0x31: /* I/O Range Check */ + CHECK_CURRENT_LD(); + + for (uint8_t reg = 0x60; reg <= 0x6e; reg += 2) { + io_addr = (dev->current_ld->regs[reg] << 8) | dev->current_ld->regs[reg + 1]; + if (dev->current_ld->regs[dev->reg] & 0x02) + io_removehandler(io_addr, 1, isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, dev->current_ld); + if (val & 0x02) + io_sethandler(io_addr, 1, isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, dev->current_ld); + } + + dev->current_ld->regs[dev->reg] = val & 0x03; + + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + CHECK_CURRENT_CARD(); + isapnp_log("ISAPnP: Write %02X to vendor-defined register %02X on CSN %02X\n", val, dev->reg, card->csn); + if (card->write_vendor_reg) + card->write_vendor_reg(0, dev->reg, val, card->priv); + break; + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: + CHECK_CURRENT_LD(); + isapnp_log("ISAPnP: Write %02X to vendor-defined register %02X on CSN %02X device %02X\n", val, dev->reg, dev->current_ld_card->csn, dev->current_ld->number); + if (dev->current_ld_card->write_vendor_reg) + dev->current_ld_card->write_vendor_reg(dev->current_ld->number, dev->reg, val, dev->current_ld_card->priv); + break; + + default: + if (dev->reg >= 0x38) { + 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); + dev->current_ld->regs[dev->reg] = val; + isapnp_device_config_changed(dev); + } + break; + } +} + + +static void * +isapnp_init(const device_t *info) +{ + isapnp_t *dev = (isapnp_t *) malloc(sizeof(isapnp_t)); + memset(dev, 0, sizeof(isapnp_t)); + + io_sethandler(0x279, 1, NULL, NULL, NULL, isapnp_write_addr, NULL, NULL, dev); + io_sethandler(0xa79, 1, NULL, NULL, NULL, isapnp_write_data, NULL, NULL, dev); + + return dev; +} + + +static void +isapnp_close(void *priv) +{ + isapnp_t *dev = (isapnp_t *) priv; + isapnp_card_t *card = dev->first_card, *next_card; + isapnp_device_t *ld, *next_ld; + + while (card) { + ld = card->first_ld; + while (ld) { + next_ld = ld->next; + free(ld); + ld = next_ld; + } + + next_card = card->next; + free(card); + card = next_card; + } + + io_removehandler(0x279, 1, NULL, NULL, NULL, isapnp_write_addr, NULL, NULL, dev); + io_removehandler(0xa79, 1, NULL, NULL, NULL, isapnp_write_data, NULL, NULL, dev); + + free(dev); +} + + +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) +{ + isapnp_t *dev = (isapnp_t *) device_get_priv(&isapnp_device); + if (!dev) + dev = (isapnp_t *) device_add(&isapnp_device); + + isapnp_card_t *card = (isapnp_card_t *) malloc(sizeof(isapnp_card_t)); + memset(card, 0, sizeof(isapnp_card_t)); + + 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; + card->read_vendor_reg = read_vendor_reg; + card->write_vendor_reg = write_vendor_reg; + + 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; + } + + return card; +} + + +void +isapnp_set_csn(void *priv, uint8_t csn) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + + card->csn = csn; + if (card->csn_changed) + card->csn_changed(card->csn, card->priv); +} + + +static const device_t isapnp_device = { + "ISA Plug and Play", + DEVICE_ISA, + 0, + isapnp_init, isapnp_close, NULL, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/include/86box/isapnp.h b/src/include/86box/isapnp.h new file mode 100644 index 000000000..eaf2cb713 --- /dev/null +++ b/src/include/86box/isapnp.h @@ -0,0 +1,58 @@ +/* + * 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. + * + * This file is part of the 86Box distribution. + * + * Definitions for ISA Plug and Play. + * + * + * + * Author: RichardG, + * + * Copyright 2021 RichardG. + */ +#ifndef EMU_ISAPNP_H +# define EMU_ISAPNP_H +# include + + +#define ISAPNP_MEM_DISABLED 0 +#define ISAPNP_IO_DISABLED 0 +#define ISAPNP_IRQ_DISABLED 0 +#define ISAPNP_DMA_DISABLED 4 + + +typedef struct { + uint8_t activate; + struct { + uint32_t base: 24, size: 24; + } mem[4]; + struct { + uint32_t base, size; + } mem32[4]; + struct { + uint16_t base; + } io[8]; + struct { + uint8_t irq: 4, level: 1, type: 1; + } irq[2]; + struct { + uint8_t dma: 3; + } dma[2]; +} isapnp_device_config_t; + + +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_set_csn(void *priv, uint8_t csn); +uint8_t isapnp_get_rom_checksum(void *priv); + + +#endif /*EMU_ISAPNP_H*/ diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index ffca090f7..f7491d742 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -649,7 +649,7 @@ MCHOBJ := machine.o machine_table.o \ m_at_misc.o DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ - lpt.o pci_bridge.o postcard.o serial.o vpc2007.o clock_ics9xxx.o \ + lpt.o pci_bridge.o postcard.o serial.o vpc2007.o clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \ From 82376a9bac55a6cd28ec7711b9887954fcf2c3fa Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 20 Mar 2021 01:21:28 -0300 Subject: [PATCH 3/4] Switch RTL8019AS to ISAPnP framework --- src/network/net_ne2000.c | 370 +++++---------------------------------- 1 file changed, 47 insertions(+), 323 deletions(-) diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index b46ac2aaf..d655e78c8 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -65,6 +65,7 @@ #include <86box/net_dp8390.h> #include <86box/net_ne2000.h> #include <86box/bswap.h> +#include <86box/isapnp.h> enum { @@ -88,12 +89,6 @@ enum { #define PCI_REGSIZE 256 /* size of PCI space */ -uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE, - 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61, - 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1, - 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; - - typedef struct { dp8390_t *dp8390; const char *name; @@ -106,27 +101,15 @@ typedef struct { 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 eeprom[128]; /* for RTL8029AS */ rom_t bios_rom; - uint8_t pnp_phase; - uint8_t pnp_magic_count; - uint8_t pnp_address; - uint8_t pnp_res_pos; - uint8_t pnp_csn; + void *pnp_card; uint8_t pnp_activate; - uint8_t pnp_io_check; uint8_t pnp_csnsav; - 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; + uint8_t maclocal[6]; /* configured MAC (local) address */ /* RTL8019AS/RTL8029AS registers */ uint8_t config0, config2, config3; @@ -508,324 +491,75 @@ nic_writel(uint16_t addr, uint32_t val, void *priv) } -static void nic_iocheckset(nic_t *dev, uint16_t addr); -static void nic_iocheckremove(nic_t *dev, uint16_t addr); static void nic_ioset(nic_t *dev, uint16_t addr); static void nic_ioremove(nic_t *dev, uint16_t addr); -static uint8_t -nic_pnp_io_check_readb(uint16_t addr, void *priv) +static void +nic_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + if (ld != 0) + return; + + nic_t *dev = (nic_t *) priv; + + if (dev->pnp_activate) + nic_ioremove(dev, dev->base_address); + + dev->base_address = config->io[0].base; + dev->base_irq = config->irq[0].irq; + dev->pnp_activate = config->activate; + + if (dev->pnp_activate && (dev->base_address != ISAPNP_IO_DISABLED) && (dev->base_irq != ISAPNP_IRQ_DISABLED)) + nic_ioset(dev, dev->base_address); +} + + +static void +nic_pnp_csn_changed(uint8_t csn, void *priv) { nic_t *dev = (nic_t *) priv; - return((dev->pnp_io_check & 0x01) ? 0x55 : 0xAA); + dev->pnp_csnsav = csn; } static uint8_t -nic_pnp_readb(uint16_t addr, void *priv) +nic_pnp_read_vendor_reg(uint8_t ld, uint8_t reg, void *priv) { + if (ld != 0) + return 0x00; + nic_t *dev = (nic_t *) priv; - uint8_t bit, next_shift; - uint8_t ret = 0xFF; - /* Plug and Play Registers */ - switch(dev->pnp_address) { - /* Card Control Registers */ - case 0x01: /* Serial Isolation */ - if (dev->pnp_phase != PNP_PHASE_ISOLATION) { - ret = 0x00; - break; - } - if (dev->pnp_serial_read_pair) { - dev->pnp_serial_read <<= 1; - /* TODO: Support for multiple PnP devices. - if (pnp_get_bus_data() != dev->pnp_serial_read) - dev->pnp_phase = PNP_PHASE_SLEEP; - } else { - */ - if (!dev->pnp_serial_read_pos) { - dev->pnp_res_pos = 0x1B; - dev->pnp_phase = PNP_PHASE_CONFIG; - nelog(1, "\nASSIGN CSN phase\n"); - } - } else { - if (dev->pnp_serial_read_pos < 64) { - bit = (dev->pnp_id >> dev->pnp_serial_read_pos) & 0x01; - next_shift = (!!(dev->pnp_id_checksum & 0x02) ^ !!(dev->pnp_id_checksum & 0x01) ^ bit) & 0x01; - dev->pnp_id_checksum >>= 1; - dev->pnp_id_checksum |= (next_shift << 7); - } else { - if (dev->pnp_serial_read_pos == 64) - dev->eeprom[0x1A] = dev->pnp_id_checksum; - bit = (dev->pnp_id_checksum >> (dev->pnp_serial_read_pos & 0x07)) & 0x01; - } - dev->pnp_serial_read = bit ? 0x55 : 0x00; - dev->pnp_serial_read_pos = (dev->pnp_serial_read_pos + 1) % 72; - } - dev->pnp_serial_read_pair ^= 1; - ret = dev->pnp_serial_read; - break; - case 0x04: /* Resource Data */ - ret = dev->eeprom[dev->pnp_res_pos]; - dev->pnp_res_pos++; - break; - case 0x05: /* Status */ - ret = 0x01; - break; - case 0x06: /* Card Select Number (CSN) */ - nelog(1, "Card Select Number (CSN)\n"); - ret = dev->pnp_csn; - break; - case 0x07: /* Logical Device Number */ - nelog(1, "Logical Device Number\n"); - ret = 0x00; - break; - case 0x30: /* Activate */ - nelog(1, "Activate\n"); - ret = dev->pnp_activate; - break; - case 0x31: /* I/O Range Check */ - nelog(1, "I/O Range Check\n"); - ret = dev->pnp_io_check; - break; + switch (reg) { + case 0xF0: + return dev->config0; - /* Logical Device Configuration Registers */ - /* Memory Configuration Registers - We currently force them to stay 0x00 because we currently do not - support a RTL8019AS BIOS. */ - case 0x40: /* BROM base address bits[23:16] */ - case 0x41: /* BROM base address bits[15:0] */ - case 0x42: /* Memory Control */ - ret = 0x00; - break; + case 0xF2: + return dev->config2; - /* I/O Configuration Registers */ - case 0x60: /* I/O base address bits[15:8] */ - ret = (dev->base_address >> 8); - break; - case 0x61: /* I/O base address bits[7:0] */ - ret = (dev->base_address & 0xFF); - break; + case 0xF3: + return dev->config3; - /* Interrupt Configuration Registers */ - case 0x70: /* IRQ level */ - ret = dev->base_irq; - break; - case 0x71: /* IRQ type */ - ret = 0x02; /* high, edge */ - break; - - /* DMA Configuration Registers */ - case 0x74: /* DMA channel select 0 */ - case 0x75: /* DMA channel select 1 */ - ret = 0x04; /* indicating no DMA channel is needed */ - break; - - /* Vendor Defined Registers */ - case 0xF0: /* CONFIG0 */ - case 0xF1: /* CONFIG1 */ - ret = 0x00; - break; - case 0xF2: /* CONFIG2 */ - ret = (dev->config2 & 0xe0); - break; - case 0xF3: /* CONFIG3 */ - ret = (dev->config3 & 0x46); - break; - case 0xF5: /* CSNSAV */ - ret = (dev->pnp_csnsav); - break; + case 0xF5: + return dev->pnp_csnsav; } - nelog(1, "nic_pnp_readb(%04X) = %02X\n", addr, ret); - return(ret); -} - - -static void nic_pnp_io_set(nic_t *dev, uint16_t read_addr); -static void nic_pnp_io_remove(nic_t *dev); - - -static void -nic_pnp_writeb(uint16_t addr, uint8_t val, void *priv) -{ - nic_t *dev = (nic_t *) priv; - uint16_t new_addr = 0; - - nelog(1, "nic_pnp_writeb(%04X, %02X)\n", addr, val); - - /* Plug and Play Registers */ - switch(dev->pnp_address) { - /* Card Control Registers */ - case 0x00: /* Set RD_DATA port */ - new_addr = val; - new_addr <<= 2; - new_addr |= 3; - nic_pnp_io_remove(dev); - nic_pnp_io_set(dev, new_addr); - nelog(1, "PnP read data address now: %04X\n", new_addr); - break; - case 0x02: /* Config Control */ - if (val & 0x01) { - /* Reset command */ - nic_pnp_io_remove(dev); - memset(dev->pnp_regs, 0, 256); - nelog(1, "All logical devices reset\n"); - } - if (val & 0x02) { - /* Wait for Key command */ - dev->pnp_phase = PNP_PHASE_WAIT_FOR_KEY; - nelog(1, "WAIT FOR KEY phase\n"); - } - if (val & 0x04) { - /* PnP Reset CSN command */ - dev->pnp_csn = dev->pnp_csnsav = 0; - nelog(1, "CSN reset\n"); - } - break; - case 0x03: /* Wake[CSN] */ - nelog(1, "Wake[%02X]\n", val); - if (val == dev->pnp_csn) { - dev->pnp_res_pos = 0x12; - dev->pnp_id_checksum = 0x6A; - if (dev->pnp_phase == PNP_PHASE_SLEEP) { - dev->pnp_phase = val ? PNP_PHASE_CONFIG : PNP_PHASE_ISOLATION; - } - } else { - if ((dev->pnp_phase == PNP_PHASE_CONFIG) || (dev->pnp_phase == PNP_PHASE_ISOLATION)) - dev->pnp_phase = PNP_PHASE_SLEEP; - } - break; - case 0x06: /* Card Select Number (CSN) */ - dev->pnp_csn = dev->pnp_csnsav = val; - dev->pnp_phase = PNP_PHASE_CONFIG; - nelog(1, "CSN set to %02X\n", dev->pnp_csn); - break; - case 0x30: /* Activate */ - if ((dev->pnp_activate ^ val) & 0x01) { - nic_ioremove(dev, dev->base_address); - if (val & 0x01) - nic_ioset(dev, dev->base_address); - - nelog(1, "I/O range %sabled\n", val & 0x02 ? "en" : "dis"); - } - dev->pnp_activate = val; - break; - case 0x31: /* I/O Range Check */ - if ((dev->pnp_io_check ^ val) & 0x02) { - nic_iocheckremove(dev, dev->base_address); - if (val & 0x02) - nic_iocheckset(dev, dev->base_address); - - nelog(1, "I/O range check %sabled\n", val & 0x02 ? "en" : "dis"); - } - dev->pnp_io_check = val; - break; - - /* Logical Device Configuration Registers */ - /* Memory Configuration Registers - We currently force them to stay 0x00 because we currently do not - support a RTL8019AS BIOS. */ - - /* I/O Configuration Registers */ - case 0x60: /* I/O base address bits[15:8] */ - if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) - nic_ioremove(dev, dev->base_address); - dev->base_address &= 0x00ff; - dev->base_address |= (((uint16_t) val) << 8); - if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) - nic_ioset(dev, dev->base_address); - nelog(1, "Base address now: %04X\n", dev->base_address); - break; - case 0x61: /* I/O base address bits[7:0] */ - if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) - nic_ioremove(dev, dev->base_address); - dev->base_address &= 0xff00; - dev->base_address |= val; - if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) - nic_ioset(dev, dev->base_address); - nelog(1, "Base address now: %04X\n", dev->base_address); - break; - - /* Interrupt Configuration Registers */ - case 0x70: /* IRQ level */ - dev->base_irq = val; - nelog(1, "IRQ now: %02i\n", dev->base_irq); - break; - - /* Vendor Defined Registers */ - case 0xF6: /* Vendor Control */ - dev->pnp_csn = 0; - break; - } - return; + return 0x00; } static void -nic_pnp_io_set(nic_t *dev, uint16_t read_addr) -{ - if ((read_addr >= 0x0200) && (read_addr <= 0x03FF)) { - io_sethandler(read_addr, 1, - nic_pnp_readb, NULL, NULL, - NULL, NULL, NULL, dev); - } - dev->pnp_read = read_addr; -} - - -static void -nic_pnp_io_remove(nic_t *dev) -{ - if ((dev->pnp_read >= 0x0200) && (dev->pnp_read <= 0x03FF)) { - io_removehandler(dev->pnp_read, 1, - nic_pnp_readb, NULL, NULL, - NULL, NULL, NULL, dev); - } -} - - -static void -nic_pnp_address_writeb(uint16_t addr, uint8_t val, void *priv) +nic_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv) { nic_t *dev = (nic_t *) priv; - /* nelog(1, "nic_pnp_address_writeb(%04X, %02X)\n", addr, val); */ - - switch(dev->pnp_phase) { - case PNP_PHASE_WAIT_FOR_KEY: - if (val == pnp_init_key[dev->pnp_magic_count]) { - dev->pnp_magic_count = (dev->pnp_magic_count + 1) & 0x1f; - if (!dev->pnp_magic_count) - dev->pnp_phase = PNP_PHASE_SLEEP; - } else - dev->pnp_magic_count = 0; - break; - default: - dev->pnp_address = val; - break; + if ((ld == 0) && (reg == 0xf6) && (val & 0x04)) { + uint8_t csn = dev->pnp_csnsav; + isapnp_set_csn(dev->pnp_card, 0); + dev->pnp_csnsav = csn; } - return; -} - - -static void -nic_iocheckset(nic_t *dev, uint16_t addr) -{ - io_sethandler(addr, 32, - nic_pnp_io_check_readb, NULL, NULL, - NULL, NULL, NULL, dev); -} - - -static void -nic_iocheckremove(nic_t *dev, uint16_t addr) -{ - io_removehandler(addr, 32, - nic_pnp_io_check_readb, NULL, NULL, - NULL, NULL, NULL, dev); } @@ -1199,7 +933,6 @@ nic_init(const device_t *info) #ifdef ENABLE_NIC_LOG int i; #endif - int c; char *ansi_id = "REALTEK PLUG & PLAY ETHERNET CARD"; uint64_t *eeprom_pnp_id; @@ -1379,14 +1112,9 @@ nic_init(const device_t *info) dev->card = pci_add_card(PCI_ADD_NORMAL, nic_pci_read, nic_pci_write, dev); } else { - io_sethandler(0x0279, 1, - NULL, NULL, NULL, - nic_pnp_address_writeb, NULL, NULL, dev); - dev->pnp_id = PNP_DEVID; dev->pnp_id <<= 32LL; dev->pnp_id |= PNP_VENDID; - dev->pnp_phase = PNP_PHASE_WAIT_FOR_KEY; } /* Initialize the RTL8029 EEPROM. */ @@ -1454,13 +1182,9 @@ nic_init(const device_t *info) /* TAG: END Tag */ dev->eeprom[0x5B] = 0x79; /* Item byte */ - for (c = 0x1b; c < 0x5c; c++) /* Checksum (2's compl) */ - dev->eeprom[0x5C] += dev->eeprom[c]; - dev->eeprom[0x5C] = -dev->eeprom[0x5C]; + /* Checksum is filled in by isapnp_add_card */ - io_sethandler(0x0A79, 1, - NULL, NULL, NULL, - nic_pnp_writeb, NULL, NULL, dev); + 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); } } From 5e5992247c68be35d8344671360e4dce6daa9e92 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 20 Mar 2021 01:21:42 -0300 Subject: [PATCH 4/4] Add PnP variants of the Sound Blaster 16 and AWE32 --- src/include/86box/snd_emu8k.h | 3 + src/include/86box/sound.h | 2 + src/sound/snd_emu8k.c | 22 ++- src/sound/snd_sb.c | 309 ++++++++++++++++++++++++++++++++++ src/sound/sound.c | 2 + 5 files changed, 335 insertions(+), 3 deletions(-) diff --git a/src/include/86box/snd_emu8k.h b/src/include/86box/snd_emu8k.h index 16323a13b..effab0f79 100644 --- a/src/include/86box/snd_emu8k.h +++ b/src/include/86box/snd_emu8k.h @@ -377,10 +377,13 @@ typedef struct emu8k_t int pos; int32_t buffer[SOUNDBUFLEN * 2]; + + uint16_t addr; } emu8k_t; +void emu8k_change_addr(emu8k_t *emu8k, uint16_t emu_addr); void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram); void emu8k_close(emu8k_t *emu8k); diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index c4b03f1a5..3b4222a37 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -111,7 +111,9 @@ extern const device_t sb_pro_v1_device; extern const device_t sb_pro_v2_device; extern const device_t sb_pro_mcv_device; extern const device_t sb_16_device; +extern const device_t sb_16_pnp_device; extern const device_t sb_awe32_device; +extern const device_t sb_awe32_pnp_device; /* Innovation SSI-2001 */ extern const device_t ssi2001_device; diff --git a/src/sound/snd_emu8k.c b/src/sound/snd_emu8k.c index 9fdbff67e..2854330ba 100644 --- a/src/sound/snd_emu8k.c +++ b/src/sound/snd_emu8k.c @@ -2134,6 +2134,24 @@ I've recopilated these sentences to get an idea of how to loop emu8k->pos = new_pos; } + +void +emu8k_change_addr(emu8k_t *emu8k, uint16_t emu_addr) +{ + if (emu8k->addr) { + io_removehandler(emu8k->addr, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_removehandler(emu8k->addr+0x400, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_removehandler(emu8k->addr+0x800, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + emu8k->addr = 0; + } + if (emu_addr) { + emu8k->addr = emu_addr; + io_sethandler(emu8k->addr, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu8k->addr+0x400, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu8k->addr+0x800, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + } +} + /* onboard_ram in kilobytes */ void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) { @@ -2196,9 +2214,7 @@ void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) } - io_sethandler(emu_addr, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); - io_sethandler(emu_addr+0x400, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); - io_sethandler(emu_addr+0x800, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + emu8k_change_addr(emu8k, emu_addr); /*Create frequency table. (Convert initial pitch register value to a linear speed change) * The input is encoded such as 0xe000 is center note (no pitch shift) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index e1cc18f7e..6b04254a0 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -35,6 +35,7 @@ #include <86box/sound.h> #include <86box/midi.h> #include <86box/filters.h> +#include <86box/isapnp.h> #include <86box/snd_sb.h> @@ -70,6 +71,91 @@ static const uint16_t sb_mcv_addr[8] = {0x200, 0x210, 0x220, 0x230, 0x240, 0x250 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" */ + + 0x15, 0x0e, 0x8c, 0x00, 0x31, 0x00, /* logical device CTL0031 */ + 0x82, 0x05, 0x00, 0x41, 0x75, 0x64, 0x69, 0x6f, /* ANSI identifier "Audio" */ + 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 */ + 0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 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" */ + + 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" */ + 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, 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 */ + 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */ + 0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 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 */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */ + 0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */ + 0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */ + 0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 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 */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */ + 0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */ + 0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */ + 0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */ + 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" */ + 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 */ + 0x47, 0x01, 0x20, 0x06, 0x20, 0x06, 0x20, 0x04, /* I/O 0x620-0x680, decodes 16-bit, 32-byte alignment, 4 addresses */ + 0x38, /* end dependent functions */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; + + #ifdef ENABLE_SB_LOG int sb_do_log = ENABLE_SB_LOG; @@ -1031,6 +1117,93 @@ sb_pro_mcv_write(int port, uint8_t val, void *p) } +static void +sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + if (ld != 0) + return; + + sb_t *sb = (sb_t *) priv; + uint16_t addr = sb->dsp.sb_addr; + uint8_t val; + + io_removehandler(addr, 0x0004, opl3_read, NULL, NULL, + 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); + + sb_dsp_setaddr(&sb->dsp, 0); + sb_dsp_setirq(&sb->dsp, 0); + sb_dsp_setdma8(&sb->dsp, 0); + sb_dsp_setdma16(&sb->dsp, 0); + + mpu401_change_addr(sb->mpu, 0); + + if (config->activate) { + addr = config->io[0].base; + if (addr != ISAPNP_IO_DISABLED) { + io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, sb); + + sb_dsp_setaddr(&sb->dsp, addr); + } + + addr = config->io[1].base; + if (addr != ISAPNP_IO_DISABLED) + mpu401_change_addr(sb->mpu, addr); + + addr = config->io[2].base; + if (addr != ISAPNP_IO_DISABLED) + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + + val = config->irq[0].irq; + if (val != ISAPNP_IRQ_DISABLED) + sb_dsp_setirq(&sb->dsp, val); + + val = config->dma[0].dma; + if (val != ISAPNP_DMA_DISABLED) + sb_dsp_setdma8(&sb->dsp, val); + + val = config->dma[1].dma; + if (val != ISAPNP_DMA_DISABLED) + sb_dsp_setdma16(&sb->dsp, val); + } +} + + +static void +sb_awe32_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + sb_t *sb = (sb_t *) priv; + uint16_t addr; + + switch (ld) { + case 0: + sb_16_pnp_config_changed(0, config, sb); + break; + + case 1: + emu8k_change_addr(&sb->emu8k, 0); + + if (config->activate) { + addr = config->io[0].base; + if (addr != ISAPNP_IO_DISABLED) + emu8k_change_addr(&sb->emu8k, addr); + } + break; + } +} + + void * sb_1_init(const device_t *info) { @@ -1404,6 +1577,36 @@ sb_16_init(const device_t *info) } +static void * +sb_16_pnp_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0x00, sizeof(sb_t)); + + sb->opl_enabled = 1; + opl3_init(&sb->opl); + + sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); + sb_ct1745_mixer_reset(sb); + + sb->mixer_enabled = 1; + sound_add_handler(sb_get_buffer_sb16_awe32, sb); + sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); + + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, 0, 0, M_UART, device_get_config_int("receive_input401")); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + isapnp_add_card(sb_16_pnp_rom, sizeof(sb_16_pnp_rom), sb_16_pnp_config_changed, NULL, NULL, NULL, sb); + + return sb; +} + + static int sb_awe32_available() { @@ -1465,6 +1668,40 @@ sb_awe32_init(const device_t *info) } +static void * +sb_awe32_pnp_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + int onboard_ram = device_get_config_int("onboard_ram"); + + memset(sb, 0x00, sizeof(sb_t)); + + sb->opl_enabled = 1; + opl3_init(&sb->opl); + + sb_dsp_init(&sb->dsp, SB16 + 1, SB_SUBTYPE_DEFAULT, sb); + sb_ct1745_mixer_reset(sb); + + sb->mixer_enabled = 1; + sound_add_handler(sb_get_buffer_sb16_awe32, sb); + sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); + + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, 0, 0, M_UART, device_get_config_int("receive_input401")); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + emu8k_init(&sb->emu8k, 0, onboard_ram); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + isapnp_add_card(sb_awe32_pnp_rom, sizeof(sb_awe32_pnp_rom), sb_awe32_pnp_config_changed, NULL, NULL, NULL, sb); + + return sb; +} + + void sb_close(void *p) { @@ -1856,6 +2093,19 @@ static const device_config_t sb_16_config[] = } }; +static const device_config_t sb_16_pnp_config[] = +{ + { + "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 + }, + { + "receive_input401", "Receive input (MPU-401)", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + static const device_config_t sb_awe32_config[] = { { @@ -2006,6 +2256,42 @@ static const device_config_t sb_awe32_config[] = } }; +static const device_config_t sb_awe32_pnp_config[] = +{ + { + "onboard_ram", "Onboard RAM", CONFIG_SELECTION, "", 512, "", { 0 }, + { + { + "None", 0 + }, + { + "512 KB", 512 + }, + { + "2 MB", 2048 + }, + { + "8 MB", 8192 + }, + { + "28 MB", 28*1024 + }, + { + "" + } + } + }, + { + "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 + }, + { + "receive_input401", "Receive input (MPU-401)", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + const device_t sb_1_device = { "Sound Blaster v1.0", @@ -2094,6 +2380,17 @@ const device_t sb_16_device = sb_16_config }; +const device_t sb_16_pnp_device = +{ + "Sound Blaster 16 PnP", + DEVICE_ISA | DEVICE_AT, + 0, + sb_16_pnp_init, sb_close, NULL, { NULL }, + sb_speed_changed, + NULL, + sb_16_pnp_config +}; + const device_t sb_awe32_device = { "Sound Blaster AWE32", @@ -2105,3 +2402,15 @@ const device_t sb_awe32_device = NULL, sb_awe32_config }; + +const device_t sb_awe32_pnp_device = +{ + "Sound Blaster AWE32 PnP", + DEVICE_ISA | DEVICE_AT, + 0, + sb_awe32_pnp_init, sb_awe32_close, NULL, + { sb_awe32_available }, + sb_speed_changed, + NULL, + sb_awe32_pnp_config +}; diff --git a/src/sound/sound.c b/src/sound/sound.c index 3751cb15a..8f363c0d5 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -94,7 +94,9 @@ static const SOUND_CARD sound_cards[] = { "sbprov1", &sb_pro_v1_device }, { "sbprov2", &sb_pro_v2_device }, { "sb16", &sb_16_device }, + { "sb16_pnp", &sb_16_pnp_device }, { "sbawe32", &sb_awe32_device }, + { "sbawe32_pnp", &sb_awe32_pnp_device }, #if defined(DEV_BRANCH) && defined(USE_PAS16) { "pas16", &pas16_device }, #endif