Game port overhaul

This commit is contained in:
RichardG867
2021-05-20 22:51:55 -03:00
parent 1de2e3dd2f
commit 77f311b179
17 changed files with 352 additions and 234 deletions

View File

@@ -1,10 +1,10 @@
/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
* 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 VARCem Project.
* This file is part of the 86Box distribution.
*
* Implementation of a generic Game Port.
*
@@ -12,27 +12,11 @@
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
* RichardG, <richardg867@gmail.com>
*
* Copyright 2016-2018 Miran Grca.
* Copyright 2008-2018 Sarah Walker.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
* Copyright 2021 RichardG.
*/
#include <stdio.h>
#include <stdint.h>
@@ -45,6 +29,7 @@
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/isapnp.h>
#include <86box/gameport.h>
#include <86box/joystick_ch_flightstick_pro.h>
#include <86box/joystick_standard.h>
@@ -55,21 +40,25 @@
typedef struct {
pc_timer_t timer;
int axis_nr;
struct _gameport_ *gameport;
struct _joystick_instance_ *joystick;
} g_axis_t;
typedef struct _gameport_ {
uint8_t state;
uint16_t addr;
g_axis_t axis[4];
const joystick_if_t *joystick;
void *joystick_dat;
struct _joystick_instance_ *joystick;
struct _gameport_ *next;
} gameport_t;
typedef struct _joystick_instance_ {
uint8_t state;
g_axis_t axis[4];
int joystick_type = 0;
const joystick_if_t *intf;
void *dat;
} joystick_instance_t;
int joystick_type = 1;
static const joystick_if_t joystick_none = {
@@ -101,22 +90,54 @@ static const struct {
{ "thrustmaster_fcs", &joystick_tm_fcs },
{ "", NULL }
};
static gameport_t *gameport_global = NULL;
static joystick_instance_t *joystick_instance = NULL;
static uint8_t gameport_pnp_rom[] = {
0x09, 0xf8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, /* BOX0002, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x82, 0x09, 0x00, 'G', 'a', 'm', 'e', ' ', 'P', 'o', 'r', 't', /* ANSI identifier */
0x15, 0x09, 0xf8, 0x00, 0x02, 0x01, /* logical device BOX0002, can participate in boot */
0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */
0x31, 0x00, /* start dependent functions, preferred */
0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */
0x30, /* start dependent functions, acceptable */
0x47, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */
0x31, 0x02, /* start dependent functions, sub-optimal */
0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x38, /* end dependent functions */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
};
static const isapnp_device_config_t gameport_pnp_defaults[] = {
{
.activate = 1,
.io = { { .base = 0x200 }, }
}
};
const device_t *standalone_gameport_type;
static int gameport_instance_id = 0;
/* Linked list of active game ports. Only the top port responds to reads
or writes, and ports at the standard 200h location are prioritized. */
static gameport_t *active_gameports = NULL;
char *
joystick_get_name(int js)
{
if (! joysticks[js].joystick)
return(NULL);
return((char *)joysticks[js].joystick->name);
if (!joysticks[js].joystick)
return NULL;
return (char *) joysticks[js].joystick->name;
}
char *
joystick_get_internal_name(int js)
{
return((char *) joysticks[js].internal_name);
return (char *) joysticks[js].internal_name;
}
@@ -125,8 +146,7 @@ joystick_get_from_internal_name(char *s)
{
int c = 0;
while (strlen((char *) joysticks[c].internal_name))
{
while (strlen((char *) joysticks[c].internal_name)) {
if (!strcmp((char *) joysticks[c].internal_name, s))
return c;
c++;
@@ -139,62 +159,63 @@ joystick_get_from_internal_name(char *s)
int
joystick_get_max_joysticks(int js)
{
return(joysticks[js].joystick->max_joysticks);
return joysticks[js].joystick->max_joysticks;
}
int
joystick_get_axis_count(int js)
{
return(joysticks[js].joystick->axis_count);
return joysticks[js].joystick->axis_count;
}
int
joystick_get_button_count(int js)
{
return(joysticks[js].joystick->button_count);
return joysticks[js].joystick->button_count;
}
int
joystick_get_pov_count(int js)
{
return(joysticks[js].joystick->pov_count);
return joysticks[js].joystick->pov_count;
}
char *
joystick_get_axis_name(int js, int id)
{
return((char *)joysticks[js].joystick->axis_names[id]);
return (char *) joysticks[js].joystick->axis_names[id];
}
char *
joystick_get_button_name(int js, int id)
{
return((char *)joysticks[js].joystick->button_names[id]);
return (char *) joysticks[js].joystick->button_names[id];
}
char *
joystick_get_pov_name(int js, int id)
{
return (char *)joysticks[js].joystick->pov_names[id];
return (char *) joysticks[js].joystick->pov_names[id];
}
static void
gameport_time(gameport_t *gameport, int nr, int axis)
gameport_time(joystick_instance_t *joystick, int nr, int axis)
{
if (axis == AXIS_NOT_PRESENT)
timer_disable(&gameport->axis[nr].timer);
timer_disable(&joystick->axis[nr].timer);
else {
/* Convert axis value to 555 timing. */
axis += 32768;
axis = (axis * 100) / 65; /*Axis now in ohms*/
axis = (axis * 100) / 65; /* axis now in ohms */
axis = (axis * 11) / 1000;
timer_set_delay_u64(&gameport->axis[nr].timer, TIMER_USEC * (axis + 24)); /*max = 11.115 ms*/
timer_set_delay_u64(&joystick->axis[nr].timer, TIMER_USEC * (axis + 24)); /* max = 11.115 ms */
}
}
@@ -202,16 +223,23 @@ gameport_time(gameport_t *gameport, int nr, int axis)
static void
gameport_write(uint16_t addr, uint8_t val, void *priv)
{
gameport_t *p = (gameport_t *)priv;
gameport_t *dev = (gameport_t *) priv;
joystick_instance_t *joystick = dev->joystick;
p->state |= 0x0f;
/* Respond only if a joystick is present and this port is at the top of the active ports list. */
if (!joystick || (active_gameports != dev))
return;
gameport_time(p, 0, p->joystick->read_axis(p->joystick_dat, 0));
gameport_time(p, 1, p->joystick->read_axis(p->joystick_dat, 1));
gameport_time(p, 2, p->joystick->read_axis(p->joystick_dat, 2));
gameport_time(p, 3, p->joystick->read_axis(p->joystick_dat, 3));
p->joystick->write(p->joystick_dat);
/* Read all axes. */
joystick->state |= 0x0f;
gameport_time(joystick, 0, joystick->intf->read_axis(joystick->dat, 0));
gameport_time(joystick, 1, joystick->intf->read_axis(joystick->dat, 1));
gameport_time(joystick, 2, joystick->intf->read_axis(joystick->dat, 2));
gameport_time(joystick, 3, joystick->intf->read_axis(joystick->dat, 3));
/* Notify the interface. */
joystick->intf->write(joystick->dat);
cycles -= ISA_CYCLES(8);
}
@@ -220,114 +248,184 @@ gameport_write(uint16_t addr, uint8_t val, void *priv)
static uint8_t
gameport_read(uint16_t addr, void *priv)
{
gameport_t *p = (gameport_t *)priv;
uint8_t ret;
gameport_t *dev = (gameport_t *) priv;
joystick_instance_t *joystick = dev->joystick;
ret = p->state | p->joystick->read(p->joystick_dat);
/* Respond only if a joystick is present and this port is at the top of the active ports list. */
if (!joystick || (active_gameports != dev))
return 0xff;
/* Merge axis state with button state. */
uint8_t ret = joystick->state | joystick->intf->read(joystick->dat);
cycles -= ISA_CYCLES(8);
return(ret);
return ret;
}
static void
timer_over(void *priv)
{
g_axis_t *axis = (g_axis_t *)priv;
gameport_t *p = axis->gameport;
g_axis_t *axis = (g_axis_t *) priv;
p->state &= ~(1 << axis->axis_nr);
axis->joystick->state &= ~(1 << axis->axis_nr);
if (axis == &p->axis[0])
p->joystick->a0_over(p->joystick_dat);
if (axis == &axis->joystick->axis[0])
axis->joystick->intf->a0_over(axis->joystick->dat);
}
void
gameport_update_joystick_type(void)
{
gameport_t *p = gameport_global;
/* Add a standalone game port if a joystick is enabled but no other game ports exist. */
if (standalone_gameport_type)
gameport_add(standalone_gameport_type);
if (p != NULL) {
p->joystick->close(p->joystick_dat);
p->joystick = joysticks[joystick_type].joystick;
p->joystick_dat = p->joystick->init();
/* Reset the joystick interface. */
if (joystick_instance) {
joystick_instance->intf->close(joystick_instance->dat);
joystick_instance->intf = joysticks[joystick_type].joystick;
joystick_instance->dat = joystick_instance->intf->init();
}
}
void
gameport_remap(uint16_t address)
gameport_remap(void *priv, uint16_t address)
{
gameport_t *p = gameport_global;
if (!p)
gameport_t *dev = (gameport_t *) priv, *other_dev;
if (dev->addr) {
/* Remove this port from the active ports list. */
if (active_gameports == dev) {
active_gameports = dev->next;
dev->next = NULL;
} else {
other_dev = active_gameports;
while (other_dev) {
if (other_dev->next == dev) {
other_dev->next = dev->next;
dev->next = NULL;
break;
}
other_dev = other_dev->next;
}
}
io_removehandler(dev->addr, (dev->addr & 1) ? 1 : 8,
gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev);
}
dev->addr = address;
if (dev->addr) {
/* Add this port to the active ports list. */
if ((dev->addr & 0xfff8) == 0x200) {
/* Port within 200-207h: add to top. */
dev->next = active_gameports;
active_gameports = dev;
} else {
/* Port at other addresses: add to bottom. */
other_dev = active_gameports;
while (other_dev->next)
other_dev = other_dev->next;
other_dev->next = dev;
}
io_sethandler(dev->addr, (dev->addr & 1) ? 1 : 8,
gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev);
}
}
static void
gameport_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
{
if (ld > 0)
return;
if (p->addr)
io_removehandler(p->addr, (p->addr & 1) ? 1 : 8,
gameport_read, NULL, NULL, gameport_write, NULL, NULL, p);
gameport_t *dev = (gameport_t *) priv;
p->addr = address;
/* Remap the game port to the specified address, or disable it. */
gameport_remap(dev, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
}
if (p->addr)
io_sethandler(p->addr, (p->addr & 1) ? 1 : 8,
gameport_read, NULL, NULL, gameport_write, NULL, NULL, p);
void *
gameport_add(const device_t *gameport_type)
{
/* Prevent a standalone game port from being added later on. */
standalone_gameport_type = NULL;
/* Add game port device. */
return device_add_inst(gameport_type, gameport_instance_id++);
}
static void *
gameport_init(const device_t *info)
{
gameport_t *p = NULL;
gameport_t *dev = NULL;
if (!joystick_type) {
gameport_global = p = NULL;
return(p);
dev = malloc(sizeof(gameport_t));
memset(dev, 0x00, sizeof(gameport_t));
/* Allocate global instance. */
if (!joystick_instance && joystick_type) {
joystick_instance = malloc(sizeof(joystick_instance_t));
memset(joystick_instance, 0x00, sizeof(joystick_instance_t));
joystick_instance->axis[0].joystick = joystick_instance;
joystick_instance->axis[1].joystick = joystick_instance;
joystick_instance->axis[2].joystick = joystick_instance;
joystick_instance->axis[3].joystick = joystick_instance;
joystick_instance->axis[0].axis_nr = 0;
joystick_instance->axis[1].axis_nr = 1;
joystick_instance->axis[2].axis_nr = 2;
joystick_instance->axis[3].axis_nr = 3;
timer_add(&joystick_instance->axis[0].timer, timer_over, &joystick_instance->axis[0], 0);
timer_add(&joystick_instance->axis[1].timer, timer_over, &joystick_instance->axis[1], 0);
timer_add(&joystick_instance->axis[2].timer, timer_over, &joystick_instance->axis[2], 0);
timer_add(&joystick_instance->axis[3].timer, timer_over, &joystick_instance->axis[3], 0);
joystick_instance->intf = joysticks[joystick_type].joystick;
joystick_instance->dat = joystick_instance->intf->init();
}
p = malloc(sizeof(gameport_t));
dev->joystick = joystick_instance;
memset(p, 0x00, sizeof(gameport_t));
/* Map game port to the default address. Not applicable on PnP-only ports. */
gameport_remap(dev, info->local);
p->axis[0].gameport = p;
p->axis[1].gameport = p;
p->axis[2].gameport = p;
p->axis[3].gameport = p;
/* Register ISAPnP if this is a standard game port card. */
if (info->local == 0x200)
isapnp_set_device_defaults(isapnp_add_card(gameport_pnp_rom, sizeof(gameport_pnp_rom), gameport_pnp_config_changed, NULL, NULL, NULL, dev), 0, gameport_pnp_defaults);
p->axis[0].axis_nr = 0;
p->axis[1].axis_nr = 1;
p->axis[2].axis_nr = 2;
p->axis[3].axis_nr = 3;
timer_add(&p->axis[0].timer, timer_over, &p->axis[0], 0);
timer_add(&p->axis[1].timer, timer_over, &p->axis[1], 0);
timer_add(&p->axis[2].timer, timer_over, &p->axis[2], 0);
timer_add(&p->axis[3].timer, timer_over, &p->axis[3], 0);
p->joystick = joysticks[joystick_type].joystick;
p->joystick_dat = p->joystick->init();
gameport_global = p;
gameport_remap(info->local);
return(p);
return dev;
}
static void
gameport_close(void *priv)
{
gameport_t *p = (gameport_t *)priv;
gameport_t *dev = (gameport_t *) priv;
if (p == NULL) return;
/* If this port was active, remove it from the active ports list. */
gameport_remap(dev, 0);
p->joystick->close(p->joystick_dat);
/* Free the global instance here, if it wasn't already freed. */
if (joystick_instance) {
joystick_instance->intf->close(joystick_instance->dat);
gameport_global = NULL;
free(joystick_instance);
joystick_instance = NULL;
}
free(p);
free(dev);
}
@@ -348,3 +446,12 @@ const device_t gameport_201_device = {
NULL, { NULL }, NULL,
NULL
};
const device_t gameport_pnp_device = {
"Game port (Plug and Play only)",
0, 0,
gameport_init,
gameport_close,
NULL, { NULL }, NULL,
NULL
};

View File

@@ -1,40 +1,22 @@
/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
* 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 VARCem Project.
* This file is part of the 86Box distribution.
*
* Definitions for the generic game port handlers.
*
* NOTE: This module needs a good cleanup someday.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
* RichardG, <richardg867@gmail.com>
*
* Copyright 2016-2018 Miran Grca.
* Copyright 2008-2017 Sarah Walker.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
* Copyright 2008-2018 Sarah Walker.
* Copyright 2021 RichardG.
*/
#ifndef EMU_GAMEPORT_H
# define EMU_GAMEPORT_H
@@ -125,8 +107,10 @@ extern "C" {
#ifdef EMU_DEVICE_H
extern const device_t gameport_device;
extern const device_t gameport_201_device;
#endif
extern const device_t gameport_pnp_device;
extern const device_t *standalone_gameport_type;
#endif
extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS];
extern joystick_t joystick_state[MAX_JOYSTICKS];
extern int joysticks_present;
@@ -150,7 +134,8 @@ extern char *joystick_get_button_name(int js, int id);
extern char *joystick_get_pov_name(int js, int id);
extern void gameport_update_joystick_type(void);
extern void gameport_remap(uint16_t address);
extern void gameport_remap(void *priv, uint16_t address);
extern void *gameport_add(const device_t *gameport_type);
#ifdef __cplusplus
}

View File

@@ -122,6 +122,7 @@ typedef struct sb_t
};
mpu_t *mpu;
emu8k_t emu8k;
void *gameport;
int pos;

View File

@@ -2516,8 +2516,7 @@ machine_amstrad_init(const machine_t *model, int type)
mouse_set_poll(ms_poll, ams);
}
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
}

View File

@@ -74,8 +74,7 @@ machine_at_common_init_ex(const machine_t *model, int type)
else if (type == 0)
device_add(&at_nvr_device);
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
}

View File

@@ -516,8 +516,7 @@ ps1_common_init(const machine_t *model)
device_add(&keyboard_ps2_ps1_device);
/* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */
if (joystick_type)
device_add(&gameport_201_device);
standalone_gameport_type = &gameport_201_device;
}

View File

@@ -1541,8 +1541,7 @@ machine_tandy1k_init(const machine_t *model, int type)
break;
}
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
eep_data_out = 0x0000;
}

