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.
This commit is contained in:
@@ -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, <mgrca8@gmail.com>
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user