summaryrefslogtreecommitdiffstats
path: root/board/MAI/bios_emulator/scitech/src/pm/linux
diff options
context:
space:
mode:
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/pm/linux')
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/cpuinfo.c68
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/event.c1361
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/event.svga1058
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/oshdr.h61
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/pm.c1810
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/vflat.c49
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/ztimer.c95
7 files changed, 4502 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/linux/cpuinfo.c
new file mode 100644
index 0000000000..e88d210954
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/cpuinfo.c
@@ -0,0 +1,68 @@
+/****************************************************************************
+*
+* Ultra Long Period Timer
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Linux
+*
+* Description: Linux specific code for the CPU detection module.
+*
+****************************************************************************/
+
+#include <ztimer.h>
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+TODO: We should implement this for Linux!
+****************************************************************************/
+#define SetMaxThreadPriority() 0
+
+/****************************************************************************
+REMARKS:
+TODO: We should implement this for Linux!
+****************************************************************************/
+#define RestoreThreadPriority(i)
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ freq->low = 1000000;
+ freq->high = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ struct timeval tv; \
+ gettimeofday(&tv,NULL); \
+ (t)->low = tv.tv_sec*1000000 + tv.tv_usec; \
+ (t)->high = 0; \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/event.c b/board/MAI/bios_emulator/scitech/src/pm/linux/event.c
new file mode 100644
index 0000000000..c2668ceb88
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/event.c
@@ -0,0 +1,1361 @@
+/****************************************************************************
+*
+* SciTech Multi-platform Graphics Library
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Linux
+*
+* Description: Linux fullscreen console implementation for the SciTech
+* cross platform event library.
+* Portions ripped straigth from the gpm source code for mouse
+* handling.
+*
+****************************************************************************/
+
+/*---------------------------- Global Variables ---------------------------*/
+
+extern int _PM_console_fd;
+static ushort keyUpMsg[256] = {0};
+static int _EVT_mouse_fd = 0;
+static int range_x, range_y;
+static int opt_baud = 1200, opt_sample = 100;
+#ifdef USE_OS_JOYSTICK
+static short *axis0 = NULL, *axis1 = NULL;
+static uchar *buts0 = NULL, *buts1 = NULL;
+static int joystick0_fd = 0, joystick1_fd = 0;
+static int js_version = 0;
+#endif
+
+/* This defines the supported mouse drivers */
+
+typedef enum {
+ EVT_noMouse = -1,
+ EVT_microsoft = 0,
+ EVT_ps2,
+ EVT_mousesystems,
+ EVT_gpm,
+ EVT_MMseries,
+ EVT_logitech,
+ EVT_busmouse,
+ EVT_mouseman,
+ EVT_intellimouse,
+ EVT_intellimouse_ps2,
+ } mouse_drivers_t;
+
+static mouse_drivers_t mouse_driver = EVT_noMouse;
+static char mouse_dev[20] = "/dev/mouse";
+
+typedef struct {
+ char *name;
+ int flags;
+ void (*init)(void);
+ uchar proto[4];
+ int packet_len;
+ int read;
+ } mouse_info;
+
+#define STD_FLG (CREAD | CLOCAL | HUPCL)
+
+static void _EVT_mouse_init(void);
+static void _EVT_logitech_init(void);
+static void _EVT_pnpmouse_init(void);
+
+mouse_info mouse_infos[] = {
+ {"Microsoft", CS7 | B1200 | STD_FLG, _EVT_mouse_init, {0x40, 0x40, 0x40, 0x00}, 3, 1},
+ {"PS2", STD_FLG, NULL, {0xc0, 0x00, 0x00, 0x00}, 3, 1},
+ {"MouseSystems", CS8 | CSTOPB | STD_FLG, _EVT_mouse_init, {0xf8, 0x80, 0x00, 0x00}, 5, 5},
+ {"GPM", CS8 | CSTOPB | STD_FLG, NULL, {0xf8, 0x80, 0x00, 0x00}, 5, 5},
+ {"MMSeries", CS8 | PARENB | PARODD | STD_FLG, _EVT_mouse_init, {0xe0, 0x80, 0x80, 0x00}, 3, 1},
+ {"Logitech", CS8 | CSTOPB | STD_FLG, _EVT_logitech_init, {0xe0, 0x80, 0x80, 0x00}, 3, 3},
+ {"BusMouse", STD_FLG, NULL, {0xf8, 0x80, 0x00, 0x00}, 3, 3},
+ {"MouseMan", CS7 | STD_FLG, _EVT_mouse_init, {0x40, 0x40, 0x40, 0x00}, 3, 1},
+ {"IntelliMouse", CS7 | STD_FLG, _EVT_pnpmouse_init, {0xc0, 0x40, 0xc0, 0x00}, 4, 1},
+ {"IMPS2", CS7 | STD_FLG, NULL, {0xc0, 0x40, 0xc0, 0x00}, 4, 1}, // ?
+ };
+
+#define NB_MICE (sizeof(mouse_infos)/sizeof(mouse_info))
+
+/* The name of the environment variables that are used to change the defaults above */
+
+#define ENV_MOUSEDRV "MGL_MOUSEDRV"
+#define ENV_MOUSEDEV "MGL_MOUSEDEV"
+#define ENV_MOUSESPD "MGL_MOUSESPD"
+#define ENV_JOYDEV0 "MGL_JOYDEV1"
+#define ENV_JOYDEV1 "MGL_JOYDEV2"
+
+/* Scancode mappings on Linux for special keys */
+
+typedef struct {
+ int scan;
+ int map;
+ } keymap;
+
+// TODO: Fix this and set it up so we can do a binary search!
+
+keymap keymaps[] = {
+ {96, KB_padEnter},
+ {74, KB_padMinus},
+ {78, KB_padPlus},
+ {55, KB_padTimes},
+ {98, KB_padDivide},
+ {71, KB_padHome},
+ {72, KB_padUp},
+ {73, KB_padPageUp},
+ {75, KB_padLeft},
+ {76, KB_padCenter},
+ {77, KB_padRight},
+ {79, KB_padEnd},
+ {80, KB_padDown},
+ {81, KB_padPageDown},
+ {82, KB_padInsert},
+ {83, KB_padDelete},
+ {105,KB_left},
+ {108,KB_down},
+ {106,KB_right},
+ {103,KB_up},
+ {110,KB_insert},
+ {102,KB_home},
+ {104,KB_pageUp},
+ {111,KB_delete},
+ {107,KB_end},
+ {109,KB_pageDown},
+ {125,KB_leftWindows},
+ {126,KB_rightWindows},
+ {127,KB_menu},
+ {100,KB_rightAlt},
+ {97,KB_rightCtrl},
+ };
+
+/* And the keypad with num lock turned on (changes the ASCII code only) */
+
+keymap keypad[] = {
+ {71, ASCII_7},
+ {72, ASCII_8},
+ {73, ASCII_9},
+ {75, ASCII_4},
+ {76, ASCII_5},
+ {77, ASCII_6},
+ {79, ASCII_1},
+ {80, ASCII_2},
+ {81, ASCII_3},
+ {82, ASCII_0},
+ {83, ASCII_period},
+ };
+
+#define NB_KEYMAPS (sizeof(keymaps)/sizeof(keymaps[0]))
+#define NB_KEYPAD (sizeof(keypad)/sizeof(keypad[0]))
+
+typedef struct {
+ int sample;
+ char code[2];
+ } sample_rate;
+
+sample_rate sampletab[]={
+ { 0,"O"},
+ { 15,"J"},
+ { 27,"K"},
+ { 42,"L"},
+ { 60,"R"},
+ { 85,"M"},
+ {125,"Q"},
+ {1E9,"N"},
+ };
+
+/* Number of keycodes to read at a time from the console */
+
+#define KBDREADBUFFERSIZE 32
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* These are not used under Linux */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flaps)
+
+/****************************************************************************
+PARAMETERS:
+scanCode - Scan code to test
+
+REMARKS:
+This macro determines if a specified key is currently down at the
+time that the call is made.
+****************************************************************************/
+#define _EVT_isKeyDown(scanCode) (keyUpMsg[scanCode] != 0)
+
+/****************************************************************************
+REMARKS:
+This function is used to return the number of ticks since system
+startup in milliseconds. This should be the same value that is placed into
+the time stamp fields of events, and is used to implement auto mouse down
+events.
+****************************************************************************/
+ulong _EVT_getTicks(void)
+{
+ static uint starttime = 0;
+ struct timeval t;
+
+ gettimeofday(&t, NULL);
+ if (starttime == 0)
+ starttime = t.tv_sec * 1000 + (t.tv_usec/1000);
+ return ((t.tv_sec * 1000 + (t.tv_usec/1000)) - starttime);
+}
+
+/****************************************************************************
+REMARKS:
+Small Unix function that checks for availability on a file using select()
+****************************************************************************/
+static ibool dataReady(
+ int fd)
+{
+ static struct timeval t = { 0L, 0L };
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ return select(fd+1, &fds, NULL, NULL, &t) > 0;
+}
+
+/****************************************************************************
+REMARKS:
+Reads mouse data according to the selected mouse driver.
+****************************************************************************/
+static ibool readMouseData(
+ int *buttons,
+ int *dx,
+ int *dy)
+{
+ static uchar data[32],prev = 0;
+ int cnt = 0,ret;
+ mouse_info *drv;
+
+ /* Read the first byte to check for the protocol */
+ drv = &mouse_infos[mouse_driver];
+ if (read(_EVT_mouse_fd, data, drv->read) != drv->read) {
+ perror("read");
+ return false;
+ }
+ if ((data[0] & drv->proto[0]) != drv->proto[1])
+ return false;
+
+ /* Load a whole protocol packet */
+ cnt += drv->read;
+ while (cnt < drv->packet_len) {
+ ret = read(_EVT_mouse_fd, data+cnt, drv->read);
+ if (ret == drv->read)
+ cnt += ret;
+ else {
+ perror("read");
+ return false;
+ }
+ }
+ if ((data[1] & drv->proto[2]) != drv->proto[3])
+ return false;
+
+ /* Now decode the protocol packet */
+ switch (mouse_driver) {
+ case EVT_microsoft:
+ if (data[0] == 0x40 && !(prev|data[1]|data[2]))
+ *buttons = 2; /* Third button on MS compatible mouse */
+ else
+ *buttons= ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4);
+ prev = *buttons;
+ *dx = (char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
+ *dy = (char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
+ break;
+ case EVT_ps2:
+ *buttons = !!(data[0]&1) * 4 + !!(data[0]&2) * 1 + !!(data[0]&4) * 2;
+ if (data[1] != 0)
+ *dx = (data[0] & 0x10) ? data[1]-256 : data[1];
+ else
+ *dx = 0;
+ if (data[2] != 0)
+ *dy = -((data[0] & 0x20) ? data[2]-256 : data[2]);
+ else
+ *dy = 0;
+ break;
+ case EVT_mousesystems: case EVT_gpm:
+ *buttons = (~data[0]) & 0x07;
+ *dx = (char)(data[1]) + (char)(data[3]);
+ *dy = -((char)(data[2]) + (char)(data[4]));
+ break;
+ case EVT_logitech:
+ *buttons= data[0] & 0x07;
+ *dx = (data[0] & 0x10) ? data[1] : - data[1];
+ *dy = (data[0] & 0x08) ? - data[2] : data[2];
+ break;
+ case EVT_busmouse:
+ *buttons= (~data[0]) & 0x07;
+ *dx = (char)data[1];
+ *dy = -(char)data[2];
+ break;
+ case EVT_MMseries:
+ *buttons = data[0] & 0x07;
+ *dx = (data[0] & 0x10) ? data[1] : - data[1];
+ *dy = (data[0] & 0x08) ? - data[2] : data[2];
+ break;
+ case EVT_intellimouse:
+ *buttons = ((data[0] & 0x20) >> 3) /* left */
+ | ((data[3] & 0x10) >> 3) /* middle */
+ | ((data[0] & 0x10) >> 4); /* right */
+ *dx = (char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
+ *dy = (char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
+ break;
+ case EVT_intellimouse_ps2:
+ *buttons = (data[0] & 0x04) >> 1 /* Middle */
+ | (data[0] & 0x02) >> 1 /* Right */
+ | (data[0] & 0x01) << 2; /* Left */
+ *dx = (data[0] & 0x10) ? data[1]-256 : data[1];
+ *dy = (data[0] & 0x20) ? -(data[2]-256) : -data[2];
+ break;
+ case EVT_mouseman: {
+ static int getextra;
+ static uchar prev=0;
+ uchar b;
+
+ /* The damned MouseMan has 3/4 bytes packets. The extra byte
+ * is only there if the middle button is active.
+ * I get the extra byte as a packet with magic numbers in it.
+ * and then switch to 4-byte mode.
+ */
+ if (data[1] == 0xAA && data[2] == 0x55) {
+ /* Got unexpected fourth byte */
+ if ((b = (*data>>4)) > 0x3)
+ return false; /* just a sanity check */
+ *dx = *dy = 0;
+ drv->packet_len=4;
+ getextra=0;
+ }
+ else {
+ /* Got 3/4, as expected */
+ /* Motion is independent of packetlen... */
+ *dx = (char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
+ *dy = (char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
+ prev = ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4);
+ if (drv->packet_len==4)
+ b = data[3]>>4;
+ }
+ if (drv->packet_len == 4) {
+ if (b == 0) {
+ drv->packet_len = 3;
+ getextra = 1;
+ }
+ else {
+ if (b & 0x2)
+ prev |= 2;
+ }
+ }
+ *buttons = prev;
+
+ /* This "chord-middle" behaviour was reported by David A. van Leeuwen */
+ if (((prev ^ *buttons) & 5) == 5)
+ *buttons = *buttons ? 2 : 0;
+ prev = *buttons;
+ break;
+ }
+ case EVT_noMouse:
+ return false;
+ break;
+ }
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Map a keypress via the key mapping table
+****************************************************************************/
+static int getKeyMapping(
+ keymap *tab,
+ int nb,
+ int key)
+{
+ int i;
+
+ for(i = 0; i < nb; i++) {
+ if (tab[i].scan == key)
+ return tab[i].map;
+ }
+ return key;
+}
+
+#ifdef USE_OS_JOYSTICK
+
+static char js0_axes = 0, js0_buttons = 0;
+static char js1_axes = 0, js1_buttons = 0;
+static char joystick0_dev[20] = "/dev/js0";
+static char joystick1_dev[20] = "/dev/js1";
+
+/****************************************************************************
+REMARKS:
+Create a joystick event from the joystick data
+****************************************************************************/
+static void makeJoyEvent(
+ event_t *evt)
+{
+ evt->message = 0;
+ if (buts0 && axis0) {
+ if (buts0[0]) evt->message |= EVT_JOY1_BUTTONA;
+ if (buts0[1]) evt->message |= EVT_JOY1_BUTTONB;
+ evt->where_x = axis0[0];
+ evt->where_y = axis0[1];
+ }
+ else
+ evt->where_x = evt->where_y = 0;
+ if (buts1 && axis1) {
+ if (buts1[0]) evt->message |= EVT_JOY2_BUTTONA;
+ if (buts1[1]) evt->message |= EVT_JOY2_BUTTONB;
+ evt->where_x = axis1[0];
+ evt->where_y = axis1[1];
+ }
+ else
+ evt->where_x = evt->where_y = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the joystick axis data
+****************************************************************************/
+int EVTAPI _EVT_readJoyAxis(
+ int jmask,
+ int *axis)
+{
+ int mask = 0;
+
+ if ((js_version & ~0xffff) == 0) {
+ /* Old 0.x driver */
+ struct JS_DATA_TYPE js;
+ if (joystick0_fd && read(joystick0_fd, &js, JS_RETURN) == JS_RETURN) {
+ if (jmask & EVT_JOY_AXIS_X1)
+ axis[0] = js.x;
+ if (jmask & EVT_JOY_AXIS_Y1)
+ axis[1] = js.y;
+ mask |= EVT_JOY_AXIS_X1|EVT_JOY_AXIS_Y1;
+ }
+ if (joystick1_fd && read(joystick1_fd, &js, JS_RETURN) == JS_RETURN) {
+ if (jmask & EVT_JOY_AXIS_X2)
+ axis[2] = js.x;
+ if (jmask & EVT_JOY_AXIS_Y2)
+ axis[3] = js.y;
+ mask |= EVT_JOY_AXIS_X2|EVT_JOY_AXIS_Y2;
+ }
+ }
+ else {
+ if (axis0) {
+ if (jmask & EVT_JOY_AXIS_X1)
+ axis[0] = axis0[0];
+ if (jmask & EVT_JOY_AXIS_Y1)
+ axis[1] = axis0[1];
+ mask |= EVT_JOY_AXIS_X1 | EVT_JOY_AXIS_Y1;
+ }
+ if (axis1) {
+ if (jmask & EVT_JOY_AXIS_X2)
+ axis[2] = axis1[0];
+ if (jmask & EVT_JOY_AXIS_Y2)
+ axis[3] = axis1[1];
+ mask |= EVT_JOY_AXIS_X2 | EVT_JOY_AXIS_Y2;
+ }
+ }
+ return mask;
+}
+
+/****************************************************************************
+REMARKS:
+Read the joystick button data
+****************************************************************************/
+int EVTAPI _EVT_readJoyButtons(void)
+{
+ int buts = 0;
+
+ if ((js_version & ~0xffff) == 0) {
+ /* Old 0.x driver */
+ struct JS_DATA_TYPE js;
+ if (joystick0_fd && read(joystick0_fd, &js, JS_RETURN) == JS_RETURN)
+ buts = js.buttons;
+ if (joystick1_fd && read(joystick1_fd, &js, JS_RETURN) == JS_RETURN)
+ buts |= js.buttons << 2;
+ }
+ else {
+ if (buts0)
+ buts |= EVT_JOY1_BUTTONA*buts0[0] + EVT_JOY1_BUTTONB*buts0[1];
+ if (buts1)
+ buts |= EVT_JOY2_BUTTONA*buts1[0] + EVT_JOY2_BUTTONB*buts1[1];
+ }
+ return buts;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns the mask indicating what joystick axes are attached.
+
+HEADER:
+event.h
+
+REMARKS:
+This function is used to detect the attached joysticks, and determine
+what axes are present and functioning. This function will re-detect any
+attached joysticks when it is called, so if the user forgot to attach
+the joystick when the application started, you can call this function to
+re-detect any newly attached joysticks.
+
+SEE ALSO:
+EVT_joySetLowerRight, EVT_joySetCenter, EVT_joyIsPresent
+****************************************************************************/
+int EVTAPI EVT_joyIsPresent(void)
+{
+ static int mask = 0;
+ int i;
+ char *tmp, name0[128], name1[128];
+ static ibool inited = false;
+
+ if (inited)
+ return mask;
+ memset(EVT.joyMin,0,sizeof(EVT.joyMin));
+ memset(EVT.joyCenter,0,sizeof(EVT.joyCenter));
+ memset(EVT.joyMax,0,sizeof(EVT.joyMax));
+ memset(EVT.joyPrev,0,sizeof(EVT.joyPrev));
+ EVT.joyButState = 0;
+ if ((tmp = getenv(ENV_JOYDEV0)) != NULL)
+ strcpy(joystick0_dev,tmp);
+ if ((tmp = getenv(ENV_JOYDEV1)) != NULL)
+ strcpy(joystick1_dev,tmp);
+ if ((joystick0_fd = open(joystick0_dev, O_RDONLY)) < 0)
+ joystick0_fd = 0;
+ if ((joystick1_fd = open(joystick1_dev, O_RDONLY)) < 0)
+ joystick1_fd = 0;
+ if (!joystick0_fd && !joystick1_fd) // No joysticks detected
+ return 0;
+ inited = true;
+ if (ioctl(joystick0_fd ? joystick0_fd : joystick1_fd, JSIOCGVERSION, &js_version) < 0)
+ return 0;
+
+ /* Initialise joystick 0 */
+ if (joystick0_fd) {
+ ioctl(joystick0_fd, JSIOCGNAME(sizeof(name0)), name0);
+ if (js_version & ~0xffff) {
+ struct js_event js;
+
+ ioctl(joystick0_fd, JSIOCGAXES, &js0_axes);
+ ioctl(joystick0_fd, JSIOCGBUTTONS, &js0_buttons);
+ axis0 = PM_calloc((int)js0_axes, sizeof(short));
+ buts0 = PM_malloc((int)js0_buttons);
+ /* Read the initial events */
+ while(dataReady(joystick0_fd)
+ && read(joystick0_fd, &js, sizeof(struct js_event)) == sizeof(struct js_event)
+ && (js.type & JS_EVENT_INIT)
+ ) {
+ if (js.type & JS_EVENT_BUTTON)
+ buts0[js.number] = js.value;
+ else if (js.type & JS_EVENT_AXIS)
+ axis0[js.number] = scaleJoyAxis(js.value,js.number);
+ }
+ }
+ else {
+ js0_axes = 2;
+ js0_buttons = 2;
+ axis0 = PM_calloc((int)js0_axes, sizeof(short));
+ buts0 = PM_malloc((int)js0_buttons);
+ }
+ }
+
+ /* Initialise joystick 1 */
+ if (joystick1_fd) {
+ ioctl(joystick1_fd, JSIOCGNAME(sizeof(name1)), name1);
+ if (js_version & ~0xffff) {
+ struct js_event js;
+
+ ioctl(joystick1_fd, JSIOCGAXES, &js1_axes);
+ ioctl(joystick1_fd, JSIOCGBUTTONS, &js1_buttons);
+ axis1 = PM_calloc((int)js1_axes, sizeof(short));
+ buts1 = PM_malloc((int)js1_buttons);
+ /* Read the initial events */
+ while(dataReady(joystick1_fd)
+ && read(joystick1_fd, &js, sizeof(struct js_event))==sizeof(struct js_event)
+ && (js.type & JS_EVENT_INIT)
+ ) {
+ if (js.type & JS_EVENT_BUTTON)
+ buts1[js.number] = js.value;
+ else if (js.type & JS_EVENT_AXIS)
+ axis1[js.number] = scaleJoyAxis(js.value,js.number<<2);
+ }
+ }
+ else {
+ js1_axes = 2;
+ js1_buttons = 2;
+ axis1 = PM_calloc((int)js1_axes, sizeof(short));
+ buts1 = PM_malloc((int)js1_buttons);
+ }
+ }
+
+#ifdef CHECKED
+ fprintf(stderr,"Using joystick driver version %d.%d.%d\n",
+ js_version >> 16, (js_version >> 8) & 0xff, js_version & 0xff);
+ if (joystick0_fd)
+ fprintf(stderr,"Joystick 1 (%s): %s\n", joystick0_dev, name0);
+ if (joystick1_fd)
+ fprintf(stderr,"Joystick 2 (%s): %s\n", joystick1_dev, name1);
+#endif
+ mask = _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyCenter);
+ if (mask) {
+ for (i = 0; i < JOY_NUM_AXES; i++)
+ EVT.joyMax[i] = EVT.joyCenter[i]*2;
+ }
+ return mask;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Polls the joystick for position and button information.
+
+HEADER:
+event.h
+
+REMARKS:
+This routine is used to poll analogue joysticks for button and position
+information. It should be called once for each main loop of the user
+application, just before processing all pending events via EVT_getNext.
+All information polled from the joystick will be posted to the event
+queue for later retrieval.
+
+Note: Most analogue joysticks will provide readings that change even
+ though the joystick has not moved. Hence if you call this routine
+ you will likely get an EVT_JOYMOVE event every time through your
+ event loop.
+
+SEE ALSO:
+EVT_getNext, EVT_peekNext, EVT_joySetUpperLeft, EVT_joySetLowerRight,
+EVT_joySetCenter, EVT_joyIsPresent
+****************************************************************************/
+void EVTAPI EVT_pollJoystick(void)
+{
+ event_t evt;
+ int i,axis[JOY_NUM_AXES],newButState,mask,moved,ps;
+
+ if ((js_version & ~0xFFFF) == 0 && EVT.joyMask) {
+ /* Read joystick axes and post movement events if they have
+ * changed since the last time we polled. Until the events are
+ * actually flushed, we keep modifying the same joystick movement
+ * event, so you won't get multiple movement event
+ */
+ mask = _EVT_readJoyAxis(EVT.joyMask,axis);
+ newButState = _EVT_readJoyButtons();
+ moved = false;
+ for (i = 0; i < JOY_NUM_AXES; i++) {
+ if (mask & (EVT_JOY_AXIS_X1 << i))
+ axis[i] = scaleJoyAxis(axis[i],i);
+ else
+ axis[i] = EVT.joyPrev[i];
+ if (axis[i] != EVT.joyPrev[i])
+ moved = true;
+ }
+ if (moved) {
+ memcpy(EVT.joyPrev,axis,sizeof(EVT.joyPrev));
+ ps = _EVT_disableInt();
+ if (EVT.oldJoyMove != -1) {
+ /* Modify the existing joystick movement event */
+ EVT.evtq[EVT.oldJoyMove].message = newButState;
+ EVT.evtq[EVT.oldJoyMove].where_x = EVT.joyPrev[0];
+ EVT.evtq[EVT.oldJoyMove].where_y = EVT.joyPrev[1];
+ EVT.evtq[EVT.oldJoyMove].relative_x = EVT.joyPrev[2];
+ EVT.evtq[EVT.oldJoyMove].relative_y = EVT.joyPrev[3];
+ }
+ else if (EVT.count < EVENTQSIZE) {
+ /* Add a new joystick movement event */
+ EVT.oldJoyMove = EVT.freeHead;
+ memset(&evt,0,sizeof(evt));
+ evt.what = EVT_JOYMOVE;
+ evt.message = EVT.joyButState;
+ evt.where_x = EVT.joyPrev[0];
+ evt.where_y = EVT.joyPrev[1];
+ evt.relative_x = EVT.joyPrev[2];
+ evt.relative_y = EVT.joyPrev[3];
+ addEvent(&evt);
+ }
+ _EVT_restoreInt(ps);
+ }
+
+ /* Read the joystick buttons, and post events to reflect the change
+ * in state for the joystick buttons.
+ */
+ if (newButState != EVT.joyButState) {
+ if (EVT.count < EVENTQSIZE) {
+ /* Add a new joystick movement event */
+ ps = _EVT_disableInt();
+ memset(&evt,0,sizeof(evt));
+ evt.what = EVT_JOYCLICK;
+ evt.message = newButState;
+ EVT.evtq[EVT.oldJoyMove].where_x = EVT.joyPrev[0];
+ EVT.evtq[EVT.oldJoyMove].where_y = EVT.joyPrev[1];
+ EVT.evtq[EVT.oldJoyMove].relative_x = EVT.joyPrev[2];
+ EVT.evtq[EVT.oldJoyMove].relative_y = EVT.joyPrev[3];
+ addEvent(&evt);
+ _EVT_restoreInt(ps);
+ }
+ EVT.joyButState = newButState;
+ }
+ }
+}
+
+/****************************************************************************
+DESCRIPTION:
+Calibrates the joystick upper left position
+
+HEADER:
+event.h
+
+REMARKS:
+This function can be used to zero in on better joystick calibration factors,
+which may work better than the default simplistic calibration (which assumes
+the joystick is centered when the event library is initialised).
+To use this function, ask the user to hold the stick in the upper left
+position and then have them press a key or button. and then call this
+function. This function will then read the joystick and update the
+calibration factors.
+
+Usually, assuming that the stick was centered when the event library was
+initialized, you really only need to call EVT_joySetLowerRight since the
+upper left position is usually always 0,0 on most joysticks. However, the
+safest procedure is to call all three calibration functions.
+
+SEE ALSO:
+EVT_joySetUpperLeft, EVT_joySetLowerRight, EVT_joyIsPresent
+****************************************************************************/
+void EVTAPI EVT_joySetUpperLeft(void)
+{
+ _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyMin);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Calibrates the joystick lower right position
+
+HEADER:
+event.h
+
+REMARKS:
+This function can be used to zero in on better joystick calibration factors,
+which may work better than the default simplistic calibration (which assumes
+the joystick is centered when the event library is initialised).
+To use this function, ask the user to hold the stick in the lower right
+position and then have them press a key or button. and then call this
+function. This function will then read the joystick and update the
+calibration factors.
+
+Usually, assuming that the stick was centered when the event library was
+initialized, you really only need to call EVT_joySetLowerRight since the
+upper left position is usually always 0,0 on most joysticks. However, the
+safest procedure is to call all three calibration functions.
+
+SEE ALSO:
+EVT_joySetUpperLeft, EVT_joySetCenter, EVT_joyIsPresent
+****************************************************************************/
+void EVTAPI EVT_joySetLowerRight(void)
+{
+ _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyMax);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Calibrates the joystick center position
+
+HEADER:
+event.h
+
+REMARKS:
+This function can be used to zero in on better joystick calibration factors,
+which may work better than the default simplistic calibration (which assumes
+the joystick is centered when the event library is initialised).
+To use this function, ask the user to hold the stick in the center
+position and then have them press a key or button. and then call this
+function. This function will then read the joystick and update the
+calibration factors.
+
+Usually, assuming that the stick was centered when the event library was
+initialized, you really only need to call EVT_joySetLowerRight since the
+upper left position is usually always 0,0 on most joysticks. However, the
+safest procedure is to call all three calibration functions.
+
+SEE ALSO:
+EVT_joySetUpperLeft, EVT_joySetLowerRight, EVT_joySetCenter
+****************************************************************************/
+void EVTAPI EVT_joySetCenter(void)
+{
+ _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyCenter);
+}
+#endif
+
+/****************************************************************************
+REMARKS:
+Pumps all messages in the message queue from Linux into our event queue.
+****************************************************************************/
+static void _EVT_pumpMessages(void)
+{
+ event_t evt;
+ int i,numkeys, c;
+ ibool release;
+ static struct kbentry ke;
+ static char buf[KBDREADBUFFERSIZE];
+ static ushort repeatKey[128] = {0};
+
+ /* Poll keyboard events */
+ while (dataReady(_PM_console_fd) && (numkeys = read(_PM_console_fd, buf, KBDREADBUFFERSIZE)) > 0) {
+ for (i = 0; i < numkeys; i++) {
+ c = buf[i];
+ release = c & 0x80;
+ c &= 0x7F;
+
+ // TODO: This is wrong! We need this to be the time stamp at
+ // ** interrupt ** time!! One solution would be to
+ // put the keyboard and mouse polling loops into
+ // a separate thread that can block on I/O to the
+ // necessay file descriptor.
+ evt.when = _EVT_getTicks();
+
+ if (release) {
+ /* Key released */
+ evt.what = EVT_KEYUP;
+ switch (c) {
+ case KB_leftShift:
+ _PM_modifiers &= ~EVT_LEFTSHIFT;
+ break;
+ case KB_rightShift:
+ _PM_modifiers &= ~EVT_RIGHTSHIFT;
+ break;
+ case 29:
+ _PM_modifiers &= ~(EVT_LEFTCTRL|EVT_CTRLSTATE);
+ break;
+ case 97: /* Control */
+ _PM_modifiers &= ~EVT_CTRLSTATE;
+ break;
+ case 56:
+ _PM_modifiers &= ~(EVT_LEFTALT|EVT_ALTSTATE);
+ break;
+ case 100:
+ _PM_modifiers &= ~EVT_ALTSTATE;
+ break;
+ default:
+ }
+ evt.modifiers = _PM_modifiers;
+ evt.message = keyUpMsg[c];
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ keyUpMsg[c] = 0;
+ repeatKey[c] = 0;
+ }
+ else {
+ /* Key pressed */
+ evt.what = EVT_KEYDOWN;
+ switch (c) {
+ case KB_leftShift:
+ _PM_modifiers |= EVT_LEFTSHIFT;
+ break;
+ case KB_rightShift:
+ _PM_modifiers |= EVT_RIGHTSHIFT;
+ break;
+ case 29:
+ _PM_modifiers |= EVT_LEFTCTRL|EVT_CTRLSTATE;
+ break;
+ case 97: /* Control */
+ _PM_modifiers |= EVT_CTRLSTATE;
+ break;
+ case 56:
+ _PM_modifiers |= EVT_LEFTALT|EVT_ALTSTATE;
+ break;
+ case 100:
+ _PM_modifiers |= EVT_ALTSTATE;
+ break;
+ case KB_capsLock: /* Caps Lock */
+ _PM_leds ^= LED_CAP;
+ ioctl(_PM_console_fd, KDSETLED, _PM_leds);
+ break;
+ case KB_numLock: /* Num Lock */
+ _PM_leds ^= LED_NUM;
+ ioctl(_PM_console_fd, KDSETLED, _PM_leds);
+ break;
+ case KB_scrollLock: /* Scroll Lock */
+ _PM_leds ^= LED_SCR;
+ ioctl(_PM_console_fd, KDSETLED, _PM_leds);
+ break;
+ default:
+ }
+ evt.modifiers = _PM_modifiers;
+ if (keyUpMsg[c]) {
+ evt.what = EVT_KEYREPEAT;
+ evt.message = keyUpMsg[c] | (repeatKey[c]++ << 16);
+ }
+ else {
+ int asc;
+
+ evt.message = getKeyMapping(keymaps, NB_KEYMAPS, c) << 8;
+ ke.kb_index = c;
+ ke.kb_table = 0;
+ if ((_PM_modifiers & EVT_SHIFTKEY) || (_PM_leds & LED_CAP))
+ ke.kb_table |= K_SHIFTTAB;
+ if (_PM_modifiers & (EVT_LEFTALT | EVT_ALTSTATE))
+ ke.kb_table |= K_ALTTAB;
+ if (ioctl(_PM_console_fd, KDGKBENT, (unsigned long)&ke)<0)
+ perror("ioctl(KDGKBENT)");
+ if ((_PM_leds & LED_NUM) && (getKeyMapping(keypad, NB_KEYPAD, c)!=c)) {
+ asc = getKeyMapping(keypad, NB_KEYPAD, c);
+ }
+ else {
+ switch (c) {
+ case 14:
+ asc = ASCII_backspace;
+ break;
+ case 15:
+ asc = ASCII_tab;
+ break;
+ case 28:
+ case 96:
+ asc = ASCII_enter;
+ break;
+ case 1:
+ asc = ASCII_esc;
+ default:
+ asc = ke.kb_value & 0xFF;
+ if (asc < 0x1B)
+ asc = 0;
+ break;
+ }
+ }
+ if ((_PM_modifiers & (EVT_CTRLSTATE|EVT_LEFTCTRL)) && isalpha(asc))
+ evt.message |= toupper(asc) - 'A' + 1;
+ else
+ evt.message |= asc;
+ keyUpMsg[c] = evt.message;
+ repeatKey[c]++;
+ }
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+ }
+ }
+
+ /* Poll mouse events */
+ if (_EVT_mouse_fd) {
+ int dx, dy, buts;
+ static int oldbuts;
+
+ while (dataReady(_EVT_mouse_fd)) {
+ if (readMouseData(&buts, &dx, &dy)) {
+ EVT.mx += dx;
+ EVT.my += dy;
+ if (EVT.mx < 0) EVT.mx = 0;
+ if (EVT.my < 0) EVT.my = 0;
+ if (EVT.mx > range_x) EVT.mx = range_x;
+ if (EVT.my > range_y) EVT.my = range_y;
+ evt.where_x = EVT.mx;
+ evt.where_y = EVT.my;
+ evt.relative_x = dx;
+ evt.relative_y = dy;
+
+ // TODO: This is wrong! We need this to be the time stamp at
+ // ** interrupt ** time!! One solution would be to
+ // put the keyboard and mouse polling loops into
+ // a separate thread that can block on I/O to the
+ // necessay file descriptor.
+ evt.when = _EVT_getTicks();
+ evt.modifiers = _PM_modifiers;
+ if (buts & 4)
+ evt.modifiers |= EVT_LEFTBUT;
+ if (buts & 1)
+ evt.modifiers |= EVT_RIGHTBUT;
+ if (buts & 2)
+ evt.modifiers |= EVT_MIDDLEBUT;
+
+ /* Left click events */
+ if ((buts&4) != (oldbuts&4)) {
+ if (buts&4)
+ evt.what = EVT_MOUSEDOWN;
+ else
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_LEFTBMASK;
+ EVT.oldMove = -1;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+ /* Right click events */
+ if ((buts&1) != (oldbuts&1)) {
+ if (buts&1)
+ evt.what = EVT_MOUSEDOWN;
+ else
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_RIGHTBMASK;
+ EVT.oldMove = -1;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+ /* Middle click events */
+ if ((buts&2) != (oldbuts&2)) {
+ if (buts&2)
+ evt.what = EVT_MOUSEDOWN;
+ else
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_MIDDLEBMASK;
+ EVT.oldMove = -1;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+ /* Mouse movement event */
+ if (dx || dy) {
+ evt.what = EVT_MOUSEMOVE;
+ evt.message = 0;
+ if (EVT.oldMove != -1) {
+ /* Modify existing movement event */
+ EVT.evtq[EVT.oldMove].where_x = evt.where_x;
+ EVT.evtq[EVT.oldMove].where_y = evt.where_y;
+ }
+ else {
+ /* Save id of this movement event */
+ EVT.oldMove = EVT.freeHead;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+ }
+ oldbuts = buts;
+ }
+ }
+ }
+
+#ifdef USE_OS_JOYSTICK
+ // Poll joystick events using the 1.x joystick driver API in the 2.2 kernels
+ if (js_version & ~0xffff) {
+ static struct js_event js;
+
+ /* Read joystick axis 0 */
+ evt.when = 0;
+ evt.modifiers = _PM_modifiers;
+ if (joystick0_fd && dataReady(joystick0_fd) &&
+ read(joystick0_fd, &js, sizeof(js)) == sizeof(js)) {
+ if (js.type & JS_EVENT_BUTTON) {
+ if (js.number < 2) { /* Only 2 buttons for now :( */
+ buts0[js.number] = js.value;
+ evt.what = EVT_JOYCLICK;
+ makeJoyEvent(&evt);
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+ }
+ else if (js.type & JS_EVENT_AXIS) {
+ axis0[js.number] = scaleJoyAxis(js.value,js.number);
+ evt.what = EVT_JOYMOVE;
+ if (EVT.oldJoyMove != -1) {
+ makeJoyEvent(&EVT.evtq[EVT.oldJoyMove]);
+ }
+ else if (EVT.count < EVENTQSIZE) {
+ EVT.oldJoyMove = EVT.freeHead;
+ makeJoyEvent(&evt);
+ addEvent(&evt);
+ }
+ }
+ }
+
+ /* Read joystick axis 1 */
+ if (joystick1_fd && dataReady(joystick1_fd) &&
+ read(joystick1_fd, &js, sizeof(js))==sizeof(js)) {
+ if (js.type & JS_EVENT_BUTTON) {
+ if (js.number < 2) { /* Only 2 buttons for now :( */
+ buts1[js.number] = js.value;
+ evt.what = EVT_JOYCLICK;
+ makeJoyEvent(&evt);
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+ }
+ else if (js.type & JS_EVENT_AXIS) {
+ axis1[js.number] = scaleJoyAxis(js.value,js.number<<2);
+ evt.what = EVT_JOYMOVE;
+ if (EVT.oldJoyMove != -1) {
+ makeJoyEvent(&EVT.evtq[EVT.oldJoyMove]);
+ }
+ else if (EVT.count < EVENTQSIZE) {
+ EVT.oldJoyMove = EVT.freeHead;
+ makeJoyEvent(&evt);
+ addEvent(&evt);
+ }
+ }
+ }
+ }
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+This macro/function is used to converts the scan codes reported by the
+keyboard to our event libraries normalised format. We only have one scan
+code for the 'A' key, and use shift _PM_modifiers to determine if it is a
+Ctrl-F1, Alt-F1 etc. The raw scan codes from the keyboard work this way,
+but the OS gives us 'cooked' scan codes, we have to translate them back
+to the raw format.
+****************************************************************************/
+#define _EVT_maskKeyCode(evt)
+
+/****************************************************************************
+REMARKS:
+Set the speed of the serial port
+****************************************************************************/
+static int setspeed(
+ int fd,
+ int old,
+ int new,
+ unsigned short flags)
+{
+ struct termios tty;
+ char *c;
+
+ tcgetattr(fd, &tty);
+ tty.c_iflag = IGNBRK | IGNPAR;
+ tty.c_oflag = 0;
+ tty.c_lflag = 0;
+ tty.c_line = 0;
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VMIN] = 1;
+ switch (old) {
+ case 9600: tty.c_cflag = flags | B9600; break;
+ case 4800: tty.c_cflag = flags | B4800; break;
+ case 2400: tty.c_cflag = flags | B2400; break;
+ case 1200:
+ default: tty.c_cflag = flags | B1200; break;
+ }
+ tcsetattr(fd, TCSAFLUSH, &tty);
+ switch (new) {
+ case 9600: c = "*q"; tty.c_cflag = flags | B9600; break;
+ case 4800: c = "*p"; tty.c_cflag = flags | B4800; break;
+ case 2400: c = "*o"; tty.c_cflag = flags | B2400; break;
+ case 1200:
+ default: c = "*n"; tty.c_cflag = flags | B1200; break;
+ }
+ write(fd, c, 2);
+ usleep(100000);
+ tcsetattr(fd, TCSAFLUSH, &tty);
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Generic mouse driver init code
+****************************************************************************/
+static void _EVT_mouse_init(void)
+{
+ int i;
+
+ /* Change from any available speed to the chosen one */
+ for (i = 9600; i >= 1200; i /= 2)
+ setspeed(_EVT_mouse_fd, i, opt_baud, mouse_infos[mouse_driver].flags);
+}
+
+/****************************************************************************
+REMARKS:
+Logitech mouse driver init code
+****************************************************************************/
+static void _EVT_logitech_init(void)
+{
+ int i;
+ struct stat buf;
+ int busmouse;
+
+ /* is this a serial- or a bus- mouse? */
+ if (fstat(_EVT_mouse_fd,&buf) == -1)
+ perror("fstat");
+ i = MAJOR(buf.st_rdev);
+ if (stat("/dev/ttyS0",&buf) == -1)
+ perror("stat");
+ busmouse=(i != MAJOR(buf.st_rdev));
+
+ /* Fix the howmany field, so that serial mice have 1, while busmice have 3 */
+ mouse_infos[mouse_driver].read = busmouse ? 3 : 1;
+
+ /* Change from any available speed to the chosen one */
+ for (i = 9600; i >= 1200; i /= 2)
+ setspeed(_EVT_mouse_fd, i, opt_baud, mouse_infos[mouse_driver].flags);
+
+ /* This stuff is peculiar of logitech mice, also for the serial ones */
+ write(_EVT_mouse_fd, "S", 1);
+ setspeed(_EVT_mouse_fd, opt_baud, opt_baud,CS8 |PARENB |PARODD |CREAD |CLOCAL |HUPCL);
+
+ /* Configure the sample rate */
+ for (i = 0; opt_sample <= sampletab[i].sample; i++)
+ ;
+ write(_EVT_mouse_fd,sampletab[i].code,1);
+}
+
+/****************************************************************************
+REMARKS:
+Microsoft Intellimouse init code
+****************************************************************************/
+static void _EVT_pnpmouse_init(void)
+{
+ struct termios tty;
+
+ tcgetattr(_EVT_mouse_fd, &tty);
+ tty.c_iflag = IGNBRK | IGNPAR;
+ tty.c_oflag = 0;
+ tty.c_lflag = 0;
+ tty.c_line = 0;
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VMIN] = 1;
+ tty.c_cflag = mouse_infos[mouse_driver].flags | B1200;
+ tcsetattr(_EVT_mouse_fd, TCSAFLUSH, &tty); /* set parameters */
+}
+
+/****************************************************************************
+PARAMETERS:
+mouseMove - Callback function to call wheneve the mouse needs to be moved
+
+REMARKS:
+Initiliase the event handling module. Here we install our mouse handling ISR
+to be called whenever any button's are pressed or released. We also build
+the free list of events in the event queue.
+
+We use handler number 2 of the mouse libraries interrupt handlers for our
+event handling routines.
+****************************************************************************/
+void EVTAPI EVT_init(
+ _EVT_mouseMoveHandler mouseMove)
+{
+ int i;
+ char *tmp;
+
+ /* Initialise the event queue */
+ EVT.mouseMove = mouseMove;
+ initEventQueue();
+ for (i = 0; i < 256; i++)
+ keyUpMsg[i] = 0;
+
+ /* Keyboard initialization */
+ if (_PM_console_fd == -1)
+ PM_fatalError("You must first call PM_openConsole to use the EVT functions!");
+ _PM_keyboard_rawmode();
+ fcntl(_PM_console_fd,F_SETFL,fcntl(_PM_console_fd,F_GETFL) | O_NONBLOCK);
+
+ /* Mouse initialization */
+ if ((tmp = getenv(ENV_MOUSEDRV)) != NULL) {
+ for (i = 0; i < NB_MICE; i++) {
+ if (!strcasecmp(tmp, mouse_infos[i].name)) {
+ mouse_driver = i;
+ break;
+ }
+ }
+ if (i == NB_MICE) {
+ fprintf(stderr,"Unknown mouse driver: %s\n", tmp);
+ mouse_driver = EVT_noMouse;
+ _EVT_mouse_fd = 0;
+ }
+ }
+ if (mouse_driver != EVT_noMouse) {
+ if (mouse_driver == EVT_gpm)
+ strcpy(mouse_dev,"/dev/gpmdata");
+ if ((tmp = getenv(ENV_MOUSEDEV)) != NULL)
+ strcpy(mouse_dev,tmp);
+#ifdef CHECKED
+ fprintf(stderr,"Using the %s MGL mouse driver on %s.\n", mouse_infos[mouse_driver].name, mouse_dev);
+#endif
+ if ((_EVT_mouse_fd = open(mouse_dev, O_RDWR)) < 0) {
+ perror("open");
+ fprintf(stderr, "Unable to open mouse device %s, dropping mouse support.\n", mouse_dev);
+ sleep(1);
+ mouse_driver = EVT_noMouse;
+ _EVT_mouse_fd = 0;
+ }
+ else {
+ char c;
+
+ /* Init and flush the mouse pending input queue */
+ if (mouse_infos[mouse_driver].init)
+ mouse_infos[mouse_driver].init();
+ while(dataReady(_EVT_mouse_fd) && read(_EVT_mouse_fd, &c, 1) == 1)
+ ;
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS
+Changes the range of coordinates returned by the mouse functions to the
+specified range of values. This is used when changing between graphics
+modes set the range of mouse coordinates for the new display mode.
+****************************************************************************/
+void EVTAPI EVT_setMouseRange(
+ int xRes,
+ int yRes)
+{
+ range_x = xRes;
+ range_y = yRes;
+}
+
+/****************************************************************************
+REMARKS
+Modifes the mouse coordinates as necessary if scaling to OS coordinates,
+and sets the OS mouse cursor position.
+****************************************************************************/
+#define _EVT_setMousePos(x,y)
+
+/****************************************************************************
+REMARKS:
+Initiailises the internal event handling modules. The EVT_suspend function
+can be called to suspend event handling (such as when shelling out to DOS),
+and this function can be used to resume it again later.
+****************************************************************************/
+void EVT_resume(void)
+{
+ // Do nothing for Linux
+}
+
+/****************************************************************************
+REMARKS
+Suspends all of our event handling operations. This is also used to
+de-install the event handling code.
+****************************************************************************/
+void EVT_suspend(void)
+{
+ // Do nothing for Linux
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+ /* Restore signal handlers */
+ _PM_restore_kb_mode();
+ if (_EVT_mouse_fd) {
+ close(_EVT_mouse_fd);
+ _EVT_mouse_fd = 0;
+ }
+#ifdef USE_OS_JOYSTICK
+ if (joystick0_fd) {
+ close(joystick0_fd);
+ free(axis0);
+ free(buts0);
+ joystick0_fd = 0;
+ }
+ if (joystick1_fd) {
+ close(joystick1_fd);
+ free(axis1);
+ free(buts1);
+ joystick1_fd = 0;
+ }
+#endif
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/event.svga b/board/MAI/bios_emulator/scitech/src/pm/linux/event.svga
new file mode 100644
index 0000000000..c0358a0f8a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/event.svga
@@ -0,0 +1,1058 @@
+/****************************************************************************
+*
+* The SuperVGA Kit - UniVBE Software Development Kit
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: IBM PC (MS DOS)
+*
+* Description: Routines to provide a Linux event queue, which automatically
+* handles keyboard and mouse events for the Linux compatability
+* libraries. Based on the event handling code in the MGL.
+*
+****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <termios.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <gpm.h>
+#include "pm.h"
+#include "vesavbe.h"
+#include "wdirect.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+#define EVENTQSIZE 100 /* Number of events in event queue */
+
+static int head = -1; /* Head of event queue */
+static int tail = -1; /* Tail of event queue */
+static int freeHead = -1; /* Head of free list */
+static int count = 0; /* No. of items currently in queue */
+static WD_event evtq[EVENTQSIZE]; /* The queue structure itself */
+static int oldMove = -1; /* Previous movement event */
+static int oldKey = -1; /* Previous key repeat event */
+static int mx,my; /* Current mouse position */
+static int xRes,yRes; /* Screen resolution coordinates */
+static void *stateBuf; /* Pointer to console state buffer */
+static int conn; /* GPM file descriptor for mouse handling */
+static int tty_fd; /* File descriptor for /dev/console */
+extern int tty_vc; /* Virtual console ID, from the PM/Pro library */
+static ibool key_down[128]; /* State of all keyboard keys */
+static struct termios old_conf; /* Saved terminal configuration */
+static int oldkbmode; /* and previous keyboard mode */
+struct vt_mode oldvtmode; /* Old virtual terminal mode */
+static int old_flags; /* Old flags for fcntl */
+static ulong key_modifiers; /* Keyboard modifiers */
+static int forbid_vt_release=0;/* Flag to forbid release of VT */
+static int forbid_vt_acquire=0;/* Flag to forbid cature of VT */
+static int oldmode; /* Old SVGA mode saved for VT switch*/
+static int initmode; /* Initial text mode */
+static ibool installed = false; /* True if we are installed */
+static void (_ASMAPI *moveCursor)(int x,int y) = NULL;
+static int (_ASMAPI *suspendAppCallback)(int flags) = NULL;
+
+#if 0
+/* Keyboard Translation table from scancodes to ASCII */
+
+static uchar keyTable[128] =
+"\0\0331234567890-=\010"
+"\011qwertyuiop[]\015"
+"\0asdfghjkl;'`\0\\"
+"zxcvbnm,./\0*\0 \0"
+"\0\0\0\0\0\0\0\0\0\0\0\0" /* Function keys */
+"789-456+1230.\0\0\0\0\0" /* Keypad keys */
+"\0\0\0\0\0\0\0\015\0/";
+
+static uchar keyTableShifted[128] =
+"\0\033!@#$%^&*()_+\010"
+"\011QWERTYUIOP{}\015"
+"\0ASDFGHJKL:\"~\0|"
+"ZXCVBNM<>?\0*\0 \0"
+"\0\0\0\0\0\0\0\0\0\0\0\0" /* Function keys */
+"789-456+1230.\0\0\0\0\0" /* Keypad keys */
+"\0\0\0\0\0\0\0\015\0/";
+#endif
+
+/* Macros to keep track of the CAPS and NUM lock states */
+
+#define EVT_CAPSSTATE 0x0100
+#define EVT_NUMSTATE 0x0200
+
+/* Helper macros for dealing with timers */
+
+#define TICKS_TO_USEC(t) ((t)*65536.0/1.193180)
+#define USEC_TO_TICKS(u) ((u)*1.193180/65536.0)
+
+/* Number of keycodes to read at a time from the console */
+
+#define KBDREADBUFFERSIZE 32
+
+/*---------------------------- Implementation -----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Returns the current time stamp in units of 18.2 ticks per second.
+****************************************************************************/
+static ulong getTimeStamp(void)
+{
+ return (ulong)(clock() / (CLOCKS_PER_SEC / 18.2));
+}
+
+/****************************************************************************
+PARAMETERS:
+evt - Event to place onto event queue
+
+REMARKS:
+Adds an event to the event queue by tacking it onto the tail of the event
+queue. This routine assumes that at least one spot is available on the
+freeList for the event to be inserted.
+****************************************************************************/
+static void addEvent(
+ WD_event *evt)
+{
+ int evtID;
+
+ /* Get spot to place the event from the free list */
+ evtID = freeHead;
+ freeHead = evtq[freeHead].next;
+
+ /* Add to the tail of the event queue */
+ evt->next = -1;
+ evt->prev = tail;
+ if (tail != -1)
+ evtq[tail].next = evtID;
+ else
+ head = evtID;
+ tail = evtID;
+ evtq[evtID] = *evt;
+ count++;
+}
+
+/****************************************************************************
+PARAMETERS:
+what - Event code
+message - Event message
+modifiers - keyboard modifiers
+x - Mouse X position at time of event
+y - Mouse Y position at time of event
+but_stat - Mouse button status at time of event
+
+REMARKS:
+Adds a new mouse event to the event queue. This routine is called from
+within the mouse interrupt subroutine, so it must be efficient.
+****************************************************************************/
+static void addMouseEvent(
+ uint what,
+ uint message,
+ int x,
+ int y,
+ uint but_stat)
+{
+ WD_event evt;
+
+ if (count < EVENTQSIZE) {
+ evt.what = what;
+ evt.when = getTimeStamp();
+ evt.message = message;
+ evt.modifiers = but_stat | key_modifiers;
+ evt.where_x = x;
+ evt.where_y = y;
+ fprintf(stderr, "(%d,%d), buttons %ld\n", x,y, evt.modifiers);
+ addEvent(&evt); /* Add to tail of event queue */
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+scancode - Raw keyboard scan code
+modifiers - Keyboard modifiers flags
+
+REMARKS:
+Converts the raw scan code into the appropriate ASCII code using the scan
+code and the keyboard modifier flags.
+****************************************************************************/
+static ulong getKeyMessage(
+ uint scancode,
+ ulong modifiers)
+{
+ ushort code = scancode << 8;
+ ushort ascii;
+ struct kbentry ke;
+
+ ke.kb_index = scancode;
+
+ /* Find the basic ASCII code for the scan code */
+ if (modifiers & EVT_CAPSSTATE) {
+ if (modifiers & EVT_SHIFTKEY)
+ ke.kb_table = K_NORMTAB;
+ // ascii = tolower(keyTableShifted[scancode]);
+ else
+ ke.kb_table = K_SHIFTTAB;
+ // ascii = toupper(keyTable[scancode]);
+ }
+ else {
+ if (modifiers & EVT_SHIFTKEY)
+ ke.kb_table = K_SHIFTTAB;
+ // ascii = keyTableShifted[scancode];
+ else
+ ke.kb_table = K_NORMTAB;
+ // ascii = keyTable[scancode];
+ }
+ if(modifiers & EVT_ALTSTATE)
+ ke.kb_table |= K_ALTTAB;
+
+ if (ioctl(tty_fd, KDGKBENT, (unsigned long)&ke)) {
+ fprintf(stderr, "KDGKBENT at index %d in table %d: ",
+ scancode, ke.kb_table);
+ return 0;
+ }
+ ascii = ke.kb_value;
+
+ /* Add ASCII code if key is not alt'ed or ctrl'ed */
+ if (!(modifiers & (EVT_ALTSTATE | EVT_CTRLSTATE)))
+ code |= ascii;
+
+ return code;
+}
+
+/****************************************************************************
+PARAMETERS:
+what - Event code
+scancode - Raw scancode of keyboard event to add
+
+REMARKS:
+Adds a new keyboard event to the event queue. We only take KEYUP and
+KEYDOWN event codes, however if a key is already down we convert the KEYDOWN
+to a KEYREPEAT.
+****************************************************************************/
+static void addKeyEvent(
+ uint what,
+ uint scancode)
+{
+ WD_event evt;
+
+ if (count < EVENTQSIZE) {
+ evt.what = what;
+ evt.when = getTimeStamp();
+ evt.message = getKeyMessage(scancode,key_modifiers) | 0x10000UL;
+ evt.where_x = evt.where_y = 0;
+ evt.modifiers = key_modifiers;
+ if (evt.what == EVT_KEYUP)
+ key_down[scancode] = false;
+ else if (evt.what == EVT_KEYDOWN) {
+ if (key_down[scancode]) {
+ if (oldKey != -1) {
+ evtq[oldKey].message += 0x10000UL;
+ }
+ else {
+ evt.what = EVT_KEYREPEAT;
+ oldKey = freeHead;
+ addEvent(&evt);
+ oldMove = -1;
+ }
+ return;
+ }
+ key_down[scancode] = true;
+ }
+
+ addEvent(&evt);
+ oldMove = -1;
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+sig - Signal being sent to this signal handler
+
+REMARKS:
+Signal handler for the timer. This routine takes care of periodically
+posting timer events to the event queue.
+****************************************************************************/
+void timerHandler(
+ int sig)
+{
+ WD_event evt;
+
+ if (sig == SIGALRM) {
+ if (count < EVENTQSIZE) {
+ evt.when = getTimeStamp();
+ evt.what = EVT_TIMERTICK;
+ evt.message = 0;
+ evt.where_x = evt.where_y = 0;
+ evt.modifiers = 0;
+ addEvent(&evt);
+ oldMove = -1;
+ oldKey = -1;
+ }
+ signal(SIGALRM, timerHandler);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Restore the terminal to normal operation on exit
+****************************************************************************/
+static void restore_term(void)
+{
+ RMREGS regs;
+
+ if (installed) {
+ /* Restore text mode and the state of the console */
+ regs.x.ax = 0x3;
+ PM_int86(0x10,&regs,&regs);
+ PM_restoreConsoleState(stateBuf,tty_fd);
+
+ /* Restore console to normal operation */
+ ioctl(tty_fd, VT_SETMODE, &oldvtmode);
+ ioctl(tty_fd, KDSKBMODE, oldkbmode);
+ tcsetattr(tty_fd, TCSAFLUSH, &old_conf);
+ fcntl(tty_fd,F_SETFL,old_flags &= ~O_NONBLOCK);
+ PM_closeConsole(tty_fd);
+
+ /* Close the mouse driver */
+ close(conn);
+
+ /* Flag that we are not no longer installed */
+ installed = false;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Signal handler to capture forced program termination conditions so that
+we can clean up properly.
+****************************************************************************/
+static void exitHandler(int sig)
+{
+ exit(-1);
+}
+
+/****************************************************************************
+REMARKS:
+Sleep until the virtual terminal is active
+****************************************************************************/
+void wait_vt_active(void)
+{
+ while (ioctl(tty_fd, VT_WAITACTIVE, tty_vc) < 0) {
+ if ((errno != EAGAIN) && (errno != EINTR)) {
+ perror("ioctl(VT_WAITACTIVE)");
+ exit(1);
+ }
+ usleep(150000);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Signal handler called when our virtual terminal has been released and we are
+losing the active focus.
+****************************************************************************/
+static void release_vt_signal(int n)
+{
+ forbid_vt_acquire = 1;
+ if (forbid_vt_release) {
+ forbid_vt_acquire = 0;
+ ioctl(tty_fd, VT_RELDISP, 0);
+ return;
+ }
+
+ // TODO: Call the user supplied suspendAppCallback and restore text
+ // mode (saving the existing mode so we can restore it).
+ //
+ // Also if the suspendAppCallback is NULL then we have to
+ // ignore the switch request!
+ if(suspendAppCallback){
+ oldmode = VBE_getVideoMode();
+ suspendAppCallback(true);
+ VBE_setVideoMode(initmode);
+ }
+
+ ioctl(tty_fd, VT_RELDISP, 1);
+ forbid_vt_acquire = 0;
+ wait_vt_active();
+}
+
+/****************************************************************************
+REMARKS:
+Signal handler called when our virtual terminal has been re-aquired and we
+are now regaiing the active focus.
+****************************************************************************/
+static void acquire_vt_signal(int n)
+{
+ forbid_vt_release = 1;
+ if (forbid_vt_acquire) {
+ forbid_vt_release = 0;
+ return;
+ }
+
+ // TODO: Restore the old display mode, call the user suspendAppCallback
+ // and and we will be back in graphics mode.
+
+ if(suspendAppCallback){
+ VBE_setVideoMode(oldmode);
+ suspendAppCallback(false);
+ }
+
+ ioctl(tty_fd, VT_RELDISP, VT_ACKACQ);
+ forbid_vt_release = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the action for a specific signal to call our signal handler.
+****************************************************************************/
+static void set_sigaction(int sig,void (*handler)(int))
+{
+ struct sigaction siga;
+
+ siga.sa_handler = handler;
+ siga.sa_flags = SA_RESTART;
+ memset(&(siga.sa_mask), 0, sizeof(sigset_t));
+ sigaction(sig, &siga, NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Function to take over control of VT switching so that we can capture
+virtual terminal release and aquire signals, allowing us to properly
+support VT switching while in graphics modes.
+****************************************************************************/
+static void take_vt_control(void)
+{
+ struct vt_mode vtmode;
+
+ ioctl(tty_fd, VT_GETMODE, &vtmode);
+ oldvtmode = vtmode;
+ vtmode.mode = VT_PROCESS;
+ vtmode.relsig = SIGUSR1;
+ vtmode.acqsig = SIGUSR2;
+ set_sigaction(SIGUSR1, release_vt_signal);
+ set_sigaction(SIGUSR2, acquire_vt_signal);
+ ioctl(tty_fd, VT_SETMODE, &oldvtmode);
+}
+
+/****************************************************************************
+REMARKS:
+Set the shift keyboard LED's based on the current keyboard modifiers flags.
+****************************************************************************/
+static void updateLEDStatus(void)
+{
+ int state = 0;
+ if (key_modifiers & EVT_CAPSSTATE)
+ state |= LED_CAP;
+ if (key_modifiers & EVT_NUMSTATE)
+ state |= LED_NUM;
+ ioctl(tty_fd,KDSETLED,state);
+}
+
+/****************************************************************************
+PARAMETERS:
+scancode - Raw scan code to handle
+
+REMARKS:
+Handles the shift key modifiers and keeps track of the shift key states
+so that we can return the correct ASCII codes for the keyboard.
+****************************************************************************/
+static void toggleModifiers(
+ int scancode)
+{
+ static int caps_down = 0,num_down = 0;
+
+ if (scancode & 0x80) {
+ /* Handle key-release function */
+ scancode &= 0x7F;
+ if (scancode == 0x2A || scancode == 0x36)
+ key_modifiers &= ~EVT_SHIFTKEY;
+ else if (scancode == 0x1D || scancode == 0x61)
+ key_modifiers &= ~EVT_CTRLSTATE;
+ else if (scancode == 0x38 || scancode == 0x64)
+ key_modifiers &= ~EVT_ALTSTATE;
+ else if (scancode == 0x3A)
+ caps_down = false;
+ else if (scancode == 0x45)
+ num_down = false;
+ }
+ else {
+ /* Handle key-down function */
+ scancode &= 0x7F;
+ if (scancode == 0x2A || scancode == 0x36)
+ key_modifiers |= EVT_SHIFTKEY;
+ else if (scancode == 0x1D || scancode == 0x61)
+ key_modifiers |= EVT_CTRLSTATE;
+ else if (scancode == 0x38 || scancode == 0x64)
+ key_modifiers |= EVT_ALTSTATE;
+ else if (scancode == 0x3A) {
+ if (!caps_down) {
+ key_modifiers ^= EVT_CAPSSTATE;
+ updateLEDStatus();
+ }
+ caps_down = true;
+ }
+ else if (scancode == 0x45) {
+ if (!num_down) {
+ key_modifiers ^= EVT_NUMSTATE;
+ updateLEDStatus();
+ }
+ num_down = true;
+ }
+ }
+}
+
+/***************************************************************************
+REMARKS:
+Returns the number of bits that have changed from 0 to 1
+(a negative value means the number of bits that have changed from 1 to 0)
+ **************************************************************************/
+static int compareBits(short a, short b)
+{
+ int ret = 0;
+ if( (a&1) != (b&1) ) ret += (b&1) ? 1 : -1;
+ if( (a&2) != (b&2) ) ret += (b&2) ? 1 : -1;
+ if( (a&4) != (b&4) ) ret += (b&4) ? 1 : -1;
+ return ret;
+}
+
+/***************************************************************************
+REMARKS:
+Turns off all keyboard state because we can't rely on them anymore as soon
+as we switch VT's
+***************************************************************************/
+static void keyboard_clearstate(void)
+{
+ key_modifiers = 0;
+ memset(key_down, 0, sizeof(key_down));
+}
+
+/****************************************************************************
+REMARKS:
+Pumps all events from the console event queue into the WinDirect event queue.
+****************************************************************************/
+static void pumpEvents(void)
+{
+ static uchar buf[KBDREADBUFFERSIZE];
+ static char data[5];
+ static int old_buts, old_mx, old_my;
+ static struct timeval t;
+ fd_set fds;
+ int numkeys,i;
+ int dx, dy, buts;
+
+ /* Read all pending keypresses from keyboard buffer and process */
+ while ((numkeys = read(tty_fd, buf, KBDREADBUFFERSIZE)) > 0) {
+ for (i = 0; i < numkeys; i++) {
+ toggleModifiers(buf[i]);
+ if (key_modifiers & EVT_ALTSTATE){
+ int fkey = 0;
+
+ // Do VT switching here for Alt+Fx keypresses
+ switch(buf[i] & 0x7F){
+ case 59 ... 68: /* F1 to F10 */
+ fkey = (buf[i] & 0x7F) - 58;
+ break;
+ case 87: /* F11 */
+ case 88: /* F12 */
+ fkey = (buf[i] & 0x7F) - 76;
+ break;
+ }
+ if(fkey){
+ struct vt_stat vts;
+ ioctl(tty_fd, VT_GETSTATE, &vts);
+
+ if(fkey != vts.v_active){
+ keyboard_clearstate();
+ ioctl(tty_fd, VT_ACTIVATE, fkey);
+ }
+ }
+ }
+
+ if (buf[i] & 0x80)
+ addKeyEvent(EVT_KEYUP,buf[i] & 0x7F);
+ else
+ addKeyEvent(EVT_KEYDOWN,buf[i] & 0x7F);
+ }
+
+ // TODO: If we want to handle VC switching we will need to do it
+ // in here so that we can switch away from the VC and then
+ // switch back to it later. Right now VC switching is disabled
+ // and in order to enable it we need to save/restore the state
+ // of the graphics screen (using the suspendAppCallback and
+ // saving/restoring the state of the current display mode).
+
+ }
+
+ /* Read all pending mouse events and process them */
+ if(conn > 0){
+ FD_ZERO(&fds);
+ FD_SET(conn, &fds);
+ t.tv_sec = t.tv_usec = 0L;
+ while (select(conn+1, &fds, NULL, NULL, &t) > 0) {
+ if(read(conn, data, 5) == 5){
+ buts = (~data[0]) & 0x07;
+ dx = (char)(data[1]) + (char)(data[3]);
+ dy = -((char)(data[2]) + (char)(data[4]));
+
+ mx += dx; my += dy;
+
+ if (dx || dy)
+ addMouseEvent(EVT_MOUSEMOVE, 0, mx, my, buts);
+
+ if (buts != old_buts){
+ int c = compareBits(buts,old_buts);
+ if(c>0)
+ addMouseEvent(EVT_MOUSEDOWN, 0, mx, my, buts);
+ else if(c<0)
+ addMouseEvent(EVT_MOUSEUP, 0, mx, my, buts);
+ }
+ old_mx = mx; old_my = my;
+ old_buts = buts;
+ FD_SET(conn, &fds);
+ t.tv_sec = t.tv_usec = 0L;
+ }
+ }
+ }
+}
+
+/*------------------------ Public interface routines ----------------------*/
+
+/****************************************************************************
+PARAMETERS:
+which - Which code for event to post
+what - Event code for event to post
+message - Event message
+modifiers - Shift key/mouse button modifiers
+
+RETURNS:
+True if the event was posted, false if queue is full.
+
+REMARKS:
+Posts an event to the event queue. This routine can be used to post any type
+of event into the queue.
+****************************************************************************/
+ibool _WDAPI WD_postEvent(
+ ulong which,
+ uint what,
+ ulong message,
+ ulong modifiers)
+{
+ WD_event evt;
+
+ if (count < EVENTQSIZE) {
+ /* Save information in event record */
+ evt.which = which;
+ evt.what = what;
+ evt.when = getTimeStamp();
+ evt.message = message;
+ evt.modifiers = modifiers;
+ addEvent(&evt); /* Add to tail of event queue */
+ return true;
+ }
+ else
+ return false;
+}
+
+/****************************************************************************
+PARAMETERS:
+mask - Event mask to use
+
+REMARKS:
+Flushes all the event specified in 'mask' from the event queue.
+****************************************************************************/
+void _WDAPI WD_flushEvent(
+ uint mask)
+{
+ WD_event evt;
+
+ do { /* Flush all events */
+ WD_getEvent(&evt,mask);
+ } while (evt.what != EVT_NULLEVT);
+}
+
+/****************************************************************************
+PARAMETERS:
+evt - Place to store event
+mask - Event mask to use
+
+REMARKS:
+Halts program execution until a specified event occurs. The event is
+returned. All pending events not in the specified mask will be ignored and
+removed from the queue.
+****************************************************************************/
+void _WDAPI WD_haltEvent(
+ WD_event *evt,
+ uint mask)
+{
+ do { /* Wait for an event */
+ WD_getEvent(evt,EVT_EVERYEVT);
+ } while (!(evt->what & mask));
+}
+
+/****************************************************************************
+PARAMETERS:
+evt - Place to store event
+mask - Event mask to use
+
+RETURNS:
+True if an event was pending.
+
+REMARKS:
+Retrieves the next pending event defined in 'mask' from the event queue.
+The event queue is adjusted to reflect the new state after the event has
+been removed.
+****************************************************************************/
+ibool _WDAPI WD_getEvent(
+ WD_event *evt,
+ uint mask)
+{
+ int evtID,next,prev;
+
+ pumpEvents();
+ if (moveCursor)
+ moveCursor(mx,my); /* Move the mouse cursor */
+ evt->what = EVT_NULLEVT; /* Default to null event */
+
+ if (count) {
+ for (evtID = head; evtID != -1; evtID = evtq[evtID].next) {
+ if (evtq[evtID].what & mask)
+ break; /* Found an event */
+ }
+ if (evtID == -1)
+ return false; /* Event was not found */
+ next = evtq[evtID].next;
+ prev = evtq[evtID].prev;
+ if (prev != -1)
+ evtq[prev].next = next;
+ else
+ head = next;
+ if (next != -1)
+ evtq[next].prev = prev;
+ else
+ tail = prev;
+ *evt = evtq[evtID]; /* Return the event */
+ evtq[evtID].next = freeHead; /* and return to free list */
+ freeHead = evtID;
+ count--;
+ if (evt->what == EVT_MOUSEMOVE)
+ oldMove = -1;
+ if (evt->what == EVT_KEYREPEAT)
+ oldKey = -1;
+ }
+ return evt->what != EVT_NULLEVT;
+}
+
+/****************************************************************************
+PARAMETERS:
+evt - Place to store event
+mask - Event mask to use
+
+RETURNS:
+True if an event is pending.
+
+REMARKS:
+Peeks at the next pending event defined in 'mask' in the event queue. The
+event is not removed from the event queue.
+****************************************************************************/
+ibool _WDAPI WD_peekEvent(
+ WD_event *evt,
+ uint mask)
+{
+ int evtID;
+
+ pumpEvents();
+ if (moveCursor)
+ moveCursor(mx,my); /* Move the mouse cursor */
+ evt->what = EVT_NULLEVT; /* Default to null event */
+
+ if (count) {
+ for (evtID = head; evtID != -1; evtID = evtq[evtID].next) {
+ if (evtq[evtID].what & mask)
+ break; /* Found an event */
+ }
+ if (evtID == -1)
+ return false; /* Event was not found */
+
+ *evt = evtq[evtID]; /* Return the event */
+ }
+ return evt->what != EVT_NULLEVT;
+}
+
+/****************************************************************************
+PARAMETERS:
+hwndMain - Handle to main window
+_xRes - X resolution of graphics mode to be used
+_yRes - Y resolulion of graphics mode to be used
+
+RETURNS:
+Handle to the fullscreen event window if (we return hwndMain on Linux)
+
+REMARKS:
+Initiliase the event handling module. Here we install our mouse handling
+ISR to be called whenever any button's are pressed or released. We also
+build the free list of events in the event queue.
+****************************************************************************/
+WD_HWND _WDAPI WD_startFullScreen(
+ WD_HWND hwndMain,
+ int _xRes,
+ int _yRes)
+{
+ int i;
+ struct termios conf;
+ if (!installed) {
+ Gpm_Connect gpm;
+
+ /* Build free list, and initialise global data structures */
+ for (i = 0; i < EVENTQSIZE; i++)
+ evtq[i].next = i+1;
+ evtq[EVENTQSIZE-1].next = -1; /* Terminate list */
+ count = freeHead = 0;
+ head = tail = -1;
+ oldMove = -1;
+ oldKey = -1;
+ xRes = _xRes;
+ yRes = _yRes;
+
+ /* Open the console device and initialise it for raw mode */
+ tty_fd = PM_openConsole();
+
+ /* Wait until virtual terminal is active and take over control */
+ wait_vt_active();
+ take_vt_control();
+
+ /* Initialise keyboard handling to raw mode */
+ if (ioctl(tty_fd, KDGKBMODE, &oldkbmode)) {
+ printf("WD_startFullScreen: cannot get keyboard mode.\n");
+ exit(-1);
+ }
+ old_flags = fcntl(tty_fd,F_GETFL);
+ fcntl(tty_fd,F_SETFL,old_flags |= O_NONBLOCK);
+ tcgetattr(tty_fd, &conf);
+ old_conf = conf;
+ conf.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH | ISIG);
+ conf.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
+ conf.c_iflag |= (IGNBRK | IGNPAR);
+ conf.c_cc[VMIN] = 1;
+ conf.c_cc[VTIME] = 0;
+ conf.c_cc[VSUSP] = 0;
+ tcsetattr(tty_fd, TCSAFLUSH, &conf);
+ ioctl(tty_fd, KDSKBMODE, K_MEDIUMRAW);
+
+ /* Clear the keyboard state information */
+ memset(key_down, 0, sizeof(key_down));
+ ioctl(tty_fd,KDSETLED,key_modifiers = 0);
+
+ /* Initialize the mouse connection
+ The user *MUST* run gpm with the option -R for this to work (or have a MouseSystems mouse)
+ */
+ if(Gpm_Open(&gpm,0) > 0){ /* GPM available */
+ if ((conn = open(GPM_NODE_FIFO,O_RDONLY|O_SYNC)) < 0)
+ fprintf(stderr,"WD_startFullScreen: Can't open mouse connection.\n");
+ }else{
+ fprintf(stderr,"Warning: when not using gpm -R, only MouseSystems mice are currently supported.\n");
+ if ((conn = open("/dev/mouse",O_RDONLY|O_SYNC)) < 0)
+ fprintf(stderr,"WD_startFullScreen: Can't open /dev/mouse.\n");
+ }
+ Gpm_Close();
+
+ /* TODO: Scale the mouse coordinates to the specific resolution */
+
+ /* Save the state of the console */
+ if ((stateBuf = malloc(PM_getConsoleStateSize())) == NULL) {
+ printf("Out of memory!\n");
+ exit(-1);
+ }
+ PM_saveConsoleState(stateBuf,tty_fd);
+ initmode = VBE_getVideoMode();
+
+ /* Initialize the signal handler for timer events */
+ signal(SIGALRM, timerHandler);
+
+ /* Capture termination signals so we can clean up properly */
+ signal(SIGTERM, exitHandler);
+ signal(SIGINT, exitHandler);
+ signal(SIGQUIT, exitHandler);
+ atexit(restore_term);
+
+ /* Signal that we are installed */
+ installed = true;
+ }
+ return hwndMain;
+}
+
+/****************************************************************************
+REMARKS:
+Lets the library know when fullscreen graphics mode has been initialized so
+that we can properly scale the mouse driver coordinates.
+****************************************************************************/
+void _WDAPI WD_inFullScreen(void)
+{
+ /* Nothing to do in here */
+}
+
+/****************************************************************************
+REMARKS:
+Suspends all of our event handling operations. This is also used to
+de-install the event handling code.
+****************************************************************************/
+void _WDAPI WD_restoreGDI(void)
+{
+ restore_term();
+}
+
+/****************************************************************************
+PARAMETERS:
+ticks - Number of ticks between timer tick messages
+
+RETURNS:
+Previous value for the timer tick event spacing.
+
+REMARKS:
+The event module will automatically generate periodic timer tick events for
+you, with 'ticks' between each event posting. If you set the value of
+'ticks' to 0, the timer tick events are turned off.
+****************************************************************************/
+int _WDAPI WD_setTimerTick(
+ int ticks)
+{
+ int old;
+ struct itimerval tim;
+ long ms = TICKS_TO_USEC(ticks);
+
+ getitimer(ITIMER_REAL, &tim);
+ old = USEC_TO_TICKS(tim.it_value.tv_sec*1000000.0 + tim.it_value.tv_usec);
+ tim.it_interval.tv_sec = ms / 1000000;
+ tim.it_interval.tv_usec = ms % 1000000;
+ setitimer(ITIMER_REAL, &tim, NULL);
+ return old;
+}
+
+/****************************************************************************
+PARAMETERS:
+saveState - Address of suspend app callback to register
+
+REMARKS:
+Registers a user application supplied suspend application callback so that
+we can properly handle virtual terminal switching.
+****************************************************************************/
+void _WDAPI WD_setSuspendAppCallback(
+ int (_ASMAPI *saveState)(int flags))
+{
+ suspendAppCallback = saveState;
+}
+
+/****************************************************************************
+PARAMETERS:
+x - New X coordinate to move the mouse cursor to
+y - New Y coordinate to move the mouse cursor to
+
+REMARKS:
+Moves to mouse cursor to the specified coordinate.
+****************************************************************************/
+void _WDAPI WD_setMousePos(
+ int x,
+ int y)
+{
+ mx = x;
+ my = y;
+}
+
+/****************************************************************************
+PARAMETERS:
+x - Place to store X coordinate of mouse cursor
+y - Place to store Y coordinate of mouse cursor
+
+REMARKS:
+Reads the current mouse cursor location int *screen* coordinates.
+****************************************************************************/
+void _WDAPI WD_getMousePos(
+ int *x,
+ int *y)
+{
+ *x = mx;
+ *y = my;
+}
+
+/****************************************************************************
+PARAMETERS:
+mcb - Address of mouse callback function
+
+REMARKS:
+Registers an application supplied mouse callback function that is called
+whenever the mouse cursor moves.
+****************************************************************************/
+void _WDAPI WD_setMouseCallback(
+ void (_ASMAPI *mcb)(int x,int y))
+{
+ moveCursor = mcb;
+}
+
+/****************************************************************************
+PARAMETERS:
+xRes - New X resolution of graphics mode
+yRes - New Y resolution of graphics mode
+
+REMARKS:
+This is called to inform the event handling code that the screen resolution
+has changed so that the mouse coordinates can be scaled appropriately.
+****************************************************************************/
+void _WDAPI WD_changeResolution(
+ int xRes,
+ int yRes)
+{
+ // Gpm_FitValues(xRes, yRes); // ??
+}
+
+/****************************************************************************
+PARAMETERS:
+scancode - Scan code to check if a key is down
+
+REMARKS:
+Determines if a particular key is down based on the scan code for the key.
+****************************************************************************/
+ibool _WDAPI WD_isKeyDown(
+ uchar scancode)
+{
+ return key_down[scancode];
+}
+
+/****************************************************************************
+REMARKS:
+Determines if the application needs to run in safe mode. Not necessary for
+anything but broken Windows 95 display drivers so we return false for
+Linux.
+****************************************************************************/
+int _WDAPI WD_isSafeMode(void)
+{
+ return false;
+}
+
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/linux/oshdr.h
new file mode 100644
index 0000000000..6023dff109
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/oshdr.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+*
+* SciTech Multi-platform Graphics Library
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Linux
+*
+* Description: Include all the OS specific header files.
+*
+****************************************************************************/
+
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/fs.h>
+#ifdef USE_OS_JOYSTICK
+#include <linux/joystick.h>
+#endif
+#include <termios.h>
+#include <signal.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/* Internal global variables */
+
+extern int _PM_console_fd,_PM_leds,_PM_modifiers;
+
+/* Internal function prototypes */
+
+void _PM_restore_kb_mode(void);
+void _PM_keyboard_rawmode(void);
+
+/* Linux needs the generic joystick scaling code */
+
+#define NEED_SCALE_JOY_AXIS
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/pm.c b/board/MAI/bios_emulator/scitech/src/pm/linux/pm.c
new file mode 100644
index 0000000000..1d52984a6a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/pm.c
@@ -0,0 +1,1810 @@
+;/****************************************************************************
+*
+* SciTech OS Portability Manager Library
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Portions copyright (C) Josh Vanderhoof
+*
+* Language: ANSI C
+* Environment: Linux
+*
+* Description: Implementation for the OS Portability Manager Library, which
+* contains functions to implement OS specific services in a
+* generic, cross platform API. Porting the OS Portability
+* Manager library is the first step to porting any SciTech
+* products to a new platform.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "drvlib/os/os.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/kd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/vt.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <syscall.h>
+#include <signal.h>
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#ifdef ENABLE_MTRR
+#include <asm/mtrr.h>
+#endif
+#include <asm/vm86.h>
+#ifdef __GLIBC__
+#include <sys/perm.h>
+#endif
+
+/*--------------------------- Global variables ----------------------------*/
+
+#define REAL_MEM_BASE ((void *)0x10000)
+#define REAL_MEM_SIZE 0x10000
+#define REAL_MEM_BLOCKS 0x100
+#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK)
+#define DEFAULT_STACK_SIZE 0x1000
+#define RETURN_TO_32_INT 255
+
+/* Quick and dirty fix for vm86() syscall from lrmi 0.6 */
+static int
+vm86(struct vm86_struct *vm)
+ {
+ int r;
+#ifdef __PIC__
+ asm volatile (
+ "pushl %%ebx\n\t"
+ "movl %2, %%ebx\n\t"
+ "int $0x80\n\t"
+ "popl %%ebx"
+ : "=a" (r)
+ : "0" (113), "r" (vm));
+#else
+ asm volatile (
+ "int $0x80"
+ : "=a" (r)
+ : "0" (113), "b" (vm));
+#endif
+ return r;
+ }
+
+
+static struct {
+ int ready;
+ unsigned short ret_seg, ret_off;
+ unsigned short stack_seg, stack_off;
+ struct vm86_struct vm;
+ } context = {0};
+
+struct mem_block {
+ unsigned int size : 20;
+ unsigned int free : 1;
+ };
+
+static struct {
+ int ready;
+ int count;
+ struct mem_block blocks[REAL_MEM_BLOCKS];
+ } mem_info = {0};
+
+int _PM_console_fd = -1;
+int _PM_leds = 0,_PM_modifiers = 0;
+static ibool inited = false;
+static int tty_vc = 0;
+static int console_count = 0;
+static int startup_vc;
+static int fd_mem = 0;
+static ibool in_raw_mode = false;
+#ifdef ENABLE_MTRR
+static int mtrr_fd;
+#endif
+static uint VESABuf_len = 1024; /* Length of the VESABuf buffer */
+static void *VESABuf_ptr = NULL; /* Near pointer to VESABuf */
+static uint VESABuf_rseg; /* Real mode segment of VESABuf */
+static uint VESABuf_roff; /* Real mode offset of VESABuf */
+#ifdef TRACE_IO
+static ulong traceAddr;
+#endif
+
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+#ifdef TRACE_IO
+extern void printk(char *msg,...);
+#endif
+
+static inline void port_out(int value, int port)
+{
+#ifdef TRACE_IO
+ printk("%04X:%04X: outb.%04X <- %02X\n", traceAddr >> 16, traceAddr & 0xFFFF, (ushort)port, (uchar)value);
+#endif
+ asm volatile ("outb %0,%1"
+ ::"a" ((unsigned char) value), "d"((unsigned short) port));
+}
+
+static inline void port_outw(int value, int port)
+{
+#ifdef TRACE_IO
+ printk("%04X:%04X: outw.%04X <- %04X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ushort)value);
+#endif
+ asm volatile ("outw %0,%1"
+ ::"a" ((unsigned short) value), "d"((unsigned short) port));
+}
+
+static inline void port_outl(int value, int port)
+{
+#ifdef TRACE_IO
+ printk("%04X:%04X: outl.%04X <- %08X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ulong)value);
+#endif
+ asm volatile ("outl %0,%1"
+ ::"a" ((unsigned long) value), "d"((unsigned short) port));
+}
+
+static inline unsigned int port_in(int port)
+{
+ unsigned char value;
+ asm volatile ("inb %1,%0"
+ :"=a" ((unsigned char)value)
+ :"d"((unsigned short) port));
+#ifdef TRACE_IO
+ printk("%04X:%04X: inb.%04X -> %02X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (uchar)value);
+#endif
+ return value;
+}
+
+static inline unsigned int port_inw(int port)
+{
+ unsigned short value;
+ asm volatile ("inw %1,%0"
+ :"=a" ((unsigned short)value)
+ :"d"((unsigned short) port));
+#ifdef TRACE_IO
+ printk("%04X:%04X: inw.%04X -> %04X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ushort)value);
+#endif
+ return value;
+}
+
+static inline unsigned int port_inl(int port)
+{
+ unsigned long value;
+ asm volatile ("inl %1,%0"
+ :"=a" ((unsigned long)value)
+ :"d"((unsigned short) port));
+#ifdef TRACE_IO
+ printk("%04X:%04X: inl.%04X -> %08X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ulong)value);
+#endif
+ return value;
+}
+
+static int real_mem_init(void)
+{
+ void *m;
+ int fd_zero;
+
+ if (mem_info.ready)
+ return 1;
+
+ if ((fd_zero = open("/dev/zero", O_RDONLY)) == -1)
+ PM_fatalError("You must have root privledges to run this program!");
+ if ((m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, fd_zero, 0)) == (void *)-1) {
+ close(fd_zero);
+ PM_fatalError("You must have root privledges to run this program!");
+ }
+ mem_info.ready = 1;
+ mem_info.count = 1;
+ mem_info.blocks[0].size = REAL_MEM_SIZE;
+ mem_info.blocks[0].free = 1;
+ return 1;
+}
+
+static void insert_block(int i)
+{
+ memmove(
+ mem_info.blocks + i + 1,
+ mem_info.blocks + i,
+ (mem_info.count - i) * sizeof(struct mem_block));
+ mem_info.count++;
+}
+
+static void delete_block(int i)
+{
+ mem_info.count--;
+
+ memmove(
+ mem_info.blocks + i,
+ mem_info.blocks + i + 1,
+ (mem_info.count - i) * sizeof(struct mem_block));
+}
+
+static inline void set_bit(unsigned int bit, void *array)
+{
+ unsigned char *a = array;
+ a[bit / 8] |= (1 << (bit % 8));
+}
+
+static inline unsigned int get_int_seg(int i)
+{
+ return *(unsigned short *)(i * 4 + 2);
+}
+
+static inline unsigned int get_int_off(int i)
+{
+ return *(unsigned short *)(i * 4);
+}
+
+static inline void pushw(unsigned short i)
+{
+ struct vm86_regs *r = &context.vm.regs;
+ r->esp -= 2;
+ *(unsigned short *)(((unsigned int)r->ss << 4) + r->esp) = i;
+}
+
+ibool PMAPI PM_haveBIOSAccess(void)
+{ return true; }
+
+void PMAPI PM_init(void)
+{
+ void *m;
+ uint r_seg,r_off;
+
+ if (inited)
+ return;
+
+ /* Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502)
+ * and the physical framebuffer and ROM images from (0xa0000 - 0x100000)
+ */
+ real_mem_init();
+ if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1) {
+ PM_fatalError("You must have root privileges to run this program!");
+ }
+ if ((m = mmap((void *)0, 0x502,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, fd_mem, 0)) == (void *)-1) {
+ PM_fatalError("You must have root privileges to run this program!");
+ }
+ if ((m = mmap((void *)0xA0000, 0xC0000 - 0xA0000,
+ PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED, fd_mem, 0xA0000)) == (void *)-1) {
+ PM_fatalError("You must have root privileges to run this program!");
+ }
+ if ((m = mmap((void *)0xC0000, 0xD0000 - 0xC0000,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, fd_mem, 0xC0000)) == (void *)-1) {
+ PM_fatalError("You must have root privileges to run this program!");
+ }
+ if ((m = mmap((void *)0xD0000, 0x100000 - 0xD0000,
+ PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED, fd_mem, 0xD0000)) == (void *)-1) {
+ PM_fatalError("You must have root privileges to run this program!");
+ }
+ inited = 1;
+
+ /* Allocate a stack */
+ m = PM_allocRealSeg(DEFAULT_STACK_SIZE,&r_seg,&r_off);
+ context.stack_seg = r_seg;
+ context.stack_off = r_off+DEFAULT_STACK_SIZE;
+
+ /* Allocate the return to 32 bit routine */
+ m = PM_allocRealSeg(2,&r_seg,&r_off);
+ context.ret_seg = r_seg;
+ context.ret_off = r_off;
+ ((uchar*)m)[0] = 0xCD; /* int opcode */
+ ((uchar*)m)[1] = RETURN_TO_32_INT;
+ memset(&context.vm, 0, sizeof(context.vm));
+
+ /* Enable kernel emulation of all ints except RETURN_TO_32_INT */
+ memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored));
+ set_bit(RETURN_TO_32_INT, &context.vm.int_revectored);
+ context.ready = 1;
+#ifdef ENABLE_MTRR
+ mtrr_fd = open("/dev/cpu/mtrr", O_RDWR, 0);
+ if (mtrr_fd < 0)
+ mtrr_fd = open("/proc/mtrr", O_RDWR, 0);
+#endif
+ /* Enable I/O permissions to directly access I/O ports. We break the
+ * allocation into two parts, one for the ports from 0-0x3FF and
+ * another for the remaining ports up to 0xFFFF. Standard Linux kernels
+ * only allow the first 0x400 ports to be enabled, so to enable all
+ * 65536 ports you need a patched kernel that will enable the full
+ * 8Kb I/O permissions bitmap.
+ */
+#ifndef TRACE_IO
+ ioperm(0x0,0x400,1);
+ ioperm(0x400,0x10000-0x400,1);
+#endif
+ iopl(3);
+}
+
+long PMAPI PM_getOSType(void)
+{ return _OS_LINUX; }
+
+int PMAPI PM_getModeType(void)
+{ return PM_386; }
+
+void PMAPI PM_backslash(char *s)
+{
+ uint pos = strlen(s);
+ if (s[pos-1] != '/') {
+ s[pos] = '/';
+ s[pos+1] = '\0';
+ }
+}
+
+void PMAPI PM_setFatalErrorCleanup(
+ void (PMAPIP cleanup)(void))
+{
+ fatalErrorCleanup = cleanup;
+}
+
+void PMAPI PM_fatalError(const char *msg)
+{
+ if (fatalErrorCleanup)
+ fatalErrorCleanup();
+ fprintf(stderr,"%s\n", msg);
+ fflush(stderr);
+ exit(1);
+}
+
+static void ExitVBEBuf(void)
+{
+ if (VESABuf_ptr)
+ PM_freeRealSeg(VESABuf_ptr);
+ VESABuf_ptr = 0;
+}
+
+void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff)
+{
+ if (!VESABuf_ptr) {
+ /* Allocate a global buffer for communicating with the VESA VBE */
+ if ((VESABuf_ptr = PM_allocRealSeg(VESABuf_len, &VESABuf_rseg, &VESABuf_roff)) == NULL)
+ return NULL;
+ atexit(ExitVBEBuf);
+ }
+ *len = VESABuf_len;
+ *rseg = VESABuf_rseg;
+ *roff = VESABuf_roff;
+ return VESABuf_ptr;
+}
+
+/* New raw console based getch and kbhit functions */
+
+#define KB_CAPS LED_CAP /* 4 */
+#define KB_NUMLOCK LED_NUM /* 2 */
+#define KB_SCROLL LED_SCR /* 1 */
+#define KB_SHIFT 8
+#define KB_CONTROL 16
+#define KB_ALT 32
+
+/* Structure used to save the keyboard mode to disk. We save it to disk
+ * so that we can properly restore the mode later if the program crashed.
+ */
+
+typedef struct {
+ struct termios termios;
+ int kb_mode;
+ int leds;
+ int flags;
+ int startup_vc;
+ } keyboard_mode;
+
+/* Name of the file used to save keyboard mode information */
+
+#define KBMODE_DAT "kbmode.dat"
+
+/****************************************************************************
+REMARKS:
+Open the keyboard mode file on disk.
+****************************************************************************/
+static FILE *open_kb_mode(
+ char *mode,
+ char *path)
+{
+ if (!PM_findBPD("graphics.bpd",path))
+ return NULL;
+ PM_backslash(path);
+ strcat(path,KBMODE_DAT);
+ return fopen(path,mode);
+}
+
+/****************************************************************************
+REMARKS:
+Restore the keyboard to normal mode
+****************************************************************************/
+void _PM_restore_kb_mode(void)
+{
+ FILE *kbmode;
+ keyboard_mode mode;
+ char path[PM_MAX_PATH];
+
+ if (_PM_console_fd != -1 && (kbmode = open_kb_mode("rb",path)) != NULL) {
+ if (fread(&mode,1,sizeof(mode),kbmode) == sizeof(mode)) {
+ if (mode.startup_vc > 0)
+ ioctl(_PM_console_fd, VT_ACTIVATE, mode.startup_vc);
+ ioctl(_PM_console_fd, KDSKBMODE, mode.kb_mode);
+ ioctl(_PM_console_fd, KDSETLED, mode.leds);
+ tcsetattr(_PM_console_fd, TCSAFLUSH, &mode.termios);
+ fcntl(_PM_console_fd,F_SETFL,mode.flags);
+ }
+ fclose(kbmode);
+ unlink(path);
+ in_raw_mode = false;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _PM_abort(
+ int signo)
+{
+ char buf[80];
+
+ sprintf(buf,"Terminating on signal %d",signo);
+ _PM_restore_kb_mode();
+ PM_fatalError(buf);
+}
+
+/****************************************************************************
+REMARKS:
+Put the keyboard into raw mode
+****************************************************************************/
+void _PM_keyboard_rawmode(void)
+{
+ struct termios conf;
+ FILE *kbmode;
+ keyboard_mode mode;
+ char path[PM_MAX_PATH];
+ int i;
+ static int sig_list[] = {
+ SIGHUP,
+ SIGINT,
+ SIGQUIT,
+ SIGILL,
+ SIGTRAP,
+ SIGABRT,
+ SIGIOT,
+ SIGBUS,
+ SIGFPE,
+ SIGKILL,
+ SIGSEGV,
+ SIGTERM,
+ };
+
+ if ((kbmode = open_kb_mode("rb",path)) == NULL) {
+ if ((kbmode = open_kb_mode("wb",path)) == NULL)
+ PM_fatalError("Unable to open kbmode.dat file for writing!");
+ if (ioctl(_PM_console_fd, KDGKBMODE, &mode.kb_mode))
+ perror("KDGKBMODE");
+ ioctl(_PM_console_fd, KDGETLED, &mode.leds);
+ _PM_leds = mode.leds & 0xF;
+ _PM_modifiers = 0;
+ tcgetattr(_PM_console_fd, &mode.termios);
+ conf = mode.termios;
+ conf.c_lflag &= ~(ICANON | ECHO | ISIG);
+ conf.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
+ conf.c_iflag |= (IGNBRK | IGNPAR);
+ conf.c_cc[VMIN] = 1;
+ conf.c_cc[VTIME] = 0;
+ conf.c_cc[VSUSP] = 0;
+ tcsetattr(_PM_console_fd, TCSAFLUSH, &conf);
+ mode.flags = fcntl(_PM_console_fd,F_GETFL);
+ if (ioctl(_PM_console_fd, KDSKBMODE, K_MEDIUMRAW))
+ perror("KDSKBMODE");
+ atexit(_PM_restore_kb_mode);
+ for (i = 0; i < sizeof(sig_list)/sizeof(sig_list[0]); i++)
+ signal(sig_list[i], _PM_abort);
+ mode.startup_vc = startup_vc;
+ if (fwrite(&mode,1,sizeof(mode),kbmode) != sizeof(mode))
+ PM_fatalError("Error writing kbmode.dat!");
+ fclose(kbmode);
+ in_raw_mode = true;
+ }
+}
+
+int PMAPI PM_kbhit(void)
+{
+ fd_set s;
+ struct timeval tv = { 0, 0 };
+
+ if (console_count == 0)
+ PM_fatalError("You *must* open a console before using PM_kbhit!");
+ if (!in_raw_mode)
+ _PM_keyboard_rawmode();
+ FD_ZERO(&s);
+ FD_SET(_PM_console_fd, &s);
+ return select(_PM_console_fd+1, &s, NULL, NULL, &tv) > 0;
+}
+
+int PMAPI PM_getch(void)
+{
+ static uchar c;
+ int release;
+ static struct kbentry ke;
+
+ if (console_count == 0)
+ PM_fatalError("You *must* open a console before using PM_getch!");
+ if (!in_raw_mode)
+ _PM_keyboard_rawmode();
+ while (read(_PM_console_fd, &c, 1) > 0) {
+ release = c & 0x80;
+ c &= 0x7F;
+ if (release) {
+ switch(c){
+ case 42: case 54: // Shift
+ _PM_modifiers &= ~KB_SHIFT;
+ break;
+ case 29: case 97: // Control
+ _PM_modifiers &= ~KB_CONTROL;
+ break;
+ case 56: case 100: // Alt / AltGr
+ _PM_modifiers &= ~KB_ALT;
+ break;
+ }
+ continue;
+ }
+ switch (c) {
+ case 42: case 54: // Shift
+ _PM_modifiers |= KB_SHIFT;
+ break;
+ case 29: case 97: // Control
+ _PM_modifiers |= KB_CONTROL;
+ break;
+ case 56: case 100: // Alt / AltGr
+ _PM_modifiers |= KB_ALT;
+ break;
+ case 58: // Caps Lock
+ _PM_modifiers ^= KB_CAPS;
+ ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
+ break;
+ case 69: // Num Lock
+ _PM_modifiers ^= KB_NUMLOCK;
+ ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
+ break;
+ case 70: // Scroll Lock
+ _PM_modifiers ^= KB_SCROLL;
+ ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
+ break;
+ case 28:
+ return 0x1C;
+ default:
+ ke.kb_index = c;
+ ke.kb_table = 0;
+ if ((_PM_modifiers & KB_SHIFT) || (_PM_modifiers & KB_CAPS))
+ ke.kb_table |= K_SHIFTTAB;
+ if (_PM_modifiers & KB_ALT)
+ ke.kb_table |= K_ALTTAB;
+ ioctl(_PM_console_fd, KDGKBENT, (ulong)&ke);
+ c = ke.kb_value & 0xFF;
+ return c;
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Sleep until the virtual terminal is active
+****************************************************************************/
+static void wait_vt_active(
+ int _PM_console_fd)
+{
+ while (ioctl(_PM_console_fd, VT_WAITACTIVE, tty_vc) < 0) {
+ if ((errno != EAGAIN) && (errno != EINTR)) {
+ perror("ioctl(VT_WAITACTIVE)");
+ exit(1);
+ }
+ usleep(150000);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Checks the owner of the specified virtual console.
+****************************************************************************/
+static int check_owner(
+ int vc)
+{
+ struct stat sbuf;
+ char fname[30];
+
+ sprintf(fname, "/dev/tty%d", vc);
+ if ((stat(fname, &sbuf) >= 0) && (getuid() == sbuf.st_uid))
+ return 1;
+ printf("You must be the owner of the current console to use this program.\n");
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Checks if the console is currently in graphics mode, and if so we forcibly
+restore it back to text mode again. This handles the case when a Nucleus or
+MGL program crashes and leaves the console in graphics mode. Running the
+textmode utility (or any other Nucleus/MGL program) via a telnet session
+into the machine will restore it back to normal.
+****************************************************************************/
+static void restore_text_console(
+ int console_id)
+{
+ if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0)
+ LOGWARN("ioctl(KDSETMODE) failed");
+ _PM_restore_kb_mode();
+}
+
+/****************************************************************************
+REMARKS:
+Opens up the console device for output by finding an appropriate virutal
+console that we can run on.
+****************************************************************************/
+PM_HWND PMAPI PM_openConsole(
+ PM_HWND hwndUser,
+ int device,
+ int xRes,
+ int yRes,
+ int bpp,
+ ibool fullScreen)
+{
+ struct vt_mode vtm;
+ struct vt_stat vts;
+ struct stat sbuf;
+ char fname[30];
+
+ /* Check if we have already opened the console */
+ if (console_count++)
+ return _PM_console_fd;
+
+ /* Now, it would be great if we could use /dev/tty and see what it is
+ * connected to. Alas, we cannot find out reliably what VC /dev/tty is
+ * bound to. Thus we parse stdin through stderr for a reliable VC.
+ */
+ startup_vc = 0;
+ for (_PM_console_fd = 0; _PM_console_fd < 3; _PM_console_fd++) {
+ if (fstat(_PM_console_fd, &sbuf) < 0)
+ continue;
+ if (ioctl(_PM_console_fd, VT_GETMODE, &vtm) < 0)
+ continue;
+ if ((sbuf.st_rdev & 0xFF00) != 0x400)
+ continue;
+ if (!(sbuf.st_rdev & 0xFF))
+ continue;
+ tty_vc = sbuf.st_rdev & 0xFF;
+ restore_text_console(_PM_console_fd);
+ return _PM_console_fd;
+ }
+ if ((_PM_console_fd = open("/dev/console", O_RDWR)) < 0) {
+ printf("open_dev_console: can't open /dev/console \n");
+ exit(1);
+ }
+ if (ioctl(_PM_console_fd, VT_OPENQRY, &tty_vc) < 0)
+ goto Error;
+ if (tty_vc <= 0)
+ goto Error;
+ sprintf(fname, "/dev/tty%d", tty_vc);
+ close(_PM_console_fd);
+
+ /* Change our control terminal */
+ setsid();
+
+ /* We must use RDWR to allow for output... */
+ if (((_PM_console_fd = open(fname, O_RDWR)) >= 0) &&
+ (ioctl(_PM_console_fd, VT_GETSTATE, &vts) >= 0)) {
+ if (!check_owner(vts.v_active))
+ goto Error;
+ restore_text_console(_PM_console_fd);
+
+ /* Success, redirect all stdios */
+ fflush(stdin);
+ fflush(stdout);
+ fflush(stderr);
+ close(0);
+ close(1);
+ close(2);
+ dup(_PM_console_fd);
+ dup(_PM_console_fd);
+ dup(_PM_console_fd);
+
+ /* clear screen and switch to it */
+ fwrite("\e[H\e[J", 6, 1, stderr);
+ fflush(stderr);
+ if (tty_vc != vts.v_active) {
+ startup_vc = vts.v_active;
+ ioctl(_PM_console_fd, VT_ACTIVATE, tty_vc);
+ wait_vt_active(_PM_console_fd);
+ }
+ }
+ return _PM_console_fd;
+
+Error:
+ if (_PM_console_fd > 2)
+ close(_PM_console_fd);
+ console_count = 0;
+ PM_fatalError(
+ "Not running in a graphics capable console,\n"
+ "and unable to find one.\n");
+ return -1;
+}
+
+#define FONT_C 0x10000 /* 64KB for font data */
+
+/****************************************************************************
+REMARKS:
+Returns the size of the console state buffer.
+****************************************************************************/
+int PMAPI PM_getConsoleStateSize(void)
+{
+ if (!inited)
+ PM_init();
+ return PM_getVGAStateSize() + FONT_C*2;
+}
+
+/****************************************************************************
+REMARKS:
+Save the state of the Linux console.
+****************************************************************************/
+void PMAPI PM_saveConsoleState(void *stateBuf,int console_id)
+{
+ uchar *regs = stateBuf;
+
+ /* Save the current console font */
+ if (ioctl(console_id,GIO_FONT,&regs[PM_getVGAStateSize()]) < 0)
+ perror("ioctl(GIO_FONT)");
+
+ /* Inform the Linux console that we are going into graphics mode */
+ if (ioctl(console_id, KDSETMODE, KD_GRAPHICS) < 0)
+ perror("ioctl(KDSETMODE)");
+
+ /* Save state of VGA registers */
+ PM_saveVGAState(stateBuf);
+}
+
+void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
+{
+ /* TODO: Implement support for allowing console switching! */
+}
+
+/****************************************************************************
+REMARKS:
+Restore the state of the Linux console.
+****************************************************************************/
+void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND console_id)
+{
+ const uchar *regs = stateBuf;
+
+ /* Restore the state of the VGA compatible registers */
+ PM_restoreVGAState(stateBuf);
+
+ /* Inform the Linux console that we are back from graphics modes */
+ if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0)
+ LOGWARN("ioctl(KDSETMODE) failed");
+
+ /* Restore the old console font */
+ if (ioctl(console_id,PIO_FONT,&regs[PM_getVGAStateSize()]) < 0)
+ LOGWARN("ioctl(KDSETMODE) failed");
+
+ /* Coming back from graphics mode on Linux also restored the previous
+ * text mode console contents, so we need to clear the screen to get
+ * around this since the cursor does not get homed by our code.
+ */
+ fflush(stdout);
+ fflush(stderr);
+ printf("\033[H\033[J");
+ fflush(stdout);
+}
+
+/****************************************************************************
+REMARKS:
+Close the Linux console and put it back to normal.
+****************************************************************************/
+void PMAPI PM_closeConsole(PM_HWND _PM_console_fd)
+{
+ /* Restore console to normal operation */
+ if (--console_count == 0) {
+ /* Re-activate the original virtual console */
+ if (startup_vc > 0)
+ ioctl(_PM_console_fd, VT_ACTIVATE, startup_vc);
+
+ /* Close the console file descriptor */
+ if (_PM_console_fd > 2)
+ close(_PM_console_fd);
+ _PM_console_fd = -1;
+ }
+}
+
+void PM_setOSCursorLocation(int x,int y)
+{
+ /* Nothing to do in here */
+}
+
+/****************************************************************************
+REMARKS:
+Set the screen width and height for the Linux console.
+****************************************************************************/
+void PM_setOSScreenWidth(int width,int height)
+{
+ struct winsize ws;
+ struct vt_sizes vs;
+
+ // Resize the software terminal
+ ws.ws_col = width;
+ ws.ws_row = height;
+ ioctl(_PM_console_fd, TIOCSWINSZ, &ws);
+
+ // And the hardware
+ vs.v_rows = height;
+ vs.v_cols = width;
+ vs.v_scrollsize = 0;
+ ioctl(_PM_console_fd, VT_RESIZE, &vs);
+}
+
+ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler ih, int frequency)
+{
+ // TODO: Implement this for Linux
+ return false;
+}
+
+void PMAPI PM_setRealTimeClockFrequency(int frequency)
+{
+ // TODO: Implement this for Linux
+}
+
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ // TODO: Implement this for Linux
+}
+
+char * PMAPI PM_getCurrentPath(
+ char *path,
+ int maxLen)
+{
+ return getcwd(path,maxLen);
+}
+
+char PMAPI PM_getBootDrive(void)
+{ return '/'; }
+
+const char * PMAPI PM_getVBEAFPath(void)
+{ return PM_getNucleusConfigPath(); }
+
+const char * PMAPI PM_getNucleusPath(void)
+{
+ char *env = getenv("NUCLEUS_PATH");
+ return env ? env : "/usr/lib/nucleus";
+}
+
+const char * PMAPI PM_getNucleusConfigPath(void)
+{
+ static char path[256];
+ strcpy(path,PM_getNucleusPath());
+ PM_backslash(path);
+ strcat(path,"config");
+ return path;
+}
+
+const char * PMAPI PM_getUniqueID(void)
+{
+ static char buf[128];
+ gethostname(buf, 128);
+ return buf;
+}
+
+const char * PMAPI PM_getMachineName(void)
+{
+ static char buf[128];
+ gethostname(buf, 128);
+ return buf;
+}
+
+void * PMAPI PM_getBIOSPointer(void)
+{
+ static uchar *zeroPtr = NULL;
+ if (!zeroPtr)
+ zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
+ return (void*)(zeroPtr + 0x400);
+}
+
+void * PMAPI PM_getA0000Pointer(void)
+{
+ /* PM_init maps in the 0xA0000 framebuffer region 1:1 with our
+ * address mapping, so we can return the address here.
+ */
+ if (!inited)
+ PM_init();
+ return (void*)(0xA0000);
+}
+
+void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{
+ uchar *p;
+ ulong baseAddr,baseOfs;
+
+ if (!inited)
+ PM_init();
+ if (base >= 0xA0000 && base < 0x100000)
+ return (void*)base;
+ if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1)
+ return NULL;
+
+ /* Round the physical address to a 4Kb boundary and the limit to a
+ * 4Kb-1 boundary before passing the values to mmap. If we round the
+ * physical address, then we also add an extra offset into the address
+ * that we return.
+ */
+ baseOfs = base & 4095;
+ baseAddr = base & ~4095;
+ limit = ((limit+baseOfs+1+4095) & ~4095)-1;
+ if ((p = mmap(0, limit+1,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd_mem, baseAddr)) == (void *)-1)
+ return NULL;
+ return (void*)(p+baseOfs);
+}
+
+void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
+{
+ if ((ulong)ptr >= 0x100000)
+ munmap(ptr,limit+1);
+}
+
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{
+ // TODO: This function should find the physical address of a linear
+ // address.
+ return 0xFFFFFFFFUL;
+}
+
+ibool PMAPI PM_getPhysicalAddrRange(void *p,ulong length,ulong *physAddress)
+{
+ // TODO: This function should find a range of physical addresses
+ // for a linear address.
+ return false;
+}
+
+void PMAPI PM_sleep(ulong milliseconds)
+{
+ // TODO: Put the process to sleep for milliseconds
+}
+
+int PMAPI PM_getCOMPort(int port)
+{
+ // TODO: Re-code this to determine real values using the Plug and Play
+ // manager for the OS.
+ switch (port) {
+ case 0: return 0x3F8;
+ case 1: return 0x2F8;
+ }
+ return 0;
+}
+
+int PMAPI PM_getLPTPort(int port)
+{
+ // TODO: Re-code this to determine real values using the Plug and Play
+ // manager for the OS.
+ switch (port) {
+ case 0: return 0x3BC;
+ case 1: return 0x378;
+ case 2: return 0x278;
+ }
+ return 0;
+}
+
+void * PMAPI PM_mallocShared(long size)
+{
+ return PM_malloc(size);
+}
+
+void PMAPI PM_freeShared(void *ptr)
+{
+ PM_free(ptr);
+}
+
+void * PMAPI PM_mapToProcess(void *base,ulong limit)
+{ return (void*)base; }
+
+void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
+{
+ /* PM_init maps in the 0xA0000-0x100000 region 1:1 with our
+ * address mapping, as well as all memory blocks in a 1:1 address
+ * mapping so we can simply return the physical address in here.
+ */
+ if (!inited)
+ PM_init();
+ return (void*)MK_PHYS(r_seg,r_off);
+}
+
+void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
+{
+ int i;
+ char *r = (char *)REAL_MEM_BASE;
+
+ if (!inited)
+ PM_init();
+ if (!mem_info.ready)
+ return NULL;
+ if (mem_info.count == REAL_MEM_BLOCKS)
+ return NULL;
+ size = (size + 15) & ~15;
+ for (i = 0; i < mem_info.count; i++) {
+ if (mem_info.blocks[i].free && size < mem_info.blocks[i].size) {
+ insert_block(i);
+ mem_info.blocks[i].size = size;
+ mem_info.blocks[i].free = 0;
+ mem_info.blocks[i + 1].size -= size;
+ *r_seg = (uint)(r) >> 4;
+ *r_off = (uint)(r) & 0xF;
+ return (void *)r;
+ }
+ r += mem_info.blocks[i].size;
+ }
+ return NULL;
+}
+
+void PMAPI PM_freeRealSeg(void *mem)
+{
+ int i;
+ char *r = (char *)REAL_MEM_BASE;
+
+ if (!mem_info.ready)
+ return;
+ i = 0;
+ while (mem != (void *)r) {
+ r += mem_info.blocks[i].size;
+ i++;
+ if (i == mem_info.count)
+ return;
+ }
+ mem_info.blocks[i].free = 1;
+ if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free) {
+ mem_info.blocks[i].size += mem_info.blocks[i + 1].size;
+ delete_block(i + 1);
+ }
+ if (i - 1 >= 0 && mem_info.blocks[i - 1].free) {
+ mem_info.blocks[i - 1].size += mem_info.blocks[i].size;
+ delete_block(i);
+ }
+}
+
+#define DIRECTION_FLAG (1 << 10)
+
+static void em_ins(int size)
+{
+ unsigned int edx, edi;
+
+ edx = context.vm.regs.edx & 0xffff;
+ edi = context.vm.regs.edi & 0xffff;
+ edi += (unsigned int)context.vm.regs.ds << 4;
+ if (context.vm.regs.eflags & DIRECTION_FLAG) {
+ if (size == 4)
+ asm volatile ("std; insl; cld"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ else if (size == 2)
+ asm volatile ("std; insw; cld"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ else
+ asm volatile ("std; insb; cld"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ }
+ else {
+ if (size == 4)
+ asm volatile ("cld; insl"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ else if (size == 2)
+ asm volatile ("cld; insw"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ else
+ asm volatile ("cld; insb"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ }
+ edi -= (unsigned int)context.vm.regs.ds << 4;
+ context.vm.regs.edi &= 0xffff0000;
+ context.vm.regs.edi |= edi & 0xffff;
+}
+
+static void em_rep_ins(int size)
+{
+ unsigned int ecx, edx, edi;
+
+ ecx = context.vm.regs.ecx & 0xffff;
+ edx = context.vm.regs.edx & 0xffff;
+ edi = context.vm.regs.edi & 0xffff;
+ edi += (unsigned int)context.vm.regs.ds << 4;
+ if (context.vm.regs.eflags & DIRECTION_FLAG) {
+ if (size == 4)
+ asm volatile ("std; rep; insl; cld"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ else if (size == 2)
+ asm volatile ("std; rep; insw; cld"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ else
+ asm volatile ("std; rep; insb; cld"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ }
+ else {
+ if (size == 4)
+ asm volatile ("cld; rep; insl"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ else if (size == 2)
+ asm volatile ("cld; rep; insw"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ else
+ asm volatile ("cld; rep; insb"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ }
+
+ edi -= (unsigned int)context.vm.regs.ds << 4;
+ context.vm.regs.edi &= 0xffff0000;
+ context.vm.regs.edi |= edi & 0xffff;
+ context.vm.regs.ecx &= 0xffff0000;
+ context.vm.regs.ecx |= ecx & 0xffff;
+}
+
+static void em_outs(int size)
+{
+ unsigned int edx, esi;
+
+ edx = context.vm.regs.edx & 0xffff;
+ esi = context.vm.regs.esi & 0xffff;
+ esi += (unsigned int)context.vm.regs.ds << 4;
+ if (context.vm.regs.eflags & DIRECTION_FLAG) {
+ if (size == 4)
+ asm volatile ("std; outsl; cld"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ else if (size == 2)
+ asm volatile ("std; outsw; cld"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ else
+ asm volatile ("std; outsb; cld"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ }
+ else {
+ if (size == 4)
+ asm volatile ("cld; outsl"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ else if (size == 2)
+ asm volatile ("cld; outsw"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ else
+ asm volatile ("cld; outsb"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ }
+
+ esi -= (unsigned int)context.vm.regs.ds << 4;
+ context.vm.regs.esi &= 0xffff0000;
+ context.vm.regs.esi |= esi & 0xffff;
+}
+
+static void em_rep_outs(int size)
+{
+ unsigned int ecx, edx, esi;
+
+ ecx = context.vm.regs.ecx & 0xffff;
+ edx = context.vm.regs.edx & 0xffff;
+ esi = context.vm.regs.esi & 0xffff;
+ esi += (unsigned int)context.vm.regs.ds << 4;
+ if (context.vm.regs.eflags & DIRECTION_FLAG) {
+ if (size == 4)
+ asm volatile ("std; rep; outsl; cld"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ else if (size == 2)
+ asm volatile ("std; rep; outsw; cld"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ else
+ asm volatile ("std; rep; outsb; cld"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ }
+ else {
+ if (size == 4)
+ asm volatile ("cld; rep; outsl"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ else if (size == 2)
+ asm volatile ("cld; rep; outsw"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ else
+ asm volatile ("cld; rep; outsb"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ }
+
+ esi -= (unsigned int)context.vm.regs.ds << 4;
+ context.vm.regs.esi &= 0xffff0000;
+ context.vm.regs.esi |= esi & 0xffff;
+ context.vm.regs.ecx &= 0xffff0000;
+ context.vm.regs.ecx |= ecx & 0xffff;
+}
+
+static int emulate(void)
+{
+ unsigned char *insn;
+ struct {
+ unsigned int size : 1;
+ unsigned int rep : 1;
+ } prefix = { 0, 0 };
+ int i = 0;
+
+ insn = (unsigned char *)((unsigned int)context.vm.regs.cs << 4);
+ insn += context.vm.regs.eip;
+
+ while (1) {
+#ifdef TRACE_IO
+ traceAddr = ((ulong)context.vm.regs.cs << 16) + context.vm.regs.eip + i;
+#endif
+ if (insn[i] == 0x66) {
+ prefix.size = 1 - prefix.size;
+ i++;
+ }
+ else if (insn[i] == 0xf3) {
+ prefix.rep = 1;
+ i++;
+ }
+ else if (insn[i] == 0xf0 || insn[i] == 0xf2
+ || insn[i] == 0x26 || insn[i] == 0x2e
+ || insn[i] == 0x36 || insn[i] == 0x3e
+ || insn[i] == 0x64 || insn[i] == 0x65
+ || insn[i] == 0x67) {
+ /* these prefixes are just ignored */
+ i++;
+ }
+ else if (insn[i] == 0x6c) {
+ if (prefix.rep)
+ em_rep_ins(1);
+ else
+ em_ins(1);
+ i++;
+ break;
+ }
+ else if (insn[i] == 0x6d) {
+ if (prefix.rep) {
+ if (prefix.size)
+ em_rep_ins(4);
+ else
+ em_rep_ins(2);
+ }
+ else {
+ if (prefix.size)
+ em_ins(4);
+ else
+ em_ins(2);
+ }
+ i++;
+ break;
+ }
+ else if (insn[i] == 0x6e) {
+ if (prefix.rep)
+ em_rep_outs(1);
+ else
+ em_outs(1);
+ i++;
+ break;
+ }
+ else if (insn[i] == 0x6f) {
+ if (prefix.rep) {
+ if (prefix.size)
+ em_rep_outs(4);
+ else
+ em_rep_outs(2);
+ }
+ else {
+ if (prefix.size)
+ em_outs(4);
+ else
+ em_outs(2);
+ }
+ i++;
+ break;
+ }
+ else if (insn[i] == 0xec) {
+ *((uchar*)&context.vm.regs.eax) = port_in(context.vm.regs.edx);
+ i++;
+ break;
+ }
+ else if (insn[i] == 0xed) {
+ if (prefix.size)
+ *((ulong*)&context.vm.regs.eax) = port_inl(context.vm.regs.edx);
+ else
+ *((ushort*)&context.vm.regs.eax) = port_inw(context.vm.regs.edx);
+ i++;
+ break;
+ }
+ else if (insn[i] == 0xee) {
+ port_out(context.vm.regs.eax,context.vm.regs.edx);
+ i++;
+ break;
+ }
+ else if (insn[i] == 0xef) {
+ if (prefix.size)
+ port_outl(context.vm.regs.eax,context.vm.regs.edx);
+ else
+ port_outw(context.vm.regs.eax,context.vm.regs.edx);
+ i++;
+ break;
+ }
+ else
+ return 0;
+ }
+
+ context.vm.regs.eip += i;
+ return 1;
+}
+
+static void debug_info(int vret)
+{
+ int i;
+ unsigned char *p;
+
+ fputs("vm86() failed\n", stderr);
+ fprintf(stderr, "return = 0x%x\n", vret);
+ fprintf(stderr, "eax = 0x%08lx\n", context.vm.regs.eax);
+ fprintf(stderr, "ebx = 0x%08lx\n", context.vm.regs.ebx);
+ fprintf(stderr, "ecx = 0x%08lx\n", context.vm.regs.ecx);
+ fprintf(stderr, "edx = 0x%08lx\n", context.vm.regs.edx);
+ fprintf(stderr, "esi = 0x%08lx\n", context.vm.regs.esi);
+ fprintf(stderr, "edi = 0x%08lx\n", context.vm.regs.edi);
+ fprintf(stderr, "ebp = 0x%08lx\n", context.vm.regs.ebp);
+ fprintf(stderr, "eip = 0x%08lx\n", context.vm.regs.eip);
+ fprintf(stderr, "cs = 0x%04x\n", context.vm.regs.cs);
+ fprintf(stderr, "esp = 0x%08lx\n", context.vm.regs.esp);
+ fprintf(stderr, "ss = 0x%04x\n", context.vm.regs.ss);
+ fprintf(stderr, "ds = 0x%04x\n", context.vm.regs.ds);
+ fprintf(stderr, "es = 0x%04x\n", context.vm.regs.es);
+ fprintf(stderr, "fs = 0x%04x\n", context.vm.regs.fs);
+ fprintf(stderr, "gs = 0x%04x\n", context.vm.regs.gs);
+ fprintf(stderr, "eflags = 0x%08lx\n", context.vm.regs.eflags);
+ fputs("cs:ip = [ ", stderr);
+ p = (unsigned char *)((context.vm.regs.cs << 4) + (context.vm.regs.eip & 0xffff));
+ for (i = 0; i < 16; ++i)
+ fprintf(stderr, "%02x ", (unsigned int)p[i]);
+ fputs("]\n", stderr);
+ fflush(stderr);
+}
+
+static int run_vm86(void)
+{
+ unsigned int vret;
+
+ for (;;) {
+ vret = vm86(&context.vm);
+ if (VM86_TYPE(vret) == VM86_INTx) {
+ unsigned int v = VM86_ARG(vret);
+ if (v == RETURN_TO_32_INT)
+ return 1;
+ pushw(context.vm.regs.eflags);
+ pushw(context.vm.regs.cs);
+ pushw(context.vm.regs.eip);
+ context.vm.regs.cs = get_int_seg(v);
+ context.vm.regs.eip = get_int_off(v);
+ context.vm.regs.eflags &= ~(VIF_MASK | TF_MASK);
+ continue;
+ }
+ if (VM86_TYPE(vret) != VM86_UNKNOWN)
+ break;
+ if (!emulate())
+ break;
+ }
+ debug_info(vret);
+ return 0;
+}
+
+#define IND(ereg) context.vm.regs.ereg = regs->ereg
+#define OUTD(ereg) regs->ereg = context.vm.regs.ereg
+
+void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ IND(eax); IND(ebx); IND(ecx); IND(edx); IND(esi); IND(edi);
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(intno);
+ context.vm.regs.eip = get_int_off(intno);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+ OUTD(eax); OUTD(ebx); OUTD(ecx); OUTD(edx); OUTD(esi); OUTD(edi);
+ regs->flags = context.vm.regs.eflags;
+}
+
+#define IN(ereg) context.vm.regs.ereg = in->e.ereg
+#define OUT(ereg) out->e.ereg = context.vm.regs.ereg
+
+int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(intno);
+ context.vm.regs.eip = get_int_off(intno);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ out->x.cflag = context.vm.regs.eflags & 1;
+ return out->x.ax;
+}
+
+int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
+ RMSREGS *sregs)
+{
+ if (!inited)
+ PM_init();
+ if (intno == 0x21) {
+ time_t today = time(NULL);
+ struct tm *t;
+ t = localtime(&today);
+ out->x.cx = t->tm_year + 1900;
+ out->h.dh = t->tm_mon + 1;
+ out->h.dl = t->tm_mday;
+ }
+ else {
+ unsigned int seg, off;
+ seg = get_int_seg(intno);
+ off = get_int_off(intno);
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = seg;
+ context.vm.regs.eip = off;
+ context.vm.regs.es = sregs->es;
+ context.vm.regs.ds = sregs->ds;
+ context.vm.regs.fs = sregs->fs;
+ context.vm.regs.gs = sregs->gs;
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ sregs->es = context.vm.regs.es;
+ sregs->ds = context.vm.regs.ds;
+ sregs->fs = context.vm.regs.fs;
+ sregs->gs = context.vm.regs.gs;
+ out->x.cflag = context.vm.regs.eflags & 1;
+ }
+ return out->e.eax;
+}
+
+#define OUTR(ereg) in->e.ereg = context.vm.regs.ereg
+
+void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
+ RMSREGS *sregs)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = seg;
+ context.vm.regs.eip = off;
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ context.vm.regs.es = sregs->es;
+ context.vm.regs.ds = sregs->ds;
+ context.vm.regs.fs = sregs->fs;
+ context.vm.regs.gs = sregs->gs;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+ OUTR(eax); OUTR(ebx); OUTR(ecx); OUTR(edx); OUTR(esi); OUTR(edi);
+ sregs->es = context.vm.regs.es;
+ sregs->ds = context.vm.regs.ds;
+ sregs->fs = context.vm.regs.fs;
+ sregs->gs = context.vm.regs.gs;
+ in->x.cflag = context.vm.regs.eflags & 1;
+}
+
+void PMAPI PM_availableMemory(ulong *physical,ulong *total)
+{
+ FILE *mem = fopen("/proc/meminfo","r");
+ char buf[1024];
+
+ fgets(buf,1024,mem);
+ fgets(buf,1024,mem);
+ sscanf(buf,"Mem: %*d %*d %ld", physical);
+ fgets(buf,1024,mem);
+ sscanf(buf,"Swap: %*d %*d %ld", total);
+ fclose(mem);
+ *total += *physical;
+}
+
+void * PMAPI PM_allocLockedMem(uint size,ulong *physAddr,ibool contiguous,ibool below16M)
+{
+ // TODO: Implement this for Linux
+ return NULL;
+}
+
+void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous)
+{
+ // TODO: Implement this for Linux
+}
+
+void * PMAPI PM_allocPage(
+ ibool locked)
+{
+ // TODO: Implement this for Linux
+ return NULL;
+}
+
+void PMAPI PM_freePage(
+ void *p)
+{
+ // TODO: Implement this for Linux
+}
+
+void PMAPI PM_setBankA(int bank)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ context.vm.regs.eax = 0x4F05;
+ context.vm.regs.ebx = 0x0000;
+ context.vm.regs.edx = bank;
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(0x10);
+ context.vm.regs.eip = get_int_off(0x10);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+}
+
+void PMAPI PM_setBankAB(int bank)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ context.vm.regs.eax = 0x4F05;
+ context.vm.regs.ebx = 0x0000;
+ context.vm.regs.edx = bank;
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(0x10);
+ context.vm.regs.eip = get_int_off(0x10);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+ context.vm.regs.eax = 0x4F05;
+ context.vm.regs.ebx = 0x0001;
+ context.vm.regs.edx = bank;
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(0x10);
+ context.vm.regs.eip = get_int_off(0x10);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+}
+
+void PMAPI PM_setCRTStart(int x,int y,int waitVRT)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ context.vm.regs.eax = 0x4F07;
+ context.vm.regs.ebx = waitVRT;
+ context.vm.regs.ecx = x;
+ context.vm.regs.edx = y;
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(0x10);
+ context.vm.regs.eip = get_int_off(0x10);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+}
+
+int PMAPI PM_enableWriteCombine(ulong base,ulong length,uint type)
+{
+#ifdef ENABLE_MTRR
+ struct mtrr_sentry sentry;
+
+ if (mtrr_fd < 0)
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+ sentry.base = base;
+ sentry.size = length;
+ sentry.type = type;
+ if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) == -1) {
+ // TODO: Need to decode MTRR error codes!!
+ return PM_MTRR_NOT_SUPPORTED;
+ }
+ return PM_MTRR_ERR_OK;
+#else
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+#endif
+}
+
+/****************************************************************************
+PARAMETERS:
+callback - Function to callback with write combine information
+
+REMARKS:
+Function to enumerate all write combine regions currently enabled for the
+processor.
+****************************************************************************/
+int PMAPI PM_enumWriteCombine(
+ PM_enumWriteCombine_t callback)
+{
+#ifdef ENABLE_MTRR
+ struct mtrr_gentry gentry;
+
+ if (mtrr_fd < 0)
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+
+ for (gentry.regnum = 0; ioctl (mtrr_fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
+ ++gentry.regnum) {
+ if (gentry.size > 0) {
+ // WARNING: This code assumes that the types in pmapi.h match the ones
+ // in the Linux kernel (mtrr.h)
+ callback(gentry.base, gentry.size, gentry.type);
+ }
+ }
+
+ return PM_MTRR_ERR_OK;
+#else
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+#endif
+}
+
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *copyOfBIOS,
+ ulong BIOSLen)
+{
+ char *bios_ptr = (char*)0xC0000;
+ char *old_bios;
+ ulong Current10, Current6D, *rvec = 0;
+ RMREGS regs;
+ RMSREGS sregs;
+
+ /* The BIOS is mapped to 0xC0000 with a private memory mapping enabled
+ * which means we have a copy on write scheme. Hence we simply copy
+ * the secondary BIOS image over the top of the old one.
+ */
+ if (!inited)
+ PM_init();
+ if ((old_bios = PM_malloc(BIOSLen)) == NULL)
+ return false;
+ if (BIOSPhysAddr != 0xC0000) {
+ memcpy(old_bios,bios_ptr,BIOSLen);
+ memcpy(bios_ptr,copyOfBIOS,BIOSLen);
+ }
+
+ /* The interrupt vectors should already be mmap()'ed from 0-0x400 in PM_init */
+ Current10 = rvec[0x10];
+ Current6D = rvec[0x6D];
+
+ /* POST the secondary BIOS */
+ rvec[0x10] = rvec[0x42]; /* Restore int 10h to STD-BIOS */
+ regs.x.ax = axVal;
+ PM_callRealMode(0xC000,0x0003,&regs,&sregs);
+
+ /* Restore interrupt vectors */
+ rvec[0x10] = Current10;
+ rvec[0x6D] = Current6D;
+
+ /* Restore original BIOS image */
+ if (BIOSPhysAddr != 0xC0000)
+ memcpy(bios_ptr,old_bios,BIOSLen);
+ PM_free(old_bios);
+ return true;
+}
+
+int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ p = p; len = len;
+ return 1;
+}
+
+int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ p = p; len = len;
+ return 1;
+}
+
+int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ p = p; len = len;
+ return 1;
+}
+
+int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ p = p; len = len;
+ return 1;
+}
+
+PM_MODULE PMAPI PM_loadLibrary(
+ const char *szDLLName)
+{
+ // TODO: Implement this to load shared libraries!
+ (void)szDLLName;
+ return NULL;
+}
+
+void * PMAPI PM_getProcAddress(
+ PM_MODULE hModule,
+ const char *szProcName)
+{
+ // TODO: Implement this!
+ (void)hModule;
+ (void)szProcName;
+ return NULL;
+}
+
+void PMAPI PM_freeLibrary(
+ PM_MODULE hModule)
+{
+ // TODO: Implement this!
+ (void)hModule;
+}
+
+int PMAPI PM_setIOPL(
+ int level)
+{
+ // TODO: Move the IOPL switching into this function!!
+ return level;
+}
+
+void PMAPI PM_flushTLB(void)
+{
+ // Do nothing on Linux.
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/linux/vflat.c
new file mode 100644
index 0000000000..579ef2c95c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/vflat.c
@@ -0,0 +1,49 @@
+/****************************************************************************
+*
+* SciTech OS Portability Manager Library
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+*
+* Description: Dummy module; no virtual framebuffer for this OS
+*
+****************************************************************************/
+
+#include "pmapi.h"
+
+ibool PMAPI VF_available(void)
+{
+ return false;
+}
+
+void * PMAPI VF_init(ulong baseAddr,int bankSize,int codeLen,void *bankFunc)
+{
+ baseAddr = baseAddr;
+ bankSize = bankSize;
+ codeLen = codeLen;
+ bankFunc = bankFunc;
+ return NULL;
+}
+
+void PMAPI VF_exit(void)
+{
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/linux/ztimer.c
new file mode 100644
index 0000000000..1b9bae28a6
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/ztimer.c
@@ -0,0 +1,95 @@
+/****************************************************************************
+*
+* Ultra Long Period Timer
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Linux
+*
+* Description: Linux specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+#include <unistd.h>
+#include <sys/time.h>
+#include "pmapi.h"
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+void __ZTimerInit(void)
+{
+}
+
+/****************************************************************************
+REMARKS:
+Use the gettimeofday() function to get microsecond precision (probably less
+though)
+****************************************************************************/
+static inline ulong __ULZReadTime(void)
+{
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ return t.tv_sec*1000000 + t.tv_usec;
+}
+
+/****************************************************************************
+REMARKS:
+Start the Zen Timer counting.
+****************************************************************************/
+#define __LZTimerOn(tm) tm->start.low = __ULZReadTime()
+
+/****************************************************************************
+REMARKS:
+Compute the lap time since the timer was started.
+****************************************************************************/
+#define __LZTimerLap(tm) (__ULZReadTime() - tm->start.low)
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOff(tm) tm->end.low = __ULZReadTime()
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerCount(tm) (tm->end.low - tm->start.low)
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 1
+
+/****************************************************************************
+REMARKS:
+Compute the elapsed time from the BIOS timer tick. Note that we check to see
+whether a midnight boundary has passed, and if so adjust the finish time to
+account for this. We cannot detect if more that one midnight boundary has
+passed, so if this happens we will be generating erronous results.
+****************************************************************************/
+ulong __ULZElapsedTime(ulong start,ulong finish)
+{ return finish - start; }
OpenPOWER on IntegriCloud