View File

@@ -30,8 +30,7 @@ machine_xt_common_init(const machine_t *model)
device_add(&fdc_xt_device);
nmi_init();
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
}

View File

@@ -56,8 +56,7 @@ machine_xt_compaq_deskpro_init(const machine_t *model)
if (fdc_type == FDC_INTERNAL)
device_add(&fdc_xt_device);
nmi_init();
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
lpt1_remove();
lpt1_init(0x03bc);

View File

@@ -174,8 +174,7 @@ machine_xt_lxt3_init(const machine_t *model)
if (fdc_type == FDC_INTERNAL)
device_add(&fdc_xt_device);
nmi_init();
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
laserxt_init(1);

View File

@@ -738,8 +738,7 @@ machine_xt_m24_init(const machine_t *model)
/* FIXME: make sure this is correct?? */
device_add(&at_nvr_device);
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
nmi_init();

View File

@@ -155,8 +155,7 @@ machine_xt_philips_common_init(const machine_t *model)
nmi_init();
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
device_add(&keyboard_pc_device);

View File

@@ -181,8 +181,7 @@ machine_xt_xi8088_init(const machine_t *model)
nmi_init();
device_add(&ibmat_nvr_device);
pic2_init();
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
return ret;
}

View File

@@ -34,6 +34,7 @@
#include <86box/rom.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/gameport.h>
#include "cpu.h"
#include <86box/video.h>
#include <86box/machine.h>
@@ -74,6 +75,7 @@ machine_init_ex(int m)
machine_log("Initializing as \"%s\"\n", machine_getname());
is_vpc = 0;
standalone_gameport_type = NULL;
/* Set up the architecture flags. */
AT = IS_AT(machine);

