@@ -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)
|
||||
|
||||
|
618
src/device/isapnp.c
Normal file
618
src/device/isapnp.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
* RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2021 RichardG.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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
|
||||
};
|
58
src/include/86box/isapnp.h
Normal file
58
src/include/86box/isapnp.h
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2021 RichardG.
|
||||
*/
|
||||
#ifndef EMU_ISAPNP_H
|
||||
# define EMU_ISAPNP_H
|
||||
# include <stdint.h>
|
||||
|
||||
|
||||
#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*/
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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 */
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
};
|
||||
|
@@ -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
|
||||
|
@@ -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 \
|
||||
|
Reference in New Issue
Block a user