Removed unncessary files.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,404 +0,0 @@
|
|||||||
/*
|
|
||||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
||||||
* running old operating systems and software designed for IBM
|
|
||||||
* PC systems and compatibles from 1981 through fairly recent
|
|
||||||
* system designs based on the PCI bus.
|
|
||||||
*
|
|
||||||
* This file is part of the 86Box distribution.
|
|
||||||
*
|
|
||||||
* Implementation of PS/2 series Mouse devices.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
#define HAVE_STDARG_H
|
|
||||||
#include <86box/86box.h>
|
|
||||||
#include <86box/device.h>
|
|
||||||
#include <86box/keyboard.h>
|
|
||||||
#include <86box/mouse.h>
|
|
||||||
|
|
||||||
enum {
|
|
||||||
MODE_STREAM,
|
|
||||||
MODE_REMOTE,
|
|
||||||
MODE_ECHO
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char *name; /* name of this device */
|
|
||||||
int8_t type; /* type of this device */
|
|
||||||
|
|
||||||
int mode;
|
|
||||||
|
|
||||||
uint16_t flags;
|
|
||||||
uint8_t resolution;
|
|
||||||
uint8_t sample_rate;
|
|
||||||
|
|
||||||
uint8_t command;
|
|
||||||
|
|
||||||
int x, y, z, b;
|
|
||||||
|
|
||||||
uint8_t last_data[6];
|
|
||||||
} mouse_t;
|
|
||||||
#define FLAG_5BTN 0x100 /* using Intellimouse Optical mode */
|
|
||||||
#define FLAG_INTELLI 0x80 /* device is IntelliMouse */
|
|
||||||
#define FLAG_INTMODE 0x40 /* using Intellimouse mode */
|
|
||||||
#define FLAG_SCALED 0x20 /* enable delta scaling */
|
|
||||||
#define FLAG_ENABLED 0x10 /* dev is enabled for use */
|
|
||||||
#define FLAG_CTRLDAT 0x08 /* ctrl or data mode */
|
|
||||||
|
|
||||||
int mouse_scan = 0;
|
|
||||||
|
|
||||||
#ifdef ENABLE_MOUSE_PS2_LOG
|
|
||||||
int mouse_ps2_do_log = ENABLE_MOUSE_PS2_LOG;
|
|
||||||
|
|
||||||
static void
|
|
||||||
mouse_ps2_log(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
if (mouse_ps2_do_log) {
|
|
||||||
va_start(ap, fmt);
|
|
||||||
pclog_ex(fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
# define mouse_ps2_log(fmt, ...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
mouse_clear_data(void *priv)
|
|
||||||
{
|
|
||||||
mouse_t *dev = (mouse_t *) priv;
|
|
||||||
|
|
||||||
dev->flags &= ~FLAG_CTRLDAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ps2_report_coordinates(mouse_t *dev, int cmd)
|
|
||||||
{
|
|
||||||
uint8_t buff[3] = { 0x08, 0x00, 0x00 };
|
|
||||||
int temp_z;
|
|
||||||
|
|
||||||
if (dev->x > 255) {
|
|
||||||
dev->x = 255;
|
|
||||||
buff[0] |= 0x40;
|
|
||||||
}
|
|
||||||
if (dev->x < -256) {
|
|
||||||
dev->x = -256;
|
|
||||||
buff[0] |= 0x40;
|
|
||||||
}
|
|
||||||
if (dev->y > 255) {
|
|
||||||
dev->y = 255;
|
|
||||||
buff[0] |= 0x80;
|
|
||||||
}
|
|
||||||
if (dev->y < -256) {
|
|
||||||
dev->y = -256;
|
|
||||||
buff[0] |= 0x80;
|
|
||||||
}
|
|
||||||
if (dev->z < -8)
|
|
||||||
dev->z = -8;
|
|
||||||
if (dev->z > 7)
|
|
||||||
dev->z = 7;
|
|
||||||
|
|
||||||
if (dev->x < 0)
|
|
||||||
buff[0] |= 0x10;
|
|
||||||
if (dev->y < 0)
|
|
||||||
buff[0] |= 0x20;
|
|
||||||
if (mouse_buttons & 0x01)
|
|
||||||
buff[0] |= 0x01;
|
|
||||||
if (mouse_buttons & 0x02)
|
|
||||||
buff[0] |= 0x02;
|
|
||||||
if (dev->flags & FLAG_INTELLI) {
|
|
||||||
if (mouse_buttons & 0x04)
|
|
||||||
buff[0] |= 0x04;
|
|
||||||
}
|
|
||||||
buff[1] = (dev->x & 0xff);
|
|
||||||
buff[2] = (dev->y & 0xff);
|
|
||||||
|
|
||||||
if (cmd) {
|
|
||||||
keyboard_at_adddata_mouse_cmd(buff[0]);
|
|
||||||
keyboard_at_adddata_mouse_cmd(buff[1]);
|
|
||||||
keyboard_at_adddata_mouse_cmd(buff[2]);
|
|
||||||
} else {
|
|
||||||
keyboard_at_adddata_mouse(buff[0]);
|
|
||||||
keyboard_at_adddata_mouse(buff[1]);
|
|
||||||
keyboard_at_adddata_mouse(buff[2]);
|
|
||||||
}
|
|
||||||
if (dev->flags & FLAG_INTMODE) {
|
|
||||||
temp_z = dev->z & 0x0f;
|
|
||||||
if ((dev->flags & FLAG_5BTN)) {
|
|
||||||
if (mouse_buttons & 8)
|
|
||||||
temp_z |= 0x10;
|
|
||||||
if (mouse_buttons & 16)
|
|
||||||
temp_z |= 0x20;
|
|
||||||
} else {
|
|
||||||
/* The wheel coordinate is sign-extended. */
|
|
||||||
if (temp_z & 0x08)
|
|
||||||
temp_z |= 0xf0;
|
|
||||||
}
|
|
||||||
if (cmd)
|
|
||||||
keyboard_at_adddata_mouse_cmd(temp_z);
|
|
||||||
else
|
|
||||||
keyboard_at_adddata_mouse(temp_z);
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->x = dev->y = dev->z = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ps2_write(uint8_t val, void *priv)
|
|
||||||
{
|
|
||||||
mouse_t *dev = (mouse_t *) priv;
|
|
||||||
uint8_t temp;
|
|
||||||
|
|
||||||
if (dev->flags & FLAG_CTRLDAT) {
|
|
||||||
dev->flags &= ~FLAG_CTRLDAT;
|
|
||||||
|
|
||||||
if (val == 0xff)
|
|
||||||
goto mouse_reset;
|
|
||||||
|
|
||||||
switch (dev->command) {
|
|
||||||
case 0xe8: /* set mouse resolution */
|
|
||||||
dev->resolution = val;
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xf3: /* set sample rate */
|
|
||||||
dev->sample_rate = val;
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa); /* Command response */
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfc);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dev->command = val;
|
|
||||||
|
|
||||||
switch (dev->command) {
|
|
||||||
case 0xe6: /* set scaling to 1:1 */
|
|
||||||
dev->flags &= ~FLAG_SCALED;
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xe7: /* set scaling to 2:1 */
|
|
||||||
dev->flags |= FLAG_SCALED;
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xe8: /* set mouse resolution */
|
|
||||||
dev->flags |= FLAG_CTRLDAT;
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xe9: /* status request */
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
|
||||||
temp = (dev->flags & 0x30);
|
|
||||||
if (mouse_buttons & 1)
|
|
||||||
temp |= 4;
|
|
||||||
if (mouse_buttons & 2)
|
|
||||||
temp |= 1;
|
|
||||||
if ((mouse_buttons & 4) && (dev->flags & FLAG_INTELLI))
|
|
||||||
temp |= 2;
|
|
||||||
keyboard_at_adddata_mouse_cmd(temp);
|
|
||||||
keyboard_at_adddata_mouse_cmd(dev->resolution);
|
|
||||||
keyboard_at_adddata_mouse_cmd(dev->sample_rate);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xea: /* set stream */
|
|
||||||
dev->flags &= ~FLAG_CTRLDAT;
|
|
||||||
mouse_scan = 1;
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xeb: /* Get mouse data */
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
|
||||||
|
|
||||||
ps2_report_coordinates(dev, 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xf2: /* read ID */
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
|
||||||
if (dev->flags & FLAG_INTMODE)
|
|
||||||
keyboard_at_adddata_mouse_cmd((dev->flags & FLAG_5BTN) ? 0x04 : 0x03);
|
|
||||||
else
|
|
||||||
keyboard_at_adddata_mouse_cmd(0x00);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xf3: /* set command mode */
|
|
||||||
dev->flags |= FLAG_CTRLDAT;
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xf4: /* enable */
|
|
||||||
dev->flags |= FLAG_ENABLED;
|
|
||||||
mouse_scan = 1;
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xf5: /* disable */
|
|
||||||
dev->flags &= ~FLAG_ENABLED;
|
|
||||||
mouse_scan = 0;
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xf6: /* set defaults */
|
|
||||||
case 0xff: /* reset */
|
|
||||||
mouse_reset:
|
|
||||||
dev->mode = MODE_STREAM;
|
|
||||||
dev->flags &= 0x88;
|
|
||||||
mouse_scan = 1;
|
|
||||||
keyboard_at_mouse_reset();
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfa);
|
|
||||||
if (dev->command == 0xff) {
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xaa);
|
|
||||||
keyboard_at_adddata_mouse_cmd(0x00);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
keyboard_at_adddata_mouse_cmd(0xfe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev->flags & FLAG_INTELLI) {
|
|
||||||
for (temp = 0; temp < 5; temp++)
|
|
||||||
dev->last_data[temp] = dev->last_data[temp + 1];
|
|
||||||
|
|
||||||
dev->last_data[5] = val;
|
|
||||||
|
|
||||||
if ((dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) &&
|
|
||||||
(dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0x64) &&
|
|
||||||
(dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50))
|
|
||||||
dev->flags |= FLAG_INTMODE;
|
|
||||||
|
|
||||||
if ((dev->flags & FLAG_INTMODE) && (dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) &&
|
|
||||||
(dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0xc8) &&
|
|
||||||
(dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50))
|
|
||||||
dev->flags |= FLAG_5BTN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ps2_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv)
|
|
||||||
{
|
|
||||||
mouse_t *dev = (mouse_t *) priv;
|
|
||||||
|
|
||||||
if (!x && !y && !z && (b == dev->b))
|
|
||||||
return (0xff);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (!(dev->flags & FLAG_ENABLED))
|
|
||||||
return(0xff);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!mouse_scan)
|
|
||||||
return (0xff);
|
|
||||||
|
|
||||||
dev->x += x;
|
|
||||||
dev->y -= y;
|
|
||||||
dev->z -= z;
|
|
||||||
#if 0
|
|
||||||
if ((dev->mode == MODE_STREAM) && (dev->flags & FLAG_ENABLED) && (keyboard_at_mouse_pos() < 13)) {
|
|
||||||
#else
|
|
||||||
if ((dev->mode == MODE_STREAM) && (keyboard_at_mouse_pos() < 13)) {
|
|
||||||
#endif
|
|
||||||
dev->b = b;
|
|
||||||
|
|
||||||
ps2_report_coordinates(dev, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize the device for use by the user.
|
|
||||||
*
|
|
||||||
* We also get called from the various machines.
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
mouse_ps2_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;
|
|
||||||
dev->type = info->local;
|
|
||||||
|
|
||||||
dev->mode = MODE_STREAM;
|
|
||||||
i = device_get_config_int("buttons");
|
|
||||||
if (i > 2)
|
|
||||||
dev->flags |= FLAG_INTELLI;
|
|
||||||
|
|
||||||
if (i == 4)
|
|
||||||
i = 3;
|
|
||||||
|
|
||||||
/* Hook into the general AT Keyboard driver. */
|
|
||||||
keyboard_at_set_mouse(ps2_write, dev);
|
|
||||||
|
|
||||||
mouse_ps2_log("%s: buttons=%d\n", dev->name, i);
|
|
||||||
|
|
||||||
/* Tell them how many buttons we have. */
|
|
||||||
mouse_set_buttons(i);
|
|
||||||
|
|
||||||
/* Return our private data to the I/O layer. */
|
|
||||||
return (dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ps2_close(void *priv)
|
|
||||||
{
|
|
||||||
mouse_t *dev = (mouse_t *) priv;
|
|
||||||
|
|
||||||
/* Unhook from the general AT Keyboard driver. */
|
|
||||||
keyboard_at_set_mouse(NULL, NULL);
|
|
||||||
|
|
||||||
free(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const device_config_t ps2_config[] = {
|
|
||||||
// clang-format off
|
|
||||||
{
|
|
||||||
.name = "buttons",
|
|
||||||
.description = "Buttons",
|
|
||||||
.type = CONFIG_SELECTION,
|
|
||||||
.default_string = "",
|
|
||||||
.default_int = 2,
|
|
||||||
.file_filter = "",
|
|
||||||
.spinner = { 0 },
|
|
||||||
.selection = {
|
|
||||||
{ .description = "Two", .value = 2 },
|
|
||||||
{ .description = "Three", .value = 3 },
|
|
||||||
{ .description = "Wheel", .value = 4 },
|
|
||||||
{ .description = "Five + Wheel", .value = 5 },
|
|
||||||
{ .description = "" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "", .description = "", .type = CONFIG_END
|
|
||||||
}
|
|
||||||
// clang-format on
|
|
||||||
};
|
|
||||||
|
|
||||||
const device_t mouse_ps2_device = {
|
|
||||||
.name = "Standard PS/2 Mouse",
|
|
||||||
.internal_name = "ps2",
|
|
||||||
.flags = DEVICE_PS2,
|
|
||||||
.local = MOUSE_TYPE_PS2,
|
|
||||||
.init = mouse_ps2_init,
|
|
||||||
.close = ps2_close,
|
|
||||||
.reset = NULL,
|
|
||||||
{ .poll = ps2_poll },
|
|
||||||
.speed_changed = NULL,
|
|
||||||
.force_redraw = NULL,
|
|
||||||
.config = ps2_config
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,69 +0,0 @@
|
|||||||
diff --git a/src/86box.c b/src/86box.c
|
|
||||||
index a14f51c41..3c96d88a4 100644
|
|
||||||
--- a/src/86box.c
|
|
||||||
+++ b/src/86box.c
|
|
||||||
@@ -1263,9 +1263,9 @@ pc_run(void)
|
|
||||||
startblit();
|
|
||||||
cpu_exec(cpu_s->rspeed / 100);
|
|
||||||
#ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */
|
|
||||||
- if (gdbstub_step == GDBSTUB_EXEC)
|
|
||||||
+ // if (gdbstub_step == GDBSTUB_EXEC)
|
|
||||||
#endif
|
|
||||||
- mouse_process();
|
|
||||||
+ // mouse_process();
|
|
||||||
joystick_process();
|
|
||||||
endblit();
|
|
||||||
|
|
||||||
diff --git a/src/device/mouse.c b/src/device/mouse.c
|
|
||||||
index 7eb6a08a9..329397d43 100644
|
|
||||||
--- a/src/device/mouse.c
|
|
||||||
+++ b/src/device/mouse.c
|
|
||||||
@@ -27,6 +27,8 @@
|
|
||||||
#define HAVE_STDARG_H
|
|
||||||
#include <86box/86box.h>
|
|
||||||
#include <86box/device.h>
|
|
||||||
+#include <86box/timer.h>
|
|
||||||
+#include <86box/gdbstub.h>
|
|
||||||
#include <86box/mouse.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
@@ -45,6 +47,8 @@ int mouse_x,
|
|
||||||
double mouse_x_abs,
|
|
||||||
mouse_y_abs;
|
|
||||||
|
|
||||||
+pc_timer_t mouse_timer; /* mouse event timer */
|
|
||||||
+
|
|
||||||
static const device_t mouse_none_device = {
|
|
||||||
.name = "None",
|
|
||||||
.internal_name = "none",
|
|
||||||
@@ -141,6 +145,20 @@ mouse_close(void)
|
|
||||||
mouse_priv = NULL;
|
|
||||||
mouse_nbut = 0;
|
|
||||||
mouse_dev_poll = NULL;
|
|
||||||
+
|
|
||||||
+ timer_stop(&mouse_timer);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+mouse_timer_poll(void *priv)
|
|
||||||
+{
|
|
||||||
+ // timer_on_auto(&mouse_timer, 1388.0 + (8.0 / 9.0));
|
|
||||||
+ timer_on_auto(&mouse_timer, 277.0 + (7.0 / 9.0));
|
|
||||||
+
|
|
||||||
+#ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */
|
|
||||||
+ if (gdbstub_step == GDBSTUB_EXEC)
|
|
||||||
+#endif
|
|
||||||
+ mouse_process();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
@@ -165,6 +183,9 @@ mouse_reset(void)
|
|
||||||
|
|
||||||
if (mouse_curr != NULL)
|
|
||||||
mouse_priv = device_add(mouse_curr);
|
|
||||||
+
|
|
||||||
+ timer_add(&mouse_timer, mouse_timer_poll, NULL, 0);
|
|
||||||
+ timer_on_auto(&mouse_timer, 10000.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Callback from the hardware driver. */
|
|
@@ -1,838 +0,0 @@
|
|||||||
/*
|
|
||||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
||||||
* running old operating systems and software designed for IBM
|
|
||||||
* PC systems and compatibles from 1981 through fairly recent
|
|
||||||
* system designs based on the PCI bus.
|
|
||||||
*
|
|
||||||
* This file is part of the 86Box distribution.
|
|
||||||
*
|
|
||||||
* Implementation of the Intel PIC chip emulation, partially
|
|
||||||
* ported from reenigne's XTCE.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Authors: Andrew Jenner, <https://www.reenigne.org>
|
|
||||||
* Miran Grca, <mgrca8@gmail.com>
|
|
||||||
*
|
|
||||||
* Copyright 2015-2020 Andrew Jenner.
|
|
||||||
* Copyright 2016-2020 Miran Grca.
|
|
||||||
*/
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
|
|
||||||
#define HAVE_STDARG_H
|
|
||||||
#include <86box/86box.h>
|
|
||||||
#include "cpu.h"
|
|
||||||
#include <86box/machine.h>
|
|
||||||
#include <86box/io.h>
|
|
||||||
#include <86box/pci.h>
|
|
||||||
#include <86box/pic.h>
|
|
||||||
#include <86box/timer.h>
|
|
||||||
#include <86box/pit.h>
|
|
||||||
#include <86box/device.h>
|
|
||||||
#include <86box/apm.h>
|
|
||||||
#include <86box/nvr.h>
|
|
||||||
#include <86box/acpi.h>
|
|
||||||
|
|
||||||
enum {
|
|
||||||
STATE_NONE = 0,
|
|
||||||
STATE_ICW2,
|
|
||||||
STATE_ICW3,
|
|
||||||
STATE_ICW4
|
|
||||||
};
|
|
||||||
|
|
||||||
pic_t pic, pic2;
|
|
||||||
|
|
||||||
static pc_timer_t pic_timer;
|
|
||||||
|
|
||||||
static int shadow = 0, elcr_enabled = 0,
|
|
||||||
tmr_inited = 0, latched = 0,
|
|
||||||
pic_pci = 0, kbd_latch = 0,
|
|
||||||
mouse_latch = 0;
|
|
||||||
|
|
||||||
static uint16_t smi_irq_mask = 0x0000,
|
|
||||||
smi_irq_status = 0x0000;
|
|
||||||
|
|
||||||
static uint16_t latched_irqs = 0x0000;
|
|
||||||
|
|
||||||
static void (*update_pending)(void);
|
|
||||||
|
|
||||||
#ifdef ENABLE_PIC_LOG
|
|
||||||
int pic_do_log = ENABLE_PIC_LOG;
|
|
||||||
|
|
||||||
static void
|
|
||||||
pic_log(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
if (pic_do_log) {
|
|
||||||
va_start(ap, fmt);
|
|
||||||
pclog_ex(fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
# define pic_log(fmt, ...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_reset_smi_irq_mask(void)
|
|
||||||
{
|
|
||||||
smi_irq_mask = 0x0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_set_smi_irq_mask(int irq, int set)
|
|
||||||
{
|
|
||||||
if ((irq >= 0) && (irq <= 15)) {
|
|
||||||
if (set)
|
|
||||||
smi_irq_mask |= (1 << irq);
|
|
||||||
else
|
|
||||||
smi_irq_mask &= ~(1 << irq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t
|
|
||||||
pic_get_smi_irq_status(void)
|
|
||||||
{
|
|
||||||
return smi_irq_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_clear_smi_irq_status(int irq)
|
|
||||||
{
|
|
||||||
if ((irq >= 0) && (irq <= 15))
|
|
||||||
smi_irq_status &= ~(1 << irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_elcr_write(uint16_t port, uint8_t val, void *priv)
|
|
||||||
{
|
|
||||||
pic_t *dev = (pic_t *) priv;
|
|
||||||
|
|
||||||
pic_log("ELCR%i: WRITE %02X\n", port & 1, val);
|
|
||||||
|
|
||||||
if (port & 1)
|
|
||||||
val &= 0xde;
|
|
||||||
else
|
|
||||||
val &= 0xf8;
|
|
||||||
|
|
||||||
dev->elcr = val;
|
|
||||||
|
|
||||||
pic_log("ELCR %i: %c %c %c %c %c %c %c %c\n",
|
|
||||||
port & 1,
|
|
||||||
(val & 1) ? 'L' : 'E',
|
|
||||||
(val & 2) ? 'L' : 'E',
|
|
||||||
(val & 4) ? 'L' : 'E',
|
|
||||||
(val & 8) ? 'L' : 'E',
|
|
||||||
(val & 0x10) ? 'L' : 'E',
|
|
||||||
(val & 0x20) ? 'L' : 'E',
|
|
||||||
(val & 0x40) ? 'L' : 'E',
|
|
||||||
(val & 0x80) ? 'L' : 'E');
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
pic_elcr_read(uint16_t port, void *priv)
|
|
||||||
{
|
|
||||||
pic_t *dev = (pic_t *) priv;
|
|
||||||
|
|
||||||
pic_log("ELCR%i: READ %02X\n", port & 1, dev->elcr);
|
|
||||||
|
|
||||||
return dev->elcr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
pic_elcr_get_enabled(void)
|
|
||||||
{
|
|
||||||
return elcr_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_elcr_set_enabled(int enabled)
|
|
||||||
{
|
|
||||||
elcr_enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_elcr_io_handler(int set)
|
|
||||||
{
|
|
||||||
io_handler(set, 0x04d0, 0x0001,
|
|
||||||
pic_elcr_read, NULL, NULL,
|
|
||||||
pic_elcr_write, NULL, NULL, &pic);
|
|
||||||
io_handler(set, 0x04d1, 0x0001,
|
|
||||||
pic_elcr_read, NULL, NULL,
|
|
||||||
pic_elcr_write, NULL, NULL, &pic2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t
|
|
||||||
pic_cascade_mode(pic_t *dev)
|
|
||||||
{
|
|
||||||
return !(dev->icw1 & 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline uint8_t
|
|
||||||
pic_slave_on(pic_t *dev, int channel)
|
|
||||||
{
|
|
||||||
pic_log("pic_slave_on(%i): %i, %02X, %02X\n", channel, pic_cascade_mode(dev), dev->icw4 & 0x0c, dev->icw3 & (1 << channel));
|
|
||||||
|
|
||||||
return pic_cascade_mode(dev) && (dev->is_master || ((dev->icw4 & 0x0c) == 0x0c)) && (dev->icw3 & (1 << channel));
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline int
|
|
||||||
find_best_interrupt(pic_t *dev)
|
|
||||||
{
|
|
||||||
uint8_t b;
|
|
||||||
uint8_t intr;
|
|
||||||
int i, j;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
j = (i + dev->priority) & 7;
|
|
||||||
b = 1 << j;
|
|
||||||
|
|
||||||
if (dev->isr & b)
|
|
||||||
break;
|
|
||||||
else if ((dev->state == 0) && ((dev->irr & ~dev->imr) & b)) {
|
|
||||||
ret = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
intr = dev->interrupt = (ret == -1) ? 0x17 : ret;
|
|
||||||
|
|
||||||
if (dev->at && (ret != -1)) {
|
|
||||||
if (dev == &pic2)
|
|
||||||
intr += 8;
|
|
||||||
|
|
||||||
if (cpu_fast_off_flags & (1u << intr))
|
|
||||||
cpu_fast_off_advance();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline void
|
|
||||||
pic_update_pending_xt(void)
|
|
||||||
{
|
|
||||||
if (find_best_interrupt(&pic) != -1) {
|
|
||||||
latched++;
|
|
||||||
if (latched == 1)
|
|
||||||
timer_on_auto(&pic_timer, 0.35);
|
|
||||||
} else if (latched == 0)
|
|
||||||
pic.int_pending = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline void
|
|
||||||
pic_update_pending_at(void)
|
|
||||||
{
|
|
||||||
pic2.int_pending = (find_best_interrupt(&pic2) != -1);
|
|
||||||
|
|
||||||
if (pic2.int_pending)
|
|
||||||
pic.irr |= (1 << pic2.icw3);
|
|
||||||
else
|
|
||||||
pic.irr &= ~(1 << pic2.icw3);
|
|
||||||
|
|
||||||
pic.int_pending = (find_best_interrupt(&pic) != -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pic_callback(void *priv)
|
|
||||||
{
|
|
||||||
pic_t *dev = (pic_t *) priv;
|
|
||||||
|
|
||||||
dev->int_pending = 1;
|
|
||||||
|
|
||||||
latched--;
|
|
||||||
if (latched > 0)
|
|
||||||
timer_on_auto(&pic_timer, 0.35);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_reset(void)
|
|
||||||
{
|
|
||||||
int is_at = IS_AT(machine);
|
|
||||||
is_at = is_at || !strcmp(machine_get_internal_name(), "xi8088");
|
|
||||||
|
|
||||||
memset(&pic, 0, sizeof(pic_t));
|
|
||||||
memset(&pic2, 0, sizeof(pic_t));
|
|
||||||
|
|
||||||
pic.is_master = 1;
|
|
||||||
pic.interrupt = pic2.interrupt = 0x17;
|
|
||||||
|
|
||||||
if (is_at)
|
|
||||||
pic.slaves[2] = &pic2;
|
|
||||||
|
|
||||||
if (tmr_inited)
|
|
||||||
timer_on_auto(&pic_timer, 0.0);
|
|
||||||
memset(&pic_timer, 0x00, sizeof(pc_timer_t));
|
|
||||||
timer_add(&pic_timer, pic_callback, &pic, 0);
|
|
||||||
tmr_inited = 1;
|
|
||||||
|
|
||||||
update_pending = is_at ? pic_update_pending_at : pic_update_pending_xt;
|
|
||||||
pic.at = pic2.at = is_at;
|
|
||||||
|
|
||||||
smi_irq_mask = smi_irq_status = 0x0000;
|
|
||||||
|
|
||||||
shadow = 0;
|
|
||||||
pic_pci = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_set_shadow(int sh)
|
|
||||||
{
|
|
||||||
shadow = sh;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
pic_get_pci_flag(void)
|
|
||||||
{
|
|
||||||
return pic_pci;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_set_pci_flag(int pci)
|
|
||||||
{
|
|
||||||
pic_pci = pci;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t
|
|
||||||
pic_level_triggered(pic_t *dev, int irq)
|
|
||||||
{
|
|
||||||
if (elcr_enabled)
|
|
||||||
return !!(dev->elcr & (1 << irq));
|
|
||||||
else
|
|
||||||
return !!(dev->icw1 & 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
picint_is_level(int irq)
|
|
||||||
{
|
|
||||||
return pic_level_triggered(((irq > 7) ? &pic2 : &pic), irq & 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pic_acknowledge(pic_t *dev)
|
|
||||||
{
|
|
||||||
int pic_int = dev->interrupt & 7;
|
|
||||||
int pic_int_num = 1 << pic_int;
|
|
||||||
|
|
||||||
dev->isr |= pic_int_num;
|
|
||||||
if (!pic_level_triggered(dev, pic_int) || !(dev->lines & pic_int_num))
|
|
||||||
dev->irr &= ~pic_int_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find IRQ for non-specific EOI (either by command or automatic) by finding the highest IRQ
|
|
||||||
priority with ISR bit set, that is also not masked if the PIC is in special mask mode. */
|
|
||||||
static uint8_t
|
|
||||||
pic_non_specific_find(pic_t *dev)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
uint8_t b, irq = 0xff;
|
|
||||||
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
j = (i + dev->priority) & 7;
|
|
||||||
b = (1 << j);
|
|
||||||
|
|
||||||
if ((dev->isr & b) && (!dev->special_mask_mode || !(dev->imr & b))) {
|
|
||||||
irq = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do the EOI and rotation, if either is requested, on the given IRQ. */
|
|
||||||
static void
|
|
||||||
pic_action(pic_t *dev, uint8_t irq, uint8_t eoi, uint8_t rotate)
|
|
||||||
{
|
|
||||||
uint8_t b = (1 << irq);
|
|
||||||
|
|
||||||
if (irq != 0xff) {
|
|
||||||
if (eoi)
|
|
||||||
dev->isr &= ~b;
|
|
||||||
if (rotate)
|
|
||||||
dev->priority = (irq + 1) & 7;
|
|
||||||
|
|
||||||
update_pending();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Automatic non-specific EOI. */
|
|
||||||
static __inline void
|
|
||||||
pic_auto_non_specific_eoi(pic_t *dev)
|
|
||||||
{
|
|
||||||
uint8_t irq;
|
|
||||||
|
|
||||||
if (dev->icw4 & 2) {
|
|
||||||
irq = pic_non_specific_find(dev);
|
|
||||||
|
|
||||||
pic_action(dev, irq, 1, dev->auto_eoi_rotate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do the PIC command specified by bits 7-5 of the value written to the OCW2 register. */
|
|
||||||
static void
|
|
||||||
pic_command(pic_t *dev)
|
|
||||||
{
|
|
||||||
uint8_t irq = 0xff;
|
|
||||||
|
|
||||||
if (dev->ocw2 & 0x60) { /* SL and/or EOI set */
|
|
||||||
if (dev->ocw2 & 0x40) /* SL set, specific priority level */
|
|
||||||
irq = (dev->ocw2 & 0x07);
|
|
||||||
else /* SL clear, non-specific priority level (find highest with ISR set) */
|
|
||||||
irq = pic_non_specific_find(dev);
|
|
||||||
|
|
||||||
pic_action(dev, irq, dev->ocw2 & 0x20, dev->ocw2 & 0x80);
|
|
||||||
} else /* SL and EOI clear */
|
|
||||||
dev->auto_eoi_rotate = !!(dev->ocw2 & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
pic_latch_read(uint16_t addr, void *priv)
|
|
||||||
{
|
|
||||||
uint8_t ret = 0xff;
|
|
||||||
|
|
||||||
pic_log("pic_latch_read(%i, %i): %02X%02X\n", kbd_latch, mouse_latch, pic2.lines & 0x10, pic.lines & 0x02);
|
|
||||||
|
|
||||||
if (kbd_latch && (latched_irqs & 0x0002))
|
|
||||||
picintc(0x0002);
|
|
||||||
|
|
||||||
if (mouse_latch && (latched_irqs & 0x1000))
|
|
||||||
picintc(0x1000);
|
|
||||||
|
|
||||||
/* Return FF - we just lower IRQ 1 and IRQ 12. */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
pic_read(uint16_t addr, void *priv)
|
|
||||||
{
|
|
||||||
pic_t *dev = (pic_t *) priv;
|
|
||||||
|
|
||||||
if (shadow) {
|
|
||||||
/* VIA PIC shadow read */
|
|
||||||
if (addr & 0x0001)
|
|
||||||
dev->data_bus = ((dev->icw2 & 0xf8) >> 3) << 0;
|
|
||||||
else {
|
|
||||||
dev->data_bus = ((dev->ocw3 & 0x20) >> 5) << 4;
|
|
||||||
dev->data_bus |= ((dev->ocw2 & 0x80) >> 7) << 3;
|
|
||||||
dev->data_bus |= ((dev->icw4 & 0x10) >> 4) << 2;
|
|
||||||
dev->data_bus |= ((dev->icw4 & 0x02) >> 1) << 1;
|
|
||||||
dev->data_bus |= ((dev->icw4 & 0x08) >> 3) << 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Standard 8259 PIC read */
|
|
||||||
#ifndef UNDEFINED_READ
|
|
||||||
/* Put the IRR on to the data bus by default until the real PIC is probed. */
|
|
||||||
dev->data_bus = dev->irr;
|
|
||||||
#endif
|
|
||||||
if (dev->ocw3 & 0x04) {
|
|
||||||
dev->interrupt &= ~0x20; /* Freeze the interrupt until the poll is over. */
|
|
||||||
if (dev->int_pending) {
|
|
||||||
dev->data_bus = 0x80 | (dev->interrupt & 7);
|
|
||||||
pic_acknowledge(dev);
|
|
||||||
dev->int_pending = 0;
|
|
||||||
update_pending();
|
|
||||||
} else
|
|
||||||
dev->data_bus = 0x00;
|
|
||||||
dev->ocw3 &= ~0x04;
|
|
||||||
} else if (addr & 0x0001)
|
|
||||||
dev->data_bus = dev->imr;
|
|
||||||
else if (dev->ocw3 & 0x02) {
|
|
||||||
if (dev->ocw3 & 0x01)
|
|
||||||
dev->data_bus = dev->isr;
|
|
||||||
#ifdef UNDEFINED_READ
|
|
||||||
else
|
|
||||||
dev->data_bus = 0x00;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/* If A0 = 0, VIA shadow is disabled, and poll mode is disabled,
|
|
||||||
simply read whatever is currently on the data bus. */
|
|
||||||
}
|
|
||||||
|
|
||||||
pic_log("pic_read(%04X, %08X) = %02X\n", addr, priv, dev->data_bus);
|
|
||||||
|
|
||||||
return dev->data_bus;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pic_write(uint16_t addr, uint8_t val, void *priv)
|
|
||||||
{
|
|
||||||
pic_t *dev = (pic_t *) priv;
|
|
||||||
|
|
||||||
pic_log("pic_write(%04X, %02X, %08X)\n", addr, val, priv);
|
|
||||||
|
|
||||||
dev->data_bus = val;
|
|
||||||
|
|
||||||
if (addr & 0x0001) {
|
|
||||||
switch (dev->state) {
|
|
||||||
case STATE_ICW2:
|
|
||||||
dev->icw2 = val;
|
|
||||||
if (pic_cascade_mode(dev))
|
|
||||||
dev->state = STATE_ICW3;
|
|
||||||
else
|
|
||||||
dev->state = (dev->icw1 & 1) ? STATE_ICW4 : STATE_NONE;
|
|
||||||
break;
|
|
||||||
case STATE_ICW3:
|
|
||||||
dev->icw3 = val;
|
|
||||||
dev->state = (dev->icw1 & 1) ? STATE_ICW4 : STATE_NONE;
|
|
||||||
break;
|
|
||||||
case STATE_ICW4:
|
|
||||||
dev->icw4 = val;
|
|
||||||
dev->state = STATE_NONE;
|
|
||||||
break;
|
|
||||||
case STATE_NONE:
|
|
||||||
dev->imr = val;
|
|
||||||
update_pending();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (val & 0x10) {
|
|
||||||
/* Treat any write with any of the bits 7 to 5 set as invalid if PCI. */
|
|
||||||
if (pic_pci && (val & 0xe0))
|
|
||||||
return;
|
|
||||||
|
|
||||||
dev->icw1 = val;
|
|
||||||
dev->icw2 = dev->icw3 = 0x00;
|
|
||||||
if (!(dev->icw1 & 1))
|
|
||||||
dev->icw4 = 0x00;
|
|
||||||
dev->ocw2 = dev->ocw3 = 0x00;
|
|
||||||
dev->irr = dev->lines;
|
|
||||||
dev->imr = dev->isr = 0x00;
|
|
||||||
dev->ack_bytes = dev->priority = 0x00;
|
|
||||||
dev->auto_eoi_rotate = dev->special_mask_mode = 0x00;
|
|
||||||
dev->interrupt = 0x17;
|
|
||||||
dev->int_pending = 0x00;
|
|
||||||
dev->state = STATE_ICW2;
|
|
||||||
update_pending();
|
|
||||||
} else if (val & 0x08) {
|
|
||||||
dev->ocw3 = val;
|
|
||||||
if (dev->ocw3 & 0x04)
|
|
||||||
dev->interrupt |= 0x20; /* Freeze the interrupt until the poll is over. */
|
|
||||||
if (dev->ocw3 & 0x40)
|
|
||||||
dev->special_mask_mode = !!(dev->ocw3 & 0x20);
|
|
||||||
} else {
|
|
||||||
dev->ocw2 = val;
|
|
||||||
pic_command(dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_set_pci(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0x0024; i < 0x0040; i += 4) {
|
|
||||||
io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
|
|
||||||
io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0x1120; i < 0x1140; i += 4) {
|
|
||||||
io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
|
|
||||||
io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_kbd_latch(int enable)
|
|
||||||
{
|
|
||||||
pic_log("PIC keyboard latch now %sabled\n", enable ? "en" : "dis");
|
|
||||||
|
|
||||||
if (!!(enable | mouse_latch) != !!(kbd_latch | mouse_latch))
|
|
||||||
io_handler(!!(enable | mouse_latch), 0x0060, 0x0001, pic_latch_read, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
kbd_latch = !!enable;
|
|
||||||
|
|
||||||
if (!enable)
|
|
||||||
picintc(0x0002);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_mouse_latch(int enable)
|
|
||||||
{
|
|
||||||
pic_log("PIC mouse latch now %sabled\n", enable ? "en" : "dis");
|
|
||||||
|
|
||||||
if (!!(kbd_latch | enable) != !!(kbd_latch | mouse_latch))
|
|
||||||
io_handler(!!(kbd_latch | enable), 0x0060, 0x0001, pic_latch_read, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
mouse_latch = !!enable;
|
|
||||||
|
|
||||||
if (!enable)
|
|
||||||
picintc(0x1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pic_reset_hard(void)
|
|
||||||
{
|
|
||||||
pic_reset();
|
|
||||||
|
|
||||||
/* Explicitly reset the latches. */
|
|
||||||
kbd_latch = mouse_latch = 0;
|
|
||||||
|
|
||||||
/* The situation is as follows: There is a giant mess when it comes to these latches on real hardware,
|
|
||||||
to the point that there's even boards with board-level latched that get used in place of the latches
|
|
||||||
on the chipset, therefore, I'm just doing this here for the sake of simplicity. */
|
|
||||||
if (machine_has_bus(machine, MACHINE_BUS_PS2)) {
|
|
||||||
pic_kbd_latch(0x01);
|
|
||||||
pic_mouse_latch(0x01);
|
|
||||||
} else {
|
|
||||||
pic_kbd_latch(0x00);
|
|
||||||
pic_mouse_latch(0x00);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_init(void)
|
|
||||||
{
|
|
||||||
pic_reset_hard();
|
|
||||||
|
|
||||||
shadow = 0;
|
|
||||||
io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic_init_pcjr(void)
|
|
||||||
{
|
|
||||||
pic_reset_hard();
|
|
||||||
|
|
||||||
shadow = 0;
|
|
||||||
io_sethandler(0x0020, 0x0008, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pic2_init(void)
|
|
||||||
{
|
|
||||||
io_sethandler(0x00a0, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2);
|
|
||||||
pic.slaves[2] = &pic2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
picint_common(uint16_t num, int level, int set)
|
|
||||||
{
|
|
||||||
int i, raise;
|
|
||||||
uint8_t b, slaves = 0;
|
|
||||||
|
|
||||||
/* Make sure to ignore all slave IRQ's, and in case of AT+,
|
|
||||||
translate IRQ 2 to IRQ 9. */
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
b = (1 << i);
|
|
||||||
raise = num & b;
|
|
||||||
|
|
||||||
if (pic.icw3 & b) {
|
|
||||||
slaves++;
|
|
||||||
|
|
||||||
if (raise) {
|
|
||||||
num &= ~b;
|
|
||||||
if (pic.at && (i == 2))
|
|
||||||
num |= (1 << 9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!slaves)
|
|
||||||
num &= 0x00ff;
|
|
||||||
|
|
||||||
if (!num) {
|
|
||||||
pic_log("Attempting to %s null IRQ\n", set ? "raise" : "lower");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num & 0x0100)
|
|
||||||
acpi_rtc_status = !!set;
|
|
||||||
|
|
||||||
if (set) {
|
|
||||||
if (smi_irq_mask & num) {
|
|
||||||
smi_raise();
|
|
||||||
smi_irq_status |= num;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num & 0xff00) {
|
|
||||||
if (level)
|
|
||||||
pic2.lines |= (num >> 8);
|
|
||||||
|
|
||||||
/* Latch IRQ 12 if the mouse latch is enabled. */
|
|
||||||
if ((num & 0x1000) && mouse_latch)
|
|
||||||
latched_irqs |= 0x1000;
|
|
||||||
|
|
||||||
pic2.irr |= (num >> 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num & 0x00ff) {
|
|
||||||
if (level)
|
|
||||||
pic.lines |= (num & 0x00ff);
|
|
||||||
|
|
||||||
/* Latch IRQ 1 if the keyboard latch is enabled. */
|
|
||||||
if (kbd_latch && (num & 0x0002))
|
|
||||||
latched_irqs |= 0x0002;
|
|
||||||
|
|
||||||
pic.irr |= (num & 0x00ff);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
smi_irq_status &= ~num;
|
|
||||||
|
|
||||||
if (num & 0xff00) {
|
|
||||||
pic2.lines &= ~(num >> 8);
|
|
||||||
|
|
||||||
/* Unlatch IRQ 12 if the mouse latch is enabled. */
|
|
||||||
if ((num & 0x1000) && mouse_latch)
|
|
||||||
latched_irqs &= 0xefff;
|
|
||||||
|
|
||||||
pic2.irr &= ~(num >> 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num & 0x00ff) {
|
|
||||||
pic.lines &= ~(num & 0x00ff);
|
|
||||||
|
|
||||||
/* Unlatch IRQ 1 if the keyboard latch is enabled. */
|
|
||||||
if (kbd_latch && (num & 0x0002))
|
|
||||||
latched_irqs &= 0xfffd;
|
|
||||||
|
|
||||||
pic.irr &= ~(num & 0x00ff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pic.interrupt & 0x20) && !(pic2.interrupt & 0x20))
|
|
||||||
update_pending();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
picint(uint16_t num)
|
|
||||||
{
|
|
||||||
picint_common(num, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
picintlevel(uint16_t num)
|
|
||||||
{
|
|
||||||
picint_common(num, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
picintc(uint16_t num)
|
|
||||||
{
|
|
||||||
picint_common(num, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t
|
|
||||||
pic_i86_mode(pic_t *dev)
|
|
||||||
{
|
|
||||||
return !!(dev->icw4 & 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t
|
|
||||||
pic_irq_ack_read(pic_t *dev, int phase)
|
|
||||||
{
|
|
||||||
uint8_t intr = dev->interrupt & 0x47;
|
|
||||||
uint8_t slave = intr & 0x40;
|
|
||||||
intr &= 0x07;
|
|
||||||
pic_log(" pic_irq_ack_read(%08X, %i)\n", dev, phase);
|
|
||||||
|
|
||||||
if (dev != NULL) {
|
|
||||||
if (phase == 0) {
|
|
||||||
dev->interrupt |= 0x20; /* Freeze it so it still takes interrupts but they do not
|
|
||||||
override the one currently being processed. */
|
|
||||||
pic_acknowledge(dev);
|
|
||||||
if (slave)
|
|
||||||
dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
|
|
||||||
else
|
|
||||||
dev->data_bus = pic_i86_mode(dev) ? 0xff : 0xcd;
|
|
||||||
} else if (pic_i86_mode(dev)) {
|
|
||||||
dev->int_pending = 0;
|
|
||||||
if (slave)
|
|
||||||
dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
|
|
||||||
else
|
|
||||||
dev->data_bus = intr + (dev->icw2 & 0xf8);
|
|
||||||
pic_auto_non_specific_eoi(dev);
|
|
||||||
} else if (phase == 1) {
|
|
||||||
if (slave)
|
|
||||||
dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
|
|
||||||
else if (dev->icw1 & 0x04)
|
|
||||||
dev->data_bus = (intr << 2) + (dev->icw1 & 0xe0);
|
|
||||||
else
|
|
||||||
dev->data_bus = (intr << 3) + (dev->icw1 & 0xc0);
|
|
||||||
} else if (phase == 2) {
|
|
||||||
dev->int_pending = 0;
|
|
||||||
if (slave)
|
|
||||||
dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
|
|
||||||
else
|
|
||||||
dev->data_bus = dev->icw2;
|
|
||||||
pic_auto_non_specific_eoi(dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dev->data_bus;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
pic_irq_ack(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Needed for Xi8088. */
|
|
||||||
if ((pic.ack_bytes == 0) && pic.int_pending && pic_slave_on(&pic, pic.interrupt)) {
|
|
||||||
if (!pic.slaves[pic.interrupt]->int_pending) {
|
|
||||||
/* If we are on AT, IRQ 2 is pending, and we cannot find a pending IRQ on PIC 2, fatal out. */
|
|
||||||
fatal("IRQ %i pending on AT without a pending IRQ on PIC %i (normal)\n", pic.interrupt, pic.interrupt);
|
|
||||||
exit(-1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pic.interrupt |= 0x40; /* Mark slave pending. */
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = pic_irq_ack_read(&pic, pic.ack_bytes);
|
|
||||||
pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3);
|
|
||||||
|
|
||||||
if (pic.ack_bytes == 0) {
|
|
||||||
/* Needed for Xi8088. */
|
|
||||||
if (pic.interrupt & 0x40)
|
|
||||||
pic2.interrupt = 0x17;
|
|
||||||
pic.interrupt = 0x17;
|
|
||||||
update_pending();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
picinterrupt(void)
|
|
||||||
{
|
|
||||||
int i, ret = -1;
|
|
||||||
|
|
||||||
if (pic.int_pending) {
|
|
||||||
if (pic_slave_on(&pic, pic.interrupt)) {
|
|
||||||
if (!pic.slaves[pic.interrupt]->int_pending) {
|
|
||||||
/* If we are on AT, IRQ 2 is pending, and we cannot find a pending IRQ on PIC 2, fatal out. */
|
|
||||||
fatal("IRQ %i pending on AT without a pending IRQ on PIC %i (normal)\n", pic.interrupt, pic.interrupt);
|
|
||||||
exit(-1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pic.interrupt |= 0x40; /* Mark slave pending. */
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((pic.interrupt == 0) && (pit_devs[1].data != NULL))
|
|
||||||
pit_devs[1].set_gate(pit_devs[1].data, 0, 0);
|
|
||||||
|
|
||||||
/* Two ACK's - do them in a loop to avoid potential compiler misoptimizations. */
|
|
||||||
for (i = 0; i < 2; i++) {
|
|
||||||
ret = pic_irq_ack_read(&pic, pic.ack_bytes);
|
|
||||||
pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3);
|
|
||||||
|
|
||||||
if (pic.ack_bytes == 0) {
|
|
||||||
if (pic.interrupt & 0x40)
|
|
||||||
pic2.interrupt = 0x17;
|
|
||||||
pic.interrupt = 0x17;
|
|
||||||
update_pending();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
Reference in New Issue
Block a user