From 77f311b179fe3d1646a8efc3c708b17eda29f5ba Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 20 May 2021 22:51:55 -0300 Subject: [PATCH] Game port overhaul --- src/game/gameport.c | 335 +++++++++++++++++++++++------------ src/include/86box/gameport.h | 41 ++--- src/include/86box/snd_sb.h | 1 + src/machine/m_amstrad.c | 3 +- src/machine/m_at.c | 3 +- src/machine/m_ps1.c | 3 +- src/machine/m_tandy.c | 3 +- src/machine/m_xt.c | 3 +- src/machine/m_xt_compaq.c | 3 +- src/machine/m_xt_laserxt.c | 3 +- src/machine/m_xt_olivetti.c | 3 +- src/machine/m_xt_philips.c | 3 +- src/machine/m_xt_xi8088.c | 3 +- src/machine/machine.c | 2 + src/sio/sio_um8669f.c | 21 ++- src/sound/snd_audiopci.c | 6 +- src/sound/snd_sb.c | 150 +++++++++------- 17 files changed, 352 insertions(+), 234 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index 7df2e7eda..d7f399ab3 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -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, * Sarah Walker, + * RichardG, * * 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 #include @@ -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 +}; diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index 4ceac12e9..406234f45 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -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, * Sarah Walker, + * RichardG, * * 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 } diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 3bb2a6496..7889380f5 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -122,6 +122,7 @@ typedef struct sb_t }; mpu_t *mpu; emu8k_t emu8k; + void *gameport; int pos; diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 6996ab1da..ddddc6705 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -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; } diff --git a/src/machine/m_at.c b/src/machine/m_at.c index e10e1f549..0e5589927 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -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; } diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 7edc81883..33b67aabe 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -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; } diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 0ec09c21f..c09ca21c8 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -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; } diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 581a5d7c9..127495259 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -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; } diff --git a/src/machine/m_xt_compaq.c b/src/machine/m_xt_compaq.c index 4874106f6..5950ec3f9 100644 --- a/src/machine/m_xt_compaq.c +++ b/src/machine/m_xt_compaq.c @@ -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); diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index cc9d32dd7..58b7d3774 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -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); diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index 331ebdcac..bc9edb672 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -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(); diff --git a/src/machine/m_xt_philips.c b/src/machine/m_xt_philips.c index f9b205d4c..164e8b093 100644 --- a/src/machine/m_xt_philips.c +++ b/src/machine/m_xt_philips.c @@ -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); diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index e5cd0e87a..d7a127119 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -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; } diff --git a/src/machine/machine.c b/src/machine/machine.c index 685165f89..e3f2ef600 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -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); diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index 4a6869a02..e7131bb45 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -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); diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index bfa4d7eb0..1c697a3a8 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -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; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index bc08c2956..9712f9cc6 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -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