View File

@@ -117,14 +117,15 @@ um8669f_log(const char *fmt, ...)
typedef struct um8669f_t
{
int locked, cur_reg_108;
void *pnp_card;
int locked, cur_reg_108;
void *pnp_card;
isapnp_device_config_t *pnp_config[5];
uint8_t regs_108[256];
uint8_t regs_108[256];
fdc_t *fdc;
serial_t *uart[2];
fdc_t *fdc;
serial_t *uart[2];
void *gameport;
} um8669f_t;
@@ -179,13 +180,13 @@ um8669f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri
break;
case 5:
gameport_remap(0);
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) {
um8669f_log("UM8669F: Game port enabled at port %04X\n", config->io[0].base);
gameport_remap(config->io[0].base);
} else
gameport_remap(dev->gameport, config->io[0].base);
} else {
um8669f_log("UM8669F: Game port disabled\n");
gameport_remap(dev->gameport, 0);
}
}
}
@@ -286,6 +287,8 @@ um8669f_init(const device_t *info)
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->gameport = gameport_add(&gameport_pnp_device);
io_sethandler(0x0108, 0x0002,
um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, dev);

View File

@@ -8,6 +8,7 @@
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/gameport.h>
#include <86box/io.h>
#include <86box/nmi.h>
#include <86box/mem.h>
@@ -1352,13 +1353,16 @@ static void *es1371_init(const device_t *info)
sound_add_handler(es1371_get_buffer, es1371);
sound_set_cd_audio_filter(es1371_filter_cd_audio, es1371);
/* Add our own always-present game port to override the standalone ISAPnP one. */
gameport_remap(gameport_add(&gameport_pnp_device), 0x200);
es1371->card = pci_add_card(info->local ? PCI_ADD_SOUND : PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371);
timer_add(&es1371->dac[1].timer, es1371_poll, es1371, 1);
generate_es1371_filter();
/* Return a CS4297A like VMWare does. */
/* Return a CS4297A like VMware does. */
es1371->codec_regs[0x7c] = 0x4352;
es1371->codec_regs[0x7e] = 0x5910;

