From d386240fcb73b52faefdf1629d8abb45de5b2e9b Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 8 Nov 2018 19:21:55 +0100 Subject: [PATCH] Removed the file pointer from the hdd_t struct; Partially split off the Logitech Serial Mouse emulation from Microsoft Serial Mouse; Slightly reworked serial port emulation (the two UART's are now device_t's, non-FIFO mode implemented and is now default, FIFO mode reimplemented from scratch so it's now actually correct); Added the emulation of the SiS 85c497 chip to the SiS 85c496/497 chipset; Bugfixes to the emulated Super I/O chips and made them all device_t's now. --- src/config.h | 110 ++++ src/device.c | 6 +- src/disk/hdd.h | 1 - src/intel.c | 134 +++-- src/intel.h | 3 +- src/machine/m_at_4x0.c | 61 +- src/machine/m_at_commodore.c | 8 +- src/machine/m_at_sis_85c471.c | 374 ++++++------ src/machine/m_at_sis_85c496.c | 190 ++++++- src/machine/m_at_wd76c10.c | 29 +- src/machine/m_pcjr.c | 4 +- src/machine/m_ps1.c | 12 +- src/machine/m_ps2_isa.c | 6 +- src/machine/m_ps2_mca.c | 42 +- src/machine/machine.c | 23 +- src/machine/machine.h | 3 + src/machine/machine_table.c | 4 +- src/mouse.c | 3 +- src/mouse.h | 13 +- src/mouse_serial.c | 582 +++++++++++++++---- src/pc.c | 10 +- src/pci.c | 5 +- src/scsi/scsi.c | 40 +- src/serial.c | 676 ++++++++++++---------- src/serial.h | 131 ++--- src/sio.h | 22 +- src/sio_detect.c | 82 ++- src/sio_fdc37c669.c | 501 ++++++++-------- src/sio_fdc37c66x.c | 457 +++++++-------- src/sio_fdc37c93x.c | 1013 ++++++++++++++++++--------------- src/sio_pc87306.c | 697 +++++++++++------------ src/sio_um8669f.c | 473 +++++++-------- src/sio_w83877f.c | 821 ++++++++++++-------------- src/win/win_settings.c | 6 +- 34 files changed, 3590 insertions(+), 2952 deletions(-) diff --git a/src/config.h b/src/config.h index 138748585..a3abf7f74 100644 --- a/src/config.h +++ b/src/config.h @@ -27,6 +27,116 @@ extern "C" { #endif +#if 0 +typedef struct { + uint8_t id, + uint8_t bus_type, /* Bus type: IDE, SCSI, etc. */ + bus, :4, /* ID of the bus (for example, for IDE, + 0 = primary, 1 = secondary, etc. */ + bus_id, :4, /* ID of the device on the bus */ + uint8_t type, /* Type flags, interpretation depends + on the device */ + uint8_t is_image; /* This is only used for CD-ROM: + 0 = Image; + 1 = Host drive */ + + wchar_t path[1024]; /* Name of current image file or + host drive */ + + uint32_t spt, /* Physical geometry parameters */ + hpc, + tracks; +} storage_cfg_t; + +typedef struct { + /* General configuration */ + int vid_resize, /* Window is resizable or not */ + vid_renderer, /* Renderer */ + vid_fullscreen_scale, /* Full screen scale type */ + vid_fullscreen_start, /* Start emulator in full screen */ + vid_force_43, /* Force 4:3 display ratio in windowed mode */ + vid_scale, /* Windowed mode scale */ + vid_overscan, /* EGA/(S)VGA overscan enabled */ + vid_cga_contrast, /* CGA alternate contrast enabled */ + vid_grayscale, /* Video is grayscale */ + vid_grayscale_type, /* Video grayscale type */ + vid_invert_display, /* Invert display */ + rctrl_is_lalt, /* Right CTRL is left ALT */ + update_icons, /* Update status bar icons */ + window_remember, /* Remember window position and size */ + window_w, /* Window coordinates */ + window_h, + window_x, + window_y, + sound_gain; /* Sound gain */ +#ifdef USE_LANGUAGE + uint16_t language_id; /* Language ID (0x0409 = English (US)) */ +#endif + + /* Machine cateogory */ + int machine, /* Machine */ + cpu_manufacturer, /* CPU manufacturer */ + cpu, /* CPU */ +#ifdef USE_DYNAREC + cpu_use_dynarec, /* CPU recompiler enabled */ +#endif + wait_states, /* CPU wait states */ + enable_external_fpu, /* FPU enabled */ + time_sync; /* Time sync enabled */ + uint32_t mem_size; /* Memory size */ + + /* Video category */ + int video_card, /* Video card */ + voodoo_enabled; /* Voodoo enabled */ + + /* Input devices category */ + int mouse_type, /* Mouse type */ + joystick_type; /* Joystick type */ + + /* Sound category */ + int sound_card, /* Sound card */ + midi_device, /* Midi device */ + mpu_401, /* Standalone MPU-401 enabled */ + ssi_2001_enabled, /* SSI-2001 enabled */ + game_blaster_enabled, /* Game blaster enabled */ + gus_enabled, /* Gravis Ultrasound enabled */ + opl_type, /* OPL emulation type */ + sound_is_float; /* Sound is 32-bit float or 16-bit integer */ + + /* Network category */ + int network_type, /* Network type (SLiRP or PCap) */ + network_card; /* Network card */ + char network_host[520]; /* PCap device */ + + /* Ports category */ + char parallel_devices[3][32]; /* LPT device names */ +#ifdef USE_SERIAL_DEVICES + char serial_devices[2][32]; /* Serial device names */ +#endif + int serial_enabled[2], /* Serial ports 1 and 2 enabled */ + parallel_enabled[3]; /* LPT1, LPT2, LPT3 enabled */ + + /* Other peripherals category */ + int hdc, /* Hard disk controller */ + scsi_card, /* SCSI controller */ + ide_ter_enabled, /* Tertiary IDE controller enabled */ + ide_qua_enabled, /* Quaternary IDE controller enabled */ + bugger_enabled, /* ISA bugger device enabled */ + isa_rtc_type, /* ISA RTC card */ + isa_mem_type[ISAMEM_MAX]; /* ISA memory boards */ + + /* Hard disks category */ + storage_cfg_t hdd[HDD_NUM]; /* Hard disk drives */ + + /* Floppy drives category */ + storage_cfg_t fdd[FDD_NUM]; /* Floppy drives */ + + /* Other removable devices category */ + storage_cfg_t cdrom[CDROM_NUM], /* CD-ROM drives */ + storage_cfg_t rdisk[ZIP_NUM]; /* Removable disk drives */ +} config_t; +#endif + extern void config_load(void); extern void config_save(void); extern void config_write(wchar_t *fn); diff --git a/src/device.c b/src/device.c index 0305a362b..47810bb09 100644 --- a/src/device.c +++ b/src/device.c @@ -9,7 +9,7 @@ * Implementation of the generic device interface to handle * all devices attached to the emulator. * - * Version: @(#)device.c 1.0.22 2018/10/25 + * Version: @(#)device.c 1.0.23 2018/11/06 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -107,9 +107,9 @@ device_add_common(const device_t *d, void *p, int inst) device_context_t old; for (c = 0; c < 256; c++) { - if (devices[c] == (device_t *)d) { + if (!inst && (devices[c] == (device_t *) d)) { device_log("DEVICE: device already exists!\n"); - return(NULL); + return (NULL); } if (devices[c] == NULL) break; } diff --git a/src/disk/hdd.h b/src/disk/hdd.h index 33e566d41..0ff451f42 100644 --- a/src/disk/hdd.h +++ b/src/disk/hdd.h @@ -85,7 +85,6 @@ typedef struct { uint8_t wp; /* Disk has been mounted READ-ONLY */ uint8_t pad, pad0; - FILE *f; /* Current file handle to image */ void *priv; wchar_t fn[1024], /* Name of current image file */ diff --git a/src/intel.c b/src/intel.c index 327052780..420250cf0 100644 --- a/src/intel.c +++ b/src/intel.c @@ -3,9 +3,11 @@ */ #include #include +#include #include #include #include "cpu/cpu.h" +#include "device.h" #include "machine/machine.h" #include "io.h" #include "mem.h" @@ -14,57 +16,113 @@ #include "intel.h" -uint8_t batman_brdconfig(uint16_t port, void *p) +typedef struct { + uint16_t timer_latch; + + int64_t timer; +} batman_t; + + +static uint8_t +batman_config_read(uint16_t port, void *priv) { - switch (port) - { - case 0x73: - return 0xff; - case 0x75: - return 0xdf; - } - return 0; + uint8_t ret = 0x00; + + switch (port & 0x000f) { + case 3: + ret = 0xff; + break; + case 5: + ret = 0xdf; + break; + } + + return ret; } -static uint16_t batman_timer_latch; -static int64_t batman_timer = 0; -static void batman_timer_over(void *p) + +static void +batman_timer_over(void *priv) { - batman_timer = 0; + batman_t *dev = (batman_t *) priv; + + dev->timer = 0; } -static void batman_timer_write(uint16_t addr, uint8_t val, void *p) + +static void +batman_timer_write(uint16_t addr, uint8_t val, void *priv) { - if (addr & 1) - batman_timer_latch = (batman_timer_latch & 0xff) | (val << 8); - else - batman_timer_latch = (batman_timer_latch & 0xff00) | val; - batman_timer = batman_timer_latch * TIMER_USEC; + batman_t *dev = (batman_t *) priv; + + if (addr & 1) + dev->timer_latch = (dev->timer_latch & 0xff) | (val << 8); + else + dev->timer_latch = (dev->timer_latch & 0xff00) | val; + + dev->timer = dev->timer_latch * TIMER_USEC; } -static uint8_t batman_timer_read(uint16_t addr, void *p) + +static uint8_t +batman_timer_read(uint16_t addr, void *priv) { - uint16_t batman_timer_latch; - - cycles -= (int)PITCONST; - - timer_clock(); + batman_t *dev = (batman_t *) priv; + uint16_t batman_timer_latch; + uint8_t ret; - if (batman_timer < 0) - return 0; - - batman_timer_latch = batman_timer / TIMER_USEC; + cycles -= (int)PITCONST; - if (addr & 1) - return batman_timer_latch >> 8; - return batman_timer_latch & 0xff; + timer_clock(); + + if (dev->timer < 0) + return 0; + + batman_timer_latch = dev->timer / TIMER_USEC; + + if (addr & 1) + ret = batman_timer_latch >> 8; + else + ret = batman_timer_latch & 0xff; + + return ret; } -void intel_batman_init() -{ - io_sethandler(0x0073, 0x0001, batman_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); - io_sethandler(0x0075, 0x0001, batman_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); - io_sethandler(0x0078, 0x0002, batman_timer_read, NULL, NULL, batman_timer_write, NULL, NULL, NULL); - timer_add(batman_timer_over, &batman_timer, &batman_timer, NULL); +static void +intel_batman_close(void *priv) +{ + batman_t *dev = (batman_t *) priv; + + free(dev); } + + +static void * +intel_batman_init(const device_t *info) +{ + batman_t *dev = (batman_t *) malloc(sizeof(batman_t)); + memset(dev, 0, sizeof(batman_t)); + + io_sethandler(0x0073, 0x0001, + batman_config_read, NULL, NULL, NULL, NULL, NULL, dev); + io_sethandler(0x0075, 0x0001, + batman_config_read, NULL, NULL, NULL, NULL, NULL, dev); + + io_sethandler(0x0078, 0x0002, + batman_timer_read, NULL, NULL, batman_timer_write, NULL, NULL, dev); + + timer_add(batman_timer_over, &dev->timer, &dev->timer, dev); + + return dev; +} + + +const device_t intel_batman_device = { + "Intel Batman board chip", + 0, + 0, + intel_batman_init, intel_batman_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/intel.h b/src/intel.h index d2603bcbd..307fd49ab 100644 --- a/src/intel.h +++ b/src/intel.h @@ -1,5 +1,4 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ -extern void intel_batman_init(void); -extern void intel_endeavor_init(void); +extern const device_t intel_batman_device; diff --git a/src/machine/m_at_4x0.c b/src/machine/m_at_4x0.c index 3efaa2be7..7ee7b21ab 100644 --- a/src/machine/m_at_4x0.c +++ b/src/machine/m_at_4x0.c @@ -8,7 +8,7 @@ * * Implementation of the Intel PCISet chips from 430LX to 440FX. * - * Version: @(#)m_at_430lx_nx.c 1.0.3 2018/09/19 + * Version: @(#)m_at_430lx_nx.c 1.0.4 2018/11/05 * * Authors: Sarah Walker, * Miran Grca, @@ -505,9 +505,8 @@ machine_at_premiere_common_init(const machine_t *model) pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&sio_device); - fdc37c665_init(); - intel_batman_init(); - + device_add(&fdc37c665_device); + device_add(&intel_batman_device); device_add(&intel_flash_bxt_ami_device); } @@ -546,8 +545,7 @@ machine_at_p54tp4xe_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430fx_device); device_add(&piix_device); - fdc37c665_init(); - + device_add(&fdc37c665_device); device_add(&intel_flash_bxt_device); } @@ -569,8 +567,7 @@ machine_at_endeavor_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430fx_device); device_add(&piix_device); - pc87306_init(); - + device_add(&pc87306_device); device_add(&intel_flash_bxt_ami_device); if (gfxcard == VID_INTERNAL) @@ -600,8 +597,7 @@ machine_at_zappa_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430fx_device); device_add(&piix_device); - pc87306_init(); - + device_add(&pc87306_device); device_add(&intel_flash_bxt_ami_device); } @@ -621,8 +617,7 @@ machine_at_mb500n_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430fx_device); device_add(&piix_device); - fdc37c665_init(); - + device_add(&fdc37c665_device); device_add(&intel_flash_bxt_device); } @@ -643,8 +638,7 @@ machine_at_president_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430fx_device); device_add(&piix_device); - w83877f_init(4); - + device_add(&w83877f_president_device); device_add(&intel_flash_bxt_device); } @@ -666,9 +660,8 @@ machine_at_thor_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430fx_device); device_add(&piix_device); - pc87306_init(); - - device_add(&intel_flash_bxt_ami_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); } @@ -689,8 +682,7 @@ machine_at_pb640_init(const machine_t *model) device_add(&i430fx_pb640_device); device_add(&piix_pb640_device); ide_enable_pio_override(); - pc87306_init(); - + device_add(&pc87306_device); device_add(&intel_flash_bxt_ami_device); if (gfxcard == VID_INTERNAL) @@ -722,7 +714,7 @@ machine_at_acerm3a_init(const machine_t *model) pci_register_slot(0x10, PCI_CARD_ONBOARD, 4, 0, 0, 0); device_add(&i430hx_device); device_add(&piix3_device); - fdc37c932fr_init(); + device_add(&fdc37c932fr_device); device_add(&acerm3a_device); device_add(&intel_flash_bxb_device); @@ -746,7 +738,7 @@ machine_at_acerv35n_init(const machine_t *model) pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); device_add(&i430hx_device); device_add(&piix3_device); - fdc37c932fr_init(); + device_add(&fdc37c932fr_device); device_add(&acerm3a_device); device_add(&intel_flash_bxb_device); @@ -771,8 +763,7 @@ machine_at_ap53_init(const machine_t *model) pci_register_slot(0x06, PCI_CARD_ONBOARD, 1, 2, 3, 4); device_add(&i430hx_device); device_add(&piix3_device); - fdc37c669_init(); - + device_add(&fdc37c669_device); device_add(&intel_flash_bxt_device); } @@ -793,8 +784,7 @@ machine_at_p55t2p4_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430hx_device); device_add(&piix3_device); - w83877f_init(5); - + device_add(&w83877f_device); device_add(&intel_flash_bxt_device); } @@ -816,8 +806,7 @@ machine_at_p55t2s_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430hx_device); device_add(&piix3_device); - pc87306_init(); - + device_add(&pc87306_device); device_add(&intel_flash_bxt_device); } @@ -838,8 +827,7 @@ machine_at_p55tvp4_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430vx_device); device_add(&piix3_device); - w83877f_init(5); - + device_add(&w83877f_device); device_add(&intel_flash_bxt_device); } @@ -860,8 +848,7 @@ machine_at_i430vx_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430vx_device); device_add(&piix3_device); - um8669f_init(); - + device_add(&um8669f_device); device_add(&intel_flash_bxt_device); } @@ -881,8 +868,7 @@ machine_at_p55va_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430vx_device); device_add(&piix3_device); - fdc37c932fr_init(); - + device_add(&fdc37c932fr_device); device_add(&intel_flash_bxt_device); } @@ -901,8 +887,7 @@ machine_at_j656vxd_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i430vx_device); device_add(&piix3_device); - fdc37c669_init(); - + device_add(&fdc37c669_device); device_add(&intel_flash_bxt_device); } @@ -925,8 +910,7 @@ machine_at_i440fx_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); device_add(&i440fx_device); device_add(&piix3_device); - fdc37c665_init(); - + device_add(&fdc37c665_device); device_add(&intel_flash_bxt_device); } @@ -948,8 +932,7 @@ machine_at_s1668_init(const machine_t *model) pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); device_add(&i440fx_device); device_add(&piix3_device); - fdc37c665_init(); - + device_add(&fdc37c665_device); device_add(&intel_flash_bxt_device); } #endif diff --git a/src/machine/m_at_commodore.c b/src/machine/m_at_commodore.c index 3fd264738..8f0eb849b 100644 --- a/src/machine/m_at_commodore.c +++ b/src/machine/m_at_commodore.c @@ -8,7 +8,7 @@ * * Implementation of the Commodore PC3 system. * - * Version: @(#)m_at_commodore.c 1.0.0 2018/09/02 + * Version: @(#)m_at_commodore.c 1.0.1 2018/11/06 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -53,6 +53,8 @@ static void cbm_io_write(uint16_t port, uint8_t val, void *p) { + serial_t *uart = machine_get_serial(0); + lpt1_remove(); lpt2_remove(); switch (val & 3) @@ -70,10 +72,10 @@ static void cbm_io_write(uint16_t port, uint8_t val, void *p) switch (val & 0xc) { case 0x4: - serial_setup(1, 0x2f8, 3); + serial_setup(uart, 0x2f8, 3); break; case 0x8: - serial_setup(1, 0x3f8, 4); + serial_setup(uart, 0x3f8, 4); break; } } diff --git a/src/machine/m_at_sis_85c471.c b/src/machine/m_at_sis_85c471.c index fc511d7c6..f32b05875 100644 --- a/src/machine/m_at_sis_85c471.c +++ b/src/machine/m_at_sis_85c471.c @@ -9,7 +9,7 @@ * SiS sis85c471 Super I/O Chip * Used by DTK PKM-0038S E-2 * - * Version: @(#)m_at_sis85c471.c 1.0.10 2018/03/18 + * Version: @(#)m_at_sis85c471.c 1.0.11 2018/11/06 * * Author: Miran Grca, * @@ -17,6 +17,7 @@ */ #include #include +#include #include #include #include "../86box.h" @@ -32,220 +33,201 @@ #include "machine.h" -static int sis_85c471_curreg; -static uint8_t sis_85c471_regs[39]; +typedef struct { + uint8_t cur_reg, + regs[39]; +} sis_85c471_t; -static void sis_85c471_write(uint16_t port, uint8_t val, void *priv) +static void +sis_85c471_write(uint16_t port, uint8_t val, void *priv) { - uint8_t index = (port & 1) ? 0 : 1; - uint8_t x; + sis_85c471_t *dev = (sis_85c471_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor; + serial_t *uart[2]; - if (index) - { - if ((val >= 0x50) && (val <= 0x76)) sis_85c471_curreg = val; - return; - } - else - { - if ((sis_85c471_curreg < 0x50) || (sis_85c471_curreg > 0x76)) return; - x = val ^ sis_85c471_regs[sis_85c471_curreg - 0x50]; - /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ - if (sis_85c471_curreg != 0x52) sis_85c471_regs[sis_85c471_curreg - 0x50] = val; - goto process_value; - } + if (index) { + if ((val >= 0x50) && (val <= 0x76)) + dev->cur_reg = val; return; + } else { + if ((dev->cur_reg < 0x50) || (dev->cur_reg > 0x76)) + return; + valxor = val ^ dev->regs[dev->cur_reg - 0x50]; + /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ + if (dev->cur_reg != 0x52) + dev->regs[dev->cur_reg - 0x50] = val; + } -process_value: - switch(sis_85c471_curreg) - { - case 0x73: -#if 0 - if (x & 0x40) - { - if (val & 0x40) - ide_pri_enable(); - else - ide_pri_disable(); - } -#endif - - if (x & 0x20) - { - if (val & 0x20) - { - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); - } - else - { - serial_remove(1); - serial_remove(2); - } - } - - if (x & 0x10) - { - if (val & 0x10) - lpt1_init(0x378); - else - lpt1_remove(); - } - - break; - } - sis_85c471_curreg = 0; -} - - -static uint8_t sis_85c471_read(uint16_t port, void *priv) -{ - uint8_t index = (port & 1) ? 0 : 1; - uint8_t temp; - - if (index) - return sis_85c471_curreg; - else - if ((sis_85c471_curreg >= 0x50) && (sis_85c471_curreg <= 0x76)) - { - temp = sis_85c471_regs[sis_85c471_curreg - 0x50]; - sis_85c471_curreg = 0; - return temp; + switch(dev->cur_reg) { + case 0x73: + if (valxor & 0x40) { + ide_pri_disable(); + if (val & 0x40) + ide_pri_enable(); } - else - return 0xFF; + if (valxor & 0x20) { + uart[0] = machine_get_serial(0); + uart[1] = machine_get_serial(1); + serial_remove(uart[0]); + serial_remove(uart[1]); + if (val & 0x20) { + serial_setup(uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(uart[0], SERIAL2_ADDR, SERIAL2_IRQ); + } + } + if (valxor & 0x10) { + lpt1_remove(); + if (val & 0x10) + lpt1_init(0x378); + } + break; + } + + dev->cur_reg = 0; } -static void sis_85c471_init(void) +static uint8_t +sis_85c471_read(uint16_t port, void *priv) { - int i = 0; + sis_85c471_t *dev = (sis_85c471_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff;; - lpt2_remove(); - - sis_85c471_curreg = 0; - for (i = 0; i < 0x27; i++) - { - sis_85c471_regs[i] = 0; - } - sis_85c471_regs[9] = 0x40; - switch (mem_size) - { - case 0: - case 1: - sis_85c471_regs[9] |= 0; - break; - case 2: - case 3: - sis_85c471_regs[9] |= 1; - break; - case 4: - sis_85c471_regs[9] |= 2; - break; - case 5: - sis_85c471_regs[9] |= 0x20; - break; - case 6: - case 7: - sis_85c471_regs[9] |= 9; - break; - case 8: - case 9: - sis_85c471_regs[9] |= 4; - break; - case 10: - case 11: - sis_85c471_regs[9] |= 5; - break; - case 12: - case 13: - case 14: - case 15: - sis_85c471_regs[9] |= 0xB; - break; - case 16: - sis_85c471_regs[9] |= 0x13; - break; - case 17: - sis_85c471_regs[9] |= 0x21; - break; - case 18: - case 19: - sis_85c471_regs[9] |= 6; - break; - case 20: - case 21: - case 22: - case 23: - sis_85c471_regs[9] |= 0xD; - break; - case 24: - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 31: - sis_85c471_regs[9] |= 0xE; - break; - case 32: - case 33: - case 34: - case 35: - sis_85c471_regs[9] |= 0x1B; - break; - case 36: - case 37: - case 38: - case 39: - sis_85c471_regs[9] |= 0xF; - break; - case 40: - case 41: - case 42: - case 43: - case 44: - case 45: - case 46: - case 47: - sis_85c471_regs[9] |= 0x17; - break; - case 48: - sis_85c471_regs[9] |= 0x1E; - break; - default: - if (mem_size < 64) - { - sis_85c471_regs[9] |= 0x1E; - } - else if ((mem_size >= 65) && (mem_size < 68)) - { - sis_85c471_regs[9] |= 0x22; - } - else - { - sis_85c471_regs[9] |= 0x24; - } - break; + if (index) + ret = dev->cur_reg; + else { + if ((dev->cur_reg >= 0x50) && (dev->cur_reg <= 0x76)) { + ret = dev->regs[dev->cur_reg - 0x50]; + dev->cur_reg = 0; } + } - sis_85c471_regs[0x11] = 9; - sis_85c471_regs[0x12] = 0xFF; - sis_85c471_regs[0x23] = 0xF0; - sis_85c471_regs[0x26] = 1; - - io_sethandler(0x0022, 0x0002, sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, NULL); + return ret; } +static void +sis_85c471_close(void *priv) +{ + sis_85c471_t *dev = (sis_85c471_t *) priv; + + free(dev); +} + + +static void * +sis_85c471_init(const device_t *info) +{ + int mem_size_mb, i = 0; + + sis_85c471_t *dev = (sis_85c471_t *) malloc(sizeof(sis_85c471_t)); + memset(dev, 0, sizeof(sis_85c471_t)); + + lpt2_remove(); + + dev->cur_reg = 0; + for (i = 0; i < 0x27; i++) + dev->regs[i] = 0x00; + + dev->regs[9] = 0x40; + + mem_size_mb = mem_size >> 10; + switch (mem_size_mb) { + case 0: case 1: + dev->regs[9] |= 0; + break; + case 2: case 3: + dev->regs[9] |= 1; + break; + case 4: + dev->regs[9] |= 2; + break; + case 5: + dev->regs[9] |= 0x20; + break; + case 6: case 7: + dev->regs[9] |= 9; + break; + case 8: case 9: + dev->regs[9] |= 4; + break; + case 10: case 11: + dev->regs[9] |= 5; + break; + case 12: case 13: case 14: case 15: + dev->regs[9] |= 0xB; + break; + case 16: + dev->regs[9] |= 0x13; + break; + case 17: + dev->regs[9] |= 0x21; + break; + case 18: case 19: + dev->regs[9] |= 6; + break; + case 20: case 21: case 22: case 23: + dev->regs[9] |= 0xD; + break; + case 24: case 25: case 26: case 27: + case 28: case 29: case 30: case 31: + dev->regs[9] |= 0xE; + break; + case 32: case 33: case 34: case 35: + dev->regs[9] |= 0x1B; + break; + case 36: case 37: case 38: case 39: + dev->regs[9] |= 0xF; + break; + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + dev->regs[9] |= 0x17; + break; + case 48: + dev->regs[9] |= 0x1E; + break; + default: + if (mem_size_mb < 64) + dev->regs[9] |= 0x1E; + else if ((mem_size_mb >= 65) && (mem_size_mb < 68)) + dev->regs[9] |= 0x22; + else + dev->regs[9] |= 0x24; + break; + } + + dev->regs[0x11] = 9; + dev->regs[0x12] = 0xFF; + dev->regs[0x23] = 0xF0; + dev->regs[0x26] = 1; + + io_sethandler(0x0022, 0x0002, + sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, dev); + + return dev; +} + + +const device_t sis_85c471_device = { + "SiS 85c471", + 0, + 0, + sis_85c471_init, sis_85c471_close, NULL, + NULL, NULL, NULL, + NULL +}; + + void machine_at_dtk486_init(const machine_t *model) { - machine_at_ide_init(model); - device_add(&fdc_at_device); + machine_at_ide_init(model); + device_add(&fdc_at_device); - memregs_init(); - sis_85c471_init(); - secondary_ide_check(); + memregs_init(); + device_add(&sis_85c471_device); + secondary_ide_check(); } diff --git a/src/machine/m_at_sis_85c496.c b/src/machine/m_at_sis_85c496.c index be457d328..b224b1228 100644 --- a/src/machine/m_at_sis_85c496.c +++ b/src/machine/m_at_sis_85c496.c @@ -8,7 +8,7 @@ * * Implementation of the SiS 85c496/85c497 chip. * - * Version: @(#)m_at_sis_85c496.c 1.0.2 2018/10/02 + * Version: @(#)m_at_sis_85c496.c 1.0.3 2018/11/05 * * Authors: Sarah Walker, * Miran Grca, @@ -35,10 +35,54 @@ typedef struct sis_85c496_t { - uint8_t pci_conf[256]; + uint8_t cur_reg, + regs[39], + pci_conf[256]; } sis_85c496_t; +static void +sis_85c497_write(uint16_t port, uint8_t val, void *priv) +{ + sis_85c496_t *dev = (sis_85c496_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + + if (index) { + if ((val >= 0x50) && (val <= 0x76)) + dev->cur_reg = val; + return; + } else { + if ((dev->cur_reg < 0x50) || (dev->cur_reg > 0x76)) + return; + /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ + if (dev->cur_reg != 0x52) + dev->regs[dev->cur_reg - 0x50] = val; + } + + dev->cur_reg = 0; +} + + +static uint8_t +sis_85c497_read(uint16_t port, void *priv) +{ + sis_85c496_t *dev = (sis_85c496_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; + + if (index) + ret = dev->cur_reg; + else { + if ((dev->cur_reg >= 0x50) && (dev->cur_reg <= 0x76)) { + ret = dev->regs[dev->cur_reg - 0x50]; + dev->cur_reg = 0; + } + } + + return ret; +} + + static void sis_85c496_recalcmapping(sis_85c496_t *dev) { @@ -72,9 +116,9 @@ sis_85c496_recalcmapping(sis_85c496_t *dev) static void -sis_85c496_write(int func, int addr, uint8_t val, void *p) +sis_85c496_write(int func, int addr, uint8_t val, void *priv) { - sis_85c496_t *dev = (sis_85c496_t *) p; + sis_85c496_t *dev = (sis_85c496_t *) priv; switch (addr) { case 0x44: /*Shadow configure*/ @@ -90,6 +134,10 @@ sis_85c496_write(int func, int addr, uint8_t val, void *p) } break; + case 0x82: + sis_85c497_write(0x22, val, priv); + break; + case 0xc0: if (val & 0x80) pci_set_irq_routing(PCI_INTA, val & 0xf); @@ -122,14 +170,104 @@ sis_85c496_write(int func, int addr, uint8_t val, void *p) static uint8_t -sis_85c496_read(int func, int addr, void *p) +sis_85c496_read(int func, int addr, void *priv) { - sis_85c496_t *dev = (sis_85c496_t *) p; + sis_85c496_t *dev = (sis_85c496_t *) priv; return dev->pci_conf[addr]; } +static void +sis_85c497_reset(sis_85c496_t *dev) +{ + int mem_size_mb, i = 0; + + memset(dev->regs, 0, sizeof(dev->regs)); + + dev->cur_reg = 0; + for (i = 0; i < 0x27; i++) + dev->regs[i] = 0x00; + + dev->regs[9] = 0x40; + + mem_size_mb = mem_size >> 10; + switch (mem_size_mb) { + case 0: case 1: + dev->regs[9] |= 0; + break; + case 2: case 3: + dev->regs[9] |= 1; + break; + case 4: + dev->regs[9] |= 2; + break; + case 5: + dev->regs[9] |= 0x20; + break; + case 6: case 7: + dev->regs[9] |= 9; + break; + case 8: case 9: + dev->regs[9] |= 4; + break; + case 10: case 11: + dev->regs[9] |= 5; + break; + case 12: case 13: case 14: case 15: + dev->regs[9] |= 0xB; + break; + case 16: + dev->regs[9] |= 0x13; + break; + case 17: + dev->regs[9] |= 0x21; + break; + case 18: case 19: + dev->regs[9] |= 6; + break; + case 20: case 21: case 22: case 23: + dev->regs[9] |= 0xD; + break; + case 24: case 25: case 26: case 27: + case 28: case 29: case 30: case 31: + dev->regs[9] |= 0xE; + break; + case 32: case 33: case 34: case 35: + dev->regs[9] |= 0x1B; + break; + case 36: case 37: case 38: case 39: + dev->regs[9] |= 0xF; + break; + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + dev->regs[9] |= 0x17; + break; + case 48: + dev->regs[9] |= 0x1E; + break; + default: + if (mem_size_mb < 64) + dev->regs[9] |= 0x1E; + else if ((mem_size_mb >= 65) && (mem_size_mb < 68)) + dev->regs[9] |= 0x22; + else + dev->regs[9] |= 0x24; + break; + } + + dev->regs[0x11] = 9; + dev->regs[0x12] = 0xFF; + dev->regs[0x23] = 0xF0; + dev->regs[0x26] = 1; + + io_removehandler(0x0022, 0x0002, + sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev); + io_sethandler(0x0022, 0x0002, + sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev); +} + + static void sis_85c496_reset(void *priv) { @@ -137,6 +275,8 @@ sis_85c496_reset(void *priv) val = sis_85c496_read(0, 0x44, priv); /* Read current value of 0x44. */ sis_85c496_write(0, 0x44, val & 0xf, priv); /* Turn off shadow BIOS but keep the lower 4 bits. */ + + sis_85c497_reset((sis_85c496_t *) priv); } @@ -152,31 +292,33 @@ sis_85c496_close(void *p) static void *sis_85c496_init(const device_t *info) { - sis_85c496_t *sis496 = malloc(sizeof(sis_85c496_t)); - memset(sis496, 0, sizeof(sis_85c496_t)); + sis_85c496_t *dev = malloc(sizeof(sis_85c496_t)); + memset(dev, 0, sizeof(sis_85c496_t)); - sis496->pci_conf[0x00] = 0x39; /*SiS*/ - sis496->pci_conf[0x01] = 0x10; - sis496->pci_conf[0x02] = 0x96; /*496/497*/ - sis496->pci_conf[0x03] = 0x04; + dev->pci_conf[0x00] = 0x39; /*SiS*/ + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x96; /*496/497*/ + dev->pci_conf[0x03] = 0x04; - sis496->pci_conf[0x04] = 7; - sis496->pci_conf[0x05] = 0; + dev->pci_conf[0x04] = 7; + dev->pci_conf[0x05] = 0; - sis496->pci_conf[0x06] = 0x80; - sis496->pci_conf[0x07] = 0x02; + dev->pci_conf[0x06] = 0x80; + dev->pci_conf[0x07] = 0x02; - sis496->pci_conf[0x08] = 2; /*Device revision*/ + dev->pci_conf[0x08] = 2; /*Device revision*/ - sis496->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ - sis496->pci_conf[0x0a] = 0x00; - sis496->pci_conf[0x0b] = 0x06; + dev->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; - sis496->pci_conf[0x0e] = 0x00; /*Single function device*/ + dev->pci_conf[0x0e] = 0x00; /*Single function device*/ - pci_add_card(5, sis_85c496_read, sis_85c496_write, sis496); + pci_add_card(5, sis_85c496_read, sis_85c496_write, dev); - return sis496; + sis_85c497_reset(dev); + + return dev; } @@ -225,5 +367,5 @@ machine_at_r418_init(const machine_t *model) { machine_at_sis_85c496_common_init(model); - fdc37c665_init(); + device_add(&fdc37c665_device); } diff --git a/src/machine/m_at_wd76c10.c b/src/machine/m_at_wd76c10.c index 670edb6d9..bb45adc9e 100644 --- a/src/machine/m_at_wd76c10.c +++ b/src/machine/m_at_wd76c10.c @@ -50,6 +50,11 @@ wd76c10_read(uint16_t port, void *priv) static void wd76c10_write(uint16_t port, uint16_t val, void *priv) { + serial_t *uart[2]; + + uart[0] = machine_get_serial(0); + uart[1] = machine_get_serial(1); + switch (port) { case 0x0092: @@ -62,28 +67,28 @@ wd76c10_write(uint16_t port, uint16_t val, void *priv) case 0x2072: wd76c10_2072 = val; - serial_remove(1); + serial_remove(uart[0]); if (!(val & 0x10)) { switch ((val >> 5) & 7) { - case 1: serial_setup(1, 0x3f8, 4); break; - case 2: serial_setup(1, 0x2f8, 4); break; - case 3: serial_setup(1, 0x3e8, 4); break; - case 4: serial_setup(1, 0x2e8, 4); break; - default: serial_remove(1); break; + case 1: serial_setup(uart[0], 0x3f8, 4); break; + case 2: serial_setup(uart[0], 0x2f8, 4); break; + case 3: serial_setup(uart[0], 0x3e8, 4); break; + case 4: serial_setup(uart[0], 0x2e8, 4); break; + default: break; } } - serial_remove(2); + serial_remove(uart[1]); if (!(val & 0x01)) { switch ((val >> 1) & 7) { - case 1: serial_setup(2, 0x3f8, 3); break; - case 2: serial_setup(2, 0x2f8, 3); break; - case 3: serial_setup(2, 0x3e8, 3); break; - case 4: serial_setup(2, 0x2e8, 3); break; - default: serial_remove(1); break; + case 1: serial_setup(uart[1], 0x3f8, 3); break; + case 2: serial_setup(uart[1], 0x2f8, 3); break; + case 3: serial_setup(uart[1], 0x3e8, 3); break; + case 4: serial_setup(uart[1], 0x2e8, 3); break; + default: break; } } break; diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 608b32bba..a5e7a0600 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -8,7 +8,7 @@ * * Emulation of the IBM PCjr. * - * Version: @(#)m_pcjr.c 1.0.10 2018/11/02 + * Version: @(#)m_pcjr.c 1.0.11 2018/11/06 * * Authors: Sarah Walker, * Miran Grca, @@ -757,7 +757,7 @@ machine_pcjr_init(const machine_t *model) setrtcconst(14318184.0); if (serial_enabled[0]) - serial_setup(1, 0x2f8, 3); + serial_setup(machine_get_serial(0), 0x2f8, 3); /* Initialize the video controller. */ mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 2e5413d0c..2ea9bd3cb 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -28,7 +28,7 @@ * boot. Sometimes, they do, and then it shows an "Incorrect * DOS" error message?? --FvK * - * Version: @(#)m_ps1.c 1.0.12 2018/09/19 + * Version: @(#)m_ps1.c 1.0.13 2018/11/06 * * Authors: Sarah Walker, * Miran Grca, @@ -292,6 +292,7 @@ static void ps1_write(uint16_t port, uint8_t val, void *priv) { ps1_t *ps = (ps1_t *)priv; + serial_t *uart; switch (port) { case 0x0092: @@ -327,10 +328,11 @@ ps1_write(uint16_t port, uint8_t val, void *priv) case 0x0102: lpt1_remove(); + uart = machine_get_serial(0); if (val & 0x04) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_remove(1); + serial_remove(uart); if (val & 0x10) { switch ((val >> 5) & 3) { case 0: @@ -457,8 +459,8 @@ ps1_setup(int model) lpt2_remove(); - serial_remove(1); - serial_remove(2); + serial_remove(machine_get_serial(0)); + serial_remove(machine_get_serial(1)); /* Enable the PS/1 VGA controller. */ if (model == 2011) diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 213e06b50..63c498edc 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -70,6 +70,8 @@ static uint8_t ps2_read(uint16_t port, void *p) static void ps2_write(uint16_t port, uint8_t val, void *p) { + serial_t *uart = machine_get_serial(0); + switch (port) { case 0x94: @@ -78,9 +80,9 @@ static void ps2_write(uint16_t port, uint8_t val, void *p) case 0x102: lpt1_remove(); if (val & 0x04) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_remove(1); + serial_remove(uart); if (val & 0x10) { switch ((val >> 5) & 3) diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index bc07919ee..30fc3a564 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -8,7 +8,7 @@ * * Implementation of MCA-based PS/2 machines. * - * Version: @(#)m_ps2_mca.c 1.0.3 2018/10/22 + * Version: @(#)m_ps2_mca.c 1.0.4 2018/11/06 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -372,6 +372,8 @@ static uint8_t model_80_read(uint16_t port) static void model_50_write(uint16_t port, uint8_t val) { + serial_t *uart = machine_get_serial(0); + switch (port) { case 0x100: @@ -381,16 +383,14 @@ static void model_50_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(1); + serial_remove(uart); if (val & 0x04) { if (val & 0x08) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(uart, SERIAL2_ADDR, SERIAL2_IRQ); } - else - serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) @@ -428,6 +428,8 @@ static void model_50_write(uint16_t port, uint8_t val) static void model_55sx_write(uint16_t port, uint8_t val) { + serial_t *uart = machine_get_serial(0); + switch (port) { case 0x100: @@ -437,16 +439,14 @@ static void model_55sx_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(1); + serial_remove(uart); if (val & 0x04) { if (val & 0x08) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(uart, SERIAL2_ADDR, SERIAL2_IRQ); } - else - serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) @@ -505,6 +505,8 @@ static void model_55sx_write(uint16_t port, uint8_t val) static void model_70_type3_write(uint16_t port, uint8_t val) { + serial_t *uart = machine_get_serial(0); + switch (port) { case 0x100: @@ -513,16 +515,14 @@ static void model_70_type3_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(1); + serial_remove(uart); if (val & 0x04) { if (val & 0x08) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(uart, SERIAL2_ADDR, SERIAL2_IRQ); } - else - serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) @@ -555,6 +555,8 @@ static void model_70_type3_write(uint16_t port, uint8_t val) static void model_80_write(uint16_t port, uint8_t val) { + serial_t *uart = machine_get_serial(0); + switch (port) { case 0x100: @@ -563,16 +565,14 @@ static void model_80_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(1); + serial_remove(uart); if (val & 0x04) { if (val & 0x08) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(uart, SERIAL2_ADDR, SERIAL2_IRQ); } - else - serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) diff --git a/src/machine/machine.c b/src/machine/machine.c index 80b3d7f6a..a186631bd 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.c 1.0.35 2018/10/22 + * Version: @(#)machine.c 1.0.36 2018/11/05 * * Authors: Sarah Walker, * Miran Grca, @@ -42,6 +42,8 @@ int machine; int AT, PCI; int romset; +static serial_t *uart[2]; + #ifdef ENABLE_MACHINE_LOG int machine_do_log = ENABLE_MACHINE_LOG; @@ -90,6 +92,12 @@ machine_init(void) /* All good, boot the machine! */ machines[machine].init(&machines[machine]); + /* For non-PCI machines, add two regular 8250 UART's. */ + if (!PCI) { + uart[0] = device_add_inst(&i8250_device, 1); + uart[1] = device_add_inst(&i8250_device, 2); + } + /* If it's a PCI or MCA machine, reset the video card after initializing the machine, so the slots work correctly. */ if (PCI || MCA) @@ -97,6 +105,13 @@ machine_init(void) } +serial_t * +machine_get_serial(int port) +{ + return uart[port]; +} + + void machine_common_init(const machine_t *model) { @@ -113,10 +128,4 @@ machine_common_init(const machine_t *model) if (lpt_enabled) lpt_init(); - - if (serial_enabled[0]) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - - if (serial_enabled[1]) - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); } diff --git a/src/machine/machine.h b/src/machine/machine.h index 710547911..ca87e3fe9 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -82,6 +82,9 @@ extern int machine_getmachine(int romset); extern char *machine_getname(void); extern char *machine_get_internal_name(void); extern int machine_get_machine_from_internal_name(char *s); +#ifdef EMU_SERIAL_H +extern serial_t *machine_get_serial(int port); +#endif extern void machine_init(void); #ifdef EMU_DEVICE_H extern const device_t *machine_getdevice(int machine); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 53c28adba..e5e7daa93 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11,7 +11,7 @@ * NOTES: OpenAT wip for 286-class machine with open BIOS. * PS2_M80-486 wip, pending receipt of TRM's for machine. * - * Version: @(#)machine_table.c 1.0.43 2018/11/02 + * Version: @(#)machine_table.c 1.0.44 2018/11/03 * * Authors: Sarah Walker, * Miran Grca, @@ -85,7 +85,7 @@ const machine_t machines[] = { { "[286 MCA] IBM PS/2 model 50", ROM_IBMPS2_M50, "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, { "[386SX ISA] AMA-932J", ROM_AMA932J, "ama932j", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 512, 8192, 128, 127, machine_at_ama932j_init, at_ama932j_get_device }, - { "[386DX ISA] AMI 386SX clone", ROM_AMI386SX_OPTI495, "ami386sx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 16, 1, 127, machine_at_opti495_ami_init, NULL }, + { "[386DX ISA] AMI 386SX clone", ROM_AMI386SX_OPTI495, "ami386sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 16, 1, 127, machine_at_opti495_ami_init, NULL }, { "[386SX ISA] AMI Unknown 386SX", ROM_AMI386SX, "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, { "[386SX ISA] Amstrad MegaPC", ROM_MEGAPC, "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 16, 1, 127, machine_at_wd76c10_init, NULL }, { "[386SX ISA] Award 386SX clone", ROM_AWARD386SX_OPTI495, "award386sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 16, 1, 127, machine_at_opti495_init, NULL }, diff --git a/src/mouse.c b/src/mouse.c index b98ebecea..74f8e9cf5 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -11,7 +11,7 @@ * TODO: Add the Genius bus- and serial mouse. * Remove the '3-button' flag from mouse types. * - * Version: @(#)mouse.c 1.0.28 2018/10/17 + * Version: @(#)mouse.c 1.0.29 2018/11/04 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -69,6 +69,7 @@ static mouse_t mouse_devices[] = { #endif { "mssystems", &mouse_mssystems_device }, { "msserial", &mouse_msserial_device }, + { "ltserial", &mouse_ltserial_device }, { "ps2", &mouse_ps2_device }, { NULL, NULL } }; diff --git a/src/mouse.h b/src/mouse.h index 341646178..d78ac2db1 100644 --- a/src/mouse.h +++ b/src/mouse.h @@ -8,7 +8,7 @@ * * Definitions for the mouse driver. * - * Version: @(#)mouse.h 1.0.15 2018/03/18 + * Version: @(#)mouse.h 1.0.14 2018/11/04 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -28,10 +28,12 @@ # define MOUSE_TYPE_GENIBUS 4 /* Genius Bus Mouse */ #endif #define MOUSE_TYPE_MSYSTEMS 5 /* Mouse Systems mouse */ -#define MOUSE_TYPE_MICROSOFT 6 /* Microsoft Serial Mouse */ -#define MOUSE_TYPE_LOGITECH 7 /* Logitech Serial Mouse */ -#define MOUSE_TYPE_MSWHEEL 8 /* Serial Wheel Mouse */ -#define MOUSE_TYPE_PS2 9 /* PS/2 series Bus Mouse */ +#define MOUSE_TYPE_MICROSOFT 6 /* Microsoft 2-button Serial Mouse */ +#define MOUSE_TYPE_MS3BUTTON 7 /* Microsoft 3-button Serial Mouse */ +#define MOUSE_TYPE_MSWHEEL 8 /* Microsoft Serial Wheel Mouse */ +#define MOUSE_TYPE_LOGITECH 9 /* Logitech 2-button Serial Mouse */ +#define MOUSE_TYPE_LT3BUTTON 10 /* Logitech 3-button Serial Mouse */ +#define MOUSE_TYPE_PS2 11 /* PS/2 series Bus Mouse */ #ifdef __cplusplus @@ -54,6 +56,7 @@ extern const device_t mouse_genibus_device; #endif extern const device_t mouse_mssystems_device; extern const device_t mouse_msserial_device; +extern const device_t mouse_ltserial_device; extern const device_t mouse_ps2_device; #endif diff --git a/src/mouse_serial.c b/src/mouse_serial.c index 77bba50e3..dff7ba0f3 100644 --- a/src/mouse_serial.c +++ b/src/mouse_serial.c @@ -10,7 +10,7 @@ * * TODO: Add the Genius Serial Mouse. * - * Version: @(#)mouse_serial.c 1.0.25 2018/10/17 + * Version: @(#)mouse_serial.c 1.0.26 2018/11/05 * * Author: Fred N. van Kempen, */ @@ -28,20 +28,35 @@ #include "mouse.h" -#define SERMOUSE_PORT 0 /* attach to Serial0 */ +#define SERMOUSE_PORT 0 /* attach to Serial0 */ + +#define PHASE_IDLE 0 +#define PHASE_ID 1 +#define PHASE_DATA 2 +#define PHASE_STATUS 3 +#define PHASE_DIAGNOSTIC 4 +#define PHASE_FORMAT_AND_REVISION 5 typedef struct { const char *name; /* name of this device */ int8_t type, /* type of this device */ port; - uint8_t flags; /* device flags */ + uint8_t flags, but, /* device flags */ + want_data, + status, format, + prompt, continuous, + id_len, id[255], + data_len, data[5]; + int abs_x, abs_y; int pos; int64_t delay; + int64_t period; int oldb; + int phase; - SERIAL *serial; + serial_t *serial; } mouse_t; #define FLAG_INPORT 0x80 /* device is MS InPort */ #define FLAG_3BTN 0x20 /* enable 3-button mode */ @@ -73,14 +88,201 @@ mouse_serial_log(const char *fmt, ...) /* Callback from serial driver: RTS was toggled. */ static void -sermouse_callback(struct SERIAL *serial, void *priv) +sermouse_callback(struct serial_s *serial, void *priv) { mouse_t *dev = (mouse_t *)priv; /* Start a timer to wake us up in a little while. */ - dev->pos = -1; - serial_clear_fifo((SERIAL *) serial); - dev->delay = 5000LL * (1LL << TIMER_SHIFT); + dev->pos = 0; + dev->phase = PHASE_ID; + dev->delay = dev->period; +} + + +static uint8_t +sermouse_data_msystems(mouse_t *dev, int x, int y, int b) +{ + dev->data[0] = 0x80; + dev->data[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ + dev->data[0] |= (b & 0x02) ? 0x00 : 0x01; /* middle button */ + dev->data[0] |= (b & 0x04) ? 0x00 : 0x02; /* right button */ + dev->data[1] = x; + dev->data[2] = -y; + dev->data[3] = x; /* same as byte 1 */ + dev->data[4] = -y; /* same as byte 2 */ + + return 5; +} + + +static uint8_t +sermouse_data_3bp(mouse_t *dev, int x, int y, int b) +{ + dev->data[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ + dev->data[0] |= (b & 0x02) ? 0x00 : 0x02; /* middle button */ + dev->data[0] |= (b & 0x04) ? 0x00 : 0x01; /* right button */ + dev->data[1] = x; + dev->data[2] = -y; + + return 3; +} + + +static uint8_t +sermouse_data_mmseries(mouse_t *dev, int x, int y, int b) +{ + if (x < -127) + x = -127; + if (y < -127) + y = -127; + + dev->data[0] = 0x80; + if (x >= 0) + dev->data[0] |= 0x10; + if (y < 0) + dev->data[0] |= 0x08; + dev->data[0] |= (b & 0x01) ? 0x04 : 0x00; /* left button */ + dev->data[0] |= (b & 0x02) ? 0x02 : 0x00; /* middle button */ + dev->data[0] |= (b & 0x04) ? 0x01 : 0x00; /* right button */ + dev->data[1] = abs(x); + dev->data[2] = abs(y); + + return 3; +} + + +static uint8_t +sermouse_data_bp1(mouse_t *dev, int x, int y, int b) +{ + dev->data[0] = 0x80; + dev->data[0] |= (b & 0x01) ? 0x10 : 0x00; /* left button */ + dev->data[0] |= (b & 0x02) ? 0x08 : 0x00; /* middle button */ + dev->data[0] |= (b & 0x04) ? 0x04 : 0x00; /* right button */ + dev->data[1] = (x & 0x3f); + dev->data[2] = (x >> 6); + dev->data[3] = (y & 0x3f); + dev->data[4] = (y >> 6); + + return 5; +} + + +static uint8_t +sermouse_data_ms(mouse_t *dev, int x, int y, int z, int b) +{ + uint8_t len; + + dev->data[0] = 0x40; + dev->data[0] |= (((y >> 6) & 0x03) << 2); + dev->data[0] |= ((x >> 6) & 0x03); + if (b & 0x01) + dev->data[0] |= 0x20; + if (b & 0x02) + dev->data[0] |= 0x10; + dev->data[1] = x & 0x3F; + dev->data[2] = y & 0x3F; + if (dev->but == 3) { + len = 3; + if (dev->type == MOUSE_TYPE_LT3BUTTON) { + if (b & 0x04) { + dev->data[3] = 0x20; + len++; + } + } else { + if ((b ^ dev->oldb) & 0x04) { + /* Microsoft 3-button mice send a fourth byte of 0x00 when the middle button + has changed. */ + dev->data[3] = 0x00; + len++; + } + } + } else if (dev->but == 4) { + len = 4; + dev->data[3] = z & 0x0F; + if (b & 0x04) + dev->data[3] |= 0x10; + } else + len = 3; + + return len; +} + + +static uint8_t +sermouse_data_hex(mouse_t *dev, int x, int y, int b) +{ + char ret[6] = { 0, 0, 0, 0, 0, 0 }; + uint8_t i, but = 0x00; + + but |= (b & 0x01) ? 0x04 : 0x00; /* left button */ + but |= (b & 0x02) ? 0x02 : 0x00; /* middle button */ + but |= (b & 0x04) ? 0x01 : 0x00; /* right button */ + + sprintf(ret, "%02X%02X%01X", (int8_t) y, (int8_t) x, but & 0x0f); + + for (i = 0; i < 5; i++) + dev->data[i] = ret[4 - i]; + + return 5; +} + + +static void +sermouse_report(int x, int y, int z, int b, mouse_t *dev) +{ + int len = 0; + + memset(dev->data, 0, 5); + + switch(dev->type) { + case MOUSE_TYPE_MSYSTEMS: + len = sermouse_data_msystems(dev, x, y, b); + break; + + case MOUSE_TYPE_MICROSOFT: + case MOUSE_TYPE_MS3BUTTON: + case MOUSE_TYPE_MSWHEEL: + len = sermouse_data_ms(dev, x, y, z, b); + break; + + case MOUSE_TYPE_LOGITECH: + case MOUSE_TYPE_LT3BUTTON: + switch (dev->format) { + case 0: + len = sermouse_data_msystems(dev, x, y, b); + break; + case 1: + len = sermouse_data_3bp(dev, x, y, b); + break; + case 2: + len = sermouse_data_hex(dev, x, y, b); + break; + case 3: /* Relative */ + len = sermouse_data_bp1(dev, x, y, b); + break; + case 5: + len = sermouse_data_mmseries(dev, x, y, b); + break; + case 6: /* Absolute */ + len = sermouse_data_bp1(dev, dev->abs_x, dev->abs_y, b); + break; + case 7: + len = sermouse_data_ms(dev, x, y, z, b); + break; + } + break; + } + + dev->oldb = b; + dev->data_len = len; + + dev->pos = 0; + + if (dev->phase != PHASE_DATA) + dev->phase = PHASE_DATA; + + if (!dev->delay) + dev->delay = dev->period; } @@ -90,36 +292,57 @@ sermouse_timer(void *priv) { mouse_t *dev = (mouse_t *)priv; - dev->delay = 0LL; - - if (dev->pos != -1) return; - - dev->pos = 0; - switch(dev->type) { - case MOUSE_TYPE_MSYSTEMS: - /* Identifies Mouse Systems serial mouse. */ - serial_write_fifo(dev->serial, 'H'); + switch (dev->phase) { + case PHASE_ID: + serial_write_fifo(dev->serial, dev->id[dev->pos]); + dev->pos++; + if (dev->pos == dev->id_len) { + dev->delay = 0LL; + dev->pos = 0; + dev->phase = PHASE_IDLE; + } else + dev->delay += dev->period; break; - - case MOUSE_TYPE_MICROSOFT: - /* Identifies a two-button Microsoft Serial mouse. */ - serial_write_fifo(dev->serial, 'M'); + case PHASE_DATA: + serial_write_fifo(dev->serial, dev->data[dev->pos]); + dev->pos++; + if (dev->pos == dev->data_len) { + dev->delay = 0LL; + dev->pos = 0; + dev->phase = PHASE_IDLE; + } else + dev->delay += dev->period; break; - - case MOUSE_TYPE_LOGITECH: - /* Identifies a two-button Logitech Serial mouse. */ - serial_write_fifo(dev->serial, 'M'); - serial_write_fifo(dev->serial, '3'); + case PHASE_STATUS: + serial_write_fifo(dev->serial, dev->status); + dev->delay = 0LL; + dev->pos = 0; + dev->phase = PHASE_IDLE; break; - - case MOUSE_TYPE_MSWHEEL: - /* Identifies multi-button Microsoft Wheel Mouse. */ - serial_write_fifo(dev->serial, 'M'); - serial_write_fifo(dev->serial, 'Z'); + case PHASE_DIAGNOSTIC: + if (dev->pos) + serial_write_fifo(dev->serial, 0x00); + else /* This should return the last button status, bits 2,1,0 = L,M,R. */ + serial_write_fifo(dev->serial, 0x00); + dev->pos++; + if (dev->pos == 3) { + dev->delay = 0LL; + dev->pos = 0; + dev->phase = PHASE_IDLE; + } else + dev->delay += dev->period; + break; + case PHASE_FORMAT_AND_REVISION: + serial_write_fifo(dev->serial, 0x10 | (dev->format << 1)); + dev->delay = 0LL; + dev->pos = 0; + dev->phase = PHASE_IDLE; break; - default: - mouse_serial_log("%s: unsupported mouse type %d?\n", dev->type); + dev->delay = 0LL; + dev->pos = 0; + dev->phase = PHASE_IDLE; + break; } } @@ -128,88 +351,160 @@ static int sermouse_poll(int x, int y, int z, int b, void *priv) { mouse_t *dev = (mouse_t *)priv; - uint8_t buff[16]; - int len; - if (!x && !y && b == dev->oldb) return(1); - -#if 0 - mouse_serial_log("%s: poll(%d,%d,%d,%02x)\n", dev->name, x, y, z, b); -#endif + if (!x && !y && (b == dev->oldb) && dev->continuous) + return(1); dev->oldb = b; + dev->abs_x += x; + dev->abs_y += y; + if (dev->abs_x < 0) + dev->abs_x = 0; + if (dev->abs_x > 4095) + dev->abs_x = 4095; + if (dev->abs_y < 0) + dev->abs_y = 0; + if (dev->abs_y > 4095) + dev->abs_y = 4095; - if (x > 127) x = 127; - if (y > 127) y = 127; - if (x <- 128) x = -128; - if (y <- 128) y = -128; - - len = 0; - switch(dev->type) { - case MOUSE_TYPE_MSYSTEMS: - buff[0] = 0x80; - buff[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ - buff[0] |= (b & 0x02) ? 0x00 : 0x01; /* middle button */ - buff[0] |= (b & 0x04) ? 0x00 : 0x02; /* right button */ - buff[1] = x; - buff[2] = -y; - buff[3] = x; /* same as byte 1 */ - buff[4] = -y; /* same as byte 2 */ - len = 5; - break; - - case MOUSE_TYPE_MICROSOFT: - case MOUSE_TYPE_LOGITECH: - case MOUSE_TYPE_MSWHEEL: - buff[0] = 0x40; - buff[0] |= (((y >> 6) & 0x03) << 2); - buff[0] |= ((x >> 6) & 0x03); - if (b & 0x01) buff[0] |= 0x20; - if (b & 0x02) buff[0] |= 0x10; - buff[1] = x & 0x3F; - buff[2] = y & 0x3F; - if (dev->type == MOUSE_TYPE_LOGITECH) { - len = 3; - if (b & 0x04) { - buff[3] = 0x20; - len++; - } - } else if (dev->type == MOUSE_TYPE_MSWHEEL) { - len = 4; - buff[3] = z & 0x0F; - if (b & 0x04) - buff[3] |= 0x10; - } else - len = 3; - break; + if (dev->format == 3) { + if (x > 2047) x = 2047; + if (y > 2047) y = 2047; + if (x <- 2048) x = -2048; + if (y <- 2048) y = -2048; + } else { + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x <- 128) x = -128; + if (y <- 128) y = -128; } -#if 0 - mouse_serial_log("%s: [", dev->name); - for (b=0; bserial != NULL) { - for (b=0; bserial, buff[b]); - } + /* No report if we're either in prompt mode, + or the mouse wants data. */ + if (!dev->prompt && !dev->want_data) + sermouse_report(x, y, z, b, dev); return(0); } +static void +ltsermouse_write(struct serial_s *serial, void *priv, uint8_t data) +{ + mouse_t *dev = (mouse_t *)priv; + +#if 0 + /* Make sure to stop any transmission when we receive a byte. */ + if (dev->phase != PHASE_IDLE) { + dev->delay = 0LL; + dev->phase = PHASE_IDLE; + } +#endif + + if (dev->want_data) switch (dev->want_data) { + case 0x2A: + dev->data_len--; + dev->want_data = 0; + dev->delay = 0LL; + dev->phase = PHASE_IDLE; + switch (data) { + default: + mouse_serial_log("Serial mouse: Invalid period %02X, using 1200 bps\n", data); + case 0x6E: + dev->period = 7500LL; /* 1200 bps */ + break; + case 0x6F: + dev->period = 3750LL; /* 2400 bps */ + break; + case 0x70: + dev->period = 1875LL; /* 4800 bps */ + break; + case 0x71: + dev->period = 938LL; /* 9600 bps */ + break; + } + dev->period *= TIMER_USEC; + break; + } else switch (data) { + case 0x2A: + dev->want_data = data; + dev->data_len = 1; + break; + case 0x44: /* Set prompt mode */ + dev->prompt = 1; + dev->status |= 0x40; + break; + case 0x50: + if (!dev->prompt) { + dev->prompt = 1; + dev->status |= 0x40; + } + /* TODO: Here we should send the current position. */ + break; + case 0x73: /* Status */ + dev->pos = 0; + dev->phase = PHASE_STATUS; + if (!dev->delay) + dev->delay = dev->period; + break; + case 0x4A: /* Report Rate Selection commands */ + case 0x4B: + case 0x4C: + case 0x52: + case 0x4D: + case 0x51: + case 0x4E: + case 0x4F: + dev->prompt = 0; + dev->status &= 0xBF; + // dev->continuous = (data == 0x4F); + break; + case 0x41: + dev->format = 6; /* Aboslute Bit Pad One Format */ + dev->abs_x = dev->abs_y = 0; + break; + case 0x42: + dev->format = 3; /* Relative Bit Pad One Format */ + break; + case 0x53: + dev->format = 5; /* MM Series Format */ + break; + case 0x54: + dev->format = 1; /* Three Byte Packed Binary Format */ + break; + case 0x55: /* This is the Mouse Systems-compatible format */ + dev->format = 0; /* Five Byte Packed Binary Format */ + break; + case 0x56: + dev->format = 7; /* Microsoft Compatible Format */ + break; + case 0x57: + dev->format = 2; /* Hexadecimal Format */ + break; + case 0x05: + dev->pos = 0; + dev->phase = PHASE_DIAGNOSTIC; + if (!dev->delay) + dev->delay = dev->period; + break; + case 0x66: + dev->pos = 0; + dev->phase = PHASE_FORMAT_AND_REVISION; + if (!dev->delay) + dev->delay = dev->period; + break; + } +} + + static void sermouse_close(void *priv) { mouse_t *dev = (mouse_t *)priv; /* Detach serial port from the mouse. */ - if ((dev != NULL) && (dev->serial != NULL)) { - dev->serial->rcr_callback = NULL; - dev->serial->rcr_callback_p = NULL; - } + if (dev && dev->serial && dev->serial->sd) + memset(dev->serial->sd, 0, sizeof(serial_device_t)); free(dev); } @@ -220,28 +515,41 @@ static void * sermouse_init(const device_t *info) { mouse_t *dev; - int i; dev = (mouse_t *)malloc(sizeof(mouse_t)); memset(dev, 0x00, sizeof(mouse_t)); dev->name = info->name; - i = device_get_config_int("buttons"); - if (i > 2) + dev->but = device_get_config_int("buttons"); + dev->continuous = 1; + if (dev->but > 2) dev->flags |= FLAG_3BTN; - if (info->local == MOUSE_TYPE_MSYSTEMS) + if (info->local == MOUSE_TYPE_MSYSTEMS) { + dev->period = 8333LL * TIMER_USEC; /* 1200 bps, 8 data bits, 1 start bit, 1 stop bit, no parity bit */ dev->type = info->local; - else { - switch(i) { + dev->id_len = 1; + dev->id[0] = 'H'; + } else { + dev->format = 7; + dev->status = 0x0f; + dev->period = 7500LL * TIMER_USEC; /* 1200 bps, 7 data bits, 1 start bit, 1 stop bit, no parity bit */ + dev->id_len = 1; + dev->id[0] = 'M'; + switch(dev->but) { case 2: default: - dev->type = MOUSE_TYPE_MICROSOFT; + dev->type = info->local ? MOUSE_TYPE_LOGITECH : MOUSE_TYPE_MICROSOFT; break; case 3: - dev->type = MOUSE_TYPE_LOGITECH; + dev->type = info->local ? MOUSE_TYPE_LT3BUTTON : MOUSE_TYPE_MS3BUTTON; + dev->id_len = 2; + dev->id[1] = '3'; break; case 4: dev->type = MOUSE_TYPE_MSWHEEL; + dev->id_len = 6; + dev->id[1] = 'Z'; + dev->id[2] = '@'; break; } } @@ -249,14 +557,12 @@ sermouse_init(const device_t *info) dev->port = device_get_config_int("port"); /* Attach a serial port to the mouse. */ - if (dev->port == 0) - dev->serial = &serial1; - else - dev->serial = &serial2; - dev->serial->rcr_callback = sermouse_callback; - dev->serial->rcr_callback_p = dev; + if (info->local) + dev->serial = serial_attach(dev->port, sermouse_callback, ltsermouse_write, dev); + else + dev->serial = serial_attach(dev->port, sermouse_callback, NULL, dev); - mouse_serial_log("%s: port=COM%d\n", dev->name, dev->port+1); + mouse_serial_log("%s: port=COM%d\n", dev->name, dev->port + 1); timer_add(sermouse_timer, &dev->delay, &dev->delay, dev); @@ -268,7 +574,7 @@ sermouse_init(const device_t *info) } -static const device_config_t sermouse_config[] = { +static const device_config_t mssermouse_config[] = { { "port", "Serial Port", CONFIG_SELECTION, "", 0, { { @@ -304,20 +610,62 @@ static const device_config_t sermouse_config[] = { }; +static const device_config_t ltsermouse_config[] = { + { + "port", "Serial Port", CONFIG_SELECTION, "", 0, { + { + "COM1", 0 + }, + { + "COM2", 1 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + const device_t mouse_mssystems_device = { "Mouse Systems Serial Mouse", 0, MOUSE_TYPE_MSYSTEMS, sermouse_init, sermouse_close, NULL, sermouse_poll, NULL, NULL, - sermouse_config + mssermouse_config }; const device_t mouse_msserial_device = { - "Microsoft/Logitech Serial Mouse", + "Microsoft Serial Mouse", 0, 0, sermouse_init, sermouse_close, NULL, sermouse_poll, NULL, NULL, - sermouse_config + mssermouse_config +}; + +const device_t mouse_ltserial_device = { + "Logitech Serial Mouse", + 0, + 1, + sermouse_init, sermouse_close, NULL, + sermouse_poll, NULL, NULL, + ltsermouse_config }; diff --git a/src/pc.c b/src/pc.c index 56c1207b5..f56cce0a5 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.88 2018/10/28 + * Version: @(#)pc.c 1.0.89 2018/11/05 * * Authors: Sarah Walker, * Miran Grca, @@ -755,9 +755,6 @@ pc_reset_hard_init(void) sound_reset(); - /* This is needed to initialize the serial timer. */ - serial_init(); - /* Initialize the actual machine and its basic modules. */ machine_init(); @@ -783,14 +780,11 @@ pc_reset_hard_init(void) /* Reset some basic devices. */ speaker_init(); - serial_reset(); lpt_devices_init(); shadowbios = 0; /* - * This has to be after the serial initialization so that - * serial_init() doesn't break the serial mouse by resetting - * the RCR callback to NULL. + * Reset the mouse, this will attach it to any port needed. */ mouse_reset(); diff --git a/src/pci.c b/src/pci.c index e5bf97209..43622857a 100644 --- a/src/pci.c +++ b/src/pci.c @@ -8,7 +8,7 @@ * * Implementation the PCI bus. * - * Version: @(#)pci.c 1.0.0 2018/10/21 + * Version: @(#)pci.c 1.0.1 2018/11/05 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -123,7 +123,7 @@ pci_write(uint16_t port, uint8_t val, void *priv) slot = pci_card_to_slot_mapping[pci_card]; if (slot != 0xff) { if (pci_cards[slot].write) { - pci_log("Reading PCI card on slot %02X (pci_cards[%i])...\n", pci_card, slot); + pci_log("Writing to PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); } } @@ -148,6 +148,7 @@ pci_read(uint16_t port, void *priv) slot = pci_card_to_slot_mapping[pci_card]; if (slot != 0xff) { if (pci_cards[slot].read) { + pci_log("Reading from PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); } } diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index 6ff1396ff..f0a5bed9c 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -8,7 +8,7 @@ * * Handling of the SCSI controllers. * - * Version: @(#)scsi.c 1.0.24 2018/10/30 + * Version: @(#)scsi.c 1.0.25 2018/10/31 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -55,27 +55,27 @@ typedef const struct { static SCSI_CARD scsi_cards[] = { - { "None", "none", NULL, }, - { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, }, - { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, }, - { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, }, - { "[ISA] BusLogic BT-542BH","bt542bh", &buslogic_device, }, - { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device, }, - { "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device, }, - { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, }, - { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, - { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, + { "None", "none", NULL, }, + { "[ISA] Adaptec AHA-1540B", "aha1540b", &aha1540b_device, }, + { "[ISA] Adaptec AHA-1542C", "aha1542c", &aha1542c_device, }, + { "[ISA] Adaptec AHA-1542CF", "aha1542cf", &aha1542cf_device, }, + { "[ISA] BusLogic BT-542BH", "bt542bh", &buslogic_device, }, + { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device, }, + { "[ISA] Longshine LCS-6821N", "lcs6821n", &scsi_lcs6821n_device, }, + { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, }, + { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, + { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, #ifdef WALTJE - { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, + { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, #endif - { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, - { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device, }, - { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, - { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device, }, - { "[PCI] NCR 53C825A", "ncr53c825a", &ncr53c825a_pci_device, }, - { "[PCI] NCR 53C875", "ncr53c875", &ncr53c875_pci_device, }, - { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device, }, - { "", "", NULL, }, + { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, + { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device, }, + { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, + { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device, }, + { "[PCI] NCR 53C825A", "ncr53c825a", &ncr53c825a_pci_device, }, + { "[PCI] NCR 53C875", "ncr53c875", &ncr53c875_pci_device, }, + { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device, }, + { "", "", NULL, }, }; diff --git a/src/serial.c b/src/serial.c index 6b7ed6915..de5d94aa9 100644 --- a/src/serial.c +++ b/src/serial.c @@ -1,11 +1,12 @@ #include #include #include -#include #include +#include #include #define HAVE_STDARG_H #include "86box.h" +#include "device.h" #include "machine/machine.h" #include "io.h" #include "pic.h" @@ -18,14 +19,15 @@ enum { - SERIAL_INT_LSR = 1, - SERIAL_INT_RECEIVE = 2, - SERIAL_INT_TRANSMIT = 4, - SERIAL_INT_MSR = 8 + SERIAL_INT_LSR = 1, + SERIAL_INT_RECEIVE = 2, + SERIAL_INT_TRANSMIT = 4, + SERIAL_INT_MSR = 8 }; -SERIAL serial1, serial2; -int serial_do_log = 0; + +static int next_inst = 0; +static serial_device_t serial_devices[SERIAL_MAX]; #ifdef ENABLE_SERIAL_LOG @@ -48,339 +50,405 @@ serial_log(const char *fmt, ...) #endif -void serial_reset() +void +serial_reset_port(serial_t *dev) { - serial1.iir = serial1.ier = serial1.lcr = 0; - serial2.iir = serial2.ier = serial2.lcr = 0; - serial1.fifo_read = serial1.fifo_write = 0; - serial2.fifo_read = serial2.fifo_write = 0; + dev->iir = dev->ier = dev->lcr = dev->fcr = 0; + dev->fifo_enabled = 0; + dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; + memset(dev->xmit_fifo, 0, 14); + memset(dev->rcvr_fifo, 0, 14); } -void serial_update_ints(SERIAL *serial) + +void +serial_update_ints(serial_t *dev) { - int stat = 0; - - serial->iir = 1; + int stat = 0; - if ((serial->ier & 4) && (serial->int_status & SERIAL_INT_LSR)) /*Line status interrupt*/ - { - stat = 1; - serial->iir = 6; - } - else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Recieved data available*/ - { - stat = 1; - serial->iir = 4; - } - else if ((serial->ier & 2) && (serial->int_status & SERIAL_INT_TRANSMIT)) /*Transmit data empty*/ - { - stat = 1; - serial->iir = 2; - } - else if ((serial->ier & 8) && (serial->int_status & SERIAL_INT_MSR)) /*Modem status interrupt*/ - { - stat = 1; - serial->iir = 0; - } + dev->iir = 1; - if (stat && ((serial->mctrl & 8) || PCJR)) { - picintlevel(1 << serial->irq); - } else - picintc(1 << serial->irq); + if ((dev->ier & 4) && (dev->int_status & SERIAL_INT_LSR)) { + /* Line status interrupt */ + stat = 1; + dev->iir = 6; + } else if ((dev->ier & 1) && (dev->int_status & SERIAL_INT_RECEIVE)) { + /* Recieved data available */ + stat = 1; + dev->iir = 4; + } else if ((dev->ier & 2) && (dev->int_status & SERIAL_INT_TRANSMIT)) { + /* Transmit data empty */ + stat = 1; + dev->iir = 2; + } else if ((dev->ier & 8) && (dev->int_status & SERIAL_INT_MSR)) { + /* Modem status interrupt */ + stat = 1; + dev->iir = 0; + } + + if (stat && ((dev->mctrl & 8) || PCJR)) { + if (dev->type >= SERIAL_NS16540) + picintlevel(1 << dev->irq); + else + picint(1 << dev->irq); + } else + picintc(1 << dev->irq); } -void serial_clear_fifo(SERIAL *serial) + +void +serial_write_fifo(serial_t *dev, uint8_t dat) { - memset(serial->fifo, 0, 256); - serial->fifo_read = serial->fifo_write = 0; + uint8_t old_lsr; + serial_log("serial_write_fifo(%08X, %02X, %i)\n", dev, dat, (dev->type >= SERIAL_NS16550) && dev->fifo_enabled); + + if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { + /* FIFO mode. */ + dev->rcvr_fifo[dev->rcvr_fifo_pos++] = dat; + dev->rcvr_fifo_pos %= dev->fifo_len; + old_lsr = dev->lsr; + dev->lsr &= 0xfe; + dev->lsr |= (!dev->rcvr_fifo_pos); + dev->int_status &= SERIAL_INT_RECEIVE; + if (!dev->rcvr_fifo_pos) + dev->int_status |= SERIAL_INT_RECEIVE; + if ((old_lsr ^ dev->lsr) & 0x01) + serial_update_ints(dev); + } else { + /* Non-FIFO mode. */ + dev->dat = dat; + dev->lsr |= 1; + dev->int_status |= SERIAL_INT_RECEIVE; + serial_update_ints(dev); + } } -void serial_write_fifo(SERIAL *serial, uint8_t dat) + +void +serial_dev_write(serial_t *dev, uint8_t val) { - serial->fifo[serial->fifo_write] = dat; - serial->fifo_write = (serial->fifo_write + 1) & 0xFF; - if (!(serial->lsr & 1)) - { - serial->lsr |= 1; - serial->int_status |= SERIAL_INT_RECEIVE; - serial_update_ints(serial); - } + if (dev->mctrl & 0x10) + serial_write_fifo(dev, val); + else if (dev->sd->dev_write) + dev->sd->dev_write(dev, dev->sd->priv, val); } -uint8_t serial_read_fifo(SERIAL *serial) -{ - if (serial->fifo_read != serial->fifo_write) - { - serial->dat = serial->fifo[serial->fifo_read]; - serial->fifo_read = (serial->fifo_read + 1) & 0xFF; - } - return serial->dat; -} -void serial_write(uint16_t addr, uint8_t val, void *p) +void +serial_write(uint16_t addr, uint8_t val, void *p) { - SERIAL *serial = (SERIAL *)p; - switch (addr&7) - { - case 0: - if (serial->lcr & 0x80) - { - serial->dlab1 = val; - return; - } - serial->thr = val; - serial->lsr |= 0x20; - serial->int_status |= SERIAL_INT_TRANSMIT; - serial_update_ints(serial); - if (serial->mctrl & 0x10) - { - serial_write_fifo(serial, val); - } - break; - case 1: - if (serial->lcr & 0x80) - { - serial->dlab2 = val; - return; - } - serial->ier = val & 0xf; - serial_update_ints(serial); - break; - case 2: - serial->fcr = val; - break; - case 3: - serial->lcr = val; - break; - case 4: - if ((val & 2) && !(serial->mctrl & 2)) - { - if (serial->rcr_callback) - serial->rcr_callback((struct SERIAL *)serial, serial->rcr_callback_p); - } - serial->mctrl = val; - if (val & 0x10) - { - uint8_t new_msr; - - new_msr = (val & 0x0c) << 4; - new_msr |= (val & 0x02) ? 0x10: 0; - new_msr |= (val & 0x01) ? 0x20: 0; - - if ((serial->msr ^ new_msr) & 0x10) - new_msr |= 0x01; - if ((serial->msr ^ new_msr) & 0x20) - new_msr |= 0x02; - if ((serial->msr ^ new_msr) & 0x80) - new_msr |= 0x08; - if ((serial->msr & 0x40) && !(new_msr & 0x40)) - new_msr |= 0x04; - - serial->msr = new_msr; - } - break; - case 5: - serial->lsr = val; - if (serial->lsr & 0x01) - serial->int_status |= SERIAL_INT_RECEIVE; - if (serial->lsr & 0x1e) - serial->int_status |= SERIAL_INT_LSR; - if (serial->lsr & 0x20) - serial->int_status |= SERIAL_INT_TRANSMIT; - serial_update_ints(serial); - break; - case 6: - serial->msr = val; - if (serial->msr & 0x0f) - serial->int_status |= SERIAL_INT_MSR; - serial_update_ints(serial); - break; - case 7: - serial->scratch = val; - break; - } -} + serial_t *dev = (serial_t *)p; + uint8_t new_msr, old_lsr, i; -uint8_t serial_read(uint16_t addr, void *p) -{ - SERIAL *serial = (SERIAL *)p; - uint8_t temp = 0; - switch (addr&7) - { - case 0: - if (serial->lcr & 0x80) - { - temp = serial->dlab1; - break; + serial_log("UART: Write %02X to port %02X\n", val, addr); + + switch (addr & 7) { + case 0: + if (dev->lcr & 0x80) { + dev->dlab1 = val; + return; } - serial->lsr &= ~1; - serial->int_status &= ~SERIAL_INT_RECEIVE; - serial_update_ints(serial); - temp = serial_read_fifo(serial); - if (serial->fifo_read != serial->fifo_write) { - serial->recieve_delay = 1000LL * TIMER_USEC; + if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { + /* FIFO mode. */ + dev->xmit_fifo[dev->xmit_fifo_pos++] = val; + dev->xmit_fifo_pos %= dev->fifo_len; + old_lsr = dev->lsr; + dev->lsr &= 0xdf; + if (!dev->xmit_fifo_pos) { + for (i = 0; i < dev->fifo_len; i++) + serial_dev_write(dev, dev->xmit_fifo[i]); + dev->lsr |= 0x20; + dev->int_status |= SERIAL_INT_TRANSMIT; + } + if ((old_lsr ^ dev->lsr) & 0x20) + serial_update_ints(dev); + } else { + /* Non-FIFO mode. */ + dev->thr = val; + dev->lsr |= 0x20; + dev->int_status |= SERIAL_INT_TRANSMIT; + serial_dev_write(dev, val); + serial_update_ints(dev); } - break; - case 1: - if (serial->lcr & 0x80) - temp = serial->dlab2; - else - temp = serial->ier; - break; - case 2: - temp = serial->iir; - if ((temp & 0xe) == 2) - { - serial->int_status &= ~SERIAL_INT_TRANSMIT; - serial_update_ints(serial); - } - if (serial->fcr & 1) - temp |= 0xc0; - break; - case 3: - temp = serial->lcr; - break; - case 4: - temp = serial->mctrl; - break; - case 5: - if (serial->lsr & 0x20) - serial->lsr |= 0x40; - serial->lsr |= 0x20; - temp = serial->lsr; - if (serial->lsr & 0x1f) - serial->lsr &= ~0x1e; - serial->int_status &= ~SERIAL_INT_LSR; - serial_update_ints(serial); - break; - case 6: - temp = serial->msr; - serial->msr &= ~0x0f; - serial->int_status &= ~SERIAL_INT_MSR; - serial_update_ints(serial); - break; - case 7: - temp = serial->scratch; - break; - } - return temp; + break; + case 1: + if (dev->lcr & 0x80) { + dev->dlab2 = val; + return; + } + dev->ier = val & 0xf; + serial_update_ints(dev); + break; + case 2: + if (dev->type >= SERIAL_NS16550) { + dev->fcr = val & 0xf9; + dev->fifo_enabled = val & 0x01; + if (val & 0x02) { + memset(dev->rcvr_fifo, 0, 14); + dev->rcvr_fifo_pos = 0; + } + if (val & 0x04) { + memset(dev->xmit_fifo, 0, 14); + dev->xmit_fifo_pos = 0; + } + switch ((val >> 6) & 0x03) { + case 0: + dev->fifo_len = 1; + break; + case 1: + dev->fifo_len = 4; + break; + case 2: + dev->fifo_len = 8; + break; + case 3: + dev->fifo_len = 14; + break; + } + } + break; + case 3: + dev->lcr = val; + break; + case 4: + if ((val & 2) && !(dev->mctrl & 2)) { + if (dev->sd->rcr_callback) + dev->sd->rcr_callback(dev, dev->sd->priv); + } + dev->mctrl = val; + if (val & 0x10) { + new_msr = (val & 0x0c) << 4; + new_msr |= (val & 0x02) ? 0x10: 0; + new_msr |= (val & 0x01) ? 0x20: 0; + + if ((dev->msr ^ new_msr) & 0x10) + new_msr |= 0x01; + if ((dev->msr ^ new_msr) & 0x20) + new_msr |= 0x02; + if ((dev->msr ^ new_msr) & 0x80) + new_msr |= 0x08; + if ((dev->msr & 0x40) && !(new_msr & 0x40)) + new_msr |= 0x04; + + dev->msr = new_msr; + } + break; + case 5: + dev->lsr = val; + if (dev->lsr & 0x01) + dev->int_status |= SERIAL_INT_RECEIVE; + if (dev->lsr & 0x1e) + dev->int_status |= SERIAL_INT_LSR; + if (dev->lsr & 0x20) + dev->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(dev); + break; + case 6: + dev->msr = val; + if (dev->msr & 0x0f) + dev->int_status |= SERIAL_INT_MSR; + serial_update_ints(dev); + break; + case 7: + dev->scratch = val; + break; + } } -void serial_recieve_callback(void *p) + +uint8_t +serial_read(uint16_t addr, void *p) { - SERIAL *serial = (SERIAL *)p; - - serial->recieve_delay = 0; - - if (serial->fifo_read != serial->fifo_write) - { - serial->lsr |= 1; - serial->int_status |= SERIAL_INT_RECEIVE; - serial_update_ints(serial); - } + serial_t *dev = (serial_t *)p; + uint8_t old_lsr, ret = 0; + + switch (addr & 7) { + case 0: + if (dev->lcr & 0x80) { + ret = dev->dlab1; + break; + } + + if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { + /* FIFO mode. */ + ret = dev->rcvr_fifo[dev->rcvr_fifo_pos++]; + dev->rcvr_fifo_pos %= dev->fifo_len; + old_lsr = dev->lsr; + if (!dev->rcvr_fifo_pos) { + dev->lsr &= 0xfe; + dev->int_status &= ~SERIAL_INT_RECEIVE; + if ((old_lsr ^ dev->lsr) & 0x01) + serial_update_ints(dev); + } + } else { + ret = dev->dat; + dev->lsr &= 0xfe; + dev->int_status &= ~SERIAL_INT_RECEIVE; + serial_update_ints(dev); + } + break; + case 1: + if (dev->lcr & 0x80) + ret = dev->dlab2; + else + ret = dev->ier; + break; + case 2: + ret = dev->iir; + if ((ret & 0xe) == 2) { + dev->int_status &= ~SERIAL_INT_TRANSMIT; + serial_update_ints(dev); + } + if (dev->fcr & 1) + ret |= 0xc0; + break; + case 3: + ret = dev->lcr; + break; + case 4: + ret = dev->mctrl; + break; + case 5: + if (dev->lsr & 0x20) + dev->lsr |= 0x40; + dev->lsr |= 0x20; + ret = dev->lsr; + if (dev->lsr & 0x1f) + dev->lsr &= ~0x1e; + dev->int_status &= ~SERIAL_INT_LSR; + serial_update_ints(dev); + break; + case 6: + ret = dev->msr; + dev->msr &= ~0x0f; + dev->int_status &= ~SERIAL_INT_MSR; + serial_update_ints(dev); + break; + case 7: + ret = dev->scratch; + break; + } + + serial_log("UART: Read %02X from port %02X\n", ret, addr); + return ret; } -uint16_t base_address[2] = { 0x0000, 0x0000 }; -void serial_remove(int port) +void +serial_remove(serial_t *dev) { - if ((port < 1) || (port > 2)) - { - fatal("serial_remove(): Invalid serial port: %i\n", port); - exit(-1); - } + if (!serial_enabled[dev->inst]) + return; - if (!serial_enabled[port - 1]) - { - return; - } + if (!dev->base_address) + return; - if (!base_address[port - 1]) - { - return; - } + serial_log("Removing serial port %i at %04X...\n", dev->inst, dev->base_address); - serial_log("Removing serial port %i at %04X...\n", port, base_address[port - 1]); - - switch(port) - { - case 1: - io_removehandler(base_address[0], 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - base_address[0] = 0x0000; - break; - case 2: - io_removehandler(base_address[1], 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - base_address[1] = 0x0000; - break; - } + io_removehandler(dev->base_address, 0x0008, + serial_read, NULL, NULL, serial_write, NULL, NULL, dev); + dev->base_address = 0x0000; } -void serial_setup(int port, uint16_t addr, int irq) + +void +serial_setup(serial_t *dev, uint16_t addr, int irq) { - serial_log("Adding serial port %i at %04X...\n", port, addr); + serial_log("Adding serial port %i at %04X...\n", dev->inst, addr); - switch(port) - { - case 1: - if (!serial_enabled[0]) - { - return; - } - if (base_address[0] != 0x0000) - { - serial_remove(port); - } - if (addr != 0x0000) - { - base_address[0] = addr; - io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - } - serial1.irq = irq; - break; - case 2: - if (!serial_enabled[1]) - { - return; - } - if (base_address[1] != 0x0000) - { - serial_remove(port); - } - if (addr != 0x0000) - { - base_address[1] = addr; - io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - } - serial2.irq = irq; - break; - default: - fatal("serial_setup(): Invalid serial port: %i\n", port); - break; - } + if (!serial_enabled[dev->inst]) + return; + if (dev->base_address != 0x0000) + serial_remove(dev); + dev->base_address = addr; + if (addr != 0x0000) + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, dev); + dev->irq = irq; } -void serial_init(void) + +serial_t * +serial_attach(int port, + void (*rcr_callback)(struct serial_s *serial, void *p), + void (*dev_write)(struct serial_s *serial, void *p, uint8_t data), + void *priv) { - base_address[0] = 0x03f8; - base_address[1] = 0x02f8; + serial_device_t *sd = &serial_devices[port]; - if (serial_enabled[0]) - { - serial_log("Adding serial port 1...\n"); - memset(&serial1, 0, sizeof(serial1)); - io_sethandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - serial1.irq = 4; - serial1.rcr_callback = NULL; - timer_add(serial_recieve_callback, &serial1.recieve_delay, &serial1.recieve_delay, &serial1); - } - if (serial_enabled[1]) - { - serial_log("Adding serial port 2...\n"); - memset(&serial2, 0, sizeof(serial2)); - io_sethandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - serial2.irq = 3; - serial2.rcr_callback = NULL; - timer_add(serial_recieve_callback, &serial2.recieve_delay, &serial2.recieve_delay, &serial2); - } + sd->rcr_callback = rcr_callback; + sd->dev_write = dev_write; + sd->priv = priv; + + return sd->serial; } + + +static void +serial_close(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + next_inst--; + + free(dev); +} + + +static void * +serial_init(const device_t *info) +{ + serial_t *dev = (serial_t *) malloc(sizeof(serial_t)); + memset(dev, 0, sizeof(serial_t)); + + dev->base_address = next_inst ? 0x03f8 : 0x02f8; + + if (serial_enabled[next_inst]) { + serial_log("Adding serial port %i...\n", next_inst); + io_sethandler(dev->base_address, 0x0008, + serial_read, NULL, NULL, serial_write, NULL, NULL, dev); + dev->irq = next_inst ? 4 : 3; + dev->type = info->local; + dev->inst = next_inst; + memset(&(serial_devices[next_inst]), 0, sizeof(serial_device_t)); + dev->sd = &(serial_devices[next_inst]); + dev->sd->serial = dev; + serial_reset_port(dev); + if (next_inst) + serial_setup(dev, SERIAL2_ADDR, SERIAL2_IRQ); + else + serial_setup(dev, SERIAL1_ADDR, SERIAL1_IRQ); + } + + next_inst++; + + return dev; +} + + +const device_t i8250_device = { + "Intel 8250(-compatible) UART", + 0, + SERIAL_8250, + serial_init, serial_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t ns16540_device = { + "National Semiconductor NS16540(-compatible) UART", + 0, + SERIAL_NS16540, + serial_init, serial_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t ns16550_device = { + "National Semiconductor NS16550(-compatible) UART", + 0, + SERIAL_NS16550, + serial_init, serial_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/serial.h b/src/serial.h index 47eafdbd3..722a4e6a1 100644 --- a/src/serial.h +++ b/src/serial.h @@ -8,7 +8,7 @@ * * Definitions for the SERIAL card. * - * Version: @(#)serial.h 1.0.7 2018/01/12 + * Version: @(#)serial.h 1.0.8 2018/11/04 * * Author: Fred N. van Kempen, * Copyright 2017,2018 Fred N. van Kempen. @@ -17,7 +17,10 @@ # define EMU_SERIAL_H -#ifdef WALTJE_SERIAL +#define SERIAL_8250 0 +#define SERIAL_NS16540 1 +#define SERIAL_NS16550 2 + /* Default settings for the standard ports. */ #define SERIAL1_ADDR 0x03f8 #define SERIAL1_IRQ 4 @@ -25,95 +28,53 @@ #define SERIAL2_IRQ 3 -/* Supported UART types. */ -#define UART_TYPE_8250 0 /* standard NS8250 */ -#define UART_TYPE_8250A 1 /* updated NS8250(A) */ -#define UART_TYPE_16450 2 /* 16450 */ -#define UART_TYPE_16550 3 /* 16550 (broken fifo) */ -#define UART_TYPE_16550A 4 /* 16550a (working fifo) */ -#define UART_TYPE_16670 5 /* 16670 (64b fifo) */ +struct serial_device_s; +struct serial_s; - -typedef struct _serial_ { - int8_t port; /* port number (1,2,..) */ - int8_t irq; /* IRQ channel used */ - uint16_t addr; /* I/O address used */ - int8_t type; /* UART type */ - uint8_t int_status; - - uint8_t lsr, thr, mctrl, rcr, /* UART registers */ - iir, ier, lcr, msr; - uint8_t dlab1, dlab2; - uint8_t dat, - hold; - uint8_t scratch; - uint8_t fcr; - - /* Data for the RTS-toggle callback. */ - void (*rts_callback)(void *); - void *rts_callback_p; - - uint8_t fifo[256]; - int fifo_read, fifo_write; - - int64_t receive_delay; - - void *bh; /* BottomHalf handler */ -} SERIAL; - - -/* Functions. */ -extern void serial_init(void); -extern void serial_reset(void); -extern void serial_setup(int port, uint16_t addr, int irq); -extern void serial_remove(int port); -extern SERIAL *serial_attach(int, void *, void *); -extern int serial_link(int, char *); - -extern void serial_clear_fifo(SERIAL *); -extern void serial_write_fifo(SERIAL *, uint8_t, int); - - -#else - - -void serial_remove(int port); -void serial_setup(int port, uint16_t addr, int irq); -void serial_init(void); -void serial_reset(); - -struct SERIAL; - -typedef struct +typedef struct serial_s { - uint8_t lsr,thr,mctrl,rcr,iir,ier,lcr,msr; - uint8_t dlab1,dlab2; - uint8_t dat; - uint8_t int_status; - uint8_t scratch; - uint8_t fcr; - - int irq; + uint8_t lsr, thr, mctrl, rcr, + iir, ier, lcr, msr; + uint8_t dlab1, dlab2; + uint8_t dat; + uint8_t int_status; + uint8_t scratch; + uint8_t fcr; - void (*rcr_callback)(struct SERIAL *serial, void *p); - void *rcr_callback_p; - uint8_t fifo[256]; - int fifo_read, fifo_write; - - int64_t recieve_delay; -} SERIAL; + uint8_t irq, type, + inst; + uint16_t base_address; -void serial_clear_fifo(SERIAL *); -void serial_write_fifo(SERIAL *serial, uint8_t dat); + uint8_t fifo_len, fifo_enabled; + uint8_t rcvr_fifo_pos, rcvr_fifo[14]; + uint8_t xmit_fifo_pos, xmit_fifo[14]; -extern SERIAL serial1, serial2; + int64_t recieve_delay; -/* Default settings for the standard ports. */ -#define SERIAL1_ADDR 0x03f8 -#define SERIAL1_IRQ 4 -#define SERIAL2_ADDR 0x02f8 -#define SERIAL2_IRQ 3 -#endif + struct serial_device_s *sd; +} serial_t; + +typedef struct serial_device_s +{ + void (*rcr_callback)(struct serial_s *serial, void *p); + void (*dev_write)(struct serial_s *serial, void *p, uint8_t data); + void *priv; + serial_t *serial; +} serial_device_t; + + +extern serial_t * serial_attach(int port, + void (*rcr_callback)(struct serial_s *serial, void *p), + void (*dev_write)(struct serial_s *serial, void *p, uint8_t data), + void *priv); +extern void serial_remove(serial_t *dev); +extern void serial_setup(serial_t *dev, uint16_t addr, int irq); +extern void serial_clear_fifo(serial_t *dev); +extern void serial_write_fifo(serial_t *dev, uint8_t dat); + +extern const device_t i8250_device; +extern const device_t ns16540_device; +extern const device_t ns16550_device; #endif /*EMU_SERIAL_H*/ diff --git a/src/sio.h b/src/sio.h index bed35af88..4b8e84f01 100644 --- a/src/sio.h +++ b/src/sio.h @@ -8,7 +8,7 @@ * * Definitions for the Super I/O chips. * - * Version: @(#)sio.h 1.0.3 2018/09/15 + * Version: @(#)sio.h 1.0.4 2018/11/05 * * Author: Fred N. van Kempen, * Copyright 2017 Fred N. van Kempen. @@ -17,15 +17,17 @@ # define EMU_SIO_H -extern void superio_detect_init(void); -extern void fdc37c663_init(void); -extern void fdc37c665_init(void); -extern void fdc37c669_init(void); -extern void fdc37c932fr_init(void); -extern void fdc37c935_init(void); -extern void pc87306_init(void); -extern void um8669f_init(void); -extern void w83877f_init(uint8_t reg16init); +extern const device_t fdc37c663_device; +extern const device_t fdc37c665_device; +extern const device_t fdc37c666_device; +extern const device_t fdc37c669_device; +extern const device_t fdc37c932fr_device; +extern const device_t fdc37c935_device; +extern const device_t pc87306_device; +extern const device_t sio_detect_device; +extern const device_t um8669f_device; +extern const device_t w83877f_device; +extern const device_t w83877f_president_device; #endif /*EMU_SIO_H*/ diff --git a/src/sio_detect.c b/src/sio_detect.c index 275a9e643..980f17a2d 100644 --- a/src/sio_detect.c +++ b/src/sio_detect.c @@ -8,7 +8,7 @@ * * Super I/O chip detection code. * - * Version: @(#)sio_detect.c 1.0.0 2018/01/16 + * Version: @(#)sio_detect.c 1.0.1 2018/11/05 * * Authors: Miran Grca, * @@ -16,6 +16,7 @@ */ #include #include +#include #include #include #include "86box.h" @@ -26,39 +27,78 @@ #include "sio.h" -static uint8_t detect_regs[2]; +typedef struct { + uint8_t regs[2]; +} sio_detect_t; -static void superio_detect_write(uint16_t port, uint8_t val, void *priv) +static void +sio_detect_write(uint16_t port, uint8_t val, void *priv) { - pclog("superio_detect_write : port=%04x = %02X\n", port, val); + sio_detect_t *dev = (sio_detect_t *) priv; - detect_regs[port & 1] = val; + pclog("sio_detect_write : port=%04x = %02X\n", port, val); - return; + dev->regs[port & 1] = val; + + return; } -static uint8_t superio_detect_read(uint16_t port, void *priv) +static uint8_t +sio_detect_read(uint16_t port, void *priv) { - pclog("superio_detect_read : port=%04x = %02X\n", port, detect_regs[port & 1]); + sio_detect_t *dev = (sio_detect_t *) priv; - return detect_regs[port & 1]; + pclog("sio_detect_read : port=%04x = %02X\n", port, dev->regs[port & 1]); + + return dev->regs[port & 1]; } -void superio_detect_init(void) +static void +sio_detect_close(void *priv) { - device_add(&fdc_at_smc_device); + sio_detect_t *dev = (sio_detect_t *) priv; - io_sethandler(0x24, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x26, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x2e, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x44, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x46, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x4e, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x108, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x250, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x370, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x3f0, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + free(dev); } + + +static void * +sio_detect_init(const device_t *info) +{ + sio_detect_t *dev = (sio_detect_t *) malloc(sizeof(sio_detect_t)); + memset(dev, 0, sizeof(sio_detect_t)); + + device_add(&fdc_at_smc_device); + + io_sethandler(0x0024, 0x0004, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x002e, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x0044, 0x0004, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x004e, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x0108, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x0250, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x0370, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x03f0, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + + return dev; +} + + +const device_t sio_detect_device = { + "Super I/O Detection Helper", + 0, + 0, + sio_detect_init, sio_detect_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_fdc37c669.c b/src/sio_fdc37c669.c index 58547c55c..3e5a0b669 100644 --- a/src/sio_fdc37c669.c +++ b/src/sio_fdc37c669.c @@ -8,13 +8,14 @@ * * Implementation of the SMC FDC37C669 Super I/O Chip. * - * Version: @(#)sio_fdc37c669.c 1.0.9 2018/04/29 + * Version: @(#)sio_fdc37c669.c 1.0.10 2018/11/05 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "86box.h" @@ -30,299 +31,267 @@ #include "sio.h" -static int fdc37c669_locked; -static int fdc37c669_rw_locked = 0; -static int fdc37c669_curreg = 0; -static uint8_t fdc37c669_regs[42]; -static uint8_t tries; -static fdc_t *fdc37c669_fdc; +typedef struct { + uint8_t tries, + regs[42]; + int locked, rw_locked, + cur_reg; + fdc_t *fdc; + serial_t *uart[2]; +} fdc37c669_t; -static uint16_t make_port(uint8_t reg) + +static uint16_t +make_port(fdc37c669_t *dev, uint8_t reg) { - uint16_t p = 0; + uint16_t p = 0; + uint16_t mask = 0; - uint16_t mask = 0; + switch(reg) { + case 0x20: + case 0x21: + case 0x22: + mask = 0xfc; + break; + case 0x23: + mask = 0xff; + break; + case 0x24: + case 0x25: + mask = 0xfe; + break; + } - switch(reg) - { - case 0x20: - case 0x21: - case 0x22: - mask = 0xfc; - break; - case 0x23: - mask = 0xff; - break; - case 0x24: - case 0x25: - mask = 0xfe; - break; - } + p = ((uint16_t) (dev->regs[reg] & mask)) << 2; + if (reg == 0x22) + p |= 6; - p = ((uint16_t) (fdc37c669_regs[reg] & mask)) << 2; - if (reg == 0x22) - { - p |= 6; - } - - return p; + return p; } -void fdc37c669_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t index = (port & 1) ? 0 : 1; - uint8_t valxor = 0; - uint8_t max = 42; - if (index) - { - if ((val == 0x55) && !fdc37c669_locked) - { - if (tries) - { - fdc37c669_locked = 1; - tries = 0; - } - else - { - tries++; - } - } - else - { - if (fdc37c669_locked) - { - if (val < max) fdc37c669_curreg = val; - if (val == 0xaa) fdc37c669_locked = 0; - } - else - { - if (tries) - tries = 0; - } - } - } - else - { - if (fdc37c669_locked) - { - if ((fdc37c669_curreg < 0x18) && (fdc37c669_rw_locked)) return; - if ((fdc37c669_curreg >= 0x26) && (fdc37c669_curreg <= 0x27)) return; - if (fdc37c669_curreg == 0x29) return; - valxor = val ^ fdc37c669_regs[fdc37c669_curreg]; - fdc37c669_regs[fdc37c669_curreg] = val; - goto process_value; +static void +fdc37c669_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c669_t *dev = (fdc37c669_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + uint8_t max = 42; + + if (index) { + if ((val == 0x55) && !dev->locked) { + if (dev->tries) { + dev->locked = 1; + dev->tries = 0; + } else + dev->tries++; + } else { + if (dev->locked) { + if (val < max) + dev->cur_reg = val; + if (val == 0xaa) + dev->locked = 0; + } else { + if (dev->tries) + dev->tries = 0; } } return; + } else { + if (dev->locked) { + if ((dev->cur_reg < 0x18) && (dev->rw_locked)) + return; + if ((dev->cur_reg >= 0x26) && (dev->cur_reg <= 0x27)) + return; + if (dev->cur_reg == 0x29) + return; + valxor = val ^ dev->regs[dev->cur_reg]; + dev->regs[dev->cur_reg] = val; + } else + return; + } -process_value: - switch(fdc37c669_curreg) - { - case 0: -#if 0 - if (valxor & 3) - { - ide_pri_disable(); - if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable(); - break; - } -#endif - if (valxor & 8) - { - fdc_remove(fdc37c669_fdc); - if ((fdc37c669_regs[0] & 8) && (fdc37c669_regs[0x20] & 0xc0)) fdc_set_base(fdc37c669_fdc, make_port(0x20)); - } - break; - case 1: - if (valxor & 4) - { - lpt1_remove(); - if ((fdc37c669_regs[1] & 4) && (fdc37c669_regs[0x23] >= 0x40)) - { - lpt1_init(make_port(0x23)); - } - } - if (valxor & 7) - { - fdc37c669_rw_locked = (val & 8) ? 0 : 1; - } - break; - case 2: - if (valxor & 8) - { - serial_remove(1); - if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] >= 0x40)) - { - serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 4); - } - } - if (valxor & 0x80) - { - serial_remove(2); - if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] >= 0x40)) - { - serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0x0F); - } - } - break; - case 3: - if (valxor & 2) fdc_update_enh_mode(fdc37c669_fdc, (val & 2) ? 1 : 0); - break; - case 5: - if (valxor & 0x18) fdc_update_densel_force(fdc37c669_fdc, (val & 0x18) >> 3); - if (valxor & 0x20) fdc_set_swap(fdc37c669_fdc, (val & 0x20) >> 5); - break; - case 0xB: - if (valxor & 3) fdc_update_rwc(fdc37c669_fdc, 0, val & 3); - if (valxor & 0xC) fdc_update_rwc(fdc37c669_fdc, 1, (val & 0xC) >> 2); - break; - case 0x20: - if (valxor & 0xfc) - { - fdc_remove(fdc37c669_fdc); - if ((fdc37c669_regs[0] & 8) && (fdc37c669_regs[0x20] & 0xc0)) fdc_set_base(fdc37c669_fdc, make_port(0x20)); - } - break; - case 0x21: - case 0x22: -#if 0 - if (valxor & 0xfc) - { - ide_pri_disable(); - switch (fdc37c669_curreg) - { - case 0x21: - ide_set_base(0, make_port(0x21)); - break; - case 0x22: - ide_set_side(0, make_port(0x22)); - break; - } - if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable(); - } -#endif - break; - case 0x23: - if (valxor) - { - lpt1_remove(); - if ((fdc37c669_regs[1] & 4) && (fdc37c669_regs[0x23] >= 0x40)) - { - lpt1_init(make_port(0x23)); - } - } - break; - case 0x24: - if (valxor & 0xfe) - { - serial_remove(1); - if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] >= 0x40)) - { - serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 4); - } - } - break; - case 0x25: - if (valxor & 0xfe) - { - serial_remove(2); - if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] >= 0x40)) - { - serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0x0F); - } - } - break; - case 0x28: - if (valxor & 0xf) - { - serial_remove(2); - if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] >= 0x40)) - { - serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0x0F); - } - } - if (valxor & 0xf0) - { - serial_remove(1); - if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] >= 0x40)) - { - serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 4); - } - } - break; - } + switch(dev->cur_reg) { + case 0: + if (valxor & 8) { + fdc_remove(dev->fdc); + if ((dev->regs[0] & 8) && (dev->regs[0x20] & 0xc0)) + fdc_set_base(dev->fdc, make_port(dev, 0x20)); + } + break; + case 1: + if (valxor & 4) { + lpt1_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt1_init(make_port(dev, 0x23)); + } + if (valxor & 7) + dev->rw_locked = (val & 8) ? 0 : 1; + break; + case 2: + if (valxor & 8) { + serial_remove(dev->uart[0]); + if ((dev->regs[2] & 8) && (dev->regs[0x24] >= 0x40)) + serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4); + } + if (valxor & 0x80) { + serial_remove(dev->uart[1]); + if ((dev->regs[2] & 0x80) && (dev->regs[0x25] >= 0x40)) + serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f); + } + break; + case 3: + if (valxor & 2) + fdc_update_enh_mode(dev->fdc, (val & 2) ? 1 : 0); + break; + case 5: + if (valxor & 0x18) + fdc_update_densel_force(dev->fdc, (val & 0x18) >> 3); + if (valxor & 0x20) + fdc_set_swap(dev->fdc, (val & 0x20) >> 5); + break; + case 0xB: + if (valxor & 3) + fdc_update_rwc(dev->fdc, 0, val & 3); + if (valxor & 0xC) + fdc_update_rwc(dev->fdc, 1, (val & 0xC) >> 2); + break; + case 0x20: + if (valxor & 0xfc) { + fdc_remove(dev->fdc); + if ((dev->regs[0] & 8) && (dev->regs[0x20] & 0xc0)) + fdc_set_base(dev->fdc, make_port(dev, 0x20)); + } + break; + case 0x23: + if (valxor) { + lpt1_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt1_init(make_port(dev, 0x23)); + } + break; + case 0x24: + if (valxor & 0xfe) { + serial_remove(dev->uart[0]); + if ((dev->regs[2] & 8) && (dev->regs[0x24] >= 0x40)) + serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4); + } + break; + case 0x25: + if (valxor & 0xfe) { + serial_remove(dev->uart[1]); + if ((dev->regs[2] & 0x80) && (dev->regs[0x25] >= 0x40)) + serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f); + } + break; + case 0x28: + if (valxor & 0xf) { + serial_remove(dev->uart[1]); + if ((dev->regs[2] & 0x80) && (dev->regs[0x25] >= 0x40)) + serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f); + } + if (valxor & 0xf0) { + serial_remove(dev->uart[0]); + if ((dev->regs[2] & 8) && (dev->regs[0x24] >= 0x40)) + serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4); + } + break; + } } -uint8_t fdc37c669_read(uint16_t port, void *priv) + +static uint8_t +fdc37c669_read(uint16_t port, void *priv) { - uint8_t index = (port & 1) ? 0 : 1; + fdc37c669_t *dev = (fdc37c669_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; - if (!fdc37c669_locked) - { - return 0xFF; - } + if (dev->locked) { + if (index) + ret = dev->cur_reg; + else if ((dev->cur_reg >= 0x18) || !dev->rw_locked) + ret = dev->regs[dev->cur_reg]; + } - if (index) - return fdc37c669_curreg; - else - { - if ((fdc37c669_curreg < 0x18) && (fdc37c669_rw_locked)) return 0xff; - return fdc37c669_regs[fdc37c669_curreg]; - } + return ret; } -void fdc37c669_reset(void) + +static void +fdc37c669_reset(fdc37c669_t *dev) { - fdc_reset(fdc37c669_fdc); + fdc_reset(dev->fdc); - serial_remove(1); - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); - serial_remove(2); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - lpt2_remove(); + lpt2_remove(); - lpt1_remove(); - lpt1_init(0x378); + lpt1_remove(); + lpt1_init(0x378); - memset(fdc37c669_regs, 0, 42); - fdc37c669_regs[0] = 0x28; - fdc37c669_regs[1] = 0x9C; - fdc37c669_regs[2] = 0x88; - fdc37c669_regs[3] = 0x78; - fdc37c669_regs[4] = 0; - fdc37c669_regs[5] = 0; - fdc37c669_regs[6] = 0xFF; - fdc37c669_regs[7] = 0; - fdc37c669_regs[8] = 0; - fdc37c669_regs[9] = 0; - fdc37c669_regs[0xA] = 0; - fdc37c669_regs[0xB] = 0; - fdc37c669_regs[0xC] = 0; - fdc37c669_regs[0xD] = 3; - fdc37c669_regs[0xE] = 2; - fdc37c669_regs[0x1E] = 0x80; /* Gameport controller. */ - fdc37c669_regs[0x20] = (0x3f0 >> 2) & 0xfc; - fdc37c669_regs[0x21] = (0x1f0 >> 2) & 0xfc; - fdc37c669_regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; - fdc37c669_regs[0x23] = (0x378 >> 2); - fdc37c669_regs[0x24] = (0x3f8 >> 2) & 0xfe; - fdc37c669_regs[0x25] = (0x2f8 >> 2) & 0xfe; - fdc37c669_regs[0x26] = (2 << 4) | 3; - fdc37c669_regs[0x27] = (6 << 4) | 7; - fdc37c669_regs[0x28] = (4 << 4) | 3; + memset(dev->regs, 0, 42); + dev->regs[0x00] = 0x28; + dev->regs[0x01] = 0x9c; + dev->regs[0x02] = 0x88; + dev->regs[0x03] = 0x78; + dev->regs[0x06] = 0xff; + dev->regs[0x0d] = 0x03; + dev->regs[0x0e] = 0x02; + dev->regs[0x1e] = 0x80; /* Gameport controller. */ + dev->regs[0x20] = (0x3f0 >> 2) & 0xfc; + dev->regs[0x21] = (0x1f0 >> 2) & 0xfc; + dev->regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; + dev->regs[0x23] = (0x378 >> 2); + dev->regs[0x24] = (0x3f8 >> 2) & 0xfe; + dev->regs[0x25] = (0x2f8 >> 2) & 0xfe; + dev->regs[0x26] = (2 << 4) | 3; + dev->regs[0x27] = (6 << 4) | 7; + dev->regs[0x28] = (4 << 4) | 3; - fdc37c669_locked = 0; - fdc37c669_rw_locked = 0; + dev->locked = 0; + dev->rw_locked = 0; } -void fdc37c669_init() + +static void +fdc37c669_close(void *priv) { - fdc37c669_fdc = device_add(&fdc_at_smc_device); + fdc37c669_t *dev = (fdc37c669_t *) priv; - io_sethandler(0x3f0, 0x0002, fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, NULL); - - fdc37c669_reset(); + free(dev); } + + +static void * +fdc37c669_init(const device_t *info) +{ + fdc37c669_t *dev = (fdc37c669_t *) malloc(sizeof(fdc37c669_t)); + memset(dev, 0, sizeof(fdc37c669_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + io_sethandler(0x3f0, 0x0002, + fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, dev); + + fdc37c669_reset(dev); + + return dev; +} + + +const device_t fdc37c669_device = { + "SMC FDC37C669 Super I/O", + 0, + 0, + fdc37c669_init, fdc37c669_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_fdc37c66x.c b/src/sio_fdc37c66x.c index eaec1a1c8..9185b397a 100644 --- a/src/sio_fdc37c66x.c +++ b/src/sio_fdc37c66x.c @@ -9,7 +9,7 @@ * Implementation of the SMC FDC37C663 and FDC37C665 Super * I/O Chips. * - * Version: @(#)sio_fdc37c66x.c 1.0.12 2018/09/15 + * Version: @(#)sio_fdc37c66x.c 1.0.13 2018/11/05 * * Authors: Sarah Walker, * Miran Grca, @@ -19,6 +19,7 @@ */ #include #include +#include #include #include #include "86box.h" @@ -34,294 +35,258 @@ #include "sio.h" -static uint8_t fdc37c66x_lock[2]; -static int fdc37c66x_curreg; -static uint8_t fdc37c66x_regs[16]; -static int com3_addr, com4_addr; -static fdc_t *fdc37c66x_fdc; +typedef struct { + uint8_t chip_id, + lock[2], + regs[16]; + int cur_reg, + com3_addr, com4_addr; + fdc_t *fdc; + serial_t *uart[2]; +} fdc37c66x_t; -static void write_lock(uint8_t val) +static void +write_lock(fdc37c66x_t *dev, uint8_t val) { - if (val == 0x55 && fdc37c66x_lock[1] == 0x55) - fdc_3f1_enable(fdc37c66x_fdc, 0); - if (fdc37c66x_lock[0] == 0x55 && fdc37c66x_lock[1] == 0x55 && val != 0x55) - fdc_3f1_enable(fdc37c66x_fdc, 1); + if (val == 0x55 && dev->lock[1] == 0x55) + fdc_3f1_enable(dev->fdc, 0); + if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55) && (val != 0x55)) + fdc_3f1_enable(dev->fdc, 1); - fdc37c66x_lock[0] = fdc37c66x_lock[1]; - fdc37c66x_lock[1] = val; + dev->lock[0] = dev->lock[1]; + dev->lock[1] = val; } -static void ide_handler() + +static void +set_com34_addr(fdc37c66x_t *dev) { -#if 0 - uint16_t or_value = 0; - ide_pri_disable(); - if (fdc37c66x_regs[0] & 1) - { - if (fdc37c66x_regs[5] & 2) - { - or_value = 0; - } - else - { - or_value = 0x800; - } - ide_set_base(0, 0x170 | or_value); - ide_set_side(0, 0x376 | or_value); - ide_pri_enable(); - } -#endif + switch (dev->regs[1] & 0x60) { + case 0x00: + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; + break; + case 0x20: + dev->com3_addr = 0x3e8; + dev->com4_addr = 0x2e8; + break; + case 0x40: + dev->com3_addr = 0x3e8; + dev->com4_addr = 0x2e0; + break; + case 0x60: + dev->com3_addr = 0x220; + dev->com4_addr = 0x228; + break; + } } -static void set_com34_addr() + +static void +set_serial_addr(fdc37c66x_t *dev, int port) { - switch (fdc37c66x_regs[1] & 0x60) - { - case 0x00: - com3_addr = 0x338; - com4_addr = 0x238; + uint8_t shift = (port << 4); + + if (dev->regs[2] & (4 << shift)) { + switch (dev->regs[2] & (3 << shift)) { + case 0: + serial_setup(dev->uart[port], SERIAL1_ADDR, SERIAL1_IRQ); break; - case 0x20: - com3_addr = 0x3e8; - com4_addr = 0x2e8; - break; - case 0x40: - com3_addr = 0x3e8; - com4_addr = 0x2e0; - break; - case 0x60: - com3_addr = 0x220; - com4_addr = 0x228; - break; - } -} - -static void set_serial1_addr() -{ - if (fdc37c66x_regs[2] & 4) - { - switch (fdc37c66x_regs[2] & 3) - { - case 0: - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - break; - - case 1: - serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); - break; - - case 2: - serial_setup(1, com3_addr, 4); - break; - - case 3: - serial_setup(1, com4_addr, 3); - break; - } - } -} - -static void set_serial2_addr() -{ - if (fdc37c66x_regs[2] & 0x40) - { - switch (fdc37c66x_regs[2] & 0x30) - { - case 0: - serial_setup(2, SERIAL1_ADDR, SERIAL1_IRQ); - break; - - case 1: - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); - break; - - case 2: - serial_setup(2, com3_addr, 4); - break; - - case 3: - serial_setup(2, com4_addr, 3); - break; - } - } -} - -static void lpt1_handler() -{ - lpt1_remove(); - switch (fdc37c66x_regs[1] & 3) - { case 1: - lpt1_init(0x3bc); + serial_setup(dev->uart[port], SERIAL2_ADDR, SERIAL2_IRQ); break; case 2: - lpt1_init(0x378); + serial_setup(dev->uart[port], dev->com3_addr, 4); break; case 3: - lpt1_init(0x278); + serial_setup(dev->uart[port], dev->com4_addr, 3); break; } + } } + +static void +lpt1_handler(fdc37c66x_t *dev) +{ + lpt1_remove(); + switch (dev->regs[1] & 3) { + case 1: + lpt1_init(0x3bc); + break; + case 2: + lpt1_init(0x378); + break; + case 3: + lpt1_init(0x278); + break; + } +} + + static void fdc37c66x_write(uint16_t port, uint8_t val, void *priv) { - uint8_t valxor = 0; - if (fdc37c66x_lock[0] == 0x55 && fdc37c66x_lock[1] == 0x55) - { - if (port == 0x3f0) - { - if (val == 0xaa) - write_lock(val); - else - fdc37c66x_curreg = val; -#if 0 - if (fdc37c66x_curreg != 0) - { - fdc37c66x_curreg = val & 0xf; - } - else - { - /* Hardcode the IDE to AT type. */ - fdc37c66x_curreg = (val & 0xf) | 2; - } -#endif - } - else - { - if (fdc37c66x_curreg > 15) - return; + fdc37c66x_t *dev = (fdc37c66x_t *) priv; + uint8_t valxor = 0; - valxor = val ^ fdc37c66x_regs[fdc37c66x_curreg]; - fdc37c66x_regs[fdc37c66x_curreg] = val; - - switch(fdc37c66x_curreg) - { - case 0: - if (valxor & 1) - { - ide_handler(); - } - break; - case 1: - if (valxor & 3) - { - lpt1_handler(); - } - if (valxor & 0x60) - { - serial_remove(1); - set_com34_addr(); - set_serial1_addr(); - set_serial2_addr(); - } - break; - case 2: - if (valxor & 7) - { - serial_remove(1); - set_serial1_addr(); - } - if (valxor & 0x70) - { - serial_remove(2); - set_serial2_addr(); - } - break; - case 3: - if (valxor & 2) - { - fdc_update_enh_mode(fdc37c66x_fdc, (fdc37c66x_regs[3] & 2) ? 1 : 0); - } - break; + if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { + if (port == 0x3f0) { + if (val == 0xaa) + write_lock(dev, val); + else + dev->cur_reg = val; + } else { + if (dev->cur_reg > 15) + return; + + valxor = val ^ dev->regs[dev->cur_reg]; + dev->regs[dev->cur_reg] = val; + + switch(dev->cur_reg) { + case 1: + if (valxor & 3) + lpt1_handler(dev); + if (valxor & 0x60) { + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + set_com34_addr(dev); + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + } + break; + case 2: + if (valxor & 7) { + serial_remove(dev->uart[0]); + set_serial_addr(dev, 0); + } + if (valxor & 0x70) { + serial_remove(dev->uart[1]); + set_serial_addr(dev, 1); + } + break; + case 3: + if (valxor & 2) + fdc_update_enh_mode(dev->fdc, (dev->regs[3] & 2) ? 1 : 0); + break; case 5: - if (valxor & 2) - { - ide_handler(); - } - if (valxor & 0x18) - { - fdc_update_densel_force(fdc37c66x_fdc, (fdc37c66x_regs[5] & 0x18) >> 3); - } - if (valxor & 0x20) - { - fdc_set_swap(fdc37c66x_fdc, (fdc37c66x_regs[5] & 0x20) >> 5); - } - break; - } - } - } - else - { - if (port == 0x3f0) - write_lock(val); - } + if (valxor & 0x18) + fdc_update_densel_force(dev->fdc, (dev->regs[5] & 0x18) >> 3); + if (valxor & 0x20) + fdc_set_swap(dev->fdc, (dev->regs[5] & 0x20) >> 5); + break; + } + } + } else { + if (port == 0x3f0) + write_lock(dev, val); + } } -static uint8_t fdc37c66x_read(uint16_t port, void *priv) + +static uint8_t +fdc37c66x_read(uint16_t port, void *priv) { - if (fdc37c66x_lock[0] == 0x55 && fdc37c66x_lock[1] == 0x55) - { - if (port == 0x3f1) - return fdc37c66x_regs[fdc37c66x_curreg]; - } - return 0xff; + fdc37c66x_t *dev = (fdc37c66x_t *) priv; + uint8_t ret = 0xff; + + if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { + if (port == 0x3f1) + ret = dev->regs[dev->cur_reg]; + } + + return ret; } -static void fdc37c66x_reset(void) + +static void +fdc37c66x_reset(fdc37c66x_t *dev) { - com3_addr = 0x338; - com4_addr = 0x238; + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; - serial_remove(1); - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); - serial_remove(2); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL2_ADDR, SERIAL2_IRQ); - lpt2_remove(); + lpt2_remove(); - lpt1_remove(); - lpt1_init(0x378); + lpt1_remove(); + lpt1_init(0x378); - fdc_reset(fdc37c66x_fdc); - - memset(fdc37c66x_lock, 0, 2); - memset(fdc37c66x_regs, 0, 16); - fdc37c66x_regs[0x0] = 0x3a; - fdc37c66x_regs[0x1] = 0x9f; - fdc37c66x_regs[0x2] = 0xdc; - fdc37c66x_regs[0x3] = 0x78; - fdc37c66x_regs[0x6] = 0xff; - fdc37c66x_regs[0xe] = 0x01; + fdc_reset(dev->fdc); + + memset(dev->lock, 0, 2); + memset(dev->regs, 0, 16); + + dev->regs[0x0] = 0x3a; + dev->regs[0x1] = 0x9f; + dev->regs[0x2] = 0xdc; + dev->regs[0x3] = 0x78; + dev->regs[0x6] = 0xff; + dev->regs[0xd] = dev->chip_id; + dev->regs[0xe] = 0x01; } -static void fdc37c663_reset(void) + +static void +fdc37c66x_close(void *priv) { - fdc37c66x_reset(); - fdc37c66x_regs[0xd] = 0x63; + fdc37c66x_t *dev = (fdc37c66x_t *) priv; + + free(dev); } -static void fdc37c665_reset(void) + +static void * +fdc37c66x_init(const device_t *info) { - fdc37c66x_reset(); - fdc37c66x_regs[0xd] = 0x65; + fdc37c66x_t *dev = (fdc37c66x_t *) malloc(sizeof(fdc37c66x_t)); + memset(dev, 0, sizeof(fdc37c66x_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + dev->chip_id = info->local; + + io_sethandler(0x03f0, 0x0002, + fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, dev); + + fdc37c66x_reset(dev); + + return dev; } -void fdc37c663_init() -{ - fdc37c66x_fdc = device_add(&fdc_at_smc_device); - io_sethandler(0x03f0, 0x0002, fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, NULL); +/* The three appear to differ only in the chip ID, if I + understood their datasheets correctly. */ +const device_t fdc37c663_device = { + "SMC FDC37C663 Super I/O", + 0, + 0x63, + fdc37c66x_init, fdc37c66x_close, NULL, + NULL, NULL, NULL, + NULL +}; - fdc37c663_reset(); -} +const device_t fdc37c665_device = { + "SMC FDC37C665 Super I/O", + 0, + 0x65, + fdc37c66x_init, fdc37c66x_close, NULL, + NULL, NULL, NULL, + NULL +}; -void fdc37c665_init() -{ - fdc37c66x_fdc = device_add(&fdc_at_smc_device); - - io_sethandler(0x03f0, 0x0002, fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, NULL); - - fdc37c665_reset(); -} +const device_t fdc37c666_device = { + "SMC FDC37C666 Super I/O", + 0, + 0x66, + fdc37c66x_init, fdc37c66x_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_fdc37c93x.c b/src/sio_fdc37c93x.c index 5d2f7816d..adf5d45f4 100644 --- a/src/sio_fdc37c93x.c +++ b/src/sio_fdc37c93x.c @@ -9,13 +9,14 @@ * Implementation of the SMC FDC37C932FR and FDC37C935 Super * I/O Chips. * - * Version: @(#)sio_fdc37c93x.c 1.0.13 2018/04/29 + * Version: @(#)sio_fdc37c93x.c 1.0.14 2018/11/05 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "86box.h" @@ -31,104 +32,9 @@ #include "sio.h" -static int fdc37c93x_locked; -static int fdc37c93x_curreg = 0; -static int fdc37c93x_gpio_reg = 0; -static uint8_t fdc37c93x_regs[48]; -static uint8_t fdc37c93x_ld_regs[10][256]; -static uint16_t fdc37c93x_gpio_base = 0x00EA; -static fdc_t *fdc37c93x_fdc; - -static uint8_t tries; - -static uint16_t make_port(uint8_t ld) -{ - uint16_t r0 = fdc37c93x_ld_regs[ld][0x60]; - uint16_t r1 = fdc37c93x_ld_regs[ld][0x61]; - - uint16_t p = (r0 << 8) + r1; - - return p; -} - -static uint8_t fdc37c93x_gpio_read(uint16_t port, void *priv) -{ - return fdc37c93x_gpio_reg; -} - -static void fdc37c93x_gpio_write(uint16_t port, uint8_t val, void *priv) -{ - fdc37c93x_gpio_reg = val; -} - -static void fdc37c93x_fdc_handler(void) -{ - uint16_t ld_port = 0; - - uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << 0)); - uint8_t local_enable = !!fdc37c93x_ld_regs[0][0x30]; - - fdc_remove(fdc37c93x_fdc); - if (global_enable && local_enable) - { - ld_port = make_port(0); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) { - fdc_set_base(fdc37c93x_fdc, ld_port); - } - } -} - -static void fdc37c93x_lpt_handler(void) -{ - uint16_t ld_port = 0; - - uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << 3)); - uint8_t local_enable = !!fdc37c93x_ld_regs[3][0x30]; - - lpt1_remove(); - if (global_enable && local_enable) - { - ld_port = make_port(3); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) - lpt1_init(ld_port); - } -} - -static void fdc37c93x_serial_handler(int uart) -{ - uint16_t ld_port = 0; - - uint8_t uart_no = 3 + uart; - - uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << uart_no)); - uint8_t local_enable = !!fdc37c93x_ld_regs[uart_no][0x30]; - - serial_remove(uart); - if (global_enable && local_enable) - { - ld_port = make_port(uart_no); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) - serial_setup(uart, ld_port, fdc37c93x_ld_regs[uart_no][0x70]); - } -} - -static void fdc37c93x_auxio_handler(void) -{ - uint16_t ld_port = 0; - - uint8_t local_enable = !!fdc37c93x_ld_regs[8][0x30]; - - io_removehandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); - if (local_enable) - { - fdc37c93x_gpio_base = ld_port = make_port(8); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF)) - io_sethandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); - } -} - #define AB_RST 0x80 + typedef struct { uint8_t control; uint8_t status; @@ -138,430 +44,637 @@ typedef struct { uint16_t base; } access_bus_t; -static access_bus_t access_bus; +typedef struct { + uint8_t chip_id, tries, + gpio_regs[2], auxio_reg, + regs[48], + ld_regs[10][256]; + uint16_t gpio_base, /* Set to EA */ + auxio_base; + int locked, + cur_reg; + fdc_t *fdc; + serial_t *uart[2]; + access_bus_t *access_bus; +} fdc37c93x_t; -static uint8_t fdc37c932fr_access_bus_read(uint16_t port, void *priv) + +static uint16_t +make_port(fdc37c93x_t *dev, uint8_t ld) { - switch(port & 3) { + uint16_t r0 = dev->ld_regs[ld][0x60]; + uint16_t r1 = dev->ld_regs[ld][0x61]; + + uint16_t p = (r0 << 8) + r1; + + return p; +} + + +static uint8_t +fdc37c93x_auxio_read(uint16_t port, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + return dev->auxio_reg; +} + + +static void +fdc37c93x_auxio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + dev->auxio_reg = val; +} + + +static uint8_t +fdc37c93x_gpio_read(uint16_t port, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + return dev->gpio_regs[port & 1]; +} + + +static void +fdc37c93x_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + dev->gpio_regs[port & 1] = val; +} + + +static void +fdc37c93x_fdc_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 0)); + uint8_t local_enable = !!dev->ld_regs[0][0x30]; + + fdc_remove(dev->fdc); + if (global_enable && local_enable) { + ld_port = make_port(dev, 0); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + fdc_set_base(dev->fdc, ld_port); + } +} + + +static void +fdc37c93x_lpt_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 3)); + uint8_t local_enable = !!dev->ld_regs[3][0x30]; + + lpt1_remove(); + if (global_enable && local_enable) { + ld_port = make_port(dev, 3); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + lpt1_init(ld_port); + } +} + + +static void +fdc37c93x_serial_handler(fdc37c93x_t *dev, int uart) +{ + uint16_t ld_port = 0; + uint8_t uart_no = 4 + uart; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << uart_no)); + uint8_t local_enable = !!dev->ld_regs[uart_no][0x30]; + + serial_remove(dev->uart[uart]); + if (global_enable && local_enable) { + ld_port = make_port(dev, uart_no); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + serial_setup(dev->uart[uart], ld_port, dev->ld_regs[uart_no][0x70]); + } +} + + +static void fdc37c93x_auxio_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable = !!dev->ld_regs[8][0x30]; + + io_removehandler(dev->auxio_base, 0x0001, + fdc37c93x_auxio_read, NULL, NULL, fdc37c93x_auxio_write, NULL, NULL, dev); + if (local_enable) { + dev->auxio_base = ld_port = make_port(dev, 8); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF)) + io_sethandler(dev->auxio_base, 0x0001, + fdc37c93x_auxio_read, NULL, NULL, fdc37c93x_auxio_write, NULL, NULL, dev); + } +} + + +static void fdc37c93x_gpio_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable; + + local_enable = !!(dev->regs[0x03] & 0x80); + + io_removehandler(dev->gpio_base, 0x0002, + fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, dev); + if (local_enable) { + switch (dev->regs[0x03] & 0x03) { case 0: - return (access_bus.status & 0xBF); + ld_port = 0xe0; break; case 1: - return (access_bus.own_addr & 0x7F); + ld_port = 0xe2; break; case 2: - return access_bus.data; + ld_port = 0xe4; break; case 3: - return (access_bus.clock & 0x87); - break; - default: - return 0xFF; - } -} - -static void fdc37c932fr_access_bus_write(uint16_t port, uint8_t val, void *priv) -{ - switch(port & 3) { - case 0: - access_bus.control = (val & 0xCF); - break; - case 1: - access_bus.own_addr = (val & 0x7F); - break; - case 2: - access_bus.data = val; - break; - case 3: - access_bus.clock &= 0x80; - access_bus.clock |= (val & 0x07); + ld_port = 0xea; /* Default */ break; } + dev->gpio_base = ld_port; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFE)) + io_sethandler(dev->gpio_base, 0x0002, + fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, dev); + } } -static void fdc37c932fr_access_bus_handler(void) +static uint8_t +fdc37c932fr_access_bus_read(uint16_t port, void *priv) { - uint16_t ld_port = 0; + access_bus_t *dev = (access_bus_t *) priv; + uint8_t ret = 0xff; - uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << 6)); - uint8_t local_enable = !!fdc37c93x_ld_regs[9][0x30]; + switch(port & 3) { + case 0: + ret = (dev->status & 0xBF); + break; + case 1: + ret = (dev->own_addr & 0x7F); + break; + case 2: + ret = dev->data; + break; + case 3: + ret = (dev->clock & 0x87); + break; + } - io_removehandler(access_bus.base, 0x0004, fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, NULL); - if (global_enable && local_enable) - { - access_bus.base = ld_port = make_port(9); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) - io_sethandler(access_bus.base, 0x0004, fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, NULL); - } + return ret; } -static void fdc37c93x_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t index = (port & 1) ? 0 : 1; - uint8_t valxor = 0; - if (index) - { - if ((val == 0x55) && !fdc37c93x_locked) - { - if (tries) - { - fdc37c93x_locked = 1; - fdc_3f1_enable(fdc37c93x_fdc, 0); - tries = 0; - } - else - { - tries++; - } - } - else - { - if (fdc37c93x_locked) - { - if (val == 0xaa) - { - fdc37c93x_locked = 0; - fdc_3f1_enable(fdc37c93x_fdc, 1); - return; - } - fdc37c93x_curreg = val; - } - else - { - if (tries) - tries = 0; - } - } - } - else - { - if (fdc37c93x_locked) - { - if (fdc37c93x_curreg < 48) - { - valxor = val ^ fdc37c93x_regs[fdc37c93x_curreg]; - if ((val == 0x20) || (val == 0x21)) - return; - fdc37c93x_regs[fdc37c93x_curreg] = val; - goto process_value; - } - else - { - valxor = val ^ fdc37c93x_ld_regs[fdc37c93x_regs[7]][fdc37c93x_curreg]; - if (((fdc37c93x_curreg & 0xF0) == 0x70) && (fdc37c93x_regs[7] < 4)) return; - /* Block writes to IDE configuration. */ - if (fdc37c93x_regs[7] == 1) return; - if (fdc37c93x_regs[7] == 2) return; - if ((fdc37c93x_regs[7] > 5) && (fdc37c93x_regs[7] != 8) && (fdc37c93x_regs[7] != 9)) return; - if ((fdc37c93x_regs[7] == 9) && (fdc37c93x_regs[0x20] != 3)) return; - fdc37c93x_ld_regs[fdc37c93x_regs[7]][fdc37c93x_curreg] = val; - goto process_value; +static void +fdc37c932fr_access_bus_write(uint16_t port, uint8_t val, void *priv) +{ + access_bus_t *dev = (access_bus_t *) priv; + + switch(port & 3) { + case 0: + dev->control = (val & 0xCF); + break; + case 1: + dev->own_addr = (val & 0x7F); + break; + case 2: + dev->data = val; + break; + case 3: + dev->clock &= 0x80; + dev->clock |= (val & 0x07); + break; + } +} + + +static void fdc37c932fr_access_bus_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 6)); + uint8_t local_enable = !!dev->ld_regs[9][0x30]; + + io_removehandler(dev->access_bus->base, 0x0004, + fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, dev->access_bus); + if (global_enable && local_enable) { + dev->access_bus->base = ld_port = make_port(dev, 9); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + io_sethandler(dev->access_bus->base, 0x0004, + fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, dev->access_bus); + } +} + + +static void +fdc37c93x_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + + if (index) { + if ((val == 0x55) && !dev->locked) { + if (dev->tries) { + dev->locked = 1; + fdc_3f1_enable(dev->fdc, 0); + dev->tries = 0; + } else + dev->tries++; + } else { + if (dev->locked) { + if (val == 0xaa) { + dev->locked = 0; + fdc_3f1_enable(dev->fdc, 1); + return; } + dev->cur_reg = val; + } else { + if (dev->tries) + dev->tries = 0; } } return; + } else { + if (dev->locked) { + if (dev->cur_reg < 48) { + valxor = val ^ dev->regs[dev->cur_reg]; + if ((val == 0x20) || (val == 0x21)) + return; + dev->regs[dev->cur_reg] = val; + } else { + valxor = val ^ dev->ld_regs[dev->regs[7]][dev->cur_reg]; + if (((dev->cur_reg & 0xF0) == 0x70) && (dev->regs[7] < 4)) + return; + /* Block writes to some logical devices. */ + if (dev->regs[7] > 9) + return; + else switch (dev->regs[7]) { + case 1: + case 2: + case 6: + case 7: + return; + case 9: + /* If we're on the FDC37C935, return as this is not a valid + logical device there. */ + if (dev->chip_id == 0x02) + return; + break; + } + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + } + } else + return; + } -process_value: - if (fdc37c93x_curreg < 48) - { - switch(fdc37c93x_curreg) - { - case 0x22: + if (dev->cur_reg < 48) { + switch(dev->cur_reg) { + case 0x03: + if (valxor & 0x83) + fdc37c93x_gpio_handler(dev); + dev->regs[0x03] &= 0x83; + break; + case 0x22: + if (valxor & 0x01) + fdc37c93x_fdc_handler(dev); + if (valxor & 0x08) + fdc37c93x_lpt_handler(dev); + if (valxor & 0x10) + fdc37c93x_serial_handler(dev, 0); + if (valxor & 0x20) + fdc37c93x_serial_handler(dev, 1); + break; + } + + return; + } + + switch(dev->regs[7]) { + case 0: + /* FDD */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + if (valxor) + fdc37c93x_fdc_handler(dev); + break; + case 0xF0: if (valxor & 0x01) - fdc37c93x_fdc_handler(); - if (valxor & 0x08) - fdc37c93x_lpt_handler(); + fdc_update_enh_mode(dev->fdc, val & 0x01); if (valxor & 0x10) - fdc37c93x_serial_handler(1); - if (valxor & 0x20) - fdc37c93x_serial_handler(2); + fdc_set_swap(dev->fdc, (val & 0x10) >> 4); + break; + case 0xF1: + if (valxor & 0xC) + fdc_update_densel_force(dev->fdc, (val & 0xC) >> 2); + break; + case 0xF2: + if (valxor & 0xC0) + fdc_update_rwc(dev->fdc, 3, (valxor & 0xC0) >> 6); + if (valxor & 0x30) + fdc_update_rwc(dev->fdc, 2, (valxor & 0x30) >> 4); + if (valxor & 0x0C) + fdc_update_rwc(dev->fdc, 1, (valxor & 0x0C) >> 2); + if (valxor & 0x03) + fdc_update_rwc(dev->fdc, 0, (valxor & 0x03)); + break; + case 0xF4: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 0, (val & 0x18) >> 3); + break; + case 0xF5: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 1, (val & 0x18) >> 3); + break; + case 0xF6: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 2, (val & 0x18) >> 3); + break; + case 0xF7: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 3, (val & 0x18) >> 3); break; } - - return; - } - - switch(fdc37c93x_regs[7]) - { - case 0: - /* FDD */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - if (valxor) - { - fdc37c93x_fdc_handler(); - } - break; - case 0xF0: - if (valxor & 0x01) fdc_update_enh_mode(fdc37c93x_fdc, val & 0x01); - if (valxor & 0x10) fdc_set_swap(fdc37c93x_fdc, (val & 0x10) >> 4); - break; - case 0xF1: - if (valxor & 0xC) fdc_update_densel_force(fdc37c93x_fdc, (val & 0xC) >> 2); - break; - case 0xF2: - if (valxor & 0xC0) fdc_update_rwc(fdc37c93x_fdc, 3, (valxor & 0xC0) >> 6); - if (valxor & 0x30) fdc_update_rwc(fdc37c93x_fdc, 2, (valxor & 0x30) >> 4); - if (valxor & 0x0C) fdc_update_rwc(fdc37c93x_fdc, 1, (valxor & 0x0C) >> 2); - if (valxor & 0x03) fdc_update_rwc(fdc37c93x_fdc, 0, (valxor & 0x03)); - break; - case 0xF4: - if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 0, (val & 0x18) >> 3); - break; - case 0xF5: - if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 1, (val & 0x18) >> 3); - break; - case 0xF6: - if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 2, (val & 0x18) >> 3); - break; - case 0xF7: - if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 3, (val & 0x18) >> 3); - break; - } - break; - case 3: - /* Parallel port */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - if (valxor) - { - fdc37c93x_lpt_handler(); - } - break; - } - break; - case 4: - /* Serial port 1 */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if (valxor) - { - fdc37c93x_serial_handler(1); - } - break; - } - break; - case 5: - /* Serial port 2 */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if (valxor) - { - fdc37c93x_serial_handler(2); - } - break; - } - break; - case 8: - /* Auxiliary I/O */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if (valxor) - { - fdc37c93x_auxio_handler(); - } - break; - } - break; - case 9: - /* Access bus (FDC37C932FR only) */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if (valxor) - { - fdc37c932fr_access_bus_handler(); - } - break; - } - break; - } + break; + case 3: + /* Parallel port */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + if (valxor) + fdc37c93x_lpt_handler(dev); + break; + } + break; + case 4: + /* Serial port 1 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_serial_handler(dev, 0); + break; + } + break; + case 5: + /* Serial port 2 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_serial_handler(dev, 1); + break; + } + break; + case 8: + /* Auxiliary I/O */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_auxio_handler(dev); + break; + } + break; + case 9: + /* Access bus (FDC37C932FR only) */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c932fr_access_bus_handler(dev); + break; + } + break; + } } + static uint8_t fdc37c93x_read(uint16_t port, void *priv) { - uint8_t index = (port & 1) ? 0 : 1; + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; - if (!fdc37c93x_locked) - { - return 0xff; - } + if (!dev->locked) + return ret; - if (index) - return fdc37c93x_curreg; - else - { - if (fdc37c93x_curreg < 0x30) - { - return fdc37c93x_regs[fdc37c93x_curreg]; - } + if (index) + ret = dev->cur_reg; + else { + if (dev->cur_reg < 0x30) { + if (dev->cur_reg == 0x20) + ret = dev->chip_id; else - { - if ((fdc37c93x_regs[7] == 0) && (fdc37c93x_curreg == 0xF2)) return (fdc_get_rwc(fdc37c93x_fdc, 0) | (fdc_get_rwc(fdc37c93x_fdc, 1) << 2)); - return fdc37c93x_ld_regs[fdc37c93x_regs[7]][fdc37c93x_curreg]; - } + ret = dev->regs[dev->cur_reg]; + } else { + if ((dev->regs[7] == 0) && (dev->cur_reg == 0xF2)) { + ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | + (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); + } else + ret = dev->ld_regs[dev->regs[7]][dev->cur_reg]; } + } + + return ret; } -static void fdc37c93x_reset(void) + +static void +fdc37c93x_reset(fdc37c93x_t *dev) { - int i = 0; + int i = 0; - memset(fdc37c93x_regs, 0, 48); + lpt2_remove(); - fdc37c93x_regs[0x03] = 3; - fdc37c93x_regs[0x21] = 1; - fdc37c93x_regs[0x22] = 0x39; - fdc37c93x_regs[0x24] = 4; - fdc37c93x_regs[0x26] = 0xF0; - fdc37c93x_regs[0x27] = 3; + memset(dev->regs, 0, 48); - for (i = 0; i < 10; i++) - { - memset(fdc37c93x_ld_regs[i], 0, 256); - } + dev->regs[0x03] = 0x03; + dev->regs[0x21] = 0x01; + dev->regs[0x20] = dev->chip_id; + dev->regs[0x22] = 0x39; + dev->regs[0x24] = 0x04; + dev->regs[0x26] = 0xF0; + dev->regs[0x27] = 0x03; - /* Logical device 0: FDD */ - fdc37c93x_ld_regs[0][0x30] = 1; - fdc37c93x_ld_regs[0][0x60] = 3; - fdc37c93x_ld_regs[0][0x61] = 0xF0; - fdc37c93x_ld_regs[0][0x70] = 6; - fdc37c93x_ld_regs[0][0x74] = 2; - fdc37c93x_ld_regs[0][0xF0] = 0xE; - fdc37c93x_ld_regs[0][0xF2] = 0xFF; + for (i = 0; i < 10; i++) + memset(dev->ld_regs[i], 0, 256); - /* Logical device 1: IDE1 */ - fdc37c93x_ld_regs[1][0x30] = 0; - fdc37c93x_ld_regs[1][0x60] = 1; - fdc37c93x_ld_regs[1][0x61] = 0xF0; - fdc37c93x_ld_regs[1][0x62] = 3; - fdc37c93x_ld_regs[1][0x63] = 0xF6; - fdc37c93x_ld_regs[1][0x70] = 0xE; - fdc37c93x_ld_regs[1][0xF0] = 0xC; + /* Logical device 0: FDD */ + dev->ld_regs[0][0x30] = 1; + dev->ld_regs[0][0x60] = 3; + dev->ld_regs[0][0x61] = 0xF0; + dev->ld_regs[0][0x70] = 6; + dev->ld_regs[0][0x74] = 2; + dev->ld_regs[0][0xF0] = 0xE; + dev->ld_regs[0][0xF2] = 0xFF; - /* Logical device 2: IDE2 */ - fdc37c93x_ld_regs[2][0x30] = 0; - fdc37c93x_ld_regs[2][0x60] = 1; - fdc37c93x_ld_regs[2][0x61] = 0x70; - fdc37c93x_ld_regs[2][0x62] = 3; - fdc37c93x_ld_regs[2][0x63] = 0x76; - fdc37c93x_ld_regs[2][0x70] = 0xF; + /* Logical device 1: IDE1 */ + dev->ld_regs[1][0x30] = 0; + dev->ld_regs[1][0x60] = 1; + dev->ld_regs[1][0x61] = 0xF0; + dev->ld_regs[1][0x62] = 3; + dev->ld_regs[1][0x63] = 0xF6; + dev->ld_regs[1][0x70] = 0xE; + dev->ld_regs[1][0xF0] = 0xC; - /* Logical device 3: Parallel Port */ - fdc37c93x_ld_regs[3][0x30] = 1; - fdc37c93x_ld_regs[3][0x60] = 3; - fdc37c93x_ld_regs[3][0x61] = 0x78; - fdc37c93x_ld_regs[3][0x70] = 7; - fdc37c93x_ld_regs[3][0x74] = 4; - fdc37c93x_ld_regs[3][0xF0] = 0x3C; + /* Logical device 2: IDE2 */ + dev->ld_regs[2][0x30] = 0; + dev->ld_regs[2][0x60] = 1; + dev->ld_regs[2][0x61] = 0x70; + dev->ld_regs[2][0x62] = 3; + dev->ld_regs[2][0x63] = 0x76; + dev->ld_regs[2][0x70] = 0xF; - /* Logical device 4: Serial Port 1 */ - fdc37c93x_ld_regs[4][0x30] = 1; - fdc37c93x_ld_regs[4][0x60] = 3; - fdc37c93x_ld_regs[4][0x61] = 0xf8; - fdc37c93x_ld_regs[4][0x70] = 4; - fdc37c93x_ld_regs[4][0xF0] = 3; - serial_setup(1, 0x3f8, fdc37c93x_ld_regs[4][0x70]); + /* Logical device 3: Parallel Port */ + dev->ld_regs[3][0x30] = 1; + dev->ld_regs[3][0x60] = 3; + dev->ld_regs[3][0x61] = 0x78; + dev->ld_regs[3][0x70] = 7; + dev->ld_regs[3][0x74] = 4; + dev->ld_regs[3][0xF0] = 0x3C; - /* Logical device 5: Serial Port 2 */ - fdc37c93x_ld_regs[5][0x30] = 1; - fdc37c93x_ld_regs[5][0x60] = 2; - fdc37c93x_ld_regs[5][0x61] = 0xf8; - fdc37c93x_ld_regs[5][0x70] = 3; - fdc37c93x_ld_regs[5][0x74] = 4; - fdc37c93x_ld_regs[5][0xF1] = 2; - fdc37c93x_ld_regs[5][0xF2] = 3; - serial_setup(2, 0x2f8, fdc37c93x_ld_regs[5][0x70]); + /* Logical device 4: Serial Port 1 */ + dev->ld_regs[4][0x30] = 1; + dev->ld_regs[4][0x60] = 3; + dev->ld_regs[4][0x61] = 0xf8; + dev->ld_regs[4][0x70] = 4; + dev->ld_regs[4][0xF0] = 3; + serial_setup(dev->uart[0], 0x3f8, dev->ld_regs[4][0x70]); - /* Logical device 6: RTC */ - fdc37c93x_ld_regs[6][0x63] = 0x70; - fdc37c93x_ld_regs[6][0xF4] = 3; + /* Logical device 5: Serial Port 2 */ + dev->ld_regs[5][0x30] = 1; + dev->ld_regs[5][0x60] = 2; + dev->ld_regs[5][0x61] = 0xf8; + dev->ld_regs[5][0x70] = 3; + dev->ld_regs[5][0x74] = 4; + dev->ld_regs[5][0xF1] = 2; + dev->ld_regs[5][0xF2] = 3; + serial_setup(dev->uart[1], 0x2f8, dev->ld_regs[5][0x70]); - /* Logical device 7: Keyboard */ - fdc37c93x_ld_regs[7][0x30] = 1; - fdc37c93x_ld_regs[7][0x61] = 0x60; - fdc37c93x_ld_regs[7][0x70] = 1; + /* Logical device 6: RTC */ + dev->ld_regs[6][0x63] = 0x70; + dev->ld_regs[6][0xF4] = 3; - /* Logical device 8: Auxiliary I/O */ - fdc37c93x_ld_regs[8][0x30] = 1; - fdc37c93x_ld_regs[8][0x61] = 0xEA; + /* Logical device 7: Keyboard */ + dev->ld_regs[7][0x30] = 1; + dev->ld_regs[7][0x61] = 0x60; + dev->ld_regs[7][0x70] = 1; - /* Logical device 8: AUX I/O */ + /* Logical device 8: Auxiliary I/O */ + io_removehandler(dev->access_bus->base, 0x0004, + fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, dev->access_bus); - /* Logical device 9: ACCESS.bus */ + /* Logical device 9: ACCESS.bus */ - io_removehandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); - fdc37c93x_gpio_base = 0x00EA; - io_sethandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); + fdc37c93x_gpio_handler(dev); + fdc37c93x_lpt_handler(dev); + fdc37c93x_serial_handler(dev, 0); + fdc37c93x_serial_handler(dev, 1); + fdc37c93x_auxio_handler(dev); + if (dev->chip_id == 0x03) + fdc37c932fr_access_bus_handler(dev); - fdc37c93x_lpt_handler(); - fdc37c93x_serial_handler(1); - fdc37c93x_serial_handler(2); - fdc37c93x_auxio_handler(); + fdc_reset(dev->fdc); - fdc_reset(fdc37c93x_fdc); - - fdc37c93x_locked = 0; + dev->locked = 0; } -static void fdc37c932fr_reset(void) + +static void +access_bus_close(void *priv) { - fdc37c93x_reset(); + access_bus_t *dev = (access_bus_t *) priv; - fdc37c93x_regs[0x20] = 3; - - fdc37c932fr_access_bus_handler(); + free(dev); } -static void fdc37c935_reset(void) + +static void * +access_bus_init(const device_t *info) { - fdc37c93x_reset(); + access_bus_t *dev = (access_bus_t *) malloc(sizeof(access_bus_t)); + memset(dev, 0, sizeof(access_bus_t)); - fdc37c93x_regs[0x20] = 2; + return dev; } -static void fdc37c93x_init(void) + +static const device_t access_bus_device = { + "SMC FDC37C932FR ACCESS.bus", + 0, + 0x03, + access_bus_init, access_bus_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +static void +fdc37c93x_close(void *priv) { - lpt2_remove(); + fdc37c93x_t *dev = (fdc37c93x_t *) priv; - fdc37c93x_fdc = device_add(&fdc_at_smc_device); - - fdc37c93x_gpio_reg = 0xFD; - - io_sethandler(0x3f0, 0x0002, fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, NULL); + free(dev); } -void fdc37c932fr_init(void) + +static void * +fdc37c93x_init(const device_t *info) { - fdc37c93x_init(); - fdc37c932fr_reset(); + fdc37c93x_t *dev = (fdc37c93x_t *) malloc(sizeof(fdc37c93x_t)); + memset(dev, 0, sizeof(fdc37c93x_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + dev->chip_id = info->local; + + dev->gpio_regs[0] = 0xFD; + dev->gpio_regs[1] = 0xFF; + + if (dev->chip_id == 0x03) + dev->access_bus = device_add(&access_bus_device); + + io_sethandler(0x3f0, 0x0002, + fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + + fdc37c93x_reset(dev); + + return dev; } -void fdc37c935_init(void) -{ - fdc37c93x_init(); - fdc37c935_reset(); -} + +const device_t fdc37c932fr_device = { + "SMC FDC37C932FR Super I/O", + 0, + 0x03, + fdc37c93x_init, fdc37c93x_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t fdc37c935_device = { + "SMC FDC37C935 Super I/O", + 0, + 0x02, + fdc37c93x_init, fdc37c93x_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_pc87306.c b/src/sio_pc87306.c index f21946c69..8901b4b02 100644 --- a/src/sio_pc87306.c +++ b/src/sio_pc87306.c @@ -8,13 +8,14 @@ * * Emulation of the NatSemi PC87306 Super I/O chip. * - * Version: @(#)sio_pc87306.c 1.0.13 2018/10/02 + * Version: @(#)sio_pc87306.c 1.0.14 2018/11/05 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "86box.h" @@ -32,423 +33,383 @@ #include "sio.h" -static int pc87306_curreg; -static uint8_t pc87306_regs[29]; -static uint8_t pc87306_gpio[2] = {0xFF, 0xFB}; -static fdc_t *pc87306_fdc; -static uint8_t tries; -static uint16_t lpt_port; +typedef struct { + uint8_t tries, + regs[29], gpio[2]; + int cur_reg; + fdc_t *fdc; + serial_t *uart[2]; +} pc87306_t; -void pc87306_gpio_remove(); -void pc87306_gpio_init(); -void pc87306_gpio_write(uint16_t port, uint8_t val, void *priv) +static void +pc87306_gpio_write(uint16_t port, uint8_t val, void *priv) { - pc87306_gpio[port & 1] = val; + pc87306_t *dev = (pc87306_t *) priv; + + dev->gpio[port & 1] = val; } -uint8_t uart1_int() + +uint8_t +pc87306_gpio_read(uint16_t port, void *priv) { - uint8_t fer_irq, pnp1_irq; - fer_irq = ((pc87306_regs[1] >> 2) & 1) ? 3 : 4; /* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */ - pnp1_irq = ((pc87306_regs[0x1C] >> 2) & 1) ? 4 : 3; - return (pc87306_regs[0x1C] & 1) ? pnp1_irq : fer_irq; + pc87306_t *dev = (pc87306_t *) priv; + + return dev->gpio[port & 1]; } -uint8_t uart2_int() + +static void +pc87306_gpio_remove(pc87306_t *dev) { - uint8_t fer_irq, pnp1_irq; - fer_irq = ((pc87306_regs[1] >> 4) & 1) ? 3 : 4; /* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */ - pnp1_irq = ((pc87306_regs[0x1C] >> 6) & 1) ? 4 : 3; - return (pc87306_regs[0x1C] & 1) ? pnp1_irq : fer_irq; + io_removehandler(dev->regs[0x0f] << 2, 0x0001, + pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev); + io_removehandler((dev->regs[0x0f] << 2) + 1, 0x0001, + pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev); } -void lpt1_handler() + +static void +pc87306_gpio_init(pc87306_t *dev) { - int temp; - uint16_t lptba; - temp = pc87306_regs[0x01] & 3; - lptba = ((uint16_t) pc87306_regs[0x19]) << 2; - if (pc87306_regs[0x1B] & 0x10) { - if (pc87306_regs[0x1B] & 0x20) - lpt_port = 0x278; - else - lpt_port = 0x378; - } else { - switch (temp) { - case 0: - lpt_port = 0x378; - break; - case 1: - lpt_port = lptba; - break; - case 2: - lpt_port = 0x278; - break; - case 3: - lpt_port = 0x000; - break; - } - } - if (lpt_port) - lpt1_init(lpt_port); + if ((dev->regs[0x12]) & 0x10) + io_sethandler(dev->regs[0x0f] << 2, 0x0001, + pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev); + + if ((dev->regs[0x12]) & 0x20) + io_sethandler((dev->regs[0x0f] << 2) + 1, 0x0001, + pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev); } -void serial1_handler() + +static void +lpt1_handler(pc87306_t *dev) { - int temp; - temp = (pc87306_regs[1] >> 2) & 3; - switch (temp) - { - case 0: serial_setup(1, SERIAL1_ADDR, uart1_int()); break; - case 1: serial_setup(1, SERIAL2_ADDR, uart1_int()); break; - case 2: - switch ((pc87306_regs[1] >> 6) & 3) - { - case 0: serial_setup(1, 0x3e8, uart1_int()); break; - case 1: serial_setup(1, 0x338, uart1_int()); break; - case 2: serial_setup(1, 0x2e8, uart1_int()); break; - case 3: serial_setup(1, 0x220, uart1_int()); break; - } - break; - case 3: - switch ((pc87306_regs[1] >> 6) & 3) - { - case 0: serial_setup(1, 0x2e8, uart1_int()); break; - case 1: serial_setup(1, 0x238, uart1_int()); break; - case 2: serial_setup(1, 0x2e0, uart1_int()); break; - case 3: serial_setup(1, 0x228, uart1_int()); break; - } - break; - } -} + int temp; + uint16_t lptba, lpt_port = 0x378; -void serial2_handler() -{ - int temp; - temp = (pc87306_regs[1] >> 4) & 3; - switch (temp) - { - case 0: serial_setup(2, SERIAL1_ADDR, uart2_int()); break; - case 1: serial_setup(2, SERIAL2_ADDR, uart2_int()); break; - case 2: - switch ((pc87306_regs[1] >> 6) & 3) - { - case 0: serial_setup(2, 0x3e8, uart2_int()); break; - case 1: serial_setup(2, 0x338, uart2_int()); break; - case 2: serial_setup(2, 0x2e8, uart2_int()); break; - case 3: serial_setup(2, 0x220, uart2_int()); break; - } - break; - case 3: - switch ((pc87306_regs[1] >> 6) & 3) - { - case 0: serial_setup(2, 0x2e8, uart2_int()); break; - case 1: serial_setup(2, 0x238, uart2_int()); break; - case 2: serial_setup(2, 0x2e0, uart2_int()); break; - case 3: serial_setup(2, 0x228, uart2_int()); break; - } - break; - } -} + temp = dev->regs[0x01] & 3; + lptba = ((uint16_t) dev->regs[0x19]) << 2; -void pc87306_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t index, valxor; - - index = (port & 1) ? 0 : 1; - - if (index) - { - pc87306_curreg = val & 0x1f; - tries = 0; - return; - } + if (dev->regs[0x1b] & 0x10) { + if (dev->regs[0x1b] & 0x20) + lpt_port = 0x278; else - { - if (tries) - { - if ((pc87306_curreg == 0) && (val == 8)) - { - val = 0x4b; - } - valxor = val ^ pc87306_regs[pc87306_curreg]; - tries = 0; - if ((pc87306_curreg == 0x19) && !(pc87306_regs[0x1B] & 0x40)) - { - return; - } - if ((pc87306_curreg <= 28) && (pc87306_curreg != 8)/* && (pc87306_curreg != 0x18)*/) - { - if (pc87306_curreg == 0) - { - val &= 0x5f; - } - if (((pc87306_curreg == 0x0F) || (pc87306_curreg == 0x12)) && valxor) - { - pc87306_gpio_remove(); - } - pc87306_regs[pc87306_curreg] = val; - goto process_value; - } - } - else - { - tries++; - return; - } - } - return; - -process_value: - switch(pc87306_curreg) - { + lpt_port = 0x378; + } else { + switch (temp) { case 0: - if (valxor & 1) - { - lpt1_remove(); - if (val & 1) - { - lpt1_handler(); - } - } - - if (valxor & 2) - { - serial_remove(1); - if (val & 2) - { - serial1_handler(); - } - } - if (valxor & 4) - { - serial_remove(2); - if (val & 4) - { - serial2_handler(); - } - } - if (valxor & 0x28) - { - fdc_remove(pc87306_fdc); - if (val & 8) - { - fdc_set_base(pc87306_fdc, (val & 0x20) ? 0x370 : 0x3f0); - } - } + lpt_port = 0x378; break; case 1: - if (valxor & 3) - { - lpt1_remove(); - if (pc87306_regs[0] & 1) - { - lpt1_handler(); - } - } - - if (valxor & 0xcc) - { - if (pc87306_regs[0] & 2) - { - serial1_handler(); - } - else - { - serial_remove(1); - } - } - - if (valxor & 0xf0) - { - if (pc87306_regs[0] & 4) - { - serial2_handler(); - } - else - { - serial_remove(2); - } - } + lpt_port = lptba; break; case 2: - if (valxor & 1) - { - if (val & 1) - { - lpt1_remove(); - serial_remove(1); - serial_remove(2); - fdc_remove(pc87306_fdc); - } - else - { - if (pc87306_regs[0] & 1) - { - lpt1_handler(); - } - if (pc87306_regs[0] & 2) - { - serial1_handler(); - } - if (pc87306_regs[0] & 4) - { - serial2_handler(); - } - if (pc87306_regs[0] & 8) - { - fdc_set_base(pc87306_fdc, (pc87306_regs[0] & 0x20) ? 0x370 : 0x3f0); - } - } - } + lpt_port = 0x278; break; - case 9: - if (valxor & 0x44) - { - fdc_update_enh_mode(pc87306_fdc, (val & 4) ? 1 : 0); - fdc_update_densel_polarity(pc87306_fdc, (val & 0x40) ? 1 : 0); - } - break; - case 0xF: - if (valxor) - { - pc87306_gpio_init(); - } - break; - case 0x12: - if (valxor & 0x30) - { - pc87306_gpio_init(); - } - break; - case 0x19: - if (valxor) - { - lpt1_remove(); - if (pc87306_regs[0] & 1) - { - lpt1_handler(); - } - } - break; - case 0x1B: - if (valxor & 0x70) - { - lpt1_remove(); - if (!(val & 0x40)) - { - pc87306_regs[0x19] = 0xEF; - } - if (pc87306_regs[0] & 1) - { - lpt1_handler(); - } - } - break; - case 0x1C: - if (valxor) - { - if (pc87306_regs[0] & 2) - { - serial1_handler(); - } - if (pc87306_regs[0] & 4) - { - serial2_handler(); - } - } + case 3: + lpt_port = 0x000; break; } + } + + if (lpt_port) + lpt1_init(lpt_port); } -uint8_t pc87306_gpio_read(uint16_t port, void *priv) + +static void +serial_handler(pc87306_t *dev, int uart) { - return pc87306_gpio[port & 1]; -} + int temp; + uint8_t fer_irq, pnp1_irq; + uint8_t fer_shift, pnp_shift; + uint8_t irq; -uint8_t pc87306_read(uint16_t port, void *priv) -{ - uint8_t index; - index = (port & 1) ? 0 : 1; + temp = (dev->regs[1] >> (2 << uart)) & 3; - tries = 0; + fer_shift = 2 << uart; /* 2 for UART 1, 4 for UART 2 */ + pnp_shift = 2 + (uart << 2); /* 2 for UART 1, 6 for UART 2 */ - if (index) - { - return pc87306_curreg & 0x1f; - } - else - { - if (pc87306_curreg >= 28) - { - return 0xff; + /* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */ + fer_irq = ((dev->regs[1] >> fer_shift) & 1) ? 3 : 4; + pnp1_irq = ((dev->regs[0x1c] >> pnp_shift) & 1) ? 4 : 3; + + irq = (dev->regs[0x1c] & 1) ? pnp1_irq : fer_irq; + + switch (temp) { + case 0: + serial_setup(dev->uart[uart], SERIAL1_ADDR, irq); + break; + case 1: + serial_setup(dev->uart[uart], SERIAL2_ADDR, irq); + break; + case 2: + switch ((dev->regs[1] >> 6) & 3) { + case 0: + serial_setup(dev->uart[uart], 0x3e8, irq); + break; + case 1: + serial_setup(dev->uart[uart], 0x338, irq); + break; + case 2: + serial_setup(dev->uart[uart], 0x2e8, irq); + break; + case 3: + serial_setup(dev->uart[uart], 0x220, irq); + break; } - else if (pc87306_curreg == 8) - { - return 0x70; + break; + case 3: + switch ((dev->regs[1] >> 6) & 3) { + case 0: + serial_setup(dev->uart[uart], 0x2e8, irq); + break; + case 1: + serial_setup(dev->uart[uart], 0x238, irq); + break; + case 2: + serial_setup(dev->uart[uart], 0x2e0, irq); + break; + case 3: + serial_setup(dev->uart[uart], 0x228, irq); + break; } - else - { - return pc87306_regs[pc87306_curreg]; + break; + } +} + + +static void +pc87306_write(uint16_t port, uint8_t val, void *priv) +{ + pc87306_t *dev = (pc87306_t *) priv; + uint8_t index, valxor; + + index = (port & 1) ? 0 : 1; + + if (index) { + dev->cur_reg = val & 0x1f; + dev->tries = 0; + return; + } else { + if (dev->tries) { + if ((dev->cur_reg == 0) && (val == 8)) + val = 0x4b; + valxor = val ^ dev->regs[dev->cur_reg]; + dev->tries = 0; + if ((dev->cur_reg == 0x19) && !(dev->regs[0x1B] & 0x40)) + return; + if ((dev->cur_reg <= 28) && (dev->cur_reg != 8)) { + if (dev->cur_reg == 0) + val &= 0x5f; + if (((dev->cur_reg == 0x0F) || (dev->cur_reg == 0x12)) && valxor) + pc87306_gpio_remove(dev); + dev->regs[dev->cur_reg] = val; + } else + return; + } else { + dev->tries++; + return; + } + } + + switch(dev->cur_reg) { + case 0: + if (valxor & 1) { + lpt1_remove(); + if (val & 1) + lpt1_handler(dev); } - } + if (valxor & 2) { + serial_remove(dev->uart[0]); + if (val & 2) + serial_handler(dev, 0); + } + if (valxor & 4) { + serial_remove(dev->uart[1]); + if (val & 4) + serial_handler(dev, 1); + } + if (valxor & 0x28) { + fdc_remove(dev->fdc); + if (val & 8) + fdc_set_base(dev->fdc, (val & 0x20) ? 0x370 : 0x3f0); + } + break; + case 1: + if (valxor & 3) { + lpt1_remove(); + if (dev->regs[0] & 1) + lpt1_handler(dev); + } + if (valxor & 0xcc) { + if (dev->regs[0] & 2) + serial_handler(dev, 0); + else + serial_remove(dev->uart[0]); + } + if (valxor & 0xf0) { + if (dev->regs[0] & 4) + serial_handler(dev, 1); + else + serial_remove(dev->uart[1]); + } + break; + case 2: + if (valxor & 1) { + lpt1_remove(); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + fdc_remove(dev->fdc); + + if (!(val & 1)) { + if (dev->regs[0] & 1) + lpt1_handler(dev); + if (dev->regs[0] & 2) + serial_handler(dev, 0); + if (dev->regs[0] & 4) + serial_handler(dev, 1); + if (dev->regs[0] & 8) + fdc_set_base(dev->fdc, (dev->regs[0] & 0x20) ? 0x370 : 0x3f0); + } + } + break; + case 9: + if (valxor & 0x44) { + fdc_update_enh_mode(dev->fdc, (val & 4) ? 1 : 0); + fdc_update_densel_polarity(dev->fdc, (val & 0x40) ? 1 : 0); + } + break; + case 0xF: + if (valxor) + pc87306_gpio_init(dev); + break; + case 0x12: + if (valxor & 0x30) + pc87306_gpio_init(dev); + break; + case 0x19: + if (valxor) { + lpt1_remove(); + if (dev->regs[0] & 1) + lpt1_handler(dev); + } + break; + case 0x1B: + if (valxor & 0x70) { + lpt1_remove(); + if (!(val & 0x40)) + dev->regs[0x19] = 0xEF; + if (dev->regs[0] & 1) + lpt1_handler(dev); + } + break; + case 0x1C: + if (valxor) { + if (dev->regs[0] & 2) + serial_handler(dev, 0); + if (dev->regs[0] & 4) + serial_handler(dev, 1); + } + break; + } } -void pc87306_gpio_remove() + +uint8_t +pc87306_read(uint16_t port, void *priv) { - io_removehandler(pc87306_regs[0xF] << 2, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); + pc87306_t *dev = (pc87306_t *) priv; + uint8_t ret = 0xff, index; + + index = (port & 1) ? 0 : 1; + + dev->tries = 0; + + if (index) + ret = dev->cur_reg & 0x1f; + else { + if (dev->cur_reg == 8) + ret = 0x70; + else if (dev->cur_reg < 28) + ret = dev->regs[dev->cur_reg]; + } + + return ret; } -void pc87306_gpio_init() + +void +pc87306_reset(pc87306_t *dev) { - if ((pc87306_regs[0x12]) & 0x10) - { - io_sethandler(pc87306_regs[0xF] << 2, 0x0001, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); - } + memset(dev->regs, 0, 29); - if ((pc87306_regs[0x12]) & 0x20) - { - io_sethandler((pc87306_regs[0xF] << 2) + 1, 0x0001, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); - } + dev->regs[0x00] = 0x0B; + dev->regs[0x01] = 0x01; + dev->regs[0x03] = 0x01; + dev->regs[0x05] = 0x0D; + dev->regs[0x08] = 0x70; + dev->regs[0x09] = 0xC0; + dev->regs[0x0b] = 0x80; + dev->regs[0x0f] = 0x1E; + dev->regs[0x12] = 0x30; + dev->regs[0x19] = 0xEF; + + dev->gpio[0] = 0xff; + dev->gpio[1] = 0xfb; + + /* + 0 = 360 rpm @ 500 kbps for 3.5" + 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" + */ + lpt1_remove(); + lpt2_remove(); + lpt1_handler(dev); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + serial_handler(dev, 0); + serial_handler(dev, 0); + fdc_reset(dev->fdc); + pc87306_gpio_init(dev); } -void pc87306_reset(void) + +static void +pc87306_close(void *priv) { - memset(pc87306_regs, 0, 29); + pc87306_t *dev = (pc87306_t *) priv; - pc87306_regs[0] = 0x0B; - pc87306_regs[1] = 0x01; - pc87306_regs[3] = 0x01; - pc87306_regs[5] = 0x0D; - pc87306_regs[8] = 0x70; - pc87306_regs[9] = 0xC0; - pc87306_regs[0xB] = 0x80; - pc87306_regs[0xF] = 0x1E; - pc87306_regs[0x12] = 0x30; - pc87306_regs[0x19] = 0xEF; - /* - 0 = 360 rpm @ 500 kbps for 3.5" - 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" - */ - lpt1_remove(); - lpt2_remove(); - lpt1_handler(); - serial_remove(1); - serial_remove(2); - serial1_handler(); - serial2_handler(); - fdc_reset(pc87306_fdc); - pc87306_gpio_init(); + free(dev); } -void pc87306_init() + +static void * +pc87306_init(const device_t *info) { - pc87306_fdc = device_add(&fdc_at_nsc_device); + pc87306_t *dev = (pc87306_t *) malloc(sizeof(pc87306_t)); + memset(dev, 0, sizeof(pc87306_t)); - lpt2_remove(); + dev->fdc = device_add(&fdc_at_nsc_device); - pc87306_reset(); + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); - io_sethandler(0x02e, 0x0002, pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, NULL); + pc87306_reset(dev); + + io_sethandler(0x02e, 0x0002, + pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, dev); + + return dev; } + + +const device_t pc87306_device = { + "National Semiconductor PC87306 Super I/O", + 0, + 0, + pc87306_init, pc87306_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_um8669f.c b/src/sio_um8669f.c index fb991fede..42652c2fc 100644 --- a/src/sio_um8669f.c +++ b/src/sio_um8669f.c @@ -23,6 +23,7 @@ PnP registers : #include #include +#include #include #include #include "86box.h" @@ -36,30 +37,6 @@ PnP registers : #include "sio.h" -typedef struct um8669f_t -{ - int locked; - int cur_reg_108; - uint8_t regs_108[256]; - - int cur_reg; - int cur_device; - struct - { - int enable; - uint16_t addr; - int irq; - int dma; - } dev[8]; - - fdc_t *fdc; - int pnp_active; -} um8669f_t; - - -static um8669f_t um8669f_global; - - #define DEV_FDC 0 #define DEV_COM1 1 #define DEV_COM2 2 @@ -74,222 +51,268 @@ static um8669f_t um8669f_global; #define REG_DMA 0x74 -void um8669f_pnp_write(uint16_t port, uint8_t val, void *p) +typedef struct um8669f_t { - um8669f_t *um8669f = (um8669f_t *)p; + int locked, cur_reg_108, + cur_reg, cur_device, + pnp_active; - uint8_t valxor = 0; + uint8_t regs_108[256]; - if (port == 0x279) - um8669f->cur_reg = val; - else - { - if (um8669f->cur_reg == REG_DEVICE) - um8669f->cur_device = val & 7; - else - { - switch (um8669f->cur_reg) - { - case REG_ENABLE: - valxor = um8669f->dev[um8669f->cur_device].enable ^ val; - um8669f->dev[um8669f->cur_device].enable = val; - break; - case REG_ADDRLO: - valxor = (um8669f->dev[um8669f->cur_device].addr & 0xff) ^ val; - um8669f->dev[um8669f->cur_device].addr = (um8669f->dev[um8669f->cur_device].addr & 0xff00) | val; - break; - case REG_ADDRHI: - valxor = ((um8669f->dev[um8669f->cur_device].addr >> 8) & 0xff) ^ val; - um8669f->dev[um8669f->cur_device].addr = (um8669f->dev[um8669f->cur_device].addr & 0x00ff) | (val << 8); - break; - case REG_IRQ: - valxor = um8669f->dev[um8669f->cur_device].irq ^ val; - um8669f->dev[um8669f->cur_device].irq = val; - break; - case REG_DMA: - valxor = um8669f->dev[um8669f->cur_device].dma ^ val; - um8669f->dev[um8669f->cur_device].dma = val; - break; - default: + struct { + int enable; + uint16_t addr; + int irq; + int dma; + } dev[8]; + + fdc_t *fdc; + serial_t *uart[2]; +} um8669f_t; + + +static void +um8669f_pnp_write(uint16_t port, uint8_t val, void *priv) +{ + um8669f_t *dev = (um8669f_t *) priv; + + uint8_t valxor = 0; + + if (port == 0x279) + dev->cur_reg = val; + else { + if (dev->cur_reg == REG_DEVICE) + dev->cur_device = val & 7; + else { + switch (dev->cur_reg) { + case REG_ENABLE: + valxor = dev->dev[dev->cur_device].enable ^ val; + dev->dev[dev->cur_device].enable = val; + break; + case REG_ADDRLO: + valxor = (dev->dev[dev->cur_device].addr & 0xff) ^ val; + dev->dev[dev->cur_device].addr = (dev->dev[dev->cur_device].addr & 0xff00) | val; + break; + case REG_ADDRHI: + valxor = ((dev->dev[dev->cur_device].addr >> 8) & 0xff) ^ val; + dev->dev[dev->cur_device].addr = (dev->dev[dev->cur_device].addr & 0x00ff) | (val << 8); + break; + case REG_IRQ: + valxor = dev->dev[dev->cur_device].irq ^ val; + dev->dev[dev->cur_device].irq = val; + break; + case REG_DMA: + valxor = dev->dev[dev->cur_device].dma ^ val; + dev->dev[dev->cur_device].dma = val; + break; + default: valxor = 0; break; - } + } - switch (um8669f->cur_device) - { - case DEV_FDC: - if ((um8669f->cur_reg == REG_ENABLE) && valxor) - { - fdc_remove(um8669f_global.fdc); - if (um8669f->dev[DEV_FDC].enable & 1) - fdc_set_base(um8669f_global.fdc, 0x03f0); + switch (dev->cur_device) { + case DEV_FDC: + if ((dev->cur_reg == REG_ENABLE) && valxor) { + fdc_remove(dev->fdc); + if (dev->dev[DEV_FDC].enable & 1) + fdc_set_base(dev->fdc, 0x03f0); } - break; - case DEV_COM1: - if ((um8669f->cur_reg == REG_ENABLE) && valxor) - { - serial_remove(1); - if (um8669f->dev[DEV_COM1].enable & 1) - serial_setup(1, um8669f->dev[DEV_COM1].addr, um8669f->dev[DEV_COM1].irq); + break; + case DEV_COM1: + if ((dev->cur_reg == REG_ENABLE) && valxor) { + serial_remove(dev->uart[0]); + if (dev->dev[DEV_COM1].enable & 1) + serial_setup(dev->uart[0], dev->dev[DEV_COM1].addr, dev->dev[DEV_COM1].irq); } - break; - case DEV_COM2: - if ((um8669f->cur_reg == REG_ENABLE) && valxor) - { - serial_remove(2); - if (um8669f->dev[DEV_COM2].enable & 1) - serial_setup(2, um8669f->dev[DEV_COM2].addr, um8669f->dev[DEV_COM2].irq); + break; + case DEV_COM2: + if ((dev->cur_reg == REG_ENABLE) && valxor) { + serial_remove(dev->uart[1]); + if (dev->dev[DEV_COM2].enable & 1) + serial_setup(dev->uart[1], dev->dev[DEV_COM2].addr, dev->dev[DEV_COM2].irq); } - break; - case DEV_LPT1: - if ((um8669f->cur_reg == REG_ENABLE) && valxor) - { - lpt1_remove(); - if (um8669f->dev[DEV_LPT1].enable & 1) - lpt1_init(um8669f->dev[DEV_LPT1].addr); + break; + case DEV_LPT1: + if ((dev->cur_reg == REG_ENABLE) && valxor) { + lpt1_remove(); + if (dev->dev[DEV_LPT1].enable & 1) + lpt1_init(dev->dev[DEV_LPT1].addr); } - break; - } - } - } -} - - -uint8_t um8669f_pnp_read(uint16_t port, void *p) -{ - um8669f_t *um8669f = (um8669f_t *)p; - - switch (um8669f->cur_reg) - { - case REG_DEVICE: - return um8669f->cur_device; - case REG_ENABLE: - return um8669f->dev[um8669f->cur_device].enable; - case REG_ADDRLO: - return um8669f->dev[um8669f->cur_device].addr & 0xff; - case REG_ADDRHI: - return um8669f->dev[um8669f->cur_device].addr >> 8; - case REG_IRQ: - return um8669f->dev[um8669f->cur_device].irq; - case REG_DMA: - return um8669f->dev[um8669f->cur_device].dma; - } - - return 0xff; -} - - -void um8669f_write(uint16_t port, uint8_t val, void *p) -{ - um8669f_t *um8669f = (um8669f_t *)p; - int new_pnp_active; - - if (um8669f->locked) - { - if (port == 0x108 && val == 0xaa) - um8669f->locked = 0; - } - else - { - if (port == 0x108) - { - if (val == 0x55) - um8669f->locked = 1; - else - um8669f->cur_reg_108 = val; - } - else - { - um8669f->regs_108[um8669f->cur_reg_108] = val; - - if (um8669f->cur_reg_108 == 0xc1) { - new_pnp_active = !!(um8669f->regs_108[0xc1] & 0x80); - if (new_pnp_active != um8669f->pnp_active) { - if (new_pnp_active) { - io_sethandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); - io_sethandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); - io_sethandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, um8669f); - } else { - io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); - io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); - io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, um8669f); - } - um8669f->pnp_active = new_pnp_active; - } - } - } - } -} - - -uint8_t um8669f_read(uint16_t port, void *p) -{ - um8669f_t *um8669f = (um8669f_t *)p; - - if (um8669f->locked) - return 0xff; - - if (port == 0x108) - return um8669f->cur_reg_108; /*???*/ - else - return um8669f->regs_108[um8669f->cur_reg_108]; -} - - -void um8669f_reset(void) -{ - fdc_t *temp_fdc = um8669f_global.fdc; - - fdc_reset(um8669f_global.fdc); - - serial_remove(1); - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - - serial_remove(2); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); - - lpt2_remove(); - - lpt1_remove(); - lpt1_init(0x378); - - if (um8669f_global.pnp_active) { - io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, &um8669f_global); - io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, &um8669f_global); - io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, &um8669f_global); - um8669f_global.pnp_active = 0; + break; + } } - - memset(&um8669f_global, 0, sizeof(um8669f_t)); - - um8669f_global.fdc = temp_fdc; - - um8669f_global.locked = 1; - - um8669f_global.dev[DEV_FDC].enable = 1; - um8669f_global.dev[DEV_FDC].addr = 0x03f0; - um8669f_global.dev[DEV_FDC].irq = 6; - um8669f_global.dev[DEV_FDC].dma = 2; - - um8669f_global.dev[DEV_COM1].enable = 1; - um8669f_global.dev[DEV_COM1].addr = 0x03f8; - um8669f_global.dev[DEV_COM1].irq = 4; - - um8669f_global.dev[DEV_COM2].enable = 1; - um8669f_global.dev[DEV_COM2].addr = 0x02f8; - um8669f_global.dev[DEV_COM2].irq = 3; - - um8669f_global.dev[DEV_LPT1].enable = 1; - um8669f_global.dev[DEV_LPT1].addr = 0x0378; - um8669f_global.dev[DEV_LPT1].irq = 7; + } } -void um8669f_init(void) +static uint8_t +um8669f_pnp_read(uint16_t port, void *priv) { - um8669f_global.fdc = device_add(&fdc_at_device); + um8669f_t *dev = (um8669f_t *) priv; + uint8_t ret = 0xff; - io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, &um8669f_global); + switch (dev->cur_reg) { + case REG_DEVICE: + ret = dev->cur_device; + break; + case REG_ENABLE: + ret = dev->dev[dev->cur_device].enable; + break; + case REG_ADDRLO: + ret = dev->dev[dev->cur_device].addr & 0xff; + break; + case REG_ADDRHI: + ret = dev->dev[dev->cur_device].addr >> 8; + break; + case REG_IRQ: + ret = dev->dev[dev->cur_device].irq; + break; + case REG_DMA: + ret = dev->dev[dev->cur_device].dma; + break; + } - um8669f_reset(); + return ret; } + + +void um8669f_write(uint16_t port, uint8_t val, void *priv) +{ + um8669f_t *dev = (um8669f_t *) priv; + int new_pnp_active; + + if (dev->locked) { + if ((port == 0x108) && (val == 0xaa)) + dev->locked = 0; + } else { + if (port == 0x108) { + if (val == 0x55) + dev->locked = 1; + else + dev->cur_reg_108 = val; + } else { + dev->regs_108[dev->cur_reg_108] = val; + + if (dev->cur_reg_108 == 0xc1) { + new_pnp_active = !!(dev->regs_108[0xc1] & 0x80); + if (new_pnp_active != dev->pnp_active) { + if (new_pnp_active) { + io_sethandler(0x0279, 0x0001, + NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_sethandler(0x0a79, 0x0001, + NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_sethandler(0x03e3, 0x0001, + um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, dev); + } else { + io_removehandler(0x0279, 0x0001, + NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_removehandler(0x0a79, 0x0001, + NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_removehandler(0x03e3, 0x0001, + um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, dev); + } + dev->pnp_active = new_pnp_active; + } + } + } + } +} + + +uint8_t um8669f_read(uint16_t port, void *priv) +{ + um8669f_t *dev = (um8669f_t *) priv; + uint8_t ret = 0xff; + + if (!dev->locked) { + if (port == 0x108) + ret = dev->cur_reg_108; /* ??? */ + else + ret = dev->regs_108[dev->cur_reg_108]; + } + + return ret; +} + + +void +um8669f_reset(um8669f_t *dev) +{ + fdc_reset(dev->fdc); + + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + + lpt2_remove(); + + lpt1_remove(); + lpt1_init(0x378); + + if (dev->pnp_active) { + io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, dev); + dev->pnp_active = 0; + } + + dev->locked = 1; + + dev->dev[DEV_FDC].enable = 1; + dev->dev[DEV_FDC].addr = 0x03f0; + dev->dev[DEV_FDC].irq = 6; + dev->dev[DEV_FDC].dma = 2; + + dev->dev[DEV_COM1].enable = 1; + dev->dev[DEV_COM1].addr = 0x03f8; + dev->dev[DEV_COM1].irq = 4; + + dev->dev[DEV_COM2].enable = 1; + dev->dev[DEV_COM2].addr = 0x02f8; + dev->dev[DEV_COM2].irq = 3; + + dev->dev[DEV_LPT1].enable = 1; + dev->dev[DEV_LPT1].addr = 0x0378; + dev->dev[DEV_LPT1].irq = 7; +} + + +static void +um8669f_close(void *priv) +{ + um8669f_t *dev = (um8669f_t *) priv; + + free(dev); +} + + +static void * +um8669f_init(const device_t *info) +{ + um8669f_t *dev = (um8669f_t *) malloc(sizeof(um8669f_t)); + memset(dev, 0, sizeof(um8669f_t)); + + dev->fdc = device_add(&fdc_at_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + io_sethandler(0x0108, 0x0002, + um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, dev); + + um8669f_reset(dev); + + return dev; +} + + +const device_t um8669f_device = { + "UMC UM8669F Super I/O", + 0, + 0, + um8669f_init, um8669f_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_w83877f.c b/src/sio_w83877f.c index 1dd4a5d56..d14cef614 100644 --- a/src/sio_w83877f.c +++ b/src/sio_w83877f.c @@ -11,13 +11,14 @@ * Winbond W83877F Super I/O Chip * Used by the Award 430HX * - * Version: @(#)sio_w83877f.c 1.0.13 2018/10/02 + * Version: @(#)sio_w83877f.c 1.0.14 2018/11/05 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "86box.h" @@ -33,507 +34,401 @@ #include "sio.h" -static int w83877f_locked; -static int w83877f_rw_locked = 0; -static int w83877f_curreg = 0; -static uint8_t w83877f_regs[0x2A]; -static uint8_t tries; -static uint8_t w83877f_reg16init = 5; -static fdc_t *w83877f_fdc; +#define FDDA_TYPE (dev->regs[7] & 3) +#define FDDB_TYPE ((dev->regs[7] >> 2) & 3) +#define FDDC_TYPE ((dev->regs[7] >> 4) & 3) +#define FDDD_TYPE ((dev->regs[7] >> 6) & 3) -static int winbond_port = 0x3f0; -static int winbond_key = 0x89; -static int winbond_key_times = 1; +#define FD_BOOT (dev->regs[8] & 3) +#define SWWP ((dev->regs[8] >> 4) & 1) +#define DISFDDWR ((dev->regs[8] >> 5) & 1) + +#define EN3MODE ((dev->regs[9] >> 5) & 1) + +#define DRV2EN_NEG (dev->regs[0xB] & 1) /* 0 = drive 2 installed */ +#define INVERTZ ((dev->regs[0xB] >> 1) & 1) /* 0 = invert DENSEL polarity */ +#define IDENT ((dev->regs[0xB] >> 3) & 1) + +#define HEFERE ((dev->regs[0xC] >> 5) & 1) + +#define HEFRAS (dev->regs[0x16] & 1) -void w83877f_write(uint16_t port, uint8_t val, void *priv); -uint8_t w83877f_read(uint16_t port, void *priv); - -#define OCSS0 (w83877f_regs[0] & 1) -#define OCSS1 ((w83877f_regs[0] >> 1) & 1) -#define PRTMODS0 ((w83877f_regs[0] >> 2) & 1) -#define PRTMODS1 ((w83877f_regs[0] >> 3) & 1) - -#define ABCHG (w83877f_regs[1] >> 7) - -#define CEA (w83877f_regs[2] & 1) -#define EA3 ((w83877f_regs[2] >> 1) & 1) -#define EA4 ((w83877f_regs[2] >> 2) & 1) -#define EA5 ((w83877f_regs[2] >> 3) & 1) -#define EA6 ((w83877f_regs[2] >> 4) & 1) -#define EA7 ((w83877f_regs[2] >> 5) & 1) -#define EA8 ((w83877f_regs[2] >> 6) & 1) -#define EA9 (w83877f_regs[2] >> 7) - -#define SUBMIDI (w83877f_regs[3] & 1) -#define SUAMIDI ((w83877f_regs[3] >> 1) & 1) -#define GMODS ((w83877f_regs[3] >> 4) & 1) -#define EPPVER ((w83877f_regs[3] >> 5) & 1) -#define GMENL ((w83877f_regs[3] >> 6) & 1) - -#define URBTRI (w83877f_regs[4] & 1) -#define URATRI ((w83877f_regs[4] >> 1) & 1) -#define GMTRI ((w83877f_regs[4] >> 2) & 1) -#define PRTTRI ((w83877f_regs[4] >> 3) & 1) -#define URBPWD ((w83877f_regs[4] >> 4) & 1) -#define URAPWD ((w83877f_regs[4] >> 5) & 1) -#define GMPWD ((w83877f_regs[4] >> 6) & 1) -#define PRTPWD (w83877f_regs[4] >> 7) - -#define ECPFTHR0 (w83877f_regs[5] & 1) -#define ECPFTHR1 ((w83877f_regs[5] >> 1) & 1) -#define ECPFTHR2 ((w83877f_regs[5] >> 2) & 1) -#define ECPFTHR3 ((w83877f_regs[5] >> 3) & 1) - -#define IDETRI (w83877f_regs[6] & 1) -#define FDCTRI ((w83877f_regs[6] >> 1) & 1) -#define IDEPWD ((w83877f_regs[6] >> 2) & 1) -#define FDCPWD ((w83877f_regs[6] >> 3) & 1) -#define FIPURDWM ((w83877f_regs[6] >> 4) & 1) -#define SEL4FDD ((w83877f_regs[6] >> 5) & 1) -#define OSCS2 ((w83877f_regs[6] >> 6) & 1) - -#define FDDA_TYPE (w83877f_regs[7] & 3) -#define FDDB_TYPE ((w83877f_regs[7] >> 2) & 3) -#define FDDC_TYPE ((w83877f_regs[7] >> 4) & 3) -#define FDDD_TYPE ((w83877f_regs[7] >> 6) & 3) - -#define FD_BOOT (w83877f_regs[8] & 3) -#define MEDIA_ID ((w83877f_regs[8] >> 2) & 3) -#define SWWP ((w83877f_regs[8] >> 4) & 1) -#define DISFDDWR ((w83877f_regs[8] >> 5) & 1) -#define APDTMS2 ((w83877f_regs[8] >> 6) & 1) -#define APDTMS1 (w83877f_regs[8] >> 7) - -#define CHIP_ID (w83877f_regs[9] & 0xF) -#define EN3MODE ((w83877f_regs[9] >> 5) & 1) -#define LOCKREG ((w83877f_regs[9] >> 6) & 1) -#define PRTMODS2 ((w83877f_regs[9] >> 7) & 1) - -#define PEXTECPP (w83877f_regs[0xA] & 1) -#define PEXT_ECP ((w83877f_regs[0xA] >> 1) & 1) -#define PEXT_EPP ((w83877f_regs[0xA] >> 2) & 1) -#define PEXT_ADP ((w83877f_regs[0xA] >> 3) & 1) -#define PDCACT ((w83877f_regs[0xA] >> 4) & 1) -#define PDIRHOP ((w83877f_regs[0xA] >> 5) & 1) -#define PEXT_ACT ((w83877f_regs[0xA] >> 6) & 1) -#define PFDCACT (w83877f_regs[0xA] >> 7) - -#define DRV2EN_NEG (w83877f_regs[0xB] & 1) /* 0 = drive 2 installed */ -#define INVERTZ ((w83877f_regs[0xB] >> 1) & 1) /* 0 = invert DENSEL polarity */ -#define MFM ((w83877f_regs[0xB] >> 2) & 1) -#define IDENT ((w83877f_regs[0xB] >> 3) & 1) -#define ENIFCHG ((w83877f_regs[0xB] >> 4) & 1) - -#define TX2INV (w83877f_regs[0xC] & 1) -#define RX2INV ((w83877f_regs[0xC] >> 1) & 1) -#define URIRSEL ((w83877f_regs[0xC] >> 3) & 1) -#define HEFERE ((w83877f_regs[0xC] >> 5) & 1) -#define TURB ((w83877f_regs[0xC] >> 6) & 1) -#define TURA (w83877f_regs[0xC] >> 7) - -#define IRMODE0 (w83877f_regs[0xD] & 1) -#define IRMODE1 ((w83877f_regs[0xD] >> 1) & 1) -#define IRMODE2 ((w83877f_regs[0xD] >> 2) & 1) -#define HDUPLX ((w83877f_regs[0xD] >> 3) & 1) -#define SIRRX0 ((w83877f_regs[0xD] >> 4) & 1) -#define SIRRX1 ((w83877f_regs[0xD] >> 5) & 1) -#define SIRTX0 ((w83877f_regs[0xD] >> 6) & 1) -#define SIRTX1 (w83877f_regs[0xD] >> 7) - -#define GIO0AD (w83877f_regs[0x10] | (((uint16_t) w83877f_regs[0x11] & 7) << 8)) -#define GIO0CADM (w83877f_regs[0x11] >> 6) -#define GIO1AD (w83877f_regs[0x12] | (((uint16_t) w83877f_regs[0x13] & 7) << 8)) -#define GIO1CADM (w83877f_regs[0x13] >> 6) - -#define GDA0IPI (w83877f_regs[0x14] & 1) -#define GDA0OPI ((w83877f_regs[0x14] >> 1) & 1) -#define GCS0IOW ((w83877f_regs[0x14] >> 2) & 1) -#define GCS0IOR ((w83877f_regs[0x14] >> 3) & 1) -#define GIO0CSH ((w83877f_regs[0x14] >> 4) & 1) -#define GIOP0MD ((w83877f_regs[0x14] >> 5) & 7) - -#define GDA1IPI (w83877f_regs[0x15] & 1) -#define GDA1OPI ((w83877f_regs[0x15] >> 1) & 1) -#define GCS1IOW ((w83877f_regs[0x15] >> 2) & 1) -#define GCS1IOR ((w83877f_regs[0x15] >> 3) & 1) -#define GIO1CSH ((w83877f_regs[0x15] >> 4) & 1) -#define GIOP1MD ((w83877f_regs[0x15] >> 5) & 7) - -#define HEFRAS (w83877f_regs[0x16] & 1) -#define IRIDE ((w83877f_regs[0x16] >> 1) & 1) -#define PNPCVS ((w83877f_regs[0x16] >> 2) & 1) -#define GMDRQ ((w83877f_regs[0x16] >> 3) & 1) -#define GOIQSEL ((w83877f_regs[0x16] >> 4) & 1) - -#define DSUBLGRQ (w83877f_regs[0x17] & 1) -#define DSUALGRQ ((w83877f_regs[0x17] >> 1) & 1) -#define DSPRLGRQ ((w83877f_regs[0x17] >> 2) & 1) -#define DSFDLGRQ ((w83877f_regs[0x17] >> 3) & 1) -#define PRIRQOD ((w83877f_regs[0x17] >> 4) & 1) - -#define GMAS (w83877f_regs[0x1E] & 3) -#define GMAD (w83877f_regs[0x1E] & 0xFC) - -#define FDCAD ((w83877f_regs[0x20] & 0xFC) << 2) - -/* Main IDE base address. */ -#define IDE0AD ((w83877f_regs[0x21] & 0xFC) << 2) -/* IDE Alternate status base address. */ -#define IDE1AD ((w83877f_regs[0x22] & 0xFC) << 2) - -#define PRTAD (((uint16_t) w83877f_regs[0x23]) << 2) - -#define URAAD (((uint16_t) w83877f_regs[0x24] & 0xFE) << 2) -#define URBAD (((uint16_t) w83877f_regs[0x25] & 0xFE) << 2) - -#define PRTDQS (w83877f[regs[0x26] & 0xF) -#define FDCDQS (w83877f[regs[0x26] >> 4) - -#define PRTIQS (w83877f[regs[0x27] & 0xF) -#define ECPIRQx (w83877f[regs[0x27] >> 5) - -#define URBIQS (w83877f[regs[0x28] & 0xF) -#define URAIQS (w83877f[regs[0x28] >> 4) - -#define IQNIQS (w83877f[regs[0x29] & 0xF) -#define FDCIQS (w83877f[regs[0x29] >> 4) - -#define W83757 (!PRTMODS2 && !PRTMODS1 && !PRTMODS0) -#define EXTFDC (!PRTMODS2 && !PRTMODS1 && PRTMODS0) -#define EXTADP (!PRTMODS2 && PRTMODS1 && !PRTMODS0) -#define EXT2FDD (!PRTMODS2 && PRTMODS1 && PRTMODS0) -#define JOYSTICK (PRTMODS2 && !PRTMODS1 && !PRTMODS0) -#define EPP_SPP (PRTMODS2 && !PRTMODS1 && PRTMODS0) -#define ECP (PRTMODS2 && PRTMODS1 && !PRTMODS0) -#define ECP_EPP (PRTMODS2 && PRTMODS1 && PRTMODS0) - -static uint16_t fdc_valid_ports[2] = {0x3F0, 0x370}; -static uint16_t ide_valid_ports[2] = {0x1F0, 0x170}; -static uint16_t ide_as_valid_ports[2] = {0x3F6, 0x376}; -static uint16_t lpt1_valid_ports[3] = {0x3BC, 0x378, 0x278}; -static uint16_t com1_valid_ports[9] = {0x3F8, 0x2F8, 0x3E8, 0x2E8}; -static uint16_t com2_valid_ports[9] = {0x3F8, 0x2F8, 0x3E8, 0x2E8}; +typedef struct { + uint8_t tries, reg16_init, + regs[42]; + int locked, rw_locked, + cur_reg, + base_address, key, + key_times; + fdc_t *fdc; + serial_t *uart[2]; +} w83877f_t; -static void w83877f_remap(void) +static void w83877f_write(uint16_t port, uint8_t val, void *priv); +static uint8_t w83877f_read(uint16_t port, void *priv); + + +static void +w83877f_remap(w83877f_t *dev) { - io_removehandler(0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); - io_removehandler(0x3f0, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); - io_sethandler(HEFRAS ? 0x3f0 : 0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); - winbond_port = (HEFRAS ? 0x3f0 : 0x250); - winbond_key_times = HEFRAS + 1; - winbond_key = (HEFRAS ? 0x86 : 0x88) | HEFERE; + uint8_t hefras = HEFRAS; + + io_removehandler(0x250, 0x0002, + w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev); + io_removehandler(0x3f0, 0x0002, + w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev); + dev->base_address = (hefras ? 0x3f0 : 0x250); + io_sethandler(dev->base_address, 0x0002, + w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev); + dev->key_times = hefras + 1; + dev->key = (hefras ? 0x86 : 0x88) | HEFERE; } -static uint8_t is_in_array(uint16_t *port_array, uint8_t max, uint16_t port) +static uint8_t +get_lpt_length(w83877f_t *dev) { - uint8_t i = 0; + uint8_t length = 4; - for (i = 0; i < max; i++) - { - if (port_array[i] == port) return 1; - } - return 0; + if (dev->regs[9] & 0x80) { + if (dev->regs[0] & 0x04) + length = 8; /* EPP mode. */ + if (dev->regs[0] & 0x08) + length |= 0x80; /* ECP mode. */ + } + + return length; } -static uint16_t make_port(uint8_t reg) +static uint16_t +make_port(w83877f_t *dev, uint8_t reg) { - uint16_t p = 0; + uint16_t p = 0; + uint8_t l; - switch(reg) - { - case 0x20: - p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; - p &= 0xFF0; - if ((p < 0x100) || (p > 0x3F0)) p = 0x3F0; - if (!(is_in_array(fdc_valid_ports, 2, p))) p = 0x3F0; - w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); - break; - case 0x21: - p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; - p &= 0xFF0; - if ((p < 0x100) || (p > 0x3F0)) p = 0x1F0; - if (!(is_in_array(ide_valid_ports, 2, p))) p = 0x1F0; - w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); - break; - case 0x22: - p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; - p &= 0xFF0; - if ((p < 0x106) || (p > 0x3F6)) p = 0x3F6; - if (!(is_in_array(ide_as_valid_ports, 2, p))) p = 0x3F6; - w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); - break; - case 0x23: - p = ((uint16_t) (w83877f_regs[reg] & 0xff)) << 2; - p &= 0xFFC; - if ((p < 0x100) || (p > 0x3F8)) p = 0x378; - if (!(is_in_array(lpt1_valid_ports, 3, p))) p = 0x378; - w83877f_regs[reg] = (p >> 2); - break; - case 0x24: - p = ((uint16_t) (w83877f_regs[reg] & 0xfe)) << 2; - p &= 0xFF8; - if ((p < 0x100) || (p > 0x3F8)) p = 0x3F8; - if (!(is_in_array(com1_valid_ports, 9, p))) p = 0x3F8; - w83877f_regs[reg] = ((p >> 2) & 0xfe) | (w83877f_regs[reg] & 1); - break; - case 0x25: - p = ((uint16_t) (w83877f_regs[reg] & 0xfe)) << 2; - p &= 0xFF8; - if ((p < 0x100) || (p > 0x3F8)) p = 0x2F8; - if (!(is_in_array(com2_valid_ports, 9, p))) p = 0x2F8; - w83877f_regs[reg] = ((p >> 2) & 0xfe) | (w83877f_regs[reg] & 1); - break; - } - - return p; -} - - -void w83877f_serial_handler(int id) -{ - int reg_mask = (id - 1) ? 0x10 : 0x20; - int reg_id = (id - 1) ? 0x24 : 0x25; - int irq_mask = (id - 1) ? 0xF : 0xF0; - - if ((w83877f_regs[4] & reg_mask) || !(w83877f_regs[reg_id] & 0xc0)) - { - serial_remove(id); - } - else - { - serial_setup(id, make_port(reg_id), w83877f_regs[0x28] & irq_mask); - } -} - - -void w83877f_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t index = (port & 1) ? 0 : 1; - uint8_t valxor = 0; - uint8_t max = 0x2A; - - if (index) - { - if ((val == winbond_key) && !w83877f_locked) - { - if (winbond_key_times == 2) - { - if (tries) - { - w83877f_locked = 1; - tries = 0; - } - else - { - tries++; - } - } - else - { - w83877f_locked = 1; - tries = 0; - } - } + switch (reg) { + case 0x20: + p = ((uint16_t) (dev->regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x100) || (p > 0x3F0)) p = 0x3F0; + break; + case 0x23: + l = get_lpt_length(dev); + p = ((uint16_t) (dev->regs[reg] & 0xff)) << 2; + /* 8 ports in EPP mode, 4 in non-EPP mode. */ + if ((l & 0x0f) == 8) + p &= 0x3F8; else - { - if (w83877f_locked) - { - if (val < max) w83877f_curreg = val; - if (val == 0xaa) - { - w83877f_locked = 0; - } - } - else - { - if (tries) - tries = 0; - } + p &= 0x3FC; + if ((p < 0x100) || (p > 0x3FF)) p = 0x378; + /* In ECP mode, A10 is active. */ + if (l & 0x80) + p |= 0x400; + break; + case 0x24: + p = ((uint16_t) (dev->regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x3F8; + break; + case 0x25: + p = ((uint16_t) (dev->regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x2F8; + break; + } + + return p; +} + + +static void +w83877f_serial_handler(w83877f_t *dev, int uart) +{ + int reg_mask = uart ? 0x10 : 0x20; + int reg_id = uart ? 0x24 : 0x25; + int irq_mask = uart ? 0x0f : 0xf0; + int irq_shift = uart ? 4 : 0; + + if ((dev->regs[4] & reg_mask) || !(dev->regs[reg_id] & 0xc0)) + serial_remove(dev->uart[uart]); + else + serial_setup(dev->uart[uart], make_port(dev, reg_id), (dev->regs[0x28] & irq_mask) >> irq_shift); +} + + +static void +w83877f_write(uint16_t port, uint8_t val, void *priv) +{ + w83877f_t *dev = (w83877f_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + uint8_t max = 0x2A; + + if (index) { + if ((val == dev->key) && !dev->locked) { + if (dev->key_times == 2) { + if (dev->tries) { + dev->locked = 1; + dev->tries = 0; + } else + dev->tries++; + } else { + dev->locked = 1; + dev->tries = 0; } - } - else - { - if (w83877f_locked) - { - if (w83877f_rw_locked) return; - if ((w83877f_curreg >= 0x26) && (w83877f_curreg <= 0x27)) return; - if (w83877f_curreg == 0x29) return; - if (w83877f_curreg == 6) val &= 0xF3; - valxor = val ^ w83877f_regs[w83877f_curreg]; - w83877f_regs[w83877f_curreg] = val; - goto process_value; + } else { + if (dev->locked) { + if (val < max) + dev->cur_reg = val; + if (val == 0xaa) + dev->locked = 0; + } else { + if (dev->tries) + dev->tries = 0; } } return; + } else { + if (dev->locked) { + if (dev->rw_locked) + return; + if ((dev->cur_reg >= 0x26) && (dev->cur_reg <= 0x27)) + return; + if (dev->cur_reg == 0x29) + return; + if (dev->cur_reg == 6) + val &= 0xF3; + valxor = val ^ dev->regs[dev->cur_reg]; + dev->regs[dev->cur_reg] = val; + } else + return; + } -process_value: - switch(w83877f_curreg) - { - case 1: - if (valxor & 0x80) - { - fdc_set_swap(w83877f_fdc, (w83877f_regs[1] & 0x80) ? 1 : 0); - } - break; - case 4: - if (valxor & 0x10) - { - w83877f_serial_handler(2); - } - if (valxor & 0x20) - { - w83877f_serial_handler(1); - } - if (valxor & 0x80) - { - lpt1_remove(); - if (!(w83877f_regs[4] & 0x80)) lpt1_init(make_port(0x23)); - } - break; - case 6: - if (valxor & 0x08) - { - fdc_remove(w83877f_fdc); - if (!(w83877f_regs[6] & 0x08)) fdc_set_base(w83877f_fdc, 0x03f0); - } - break; - case 7: - if (valxor & 3) fdc_update_rwc(w83877f_fdc, 0, FDDA_TYPE); - if (valxor & 0xC) fdc_update_rwc(w83877f_fdc, 1, FDDB_TYPE); - if (valxor & 0x30) fdc_update_rwc(w83877f_fdc, 2, FDDC_TYPE); - if (valxor & 0xC0) fdc_update_rwc(w83877f_fdc, 3, FDDD_TYPE); - break; - case 8: - if (valxor & 3) fdc_update_boot_drive(w83877f_fdc, FD_BOOT); - if (valxor & 0x10) fdc_set_swwp(w83877f_fdc, SWWP ? 1 : 0); - if (valxor & 0x20) fdc_set_diswr(w83877f_fdc, DISFDDWR ? 1 : 0); - break; - case 9: - if (valxor & 0x20) - { - fdc_update_enh_mode(w83877f_fdc, EN3MODE ? 1 : 0); - } - if (valxor & 0x40) - { - w83877f_rw_locked = (val & 0x40) ? 1 : 0; - } - break; - case 0xB: - if (valxor & 1) fdc_update_drv2en(w83877f_fdc, DRV2EN_NEG ? 0 : 1); - if (valxor & 2) fdc_update_densel_polarity(w83877f_fdc, INVERTZ ? 1 : 0); - break; - case 0xC: - if (valxor & 0x20) w83877f_remap(); - break; - case 0x16: - if (valxor & 1) w83877f_remap(); - break; - case 0x23: - if (valxor) - { - lpt1_remove(); - if (!(w83877f_regs[4] & 0x80)) lpt1_init(make_port(0x23)); - } - break; - case 0x24: - if (valxor & 0xfe) - { - w83877f_serial_handler(1); - } - break; - case 0x25: - if (valxor & 0xfe) - { - w83877f_serial_handler(2); - } - break; - case 0x28: - if (valxor & 0xf) - { - if ((w83877f_regs[0x28] & 0xf) == 0) w83877f_regs[0x28] |= 0x3; - if (!(w83877f_regs[2] & 0x10)) serial_setup(2, make_port(0x25), w83877f_regs[0x28] & 0xF); - } - if (valxor & 0xf0) - { - if ((w83877f_regs[0x28] & 0xf0) == 0) w83877f_regs[0x28] |= 0x40; - if (!(w83877f_regs[4] & 0x20)) - { - serial_setup(1, make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); - } - } - break; - } + switch (dev->cur_reg) { + case 0: + if (valxor & 0xc0) { + lpt1_remove(); + if (!(dev->regs[4] & 0x80)) + lpt1_init(make_port(dev, 0x23)); + } + break; + case 1: + if (valxor & 0x80) + fdc_set_swap(dev->fdc, (dev->regs[1] & 0x80) ? 1 : 0); + break; + case 4: + if (valxor & 0x10) + w83877f_serial_handler(dev, 1); + if (valxor & 0x20) + w83877f_serial_handler(dev, 0); + if (valxor & 0x80) { + lpt1_remove(); + if (!(dev->regs[4] & 0x80)) + lpt1_init(make_port(dev, 0x23)); + } + break; + case 6: + if (valxor & 0x08) { + fdc_remove(dev->fdc); + if (!(dev->regs[6] & 0x08)) + fdc_set_base(dev->fdc, 0x03f0); + } + break; + case 7: + if (valxor & 0x03) + fdc_update_rwc(dev->fdc, 0, FDDA_TYPE); + if (valxor & 0x0c) + fdc_update_rwc(dev->fdc, 1, FDDB_TYPE); + if (valxor & 0x30) + fdc_update_rwc(dev->fdc, 2, FDDC_TYPE); + if (valxor & 0xc0) + fdc_update_rwc(dev->fdc, 3, FDDD_TYPE); + break; + case 8: + if (valxor & 0x03) + fdc_update_boot_drive(dev->fdc, FD_BOOT); + if (valxor & 0x10) + fdc_set_swwp(dev->fdc, SWWP ? 1 : 0); + if (valxor & 0x20) + fdc_set_diswr(dev->fdc, DISFDDWR ? 1 : 0); + break; + case 9: + if (valxor & 0x20) + fdc_update_enh_mode(dev->fdc, EN3MODE ? 1 : 0); + if (valxor & 0x40) + dev->rw_locked = (val & 0x40) ? 1 : 0; + if (valxor & 0x80) { + lpt1_remove(); + if (!(dev->regs[4] & 0x80)) + lpt1_init(make_port(dev, 0x23)); + } + break; + case 0xB: + if (valxor & 1) + fdc_update_drv2en(dev->fdc, DRV2EN_NEG ? 0 : 1); + if (valxor & 2) + fdc_update_densel_polarity(dev->fdc, INVERTZ ? 1 : 0); + break; + case 0xC: + if (valxor & 0x20) + w83877f_remap(dev); + break; + case 0x16: + if (valxor & 1) + w83877f_remap(dev); + break; + case 0x20: + if (valxor) { + fdc_remove(dev->fdc); + if (!(dev->regs[4] & 0x80)) + fdc_set_base(dev->fdc, make_port(dev, 0x20)); + } + break; + case 0x23: + if (valxor) { + lpt1_remove(); + if (!(dev->regs[4] & 0x80)) + lpt1_init(make_port(dev, 0x23)); + } + break; + case 0x24: + if (valxor & 0xfe) + w83877f_serial_handler(dev, 0); + break; + case 0x25: + if (valxor & 0xfe) + w83877f_serial_handler(dev, 1); + break; + case 0x28: + if (valxor & 0xf) { + if ((dev->regs[0x28] & 0x0f) == 0) + dev->regs[0x28] |= 0x03; + if (!(dev->regs[2] & 0x10)) + serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f); + } + if (valxor & 0xf0) { + if ((dev->regs[0x28] & 0xf0) == 0) + dev->regs[0x28] |= 0x40; + if (!(dev->regs[4] & 0x20)) + serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4); + } + break; + } } -uint8_t w83877f_read(uint16_t port, void *priv) +static uint8_t +w83877f_read(uint16_t port, void *priv) { - uint8_t index = (port & 1) ? 0 : 1; - - if (!w83877f_locked) - { - return 0xff; - } + w83877f_t *dev = (w83877f_t *) priv; + uint8_t ret = 0xff; + uint8_t index = (port & 1) ? 0 : 1; + if (dev->locked) { if (index) - { - return w83877f_curreg; - } - else - { - if ((w83877f_curreg < 0x18) && w83877f_rw_locked) return 0xff; - if (w83877f_curreg == 7) - return (fdc_get_rwc(w83877f_fdc, 0) | (fdc_get_rwc(w83877f_fdc, 1) << 2)); - return w83877f_regs[w83877f_curreg]; + ret = dev->cur_reg; + else { + if (dev->cur_reg == 7) + ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2)); + else if ((dev->cur_reg >= 0x18) || !dev->rw_locked) + ret = dev->regs[dev->cur_reg]; } + } + + return ret; } -void w83877f_reset(void) +static void +w83877f_reset(w83877f_t *dev) { - lpt1_remove(); - lpt1_init(0x378); + lpt2_remove(); - fdc_reset(w83877f_fdc); + lpt1_remove(); + lpt1_init(0x378); - memset(w83877f_regs, 0, 0x2A); - w83877f_regs[3] = 0x30; - w83877f_regs[7] = 0xF5; - w83877f_regs[9] = 0x0A; - w83877f_regs[0xA] = 0x1F; - w83877f_regs[0xC] = 0x28; - w83877f_regs[0xD] = 0xA3; - w83877f_regs[0x16] = w83877f_reg16init; - w83877f_regs[0x1E] = 0x81; - w83877f_regs[0x20] = (0x3f0 >> 2) & 0xfc; - w83877f_regs[0x21] = (0x1f0 >> 2) & 0xfc; - w83877f_regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; - w83877f_regs[0x23] = (0x378 >> 2); - w83877f_regs[0x24] = (0x3f8 >> 2) & 0xfe; - w83877f_regs[0x25] = (0x2f8 >> 2) & 0xfe; - w83877f_regs[0x26] = (2 << 4) | 4; - w83877f_regs[0x27] = (6 << 4) | 7; - w83877f_regs[0x28] = (4 << 4) | 3; - w83877f_regs[0x29] = 0x62; + fdc_reset(dev->fdc); - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); - w83877f_remap(); - w83877f_locked = 0; - w83877f_rw_locked = 0; + memset(dev->regs, 0, 0x2A); + dev->regs[0x03] = 0x30; + dev->regs[0x07] = 0xF5; + dev->regs[0x09] = 0x0A; + dev->regs[0x0a] = 0x1F; + dev->regs[0x0c] = 0x28; + dev->regs[0x0d] = 0xA3; + dev->regs[0x16] = dev->reg16_init; + dev->regs[0x1e] = 0x81; + dev->regs[0x20] = (0x3f0 >> 2) & 0xfc; + dev->regs[0x21] = (0x1f0 >> 2) & 0xfc; + dev->regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; + dev->regs[0x23] = (0x378 >> 2); + dev->regs[0x24] = (0x3f8 >> 2) & 0xfe; + dev->regs[0x25] = (0x2f8 >> 2) & 0xfe; + dev->regs[0x26] = (2 << 4) | 4; + dev->regs[0x27] = (6 << 4) | 7; + dev->regs[0x28] = (4 << 4) | 3; + dev->regs[0x29] = 0x62; + + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + + dev->base_address = 0x3f0; + dev->key = 0x89; + dev->key_times = 1; + + w83877f_remap(dev); + + dev->locked = 0; + dev->rw_locked = 0; } -void w83877f_init(uint8_t reg16init) +static void +w83877f_close(void *priv) { - w83877f_fdc = device_add(&fdc_at_winbond_device); + w83877f_t *dev = (w83877f_t *) priv; - lpt2_remove(); - - w83877f_reg16init = reg16init; - w83877f_reset(); + free(dev); } + + +static void * +w83877f_init(const device_t *info) +{ + w83877f_t *dev = (w83877f_t *) malloc(sizeof(w83877f_t)); + memset(dev, 0, sizeof(w83877f_t)); + + dev->fdc = device_add(&fdc_at_winbond_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + dev->reg16_init = info->local; + + w83877f_reset(dev); + + return dev; +} + + +const device_t w83877f_device = { + "Winbond W83877F Super I/O", + 0, + 5, + w83877f_init, w83877f_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t w83877f_president_device = { + "Winbond W83877F Super I/O (President)", + 0, + 4, + w83877f_init, w83877f_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 0e0f33052..86ef51bdb 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -8,7 +8,7 @@ * * Windows 86Box Settings dialog handler. * - * Version: @(#)win_settings.c 1.0.73 2018/10/30 + * Version: @(#)win_settings.c 1.0.74 2018/11/04 * * Authors: Miran Grca, * David Hrdlička, @@ -477,10 +477,8 @@ win_settings_save(void) /* Hard disks category */ memcpy(hdd, temp_hdd, HDD_NUM * sizeof(hard_disk_t)); - for (i = 0; i < HDD_NUM; i++) { - hdd[i].f = NULL; + for (i = 0; i < HDD_NUM; i++) hdd[i].priv = NULL; - } /* Floppy drives category */ for (i = 0; i < FDD_NUM; i++) {