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:
OBattler
2018-11-08 19:21:55 +01:00
parent 7b1a40164e
commit d386240fcb
34 changed files with 3590 additions and 2952 deletions

View File

@@ -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, <decwiz@yahoo.com>
*/
@@ -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; b<len; b++) mouse_serial_log(" %02X", buff[b]);
mouse_serial_log(" ] (%d)\n", len);
#endif
/* Send the packet to the bottom-half of the attached port. */
if (dev->serial != NULL) {
for (b=0; b<len; b++)
serial_write_fifo(dev->serial, 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
};