diff options
author | Kevin | 2014-11-15 11:48:36 +0800 |
---|---|---|
committer | Kevin | 2014-11-15 11:48:36 +0800 |
commit | d04075478d378d9e15f3e1abfd14b0bd124077d4 (patch) | |
tree | 733dd964582f388b9e3e367c249946cd32a2851f /board/MAI/bios_emulator/scitech/src/pm/linux | |
download | FOSSEE-netbook-uboot-source-d04075478d378d9e15f3e1abfd14b0bd124077d4.tar.gz FOSSEE-netbook-uboot-source-d04075478d378d9e15f3e1abfd14b0bd124077d4.tar.bz2 FOSSEE-netbook-uboot-source-d04075478d378d9e15f3e1abfd14b0bd124077d4.zip |
init commit via android 4.4 uboot
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/pm/linux')
-rwxr-xr-x | board/MAI/bios_emulator/scitech/src/pm/linux/cpuinfo.c | 68 | ||||
-rwxr-xr-x | board/MAI/bios_emulator/scitech/src/pm/linux/event.c | 1360 | ||||
-rwxr-xr-x | board/MAI/bios_emulator/scitech/src/pm/linux/event.svga | 1058 | ||||
-rwxr-xr-x | board/MAI/bios_emulator/scitech/src/pm/linux/oshdr.h | 60 | ||||
-rwxr-xr-x | board/MAI/bios_emulator/scitech/src/pm/linux/pm.c | 1809 | ||||
-rwxr-xr-x | board/MAI/bios_emulator/scitech/src/pm/linux/vflat.c | 49 | ||||
-rwxr-xr-x | board/MAI/bios_emulator/scitech/src/pm/linux/ztimer.c | 95 |
7 files changed, 4499 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 100755 index 0000000..e88d210 --- /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 100755 index 0000000..ce38732 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/linux/event.c @@ -0,0 +1,1360 @@ +/**************************************************************************** +* +* 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 100755 index 0000000..c0358a0 --- /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,®s,®s); + 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 100755 index 0000000..eadedfb --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/linux/oshdr.h @@ -0,0 +1,60 @@ +/**************************************************************************** +* +* 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 100755 index 0000000..c12a835 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/linux/pm.c @@ -0,0 +1,1809 @@ +;/**************************************************************************** +* +* 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,®s[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,®s[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,®s,&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 100755 index 0000000..579ef2c --- /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 100755 index 0000000..1b9bae2 --- /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; } |