View File

@@ -31,6 +31,7 @@
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/device.h>
#include <86box/gameport.h>
#include <86box/pic.h>
#include <86box/sound.h>
#include <86box/midi.h>
@@ -71,6 +72,9 @@ 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};
/* Each card in the SB16 family has a million variants, and it shows in the large variety of device IDs for the PnP models.
These ROMs were reconstructed in a best-effort basis, around what Linux pnpdump configs and kernel logs could be found
in mailing lists, forums and other places, as well as Linux's own SB PnP card tables for ALSA and OSS. */
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 */
@@ -87,14 +91,19 @@ static uint8_t sb_16_pnp_rom[] = {
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */
0x38, /* end dependent functions */
0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */
0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */
0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */
0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
};
static uint8_t sb_32_pnp_rom[] = {
0x0e, 0x8c, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL009C, dummy checksum (filled in by isapnp_add_card) */
0x0e, 0x8c, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0048, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x82, 0x11, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', '3', '2', ' ', 'P', 'n', 'P', /* ANSI identifier */
0x16, 0x0e, 0x8c, 0x00, 0x41, 0x00, 0xa9, /* logical device CTL0041, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
0x16, 0x0e, 0x8c, 0x00, 0x31, 0x00, 0xa9, /* logical device CTL0031, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x22, 0x20, 0x00, /* IRQ 5 */
@@ -153,14 +162,19 @@ static uint8_t sb_32_pnp_rom[] = {
0x47, 0x01, 0x20, 0x06, 0x80, 0x06, 0x20, 0x04, /* I/O 0x620-0x680, decodes 16-bit, 32-byte alignment, 4 addresses */
0x38, /* end dependent functions */
0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */
0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */
0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */
0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
};
static uint8_t sb_awe32_pnp_rom[] = {
0x0e, 0x8c, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL009A, dummy checksum (filled in by isapnp_add_card) */
0x0e, 0x8c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0043, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x82, 0x15, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', ' ', 'A', 'W', 'E', '3', '2', ' ', 'P', 'n', 'P', /* ANSI identifier */
0x16, 0x0e, 0x8c, 0x00, 0x41, 0x00, 0xa9, /* logical device CTL0041, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
0x16, 0x0e, 0x8c, 0x00, 0x31, 0x00, 0xa9, /* logical device CTL0031, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x22, 0x20, 0x00, /* IRQ 5 */
@@ -223,6 +237,11 @@ static uint8_t sb_awe32_pnp_rom[] = {
0x47, 0x01, 0x20, 0x0e, 0x80, 0x0e, 0x20, 0x04, /* I/O 0xE20-0xE80, decodes 16-bit, 32-byte alignment, 4 addresses */
0x38, /* end dependent functions */
0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */
0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */
0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */
0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
};
@@ -1188,69 +1207,75 @@ 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(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL,
sb_ct1745_mixer_write, NULL, NULL, sb);
switch (ld) {
case 0: /* Audio */
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(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL,
sb_ct1745_mixer_write, NULL, NULL, sb);
addr = sb->opl_pnp_addr;
if (addr) {
sb->opl_pnp_addr = 0;
io_removehandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
}
addr = sb->opl_pnp_addr;
if (addr) {
sb->opl_pnp_addr = 0;
io_removehandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
}
sb_dsp_setaddr(&sb->dsp, 0);
sb_dsp_setirq(&sb->dsp, 0);
sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED);
sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED);
sb_dsp_setaddr(&sb->dsp, 0);
sb_dsp_setirq(&sb->dsp, 0);
sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED);
sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED);
mpu401_change_addr(sb->mpu, 0);
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);
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);
}
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[1].base;
if (addr != ISAPNP_IO_DISABLED)
mpu401_change_addr(sb->mpu, addr);
addr = config->io[2].base;
if (addr != ISAPNP_IO_DISABLED) {
sb->opl_pnp_addr = addr;
io_sethandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
}
addr = config->io[2].base;
if (addr != ISAPNP_IO_DISABLED) {
sb->opl_pnp_addr = addr;
io_sethandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
}
val = config->irq[0].irq;
if (val != ISAPNP_IRQ_DISABLED)
sb_dsp_setirq(&sb->dsp, val);
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[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);
val = config->dma[1].dma;
if (val != ISAPNP_DMA_DISABLED)
sb_dsp_setdma16(&sb->dsp, val);
}
break;
case 1: /* Game */
gameport_remap(sb->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
break;
}
}
@@ -1259,21 +1284,18 @@ 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:
case 0: /* Audio */
sb_16_pnp_config_changed(0, config, sb);
break;
case 1:
emu8k_change_addr(&sb->emu8k, 0);
case 1: /* WaveTable */
emu8k_change_addr(&sb->emu8k, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
break;
if (config->activate) {
addr = config->io[0].base;
if (addr != ISAPNP_IO_DISABLED)
emu8k_change_addr(&sb->emu8k, addr);
}
case 2: /* Game */
sb_16_pnp_config_changed(1, config, sb);
break;
}
}
@@ -1701,6 +1723,8 @@ sb_16_pnp_init(const device_t *info)
if (device_get_config_int("receive_input"))
midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp);
sb->gameport = gameport_add(&gameport_pnp_device);
isapnp_add_card(sb_16_pnp_rom, sizeof(sb_16_pnp_rom), sb_16_pnp_config_changed, NULL, NULL, NULL, sb);
return sb;
@@ -1796,6 +1820,8 @@ sb_awe32_pnp_init(const device_t *info)
if (device_get_config_int("receive_input"))
midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp);
sb->gameport = gameport_add(&gameport_pnp_device);
if (info->local == 1)
isapnp_add_card(sb_32_pnp_rom, sizeof(sb_32_pnp_rom), sb_awe32_pnp_config_changed, NULL, NULL, NULL, sb);
else