summaryrefslogtreecommitdiffstats
path: root/board/MAI/bios_emulator/scitech/src/pm
diff options
context:
space:
mode:
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/pm')
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/beos/cpuinfo.c80
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/beos/event.c199
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/beos/oshdr.h32
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/beos/pm.c539
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/beos/vflat.c49
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/beos/ztimer.c111
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/codepage/us_eng.c285
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common.c480
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_cpuinfo.asm600
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_dma.asm246
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_int64.asm309
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_joy.asm230
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_mtrr.asm272
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/_pcihelp.asm358
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/agp.c190
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/keyboard.c450
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/malloc.c205
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/mtrr.c867
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/pcilib.c747
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/unixio.c306
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/common/vgastate.c377
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/cpuinfo.c808
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/debug.c107
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/_event.asm194
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/_lztimer.asm438
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/_pm.asm656
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/_pmdos.asm1105
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/_vflat.asm652
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/cpuinfo.c72
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/event.c494
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/oshdr.h29
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/pm.c2243
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/pmdos.c1637
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/vflat.c251
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/ztimer.c111
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/event.c1115
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/cpuinfo.c68
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/event.c1361
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/event.svga1058
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/oshdr.h61
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/pm.c1810
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/vflat.c49
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/linux/ztimer.c95
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/makefile290
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/_irq.asm288
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/_pm.asm281
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/cpuinfo.c65
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/int86.c252
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/irq.c143
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/mem.c519
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/oshdr.h46
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/pm.c934
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/stdio.c331
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/stdlib.c140
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/vflat.c45
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ntdrv/ztimer.c124
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/os2/_pmos2.asm180
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/os2/cpuinfo.c66
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/os2/event.c566
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/os2/mon.h165
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/os2/oshdr.h42
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/os2/pm.c2008
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/os2/vflat.c49
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/os2/ztimer.c110
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/os2pm/event.c170
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/os2pm/oshdr.h36
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/oshdr.h70
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/photon/event.c268
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/photon/oshdr.h38
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/pm.vpw43
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/pmcommon.vpj45
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/pmdos.vpj41
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/pmlinux.vpj35
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/pmntdrv.vpj39
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/pmqnx.vpj35
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/pmvxd.vpj34
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/pmwin32.vpj35
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/qnx/_mtrrqnx.asm226
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/qnx/cpuinfo.c64
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/qnx/event.c602
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/qnx/mtrrqnx.c182
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/qnx/oshdr.h103
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/qnx/pm.c891
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/qnx/vflat.c49
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/qnx/ztimer.c91
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/rttarget/cpuinfo.c94
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/rttarget/event.c287
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/rttarget/oshdr.h34
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/rttarget/pm.c701
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/rttarget/vflat.c48
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/rttarget/ztimer.c136
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/_event.asm175
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/_lztimer.asm58
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/_pm.asm448
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/_pmsmx.asm933
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/_vflat.asm652
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/cpuinfo.c72
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/event.c368
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/oshdr.h29
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/pm.c1187
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/pmsmx.c471
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/vflat.c49
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/smx/ztimer.c115
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/stub/cpuinfo.c79
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/stub/event.c199
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/stub/oshdr.h33
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/stub/pm.c980
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/stub/vflat.c49
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/stub/ztimer.c111
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/altbrk.c90
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/altcrit.c85
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/biosptr.c92
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/block.c69
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/brk.c78
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/callreal.c107
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/checks.c100
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/cpu.c46
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/critical.c70
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/getch.c501
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/isvesa.c110
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/key.c92
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/key15.c96
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/memtest.c106
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/mouse.c109
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/restore.c82
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/rtc.c92
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/save.c70
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/showpci.c253
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/tick.c94
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/timerc.c87
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/timercpp.cpp107
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/uswc.c311
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/vftest.c78
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/tests/video.c200
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vdd/cpuinfo.c66
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vdd/fileio.c359
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vdd/oshdr.h29
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vdd/pm.c1050
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vdd/vflat.c45
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vdd/ztimer.c103
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vxd/_pm.asm299
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vxd/cpuinfo.c66
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vxd/fileio.c305
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vxd/oshdr.h29
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vxd/pm.c1360
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vxd/vflat.c45
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/vxd/ztimer.c105
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/win32/_pmwin32.asm78
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/win32/cpuinfo.c94
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/win32/ddraw.c583
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/win32/event.c460
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/win32/ntservc.c259
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/win32/oshdr.h80
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/win32/pm.c1460
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/win32/vflat.c53
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/win32/ztimer.c136
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/x11/event.c307
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/x11/oshdr.h38
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/z_samples.vpj74
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/ztimer.c517
160 files changed, 49520 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/scitech/src/pm/beos/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/beos/cpuinfo.c
new file mode 100644
index 0000000000..c8f825e25b
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/beos/cpuinfo.c
@@ -0,0 +1,80 @@
+/****************************************************************************
+*
+* 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: *** TODO: ADD YOUR OS ENVIRONMENT NAME HERE ***
+*
+* Description: Module to implement OS specific services to measure the
+* CPU frequency.
+*
+****************************************************************************/
+
+#include <OS.h>
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Increase the thread priority to maximum, if possible.
+****************************************************************************/
+static int SetMaxThreadPriority(void)
+{
+ thread_id thid = find_thread(NULL);
+ thread_info tinfo;
+ get_thread_info(thid, &tinfo);
+ set_thread_priority(thid, B_REAL_TIME_PRIORITY);
+ return tinfo.priority;
+}
+
+/****************************************************************************
+REMARKS:
+Restore the original thread priority.
+****************************************************************************/
+static void RestoreThreadPriority(
+ int priority)
+{
+ thread_id thid = find_thread(NULL);
+ set_thread_priority(thid, priority);
+}
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ // TODO: Return the frequency of the counter in here. You should try to
+ // normalise this value to be around 100,000 ticks per second.
+ freq->low = 1000000;
+ freq->high = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+
+TODO: Implement this to read the counter. It should be done as a macro
+ for accuracy.
+****************************************************************************/
+#define GetCounter(t) { *((bigtime_t*) t) = system_time(); }
diff --git a/board/MAI/bios_emulator/scitech/src/pm/beos/event.c b/board/MAI/bios_emulator/scitech/src/pm/beos/event.c
new file mode 100644
index 0000000000..4c32ce7434
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/beos/event.c
@@ -0,0 +1,199 @@
+/****************************************************************************
+*
+* 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: BeOS
+*
+* Description: BeOS implementation for the SciTech cross platform
+* event library.
+*
+****************************************************************************/
+
+/*---------------------------- Global Variables ---------------------------*/
+
+static ushort keyUpMsg[256] = {0};/* Table of key up messages */
+static int rangeX,rangeY; /* Range of mouse coordinates */
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* These are not used under non-DOS systems */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flags)
+
+/****************************************************************************
+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)
+{
+ // TODO: Implement this for your OS!
+}
+
+/****************************************************************************
+REMARKS:
+Pumps all messages in the application message queue into our event queue.
+****************************************************************************/
+static void _EVT_pumpMessages(void)
+{
+ // TODO: The purpose of this function is to read all keyboard and mouse
+ // events from the OS specific event queue, translate them and post
+ // them into the SciTech event queue.
+ //
+ // NOTE: There are a couple of important things that this function must
+ // take care of:
+ //
+ // 1. Support for KEYDOWN, KEYREPEAT and KEYUP is required.
+ //
+ // 2. Support for reading hardware scan code as well as ASCII
+ // translated values is required. Games use the scan codes rather
+ // than ASCII values. Scan codes go into the high order byte of the
+ // keyboard message field.
+ //
+ // 3. Support for at least reading mouse motion data (mickeys) from the
+ // mouse is required. Using the mickey values, we can then translate
+ // to mouse cursor coordinates scaled to the range of the current
+ // graphics display mode. Mouse values are scaled based on the
+ // global 'rangeX' and 'rangeY'.
+ //
+ // 4. Support for a timestamp for the events is required, which is
+ // defined as the number of milliseconds since some event (usually
+ // system startup). This is the timestamp when the event occurred
+ // (ie: at interrupt time) not when it was stuff into the SciTech
+ // event queue.
+ //
+ // 5. Support for mouse double click events. If the OS has a native
+ // mechanism to determine this, it should be used. Otherwise the
+ // time stamp information will be used by the generic event code
+ // to generate double click events.
+}
+
+/****************************************************************************
+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 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:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort()
+{
+ EVT_exit();
+ PM_fatalError("Unhandled exception!");
+}
+
+/****************************************************************************
+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)
+{
+ /* Initialise the event queue */
+ _mouseMove = mouseMove;
+ initEventQueue();
+ memset(keyUpMsg,0,sizeof(keyUpMsg));
+
+ // TODO: Do any OS specific initialisation here
+
+ /* Catch program termination signals so we can clean up properly */
+ signal(SIGABRT, _EVT_abort);
+ signal(SIGFPE, _EVT_abort);
+ signal(SIGINT, _EVT_abort);
+}
+
+/****************************************************************************
+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)
+{
+ rangeX = xRes;
+ rangeY = yRes;
+}
+
+/****************************************************************************
+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 non DOS systems
+}
+
+/****************************************************************************
+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 non DOS systems
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+ /* Restore signal handlers */
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+
+ // TODO: Do any OS specific cleanup in here
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/beos/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/beos/oshdr.h
new file mode 100644
index 0000000000..ab423d4be6
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/beos/oshdr.h
@@ -0,0 +1,32 @@
+/****************************************************************************
+*
+* 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: BeOS
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
+
+// This is where you include OS specific headers for the event handling
+// library.
diff --git a/board/MAI/bios_emulator/scitech/src/pm/beos/pm.c b/board/MAI/bios_emulator/scitech/src/pm/beos/pm.c
new file mode 100644
index 0000000000..c57d82ab68
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/beos/pm.c
@@ -0,0 +1,539 @@
+/****************************************************************************
+*
+* 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: BeOS
+*
+* 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>
+
+// TODO: Include any BeOS specific headers here!
+
+/*--------------------------- Global variables ----------------------------*/
+
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+void PMAPI PM_init(void)
+{
+ // TODO: Do any initialisation in here. This includes getting IOPL
+ // access for the process calling PM_init. This will get called
+ // more than once.
+
+ // TODO: If you support the supplied MTRR register stuff (you need to
+ // be at ring 0 for this!), you should initialise it in here.
+
+/* MTRR_init(); */
+}
+
+long PMAPI PM_getOSType(void)
+{ return _OS_BEOS; }
+
+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)
+{
+ // TODO: If you are running in a GUI environment without a console,
+ // this needs to be changed to bring up a fatal error message
+ // box and terminate the program.
+ if (fatalErrorCleanup)
+ fatalErrorCleanup();
+ fprintf(stderr,"%s\n", msg);
+ exit(1);
+}
+
+void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff)
+{
+ // No BIOS access for the BeOS
+ return NULL;
+}
+
+int PMAPI PM_kbhit(void)
+{
+ // TODO: This function checks if a key is available to be read. This
+ // should be implemented, but is mostly used by the test programs
+ // these days.
+ return true;
+}
+
+int PMAPI PM_getch(void)
+{
+ // TODO: This returns the ASCII code of the key pressed. This
+ // should be implemented, but is mostly used by the test programs
+ // these days.
+ return 0xD;
+}
+
+int PMAPI PM_openConsole(void)
+{
+ // TODO: Opens up a fullscreen console for graphics output. If your
+ // console does not have graphics/text modes, this can be left
+ // empty. The main purpose of this is to disable console switching
+ // when in graphics modes if you can switch away from fullscreen
+ // consoles (if you want to allow switching, this can be done
+ // elsewhere with a full save/restore state of the graphics mode).
+ return 0;
+}
+
+int PMAPI PM_getConsoleStateSize(void)
+{
+ // TODO: Returns the size of the console state buffer used to save the
+ // state of the console before going into graphics mode. This is
+ // used to restore the console back to normal when we are done.
+ return 1;
+}
+
+void PMAPI PM_saveConsoleState(void *stateBuf,int console_id)
+{
+ // TODO: Saves the state of the console into the state buffer. This is
+ // used to restore the console back to normal when we are done.
+ // We will always restore 80x25 text mode after being in graphics
+ // mode, so if restoring text mode is all you need to do this can
+ // be left empty.
+}
+
+void PMAPI PM_restoreConsoleState(const void *stateBuf,int console_id)
+{
+ // TODO: Restore the state of the console from the state buffer. This is
+ // used to restore the console back to normal when we are done.
+ // We will always restore 80x25 text mode after being in graphics
+ // mode, so if restoring text mode is all you need to do this can
+ // be left empty.
+}
+
+void PMAPI PM_closeConsole(int console_id)
+{
+ // TODO: Close the console when we are done, going back to text mode.
+}
+
+void PM_setOSCursorLocation(int x,int y)
+{
+ // TODO: Set the OS console cursor location to the new value. This is
+ // generally used for new OS ports (used mostly for DOS).
+}
+
+void PM_setOSScreenWidth(int width,int height)
+{
+ // TODO: Set the OS console screen width. This is generally unused for
+ // new OS ports.
+}
+
+ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler ih, int frequency)
+{
+ // TODO: Install a real time clock interrupt handler. Normally this
+ // will not be supported from most OS'es in user land, so an
+ // alternative mechanism is needed to enable software stereo.
+ // Hence leave this unimplemented unless you have a high priority
+ // mechanism to call the 32-bit callback when the real time clock
+ // interrupt fires.
+ return false;
+}
+
+void PMAPI PM_setRealTimeClockFrequency(int frequency)
+{
+ // TODO: Set the real time clock interrupt frequency. Used for stereo
+ // LC shutter glasses when doing software stereo. Usually sets
+ // the frequency to around 2048 Hz.
+}
+
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ // TODO: Restores the real time clock handler.
+}
+
+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)
+{
+ // TODO: Return a unique ID for the machine. If a unique ID is not
+ // available, return the machine name.
+ static char buf[128];
+ gethostname(buf, 128);
+ return buf;
+}
+
+const char * PMAPI PM_getMachineName(void)
+{
+ // TODO: Return the network machine name for the machine.
+ static char buf[128];
+ gethostname(buf, 128);
+ return buf;
+}
+
+void * PMAPI PM_getBIOSPointer(void)
+{
+ // No BIOS access on the BeOS
+ return NULL;
+}
+
+void * PMAPI PM_getA0000Pointer(void)
+{
+ static void *bankPtr;
+ if (!bankPtr)
+ bankPtr = PM_mapPhysicalAddr(0xA0000,0xFFFF,true);
+ return bankPtr;
+}
+
+void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{
+ // TODO: This function maps a physical memory address to a linear
+ // address in the address space of the calling process.
+
+ // NOTE: This function *must* be able to handle any phsyical base
+ // address, and hence you will have to handle rounding of
+ // the physical base address to a page boundary (ie: 4Kb on
+ // x86 CPU's) to be able to properly map in the memory
+ // region.
+
+ // NOTE: If possible the isCached bit should be used to ensure that
+ // the PCD (Page Cache Disable) and PWT (Page Write Through)
+ // bits are set to disable caching for a memory mapping used
+ // for MMIO register access. We also disable caching using
+ // the MTRR registers for Pentium Pro and later chipsets so if
+ // MTRR support is enabled for your OS then you can safely ignore
+ // the isCached flag and always enable caching in the page
+ // tables.
+ return NULL;
+}
+
+void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
+{
+ // TODO: This function will free a physical memory mapping previously
+ // allocated with PM_mapPhysicalAddr() if at all possible. If
+ // you can't free physical memory mappings, simply do nothing.
+}
+
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{
+ // TODO: This function should find the physical address of a linear
+ // address.
+ return 0xFFFFFFFFUL;
+}
+
+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)
+{
+ // TODO: This is used to allocate memory that is shared between process
+ // that all access the common Nucleus drivers via a common display
+ // driver DLL. If your OS does not support shared memory (or if
+ // the display driver does not need to allocate shared memory
+ // for each process address space), this should just call PM_malloc.
+ return PM_malloc(size);
+}
+
+void PMAPI PM_freeShared(void *ptr)
+{
+ // TODO: Free the shared memory block. This will be called in the context
+ // of the original calling process that allocated the shared
+ // memory with PM_mallocShared. Simply call free if you do not
+ // need this.
+ PM_free(ptr);
+}
+
+void * PMAPI PM_mapToProcess(void *base,ulong limit)
+{
+ // TODO: This function is used to map a physical memory mapping
+ // previously allocated with PM_mapPhysicalAddr into the
+ // address space of the calling process. If the memory mapping
+ // allocated by PM_mapPhysicalAddr is global to all processes,
+ // simply return the pointer.
+ return base;
+}
+
+void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
+{
+ // No BIOS access on the BeOS
+ return NULL;
+}
+
+void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
+{
+ // No BIOS access on the BeOS
+ return NULL;
+}
+
+void PMAPI PM_freeRealSeg(void *mem)
+{
+ // No BIOS access on the BeOS
+}
+
+void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
+{
+ // No BIOS access on the BeOS
+}
+
+int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
+{
+ // No BIOS access on the BeOS
+ return 0;
+}
+
+int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
+ RMSREGS *sregs)
+{
+ // No BIOS access on the BeOS
+ return 0;
+}
+
+void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
+ RMSREGS *sregs)
+{
+ // No BIOS access on the BeOS
+}
+
+void PMAPI PM_availableMemory(ulong *physical,ulong *total)
+{
+ // TODO: Report the amount of available memory, both the amount of
+ // physical memory left and the amount of virtual memory left.
+ // If the OS does not provide these services, report 0's.
+ *physical = *total = 0;
+}
+
+void * PMAPI PM_allocLockedMem(uint size,ulong *physAddr,ibool contiguous,ibool below16Meg)
+{
+ // TODO: Allocate a block of locked, physical memory of the specified
+ // size. This is used for bus master operations. If this is not
+ // supported by the OS, return NULL and bus mastering will not
+ // be used.
+ return NULL;
+}
+
+void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous)
+{
+ // TODO: Free a memory block allocated with PM_allocLockedMem.
+}
+
+void PMAPI PM_setBankA(int bank)
+{
+ // No BIOS access on the BeOS
+}
+
+void PMAPI PM_setBankAB(int bank)
+{
+ // No BIOS access on the BeOS
+}
+
+void PMAPI PM_setCRTStart(int x,int y,int waitVRT)
+{
+ // No BIOS access on the BeOS
+}
+
+ibool PMAPI PM_enableWriteCombine(ulong base,ulong length,uint type)
+{
+ // TODO: This function should enable Pentium Pro and Pentium II MTRR
+ // write combining for the passed in physical memory base address
+ // and length. Normally this is done via calls to an OS specific
+ // device driver as this can only be done at ring 0.
+ //
+ // NOTE: This is a *very* important function to implement! If you do
+ // not implement, graphics performance on the latest Intel chips
+ // will be severly impaired. For sample code that can be used
+ // directly in a ring 0 device driver, see the MSDOS implementation
+ // which includes assembler code to do this directly (if the
+ // program is running at ring 0).
+ return false;
+}
+
+ibool PMAPI PM_doBIOSPOST(ushort axVal,ulong BIOSPhysAddr,void *mappedBIOS)
+{
+ // TODO: This function is used to run the BIOS POST code on a secondary
+ // controller to initialise it for use. This is not necessary
+ // for multi-controller operation, but it will make it a lot
+ // more convenicent for end users (otherwise they have to boot
+ // the system once with the secondary controller as primary, and
+ // then boot with both controllers installed).
+ //
+ // Even if you don't support full BIOS access, it would be
+ // adviseable to be able to POST the secondary controllers in the
+ // system using this function as a minimum requirement. Some
+ // graphics hardware has registers that contain values that only
+ // the BIOS knows about, which makes bring up a card from cold
+ // reset difficult if the BIOS has not POST'ed it.
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+ulong PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ (void)filename;
+ (void)findData;
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ ulong handle,
+ PM_findData *findData)
+{
+ (void)handle;
+ (void)findData;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ ulong handle)
+{
+ (void)handle;
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ if (drive == 3)
+ return true;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ (void)drive;
+ getcwd(dir,len);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+ // TODO: Set the file attributes for a file
+ (void)filename;
+ (void)attrib;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/beos/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/beos/vflat.c
new file mode 100644
index 0000000000..579ef2c95c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/beos/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/beos/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/beos/ztimer.c
new file mode 100644
index 0000000000..a5637a5ecf
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/beos/ztimer.c
@@ -0,0 +1,111 @@
+/****************************************************************************
+*
+* 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: *** TODO: ADD YOUR OS ENVIRONMENT NAME HERE ***
+*
+* Description: OS specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+void _ZTimerInit(void)
+{
+ // TODO: Do any specific internal initialisation in here
+}
+
+/****************************************************************************
+REMARKS:
+Start the Zen Timer counting.
+****************************************************************************/
+static void _LZTimerOn(
+ LZTimerObject *tm)
+{
+ // TODO: Start the Zen Timer counting. This should be a macro if
+ // possible.
+}
+
+/****************************************************************************
+REMARKS:
+Compute the lap time since the timer was started.
+****************************************************************************/
+static ulong _LZTimerLap(
+ LZTimerObject *tm)
+{
+ // TODO: Compute the lap time between the current time and when the
+ // timer was started.
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Stop the Zen Timer counting.
+****************************************************************************/
+static void _LZTimerOff(
+ LZTimerObject *tm)
+{
+ // TODO: Stop the timer counting. Should be a macro if possible.
+}
+
+/****************************************************************************
+REMARKS:
+Compute the elapsed time in microseconds between start and end timings.
+****************************************************************************/
+static ulong _LZTimerCount(
+ LZTimerObject *tm)
+{
+ // TODO: Compute the elapsed time and return it. Always microseconds.
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 1
+
+/****************************************************************************
+REMARKS:
+Read the Long Period timer from the OS
+****************************************************************************/
+static ulong _ULZReadTime(void)
+{
+ // TODO: Read the long period timer from the OS. The resolution of this
+ // timer should be around 1/20 of a second for timing long
+ // periods if possible.
+}
+
+/****************************************************************************
+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; }
diff --git a/board/MAI/bios_emulator/scitech/src/pm/codepage/us_eng.c b/board/MAI/bios_emulator/scitech/src/pm/codepage/us_eng.c
new file mode 100644
index 0000000000..9aa871423e
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/codepage/us_eng.c
@@ -0,0 +1,285 @@
+/****************************************************************************
+*
+* 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: Keyboard translation code pages for US English keyboards.
+*
+****************************************************************************/
+
+#include "event.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+/* This table is used for all normal key translations, and is the fallback
+ * table if the key is not found in any of the other translation tables.
+ * If the code is not found in this table, the ASCII code is set to 0 to
+ * indicate that there is no ASCII code equivalent for this key.
+ */
+static codepage_entry_t US_normal[] = {
+ {0x01, 0x1B},
+ {0x02, '1'},
+ {0x03, '2'},
+ {0x04, '3'},
+ {0x05, '4'},
+ {0x06, '5'},
+ {0x07, '6'},
+ {0x08, '7'},
+ {0x09, '8'},
+ {0x0A, '9'},
+ {0x0B, '0'},
+ {0x0C, '-'},
+ {0x0D, '='},
+ {0x0E, 0x08},
+ {0x0F, 0x09},
+ {0x10, 'q'},
+ {0x11, 'w'},
+ {0x12, 'e'},
+ {0x13, 'r'},
+ {0x14, 't'},
+ {0x15, 'y'},
+ {0x16, 'u'},
+ {0x17, 'i'},
+ {0x18, 'o'},
+ {0x19, 'p'},
+ {0x1A, '['},
+ {0x1B, ']'},
+ {0x1C, 0x0D},
+ {0x1E, 'a'},
+ {0x1F, 's'},
+ {0x20, 'd'},
+ {0x21, 'f'},
+ {0x22, 'g'},
+ {0x23, 'h'},
+ {0x24, 'j'},
+ {0x25, 'k'},
+ {0x26, 'l'},
+ {0x27, ';'},
+ {0x28, '\''},
+ {0x29, '`'},
+ {0x2B, '\\'},
+ {0x2C, 'z'},
+ {0x2D, 'x'},
+ {0x2E, 'c'},
+ {0x2F, 'v'},
+ {0x30, 'b'},
+ {0x31, 'n'},
+ {0x32, 'm'},
+ {0x33, ','},
+ {0x34, '.'},
+ {0x35, '/'},
+ {0x37, '*'}, /* Keypad */
+ {0x39, ' '},
+ {0x4A, '-'}, /* Keypad */
+ {0x4E, '+'}, /* Keypad */
+ {0x60, 0x0D}, /* Keypad */
+ {0x61, '/'}, /* Keypad */
+ };
+
+/* This table is used for when CAPSLOCK is active and the shift or ctrl
+ * keys are not down. If the code is not found in this table, the normal
+ * table above is then searched.
+ */
+static codepage_entry_t US_caps[] = {
+ {0x10, 'Q'},
+ {0x11, 'W'},
+ {0x12, 'E'},
+ {0x13, 'R'},
+ {0x14, 'T'},
+ {0x15, 'Y'},
+ {0x16, 'U'},
+ {0x17, 'I'},
+ {0x18, 'O'},
+ {0x19, 'P'},
+ {0x1E, 'A'},
+ {0x1F, 'S'},
+ {0x20, 'D'},
+ {0x21, 'F'},
+ {0x22, 'G'},
+ {0x23, 'H'},
+ {0x24, 'J'},
+ {0x25, 'K'},
+ {0x26, 'L'},
+ {0x2C, 'Z'},
+ {0x2D, 'X'},
+ {0x2E, 'C'},
+ {0x2F, 'V'},
+ {0x30, 'B'},
+ {0x31, 'N'},
+ {0x32, 'M'},
+ };
+
+/* This table is used for when shift key is down, but the ctrl key is not
+ * down and CAPSLOCK is not active. If the code is not found in this table,
+ * the normal table above is then searched.
+ */
+static codepage_entry_t US_shift[] = {
+ {0x02, '!'},
+ {0x03, '@'},
+ {0x04, '#'},
+ {0x05, '$'},
+ {0x06, '%'},
+ {0x07, '^'},
+ {0x08, '&'},
+ {0x09, '*'},
+ {0x0A, '('},
+ {0x0B, ')'},
+ {0x0C, '_'},
+ {0x0D, '+'},
+ {0x10, 'Q'},
+ {0x11, 'W'},
+ {0x12, 'E'},
+ {0x13, 'R'},
+ {0x14, 'T'},
+ {0x15, 'Y'},
+ {0x16, 'U'},
+ {0x17, 'I'},
+ {0x18, 'O'},
+ {0x19, 'P'},
+ {0x1A, '{'},
+ {0x1B, '}'},
+ {0x1E, 'A'},
+ {0x1F, 'S'},
+ {0x20, 'D'},
+ {0x21, 'F'},
+ {0x22, 'G'},
+ {0x23, 'H'},
+ {0x24, 'J'},
+ {0x25, 'K'},
+ {0x26, 'L'},
+ {0x27, ':'},
+ {0x28, '"'},
+ {0x29, '~'},
+ {0x2B, '|'},
+ {0x2C, 'Z'},
+ {0x2D, 'X'},
+ {0x2E, 'C'},
+ {0x2F, 'V'},
+ {0x30, 'B'},
+ {0x31, 'N'},
+ {0x32, 'M'},
+ {0x33, '<'},
+ {0x34, '>'},
+ {0x35, '?'},
+ };
+
+/* This table is used for when CAPSLOCK is active and the shift key is
+ * down, but the ctrl key is not. If the code is not found in this table,
+ * the shift table above is then searched.
+ */
+static codepage_entry_t US_shiftCaps[] = {
+ {0x10, 'q'},
+ {0x11, 'w'},
+ {0x12, 'e'},
+ {0x13, 'r'},
+ {0x14, 't'},
+ {0x15, 'y'},
+ {0x16, 'u'},
+ {0x17, 'i'},
+ {0x18, 'o'},
+ {0x19, 'p'},
+ {0x1E, 'a'},
+ {0x1F, 's'},
+ {0x20, 'd'},
+ {0x21, 'f'},
+ {0x22, 'g'},
+ {0x23, 'h'},
+ {0x24, 'j'},
+ {0x25, 'k'},
+ {0x26, 'l'},
+ {0x2C, 'z'},
+ {0x2D, 'x'},
+ {0x2E, 'c'},
+ {0x2F, 'v'},
+ {0x30, 'b'},
+ {0x31, 'n'},
+ {0x32, 'm'},
+ };
+
+/* This table is used for all key translations when the ctrl key is down,
+ * regardless of the state of the shift key and CAPSLOCK. If the code is
+ * not found in this table, the ASCII code is set to 0 to indicate that
+ * there is no ASCII code equivalent for this key.
+ */
+static codepage_entry_t US_ctrl[] = {
+ {0x01, 0x1B},
+ {0x06, 0x1E},
+ {0x0C, 0x1F},
+ {0x0E, 0x7F},
+ {0x10, 0x11},
+ {0x11, 0x17},
+ {0x12, 0x05},
+ {0x13, 0x12},
+ {0x14, 0x14},
+ {0x15, 0x19},
+ {0x16, 0x16},
+ {0x17, 0x09},
+ {0x18, 0x0F},
+ {0x19, 0x10},
+ {0x1A, 0x1B},
+ {0x1B, 0x1D},
+ {0x1C, 0x0A},
+ {0x1E, 0x01},
+ {0x1F, 0x13},
+ {0x20, 0x04},
+ {0x21, 0x06},
+ {0x22, 0x07},
+ {0x23, 0x08},
+ {0x24, 0x0A},
+ {0x25, 0x0B},
+ {0x26, 0x0C},
+ {0x2B, 0x1C},
+ {0x2C, 0x1A},
+ {0x2D, 0x18},
+ {0x2E, 0x03},
+ {0x2F, 0x16},
+ {0x30, 0x02},
+ {0x31, 0x0E},
+ {0x32, 0x0D},
+ {0x39, ' '},
+ };
+
+static codepage_entry_t US_numPad[] = {
+ {0x4C, '5'},
+ {0x62, '4'},
+ {0x63, '6'},
+ {0x64, '8'},
+ {0x65, '2'},
+ {0x66, '0'},
+ {0x67, '.'},
+ {0x68, '7'},
+ {0x69, '1'},
+ {0x6A, '9'},
+ {0x6B, '3'},
+ };
+
+codepage_t _CP_US_English = {
+ "US English",
+ US_normal, EVT_ARR_SIZE(US_normal),
+ US_caps, EVT_ARR_SIZE(US_caps),
+ US_shift, EVT_ARR_SIZE(US_shift),
+ US_shiftCaps, EVT_ARR_SIZE(US_shiftCaps),
+ US_ctrl, EVT_ARR_SIZE(US_ctrl),
+ US_numPad, EVT_ARR_SIZE(US_numPad),
+ };
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common.c b/board/MAI/bios_emulator/scitech/src/pm/common.c
new file mode 100644
index 0000000000..b100b8ad42
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common.c
@@ -0,0 +1,480 @@
+/****************************************************************************
+*
+* 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: Module containing code common to all platforms.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "drvlib/os/os.h"
+#if defined(__WIN32_VXD__) || defined(__OS2_VDD__) || defined(__NT_DRIVER__)
+#include "sdd/sddhelp.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+/*---------------------------- Global variables ---------------------------*/
+
+/* {secret} */
+long _VARAPI ___drv_os_type = _OS_UNSUPPORTED;
+static char localBPDPath[PM_MAX_PATH] = "";
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+path - Local path to the Nucleus BPD driver files.
+
+REMARKS:
+This function is used by the application program to override the location
+of the Nucleus driver files that are loaded. Normally the loader code
+will look in the system Nucleus directories first, then in the 'drivers'
+directory relative to the current working directory, and finally relative
+to the MGL_ROOT environment variable. By default the local BPD path is
+always set to the current directory if not initialised.
+****************************************************************************/
+void PMAPI PM_setLocalBPDPath(
+ const char *path)
+{
+ PM_init();
+ strncpy(localBPDPath,path,sizeof(localBPDPath));
+ localBPDPath[sizeof(localBPDPath)-1] = 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+bpdpath - Place to store the actual path to the file
+cachedpath - Place to store the cached BPD driver path
+trypath - Path to try to find the BPD file in
+subpath - Optional sub path to append to trypath
+dllname - Name of the Binary Portable DLL to load
+
+RETURNS:
+True if found, false if not.
+
+REMARKS:
+Trys the specified path to see if the BPD file can be found or not. If so,
+the path used is returned in bpdpath and cachedpath.
+****************************************************************************/
+static ibool TryPath(
+ char *bpdpath,
+ char *cachedpath,
+ const char *trypath,
+ const char *subpath,
+ const char *dllname)
+{
+ char filename[256];
+ FILE *f;
+
+ strcpy(bpdpath, trypath);
+ PM_backslash(bpdpath);
+ strcat(bpdpath,subpath);
+ PM_backslash(bpdpath);
+ strcpy(filename,bpdpath);
+ strcat(filename,dllname);
+ if ((f = fopen(filename,"rb")) == NULL)
+ return false;
+ if (cachedpath)
+ strcpy(cachedpath,bpdpath);
+ fclose(f);
+ return true;
+}
+
+/****************************************************************************
+RETURNS:
+True if local override enabled, false if not.
+
+REMARKS:
+Tests to see if the local override option is enabled, and if so it will
+look for the Nucleus drivers in the local application directories in
+preference to the Nucleus system directories.
+****************************************************************************/
+static ibool GetLocalOverride(void)
+{
+ char filename[256];
+ FILE *f;
+ static ibool local_override = -1;
+
+ if (local_override == -1) {
+ local_override = false;
+ strcpy(filename,PM_getNucleusPath());
+ PM_backslash(filename);
+ strcat(filename,"graphics.ini");
+ if ((f = fopen(filename,"r")) != NULL) {
+ while (!feof(f) && fgets(filename,sizeof(filename),f)) {
+ if (strnicmp(filename,"uselocal",8) == 0) {
+ local_override = ((*(filename+9) - '0') == 1);
+ break;
+ }
+ }
+ fclose(f);
+ }
+ }
+ return local_override;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Sets the location of the debug log file.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+dllname - Name of the Binary Portable DLL to load
+bpdpath - Place to store the actual path to the file
+
+RETURNS:
+True if found, false if not.
+
+REMARKS:
+Finds the location of a specific Binary Portable DLL, by searching all
+the standard SciTech Nucleus driver locations.
+****************************************************************************/
+ibool PMAPI PM_findBPD(
+ const char *dllname,
+ char *bpdpath)
+{
+ static char cachedpath[PM_MAX_PATH] = "";
+
+ /* On the first call determine the path to the Nucleus drivers */
+ if (cachedpath[0] == 0) {
+ /* First try in the global system Nucleus driver path if
+ * the local override setting is not enabled.
+ */
+ PM_init();
+ if (!GetLocalOverride()) {
+ if (TryPath(bpdpath,cachedpath,PM_getNucleusPath(),"",dllname))
+ return true;
+ }
+
+ /* Next try in the local application directory if available */
+ if (localBPDPath[0] != 0) {
+ if (TryPath(bpdpath,cachedpath,localBPDPath,"",dllname))
+ return true;
+ }
+ else {
+#if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__)
+ char *mgl_root;
+ if ((mgl_root = getenv("MGL_ROOT")) != NULL) {
+ if (TryPath(bpdpath,cachedpath,mgl_root,"drivers",dllname))
+ return true;
+ }
+#endif
+ PM_getCurrentPath(bpdpath,PM_MAX_PATH);
+ if (TryPath(bpdpath,cachedpath,bpdpath,"drivers",dllname))
+ return true;
+ }
+
+ /* Finally try in the global system path again so that we
+ * will still find the drivers in the global system path if
+ * the local override option is on, but the application does
+ * not have any local override drivers.
+ */
+ if (TryPath(bpdpath,cachedpath,PM_getNucleusPath(),"",dllname))
+ return true;
+
+ /* Whoops, we can't find the BPD file! */
+ return false;
+ }
+
+ /* Always try in the previously discovered path */
+ return TryPath(bpdpath,NULL,cachedpath,"",dllname);
+}
+
+/****************************************************************************
+REMARKS:
+Copies a string into another, and returns dest + strlen(src).
+****************************************************************************/
+static char *_stpcpy(
+ char *_dest,
+ const char *_src)
+{
+ if (!_dest || !_src)
+ return 0;
+ while ((*_dest++ = *_src++) != 0)
+ ;
+ return --_dest;
+}
+
+/****************************************************************************
+REMARKS:
+Copies a string into another, stopping at the maximum length. The string
+is properly terminated (unlike strncpy).
+****************************************************************************/
+static void safe_strncpy(
+ char *dst,
+ const char *src,
+ unsigned maxlen)
+{
+ if (dst) {
+ if(strlen(src) >= maxlen) {
+ strncpy(dst, src, maxlen);
+ dst[maxlen] = 0;
+ }
+ else
+ strcpy(dst, src);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Determins if the dot separator is present in the string.
+****************************************************************************/
+static int findDot(
+ char *p)
+{
+ if (*(p-1) == '.')
+ p--;
+ switch (*--p) {
+ case ':':
+ if (*(p-2) != '\0')
+ break;
+ case '/':
+ case '\\':
+ case '\0':
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Make a full pathname from split components.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+path - Place to store full path
+drive - Drive component for path
+dir - Directory component for path
+name - Filename component for path
+ext - Extension component for path
+
+REMARKS:
+Function to make a full pathname from split components. Under Unix the
+drive component will usually be empty. If the drive, dir, name, or ext
+parameters are null or empty, they are not inserted in the path string.
+Otherwise, if the drive doesn't end with a colon, one is inserted in the
+path. If the dir doesn't end in a slash, one is inserted in the path.
+If the ext doesn't start with a dot, one is inserted in the path.
+
+The maximum sizes for the path string is given by the constant PM_MAX_PATH,
+which includes space for the null-terminator.
+
+SEE ALSO:
+PM_splitPath
+****************************************************************************/
+void PMAPI PM_makepath(
+ char *path,
+ const char *drive,
+ const char *dir,
+ const char *name,
+ const char *ext)
+{
+ if (drive && *drive) {
+ *path++ = *drive;
+ *path++ = ':';
+ }
+ if (dir && *dir) {
+ path = _stpcpy(path,dir);
+ if (*(path-1) != '\\' && *(path-1) != '/')
+#ifdef __UNIX__
+ *path++ = '/';
+#else
+ *path++ = '\\';
+#endif
+ }
+ if (name)
+ path = _stpcpy(path,name);
+ if (ext && *ext) {
+ if (*ext != '.')
+ *path++ = '.';
+ path = _stpcpy(path,ext);
+ }
+ *path = 0;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Split a full pathname into components.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+path - Full path to split
+drive - Drive component for path
+dir - Directory component for path
+name - Filename component for path
+ext - Extension component for path
+
+RETURNS:
+Flags indicating what components were parsed.
+
+REMARKS:
+Function to split a full pathmame into separate components in the form
+
+ X:\DIR\SUBDIR\NAME.EXT
+
+and splits path into its four components. It then stores those components
+in the strings pointed to by drive, dir, name and ext. (Each component is
+required but can be a NULL, which means the corresponding component will be
+parsed but not stored).
+
+The maximum sizes for these strings are given by the constants PM_MAX_DRIVE
+and PM_MAX_PATH. PM_MAX_DRIVE is always 4, and PM_MAX_PATH is usually at
+least 256 characters. Under Unix the dir, name and ext components may be
+up to the full path in length.
+
+SEE ALSO:
+PM_makePath
+****************************************************************************/
+int PMAPI PM_splitpath(
+ const char *path,
+ char *drive,
+ char *dir,
+ char *name,
+ char *ext)
+{
+ char *p;
+ int temp,ret;
+ char buf[PM_MAX_PATH+2];
+
+ /* Set all string to default value zero */
+ ret = 0;
+ if (drive) *drive = 0;
+ if (dir) *dir = 0;
+ if (name) *name = 0;
+ if (ext) *ext = 0;
+
+ /* Copy filename into template up to PM_MAX_PATH characters */
+ p = buf;
+ if ((temp = strlen(path)) > PM_MAX_PATH)
+ temp = PM_MAX_PATH;
+ *p++ = 0;
+ strncpy(p, path, temp);
+ *(p += temp) = 0;
+
+ /* Split the filename and fill corresponding nonzero pointers */
+ temp = 0;
+ for (;;) {
+ switch (*--p) {
+ case '.':
+ if (!temp && (*(p+1) == '\0'))
+ temp = findDot(p);
+ if ((!temp) && ((ret & PM_HAS_EXTENSION) == 0)) {
+ ret |= PM_HAS_EXTENSION;
+ safe_strncpy(ext, p, PM_MAX_PATH - 1);
+ *p = 0;
+ }
+ continue;
+ case ':':
+ if (p != &buf[2])
+ continue;
+ case '\0':
+ if (temp) {
+ if (*++p)
+ ret |= PM_HAS_DIRECTORY;
+ safe_strncpy(dir, p, PM_MAX_PATH - 1);
+ *p-- = 0;
+ break;
+ }
+ case '/':
+ case '\\':
+ if (!temp) {
+ temp++;
+ if (*++p)
+ ret |= PM_HAS_FILENAME;
+ safe_strncpy(name, p, PM_MAX_PATH - 1);
+ *p-- = 0;
+ if (*p == 0 || (*p == ':' && p == &buf[2]))
+ break;
+ }
+ continue;
+ case '*':
+ case '?':
+ if (!temp)
+ ret |= PM_HAS_WILDCARDS;
+ default:
+ continue;
+ }
+ break;
+ }
+ if (*p == ':') {
+ if (buf[1])
+ ret |= PM_HAS_DRIVE;
+ safe_strncpy(drive, &buf[1], PM_MAX_DRIVE - 1);
+ }
+ return ret;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Block until a specific time has elapsed since the last call
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+milliseconds - Number of milliseconds for delay
+
+REMARKS:
+This function will block the calling thread or process until the specified
+number of milliseconds have passed since the /last/ call to this function.
+The first time this function is called, it will return immediately. On
+subsquent calls it will block until the specified time has elapsed, or it
+will return immediately if the time has already elapsed.
+
+This function is useful to provide constant time functionality in a
+program, such as a frame rate limiter for graphics applications etc.
+
+SEE ALSO:
+PM_sleep
+****************************************************************************/
+void PMAPI PM_blockUntilTimeout(
+ ulong milliseconds)
+{
+ ulong microseconds = milliseconds * 1000L,msDelay;
+ static LZTimerObject tm;
+ static ibool firstTime = true;
+
+ if (firstTime) {
+ firstTime = false;
+ LZTimerOnExt(&tm);
+ }
+ else {
+ if ((msDelay = (microseconds - LZTimerLapExt(&tm)) / 1000L) > 0)
+ PM_sleep(msDelay);
+ while (LZTimerLapExt(&tm) < microseconds)
+ ;
+ LZTimerOffExt(&tm);
+ LZTimerOnExt(&tm);
+ }
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_cpuinfo.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_cpuinfo.asm
new file mode 100644
index 0000000000..60ebed713f
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_cpuinfo.asm
@@ -0,0 +1,600 @@
+;****************************************************************************
+;*
+;* 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: NASM or TASM Assembler
+;* Environment: Intel 32 bit Protected Mode.
+;*
+;* Description: Code to determine the Intel processor type.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac"
+
+header _cpuinfo
+
+begdataseg _cpuinfo ; Start of data segment
+
+cache_id db "01234567890123456"
+intel_id db "GenuineIntel" ; Intel vendor ID
+cyrix_id db "CyrixInstead" ; Cyrix vendor ID
+amd_id db "AuthenticAMD" ; AMD vendor ID
+idt_id db "CentaurHauls" ; IDT vendor ID
+
+CPU_IDT EQU 01000h ; Flag for IDT processors
+CPU_Cyrix EQU 02000h ; Flag for Cyrix processors
+CPU_AMD EQU 04000h ; Flag for AMD processors
+CPU_Intel EQU 08000h ; Flag for Intel processors
+
+enddataseg _cpuinfo
+
+begcodeseg _cpuinfo ; Start of code segment
+
+ifdef USE_NASM
+%macro mCPU_ID 0
+db 00Fh,0A2h
+%endmacro
+else
+MACRO mCPU_ID
+db 00Fh,0A2h
+ENDM
+endif
+
+ifdef USE_NASM
+%macro mRDTSC 0
+db 00Fh,031h
+%endmacro
+else
+MACRO mRDTSC
+db 00Fh,031h
+ENDM
+endif
+
+;----------------------------------------------------------------------------
+; bool _CPU_check80386(void)
+;----------------------------------------------------------------------------
+; Determines if we have an i386 processor.
+;----------------------------------------------------------------------------
+cprocstart _CPU_check80386
+
+ enter_c
+
+ xor edx,edx ; EDX = 0, not an 80386
+ mov bx, sp
+ifdef USE_NASM
+ and sp, ~3
+else
+ and sp, not 3
+endif
+ pushfd ; Push original EFLAGS
+ pop eax ; Get original EFLAGS
+ mov ecx, eax ; Save original EFLAGS
+ xor eax, 40000h ; Flip AC bit in EFLAGS
+ push eax ; Save new EFLAGS value on
+ ; stack
+ popfd ; Replace current EFLAGS value
+ pushfd ; Get new EFLAGS
+ pop eax ; Store new EFLAGS in EAX
+ xor eax, ecx ; Can't toggle AC bit,
+ ; processor=80386
+ jnz @@Done ; Jump if not an 80386 processor
+ inc edx ; We have an 80386
+
+@@Done: push ecx
+ popfd
+ mov sp, bx
+ mov eax, edx
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; bool _CPU_check80486(void)
+;----------------------------------------------------------------------------
+; Determines if we have an i486 processor.
+;----------------------------------------------------------------------------
+cprocstart _CPU_check80486
+
+ enter_c
+
+; Distinguish between the i486 and Pentium by the ability to set the ID flag
+; in the EFLAGS register. If the ID flag is set, then we can use the CPUID
+; instruction to determine the final version of the chip. Otherwise we
+; simply have an 80486.
+
+; Distinguish between the i486 and Pentium by the ability to set the ID flag
+; in the EFLAGS register. If the ID flag is set, then we can use the CPUID
+; instruction to determine the final version of the chip. Otherwise we
+; simply have an 80486.
+
+ pushfd ; Get original EFLAGS
+ pop eax
+ mov ecx, eax
+ xor eax, 200000h ; Flip ID bit in EFLAGS
+ push eax ; Save new EFLAGS value on stack
+ popfd ; Replace current EFLAGS value
+ pushfd ; Get new EFLAGS
+ pop eax ; Store new EFLAGS in EAX
+ xor eax, ecx ; Can not toggle ID bit,
+ jnz @@1 ; Processor=80486
+ mov eax,1 ; We dont have a Pentium
+ jmp @@Done
+@@1: mov eax,0 ; We have Pentium or later
+@@Done: leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; bool _CPU_checkClone(void)
+;----------------------------------------------------------------------------
+; Checks if the i386 or i486 processor is a clone or genuine Intel.
+;----------------------------------------------------------------------------
+cprocstart _CPU_checkClone
+
+ enter_c
+
+ mov ax,5555h ; Check to make sure this is a 32-bit processor
+ xor dx,dx
+ mov cx,2h
+ div cx ; Perform Division
+ clc
+ jnz @@NoClone
+ jmp @@Clone
+@@NoClone:
+ stc
+@@Clone:
+ pushfd
+ pop eax ; Get the flags
+ and eax,1
+ xor eax,1 ; EAX=0 is probably Intel, EAX=1 is a Clone
+
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; bool _CPU_haveCPUID(void)
+;----------------------------------------------------------------------------
+; Determines if we have support for the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_haveCPUID
+
+ enter_c
+
+ifdef flatmodel
+ pushfd ; Get original EFLAGS
+ pop eax
+ mov ecx, eax
+ xor eax, 200000h ; Flip ID bit in EFLAGS
+ push eax ; Save new EFLAGS value on stack
+ popfd ; Replace current EFLAGS value
+ pushfd ; Get new EFLAGS
+ pop eax ; Store new EFLAGS in EAX
+ xor eax, ecx ; Can not toggle ID bit,
+ jnz @@1 ; Processor=80486
+ mov eax,0 ; We dont have CPUID support
+ jmp @@Done
+@@1: mov eax,1 ; We have CPUID support
+else
+ mov eax,0 ; CPUID requires 32-bit pmode
+endif
+@@Done: leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_checkCPUID(void)
+;----------------------------------------------------------------------------
+; Determines the CPU type using the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_checkCPUID
+
+ enter_c
+
+ xor eax, eax ; Set up for CPUID instruction
+ mCPU_ID ; Get and save vendor ID
+ cmp eax, 1 ; Make sure 1 is valid input for CPUID
+ jl @@Fail ; We dont have the CPUID instruction
+ xor eax,eax ; Assume vendor is unknown
+
+; Check for GenuineIntel processors
+
+ LEA_L esi,intel_id
+ cmp [DWORD esi], ebx
+ jne @@NotIntel
+ cmp [DWORD esi+4], edx
+ jne @@NotIntel
+ cmp [DWORD esi+8], ecx
+ jne @@NotIntel
+ mov eax,CPU_Intel ; Flag that we have GenuineIntel
+ jmp @@FoundVendor
+
+; Check for CyrixInstead processors
+
+@@NotIntel:
+ LEA_L esi,cyrix_id
+ cmp [DWORD esi], ebx
+ jne @@NotCyrix
+ cmp [DWORD esi+4], edx
+ jne @@NotCyrix
+ cmp [DWORD esi+8], ecx
+ jne @@NotCyrix
+ mov eax,CPU_Cyrix ; Flag that we have CyrixInstead
+ jmp @@FoundVendor
+
+; Check for AuthenticAMD processors
+
+@@NotCyrix:
+ LEA_L esi,amd_id
+ cmp [DWORD esi], ebx
+ jne @@NotAMD
+ cmp [DWORD esi+4], edx
+ jne @@NotAMD
+ cmp [DWORD esi+8], ecx
+ jne @@NotAMD
+ mov eax,CPU_AMD ; Flag that we have AuthenticAMD
+ jmp @@FoundVendor
+
+; Check for CentaurHauls processors
+
+@@NotAMD:
+ LEA_L esi,idt_id
+ cmp [DWORD esi], ebx
+ jne @@NotIDT
+ cmp [DWORD esi+4], edx
+ jne @@NotIDT
+ cmp [DWORD esi+8], ecx
+ jne @@NotIDT
+ mov eax,CPU_IDT ; Flag that we have AuthenticIDT
+ jmp @@FoundVendor
+
+@@NotIDT:
+
+@@FoundVendor:
+ push eax
+ xor eax, eax
+ inc eax
+ mCPU_ID ; Get family/model/stepping/features
+ and eax, 0F00h
+ shr eax, 8 ; Isolate family
+ and eax, 0Fh
+ pop ecx
+ or eax,ecx ; Combine in the clone flag
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_getCPUIDModel(void)
+;----------------------------------------------------------------------------
+; Determines the CPU type using the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_getCPUIDModel
+
+ enter_c
+
+ xor eax, eax ; Set up for CPUID instruction
+ mCPU_ID ; Get and save vendor ID
+ cmp eax, 1 ; Make sure 1 is valid input for CPUID
+ jl @@Fail ; We dont have the CPUID instruction
+ xor eax, eax
+ inc eax
+ mCPU_ID ; Get family/model/stepping/features
+ and eax, 0F0h
+ shr eax, 4 ; Isolate model
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_getCPUIDStepping(void)
+;----------------------------------------------------------------------------
+; Determines the CPU type using the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_getCPUIDStepping
+
+ enter_c
+
+ xor eax, eax ; Set up for CPUID instruction
+ mCPU_ID ; Get and save vendor ID
+ cmp eax, 1 ; Make sure 1 is valid input for CPUID
+ jl @@Fail ; We dont have the CPUID instruction
+ xor eax, eax
+ inc eax
+ mCPU_ID ; Get family/model/stepping/features
+ and eax, 00Fh ; Isolate stepping
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_getCPUIDFeatures(void)
+;----------------------------------------------------------------------------
+; Determines the CPU type using the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_getCPUIDFeatures
+
+ enter_c
+
+ xor eax, eax ; Set up for CPUID instruction
+ mCPU_ID ; Get and save vendor ID
+ cmp eax, 1 ; Make sure 1 is valid input for CPUID
+ jl @@Fail ; We dont have the CPUID instruction
+ xor eax, eax
+ inc eax
+ mCPU_ID ; Get family/model/stepping/features
+ mov eax, edx
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_getCacheSize(void)
+;----------------------------------------------------------------------------
+; Determines the CPU cache size for Intel processors
+;----------------------------------------------------------------------------
+cprocstart _CPU_getCacheSize
+
+ enter_c
+ xor eax, eax ; Set up for CPUID instruction
+ mCPU_ID ; Get and save vendor ID
+ cmp eax,2 ; Make sure 2 is valid input for CPUID
+ jl @@Fail ; We dont have the CPUID instruction
+ mov eax,2
+ mCPU_ID ; Get cache descriptors
+ LEA_L esi,cache_id ; Get address of cache ID (-fPIC aware)
+ shr eax,8
+ mov [esi+0],eax
+ mov [esi+3],ebx
+ mov [esi+7],ecx
+ mov [esi+11],edx
+ xor eax,eax
+ LEA_L esi,cache_id ; Get address of cache ID (-fPIC aware)
+ mov edi,15
+@@ScanLoop:
+ cmp [BYTE esi],41h
+ mov eax,128
+ je @@Done
+ cmp [BYTE esi],42h
+ mov eax,256
+ je @@Done
+ cmp [BYTE esi],43h
+ mov eax,512
+ je @@Done
+ cmp [BYTE esi],44h
+ mov eax,1024
+ je @@Done
+ cmp [BYTE esi],45h
+ mov eax,2048
+ je @@Done
+ inc esi
+ dec edi
+ jnz @@ScanLoop
+
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uint _CPU_have3DNow(void)
+;----------------------------------------------------------------------------
+; Determines the CPU type using the CPUID instruction.
+;----------------------------------------------------------------------------
+cprocstart _CPU_have3DNow
+
+ enter_c
+
+ mov eax,80000000h ; Query for extended functions
+ mCPU_ID ; Get extended function limit
+ cmp eax,80000001h
+ jbe @@Fail ; Nope, we dont have function 800000001h
+ mov eax,80000001h ; Setup extended function 800000001h
+ mCPU_ID ; and get the information
+ test edx,80000000h ; Bit 31 is set if 3DNow! present
+ jz @@Fail ; Nope, we dont have 3DNow support
+ mov eax,1 ; Yep, we have 3DNow! support!
+@@Done: leave_c
+ ret
+
+@@Fail: xor eax,eax
+ jmp @@Done
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _CPU_quickRDTSC(void)
+;----------------------------------------------------------------------------
+; Reads the time stamp counter and returns the low order 32-bits
+;----------------------------------------------------------------------------
+cprocstart _CPU_quickRDTSC
+
+ mRDTSC
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _CPU_runBSFLoop(ulong interations)
+;----------------------------------------------------------------------------
+; Runs a loop of BSF instructions for the specified number of iterations
+;----------------------------------------------------------------------------
+cprocstart _CPU_runBSFLoop
+
+ ARG iterations:ULONG
+
+ push _bp
+ mov _bp,_sp
+ push _bx
+
+ mov edx,[iterations]
+ mov eax,80000000h
+ mov ebx,edx
+
+ ALIGN 4
+
+@@loop: bsf ecx,eax
+ dec ebx
+ jnz @@loop
+
+ pop _bx
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _CPU_readTimeStamp(CPU_largeInteger *time);
+;----------------------------------------------------------------------------
+; Reads the time stamp counter and returns the 64-bit result.
+;----------------------------------------------------------------------------
+cprocstart _CPU_readTimeStamp
+
+ mRDTSC
+ mov ecx,[esp+4] ; Access directly without stack frame
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _CPU_diffTime64(CPU_largeInteger *t1,CPU_largeInteger *t2,CPU_largeInteger *t)
+;----------------------------------------------------------------------------
+; Computes the difference between two 64-bit numbers.
+;----------------------------------------------------------------------------
+cprocstart _CPU_diffTime64
+
+ ARG t1:DPTR, t2:DPTR, t:DPTR
+
+ enter_c
+
+ mov ecx,[t2]
+ mov eax,[ecx] ; EAX := t2.low
+ mov ecx,[t1]
+ sub eax,[ecx]
+ mov edx,eax ; EDX := low difference
+ mov ecx,[t2]
+ mov eax,[ecx+4] ; ECX := t2.high
+ mov ecx,[t1]
+ sbb eax,[ecx+4] ; EAX := high difference
+
+ mov ebx,[t] ; Store the result
+ mov [ebx],edx ; Store low part
+ mov [ebx+4],eax ; Store high part
+ mov eax,edx ; Return low part
+ifndef flatmodel
+ shld edx,eax,16 ; Return in DX:AX
+endif
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _CPU_calcMicroSec(CPU_largeInteger *count,ulong freq);
+;----------------------------------------------------------------------------
+; Computes the value in microseconds for the elapsed time with maximum
+; precision. The formula we use is:
+;
+; us = (((diff * 0x100000) / freq) * 1000000) / 0x100000)
+;
+; The power of two multiple before the first divide allows us to scale the
+; 64-bit difference using simple shifts, and then the divide brings the
+; final result into the range to fit into a 32-bit integer.
+;----------------------------------------------------------------------------
+cprocstart _CPU_calcMicroSec
+
+ ARG count:DPTR, freq:ULONG
+
+ enter_c
+
+ mov ecx,[count]
+ mov eax,[ecx] ; EAX := low part
+ mov edx,[ecx+4] ; EDX := high part
+ shld edx,eax,20
+ shl eax,20 ; diff * 0x100000
+ div [DWORD freq] ; (diff * 0x100000) / freq
+ mov ecx,1000000
+ xor edx,edx
+ mul ecx ; ((diff * 0x100000) / freq) * 1000000)
+ shrd eax,edx,20 ; ((diff * 0x100000) / freq) * 1000000) / 0x100000
+ifndef flatmodel
+ shld edx,eax,16 ; Return in DX:AX
+endif
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _CPU_mulDiv(ulong a,ulong b,ulong c);
+;----------------------------------------------------------------------------
+; Computes the following with 64-bit integer precision:
+;
+; result = (a * b) / c
+;
+;----------------------------------------------------------------------------
+cprocstart _CPU_mulDiv
+
+ ARG a:ULONG, b:ULONG, c:ULONG
+
+ enter_c
+ mov eax,[a]
+ imul [ULONG b]
+ idiv [ULONG c]
+ifndef flatmodel
+ shld edx,eax,16 ; Return in DX:AX
+endif
+ leave_c
+ ret
+
+cprocend
+
+endcodeseg _cpuinfo
+
+ END
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_dma.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_dma.asm
new file mode 100644
index 0000000000..2b6e1e8b56
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_dma.asm
@@ -0,0 +1,246 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: 16/32 bit Ring 0 device driver
+;*
+;* Description: Assembler support routines for ISA DMA controller.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _dma ; Set up memory model
+
+begdataseg _dma ; Start of data segment
+
+cpublic _PM_DMADataStart
+
+; DMA register I/O addresses for channels 0-7 (except 4)
+
+DMAC_page db 087h,083h,081h,082h, -1,08Bh,089h,08Ah
+DMAC_addr db 000h,002h,004h,006h, -1,0C4h,0C8h,0CCh
+DMAC_cnt db 001h,003h,005h,007h, -1,0C6h,0CAh,0CEh
+DMAC_mask db 00Ah,00Ah,00Ah,00Ah, -1,0D4h,0D4h,0D4h
+DMAC_mode db 00Bh,00Bh,00Bh,00Bh, -1,0D6h,0D6h,0D6h
+DMAC_FF db 00Ch,00Ch,00Ch,00Ch, -1,0D8h,0D8h,0D8h
+
+cpublic _PM_DMADataEnd
+
+enddataseg _dma
+
+begcodeseg _dma ; Start of code segment
+
+ifdef flatmodel
+
+cpublic _PM_DMACodeStart
+
+;----------------------------------------------------------------------------
+; void PM_DMACDisable(int channel);
+;----------------------------------------------------------------------------
+; Masks DMA channel, inhibiting DMA transfers
+;----------------------------------------------------------------------------
+cprocstart PM_DMACDisable
+
+ ARG channel:UINT
+
+ push ebp
+ mov ebp,esp
+ mov ecx,[channel] ; ECX indexes DMAC register tables
+ mov dh,0 ; DH = 0 for DMAC register port access
+ mov al,cl
+ and al,11b
+ or al,100b ; AL = (channel & 3) | "set mask bit"
+ mov dl,[DMAC_mask+ecx]
+ out dx,al
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_DMACEnable(int channel);
+;----------------------------------------------------------------------------
+; Unmasks DMA channel, enabling DMA transfers
+;----------------------------------------------------------------------------
+cprocstart PM_DMACEnable
+
+ ARG channel:UINT
+
+ push ebp
+ mov ebp,esp
+ mov ecx,[channel] ; ECX indexes DMAC register tables
+ mov dh,0 ; DH = 0 for DMAC register port access
+ mov al,cl
+ and al,11b ; AL = (channel & 3), "set mask bit"=0
+ mov dl,[DMAC_mask+ecx]
+ out dx,al
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_DMACProgram(int channel,int mode,ulong bufferPhys,int count);
+;----------------------------------------------------------------------------
+; Purpose: Program DMA controller to perform transfer from first 16MB
+; based on previously selected mode and channel. DMA transfer may be enabled
+; by subsequent call to PM_DMACEnable.
+;
+; Entry: channel - DMA channel in use (0-7)
+; mode - Selected DMAMODE type for transfer
+; buffer - 32-bit physical address of DMA buffer
+; count - DMA byte count (1-65536 bytes)
+;----------------------------------------------------------------------------
+cprocstart PM_DMACProgram
+
+ ARG channel:UINT, mode:UINT, bufferPhys:ULONG, count:UINT
+
+ enter_c
+ pushfd
+ cli ; Disable interrupts
+
+; Mask DMA channel to disable it
+
+ mov ebx,[channel] ; EBX indexes DMAC register tables
+ mov dh,0 ; DH = 0 for DMAC register port access
+ mov al,bl
+ and al,11b
+ or al,100b ; AL = (channel & 3) | "set mask bit"
+ mov dl,[DMAC_mask+ebx]
+ out dx,al
+
+; Generate IOW to clear FF toggle state
+
+ mov al,0
+ mov dl,[DMAC_FF+ebx]
+ out dx,al
+
+; Compute buffer address to program
+
+ mov eax,[bufferPhys] ; AX := DMA address offset
+ mov ecx,eax
+ shr ecx,16 ; CL := bufferPhys >> 16 (DMA page)
+ mov esi,[count] ; ESI = # of bytes to transfer
+ cmp ebx,4 ; 16-bit channel?
+ jb @@WriteDMAC ; No, program DMAC
+ shr eax,1 ; Yes, convert address and count
+ shr esi,1 ; to 16-bit, 128K/page format
+
+; Set the DMA address word (bits 0-15)
+
+@@WriteDMAC:
+ mov dl,[DMAC_addr+ebx]
+ out dx,al
+ mov al,ah
+ out dx,al
+
+; Set DMA transfer count
+
+ mov eax,esi
+ dec eax ; ESI = # of bytes to transfer - 1
+ mov dl,[DMAC_cnt+ebx]
+ out dx,al
+ mov al,ah
+ out dx,al
+
+; Set DMA page byte (bits 16-23)
+
+ mov al,cl
+ mov dl,[DMAC_page+ebx]
+ out dx,al
+
+; Set the DMA channel mode
+
+ mov al,bl
+ and al,11b
+ or al,[BYTE mode] ; EAX = (channel & 3) | mode
+ mov dl,[DMAC_mode+ebx]
+ out dx,al
+
+ pop eax ; SMP safe interrupt state restore!
+ test eax,200h
+ jz @@1
+ sti
+@@1: leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong PMAPI PM_DMACPosition(int channel);
+;----------------------------------------------------------------------------
+; Returns the current position in a dma transfer. Interrupts should be
+; disabled before calling this function.
+;----------------------------------------------------------------------------
+cprocstart PM_DMACPosition
+
+ ARG channel:UINT
+
+ enter_c
+ mov ecx,[channel] ; ECX indexes DMAC register tables
+ mov dh,0 ; DH = 0 for DMAC register port access
+
+; Generate IOW to clear FF toggle state
+
+ mov al,0
+ mov dl,[DMAC_FF+ebx]
+ out dx,al
+ xor eax,eax
+ xor ecx,ecx
+
+; Now read the current position for the channel
+
+@@ReadLoop:
+ mov dl,[DMAC_cnt+ebx]
+ out dx,al
+ in al,dx
+ mov cl,al
+ in al,dx
+ mov ch,al ; ECX := first count read
+ in al,dx
+ mov ah,al
+ in al,dx
+ xchg al,ah ; EAX := second count read
+ sub ecx,eax
+ cmp ecx,40h
+ jg @@ReadLoop
+ cmp ebx,4 ; 16-bit channel?
+ jb @@Exit ; No, we are done
+ shl eax,1 ; Yes, adjust to byte address
+
+@@Exit: leave_c
+ ret
+
+cprocend
+
+
+cpublic _PM_DMACodeEnd
+
+endif
+
+endcodeseg _dma
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_int64.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_int64.asm
new file mode 100644
index 0000000000..fdec1b58d8
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_int64.asm
@@ -0,0 +1,309 @@
+;****************************************************************************
+;*
+;* 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: NASM or TASM Assembler
+;* Environment: Intel 32 bit Protected Mode.
+;*
+;* Description: Code for 64-bit arhithmetic
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac"
+
+header _int64
+
+begcodeseg _int64 ; Start of code segment
+
+a_low EQU 04h ; Access a_low directly on stack
+a_high EQU 08h ; Access a_high directly on stack
+b_low EQU 0Ch ; Access b_low directly on stack
+shift EQU 0Ch ; Access shift directly on stack
+result_2 EQU 0Ch ; Access result directly on stack
+b_high EQU 10h ; Access b_high directly on stack
+result_3 EQU 10h ; Access result directly on stack
+result_4 EQU 14h ; Access result directly on stack
+
+;----------------------------------------------------------------------------
+; void _PM_add64(u32 a_low,u32 a_high,u32 b_low,u32 b_high,__u64 *result);
+;----------------------------------------------------------------------------
+; Adds two 64-bit numbers.
+;----------------------------------------------------------------------------
+cprocstart _PM_add64
+
+ mov eax,[esp+a_low]
+ add eax,[esp+b_low]
+ mov edx,[esp+a_high]
+ adc edx,[esp+b_high]
+ mov ecx,[esp+result_4]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_sub64(u32 a_low,u32 a_high,u32 b_low,u32 b_high,__u64 *result);
+;----------------------------------------------------------------------------
+; Subtracts two 64-bit numbers.
+;----------------------------------------------------------------------------
+cprocstart _PM_sub64
+
+ mov eax,[esp+a_low]
+ sub eax,[esp+b_low]
+ mov edx,[esp+a_high]
+ sbb edx,[esp+b_high]
+ mov ecx,[esp+result_4]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_mul64(u32 a_high,u32 a_low,u32 b_high,u32 b_low,__u64 *result);
+;----------------------------------------------------------------------------
+; Multiples two 64-bit numbers.
+;----------------------------------------------------------------------------
+cprocstart _PM_mul64
+
+ mov eax,[esp+a_high]
+ mov ecx,[esp+b_high]
+ or ecx,eax
+ mov ecx,[esp+b_low]
+ jnz @@FullMultiply
+ mov eax,[esp+a_low] ; EDX:EAX = b.low * a.low
+ mul ecx
+ mov ecx,[esp+result_4]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+@@FullMultiply:
+ push ebx
+ mul ecx ; EDX:EAX = a.high * b.low
+ mov ebx,eax
+ mov eax,[esp+a_low+4]
+ mul [DWORD esp+b_high+4] ; EDX:EAX = b.high * a.low
+ add ebx,eax
+ mov eax,[esp+a_low+4]
+ mul ecx ; EDX:EAX = a.low * b.low
+ add edx,ebx
+ pop ebx
+ mov ecx,[esp+result_4]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_div64(u32 a_low,u32 a_high,u32 b_low,u32 b_high,__u64 *result);
+;----------------------------------------------------------------------------
+; Divides two 64-bit numbers.
+;----------------------------------------------------------------------------
+cprocstart _PM_div64
+
+ push edi
+ push esi
+ push ebx
+ xor edi,edi
+ mov eax,[esp+a_high+0Ch]
+ or eax,eax
+ jns @@ANotNeg
+
+; Dividend is negative, so negate it and save result for later
+
+ inc edi
+ mov edx,[esp+a_low+0Ch]
+ neg eax
+ neg edx
+ sbb eax,0
+ mov [esp+a_high+0Ch],eax
+ mov [esp+a_low+0Ch],edx
+
+@@ANotNeg:
+ mov eax,[esp+b_high+0Ch]
+ or eax,eax
+ jns @@BNotNeg
+
+; Divisor is negative, so negate it and save result for later
+
+ inc edi
+ mov edx,[esp+b_low+0Ch]
+ neg eax
+ neg edx
+ sbb eax,0
+ mov [esp+b_high+0Ch],eax
+ mov [esp+b_low+0Ch],edx
+
+@@BNotNeg:
+ or eax,eax
+ jnz @@BHighNotZero
+
+; b.high is zero, so handle this faster
+
+ mov ecx,[esp+b_low+0Ch]
+ mov eax,[esp+a_high+0Ch]
+ xor edx,edx
+ div ecx
+ mov ebx,eax
+ mov eax,[esp+a_low+0Ch]
+ div ecx
+ mov edx,ebx
+ jmp @@BHighZero
+
+@@BHighNotZero:
+ mov ebx,eax
+ mov ecx,[esp+b_low+0Ch]
+ mov edx,[esp+a_high+0Ch]
+ mov eax,[esp+a_low+0Ch]
+
+; Shift values right until b.high becomes zero
+
+@@ShiftLoop:
+ shr ebx,1
+ rcr ecx,1
+ shr edx,1
+ rcr eax,1
+ or ebx,ebx
+ jnz @@ShiftLoop
+
+; Now complete the divide process
+
+ div ecx
+ mov esi,eax
+ mul [DWORD esp+b_high+0Ch]
+ mov ecx,eax
+ mov eax,[esp+b_low+0Ch]
+ mul esi
+ add edx,ecx
+ jb @@8
+ cmp edx,[esp+a_high+0Ch]
+ ja @@8
+ jb @@9
+ cmp eax,[esp+a_low+0Ch]
+ jbe @@9
+@@8: dec esi
+@@9: xor edx,edx
+ mov eax,esi
+
+@@BHighZero:
+ dec edi
+ jnz @@Done
+
+; The result needs to be negated as either a or b was negative
+
+ neg edx
+ neg eax
+ sbb edx,0
+
+@@Done: pop ebx
+ pop esi
+ pop edi
+ mov ecx,[esp+result_4]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; __i64 _PM_shr64(u32 a_low,s32 a_high,s32 shift,__u64 *result);
+;----------------------------------------------------------------------------
+; Shift a 64-bit number right
+;----------------------------------------------------------------------------
+cprocstart _PM_shr64
+
+ mov eax,[esp+a_low]
+ mov edx,[esp+a_high]
+ mov cl,[esp+shift]
+ shrd edx,eax,cl
+ mov ecx,[esp+result_3]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; __i64 _PM_sar64(u32 a_low,s32 a_high,s32 shift,__u64 *result);
+;----------------------------------------------------------------------------
+; Shift a 64-bit number right (signed)
+;----------------------------------------------------------------------------
+cprocstart _PM_sar64
+
+ mov eax,[esp+a_low]
+ mov edx,[esp+a_high]
+ mov cl,[esp+shift]
+ sar edx,cl
+ rcr eax,cl
+ mov ecx,[esp+result_3]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; __i64 _PM_shl64(u32 a_low,s32 a_high,s32 shift,__u64 *result);
+;----------------------------------------------------------------------------
+; Shift a 64-bit number left
+;----------------------------------------------------------------------------
+cprocstart _PM_shl64
+
+ mov eax,[esp+a_low]
+ mov edx,[esp+a_high]
+ mov cl,[esp+shift]
+ shld edx,eax,cl
+ mov ecx,[esp+result_3]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; __i64 _PM_neg64(u32 a_low,s32 a_high,__u64 *result);
+;----------------------------------------------------------------------------
+; Shift a 64-bit number left
+;----------------------------------------------------------------------------
+cprocstart _PM_neg64
+
+ mov eax,[esp+a_low]
+ mov edx,[esp+a_high]
+ neg eax
+ neg edx
+ sbb eax,0
+ mov ecx,[esp+result_2]
+ mov [ecx],eax
+ mov [ecx+4],edx
+ ret
+
+cprocend
+
+
+endcodeseg _int64
+
+ END
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_joy.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_joy.asm
new file mode 100644
index 0000000000..0ff1ecf55d
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_joy.asm
@@ -0,0 +1,230 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler
+;* Environment: Intel x86, any OS
+;*
+;* Description: Assembly language support routines for reading analogue
+;* joysticks.
+;*
+;****************************************************************************
+
+ ideal
+
+include "scitech.mac" ; Memory model macros
+
+ifdef flatmodel
+
+header _joy ; Set up memory model
+
+begcodeseg _joy ; Start of code segment
+
+;----------------------------------------------------------------------------
+; initTimer
+;----------------------------------------------------------------------------
+; Sets up 8253 timer 2 (PC speaker) to start timing, but not produce output.
+;----------------------------------------------------------------------------
+cprocstatic initTimer
+
+; Start timer 2 counting
+
+ in al,61h
+ and al,0FDh ; Disable speaker output (just in case)
+ or al,1
+ out 61h,al
+
+; Set the timer 2 count to 0 again to start the timing interval.
+
+ mov al,10110100b ; set up to load initial (timer 2)
+ out 43h,al ; timer count
+ sub al,al
+ out 42h,al ; load count lsb
+ out 42h,al ; load count msb
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; readTimer2
+;----------------------------------------------------------------------------
+; Reads the number of ticks from the 8253 timer chip using channel 2 (PC
+; speaker). This is non-destructive and does not screw up other libraries.
+;----------------------------------------------------------------------------
+cprocstatic readTimer
+
+ xor al,al ; Latch timer 0 command
+ out 43h,al ; Latch timer
+ in al,42h ; least significant byte
+ mov ah,al
+ in al,42h ; most significant byte
+ xchg ah,al
+ and eax,0FFFFh
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; exitTimer
+;----------------------------------------------------------------------------
+; Stops the 8253 timer 2 (PC speaker) counting
+;----------------------------------------------------------------------------
+cprocstatic exitTimer
+
+; Stop timer 2 from counting
+
+ push eax
+ in al,61h
+ and al,0FEh
+ out 61h,al
+
+; Some programs have a problem if we change the control port; better change it
+; to something they expect (mode 3 - square wave generator)...
+ mov al,0B6h
+ out 43h,al
+
+ pop eax
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int _EVT_readJoyAxis(int jmask,int *axis);
+;----------------------------------------------------------------------------
+; Function to poll the joystick to read the current axis positions.
+;----------------------------------------------------------------------------
+cprocstart _EVT_readJoyAxis
+
+ ARG jmask:UINT, axis:DPTR
+
+ LOCAL firstTick:UINT, lastTick:UINT, totalTicks:UINT = LocalSize
+
+ enter_c
+
+ mov ebx,[jmask]
+ mov edi,[axis]
+ mov ecx,(1193180/100)
+ and ebx,01111b ; Mask out supported axes
+ mov dx,201h ; DX := joystick I/O port
+ call initTimer ; Start timer 2 counting
+ call readTimer ; Returns counter in EAX
+ mov [lastTick],eax
+
+@@WaitStable:
+ in al,dx
+ and al,bl ; Wait for the axes in question to be
+ jz @@Stable ; done reading...
+ call readTimer ; Returns counter in EAX
+ xchg eax,[lastTick]
+ cmp eax,[lastTick]
+ jb @@1
+ sub eax,[lastTick]
+@@1: add [totalTicks],eax
+ cmp [totalTicks],ecx ; Check for timeout
+ jae @@Stable
+ jmp @@WaitStable
+
+@@Stable:
+ mov al,0FFh
+ out dx,al ; Start joystick reading
+ call initTimer ; Start timer 2 counting
+ call readTimer ; Returns counter in EAX
+ mov [firstTick],eax ; Store initial count
+ mov [lastTick],eax
+ mov [DWORD totalTicks],0
+ cli
+
+@@PollLoop:
+ in al,dx ; Read Joystick port
+ not al
+ and al,bl ; Mask off channels we don't want to read
+ jnz @@AxisFlipped ; See if any of the channels flipped
+ call readTimer ; Returns counter in EAX
+ xchg eax,[lastTick]
+ cmp eax,[lastTick]
+ jb @@2
+ sub eax,[lastTick]
+@@2: add [totalTicks],eax
+ cmp [totalTicks],ecx ; Check for timeout
+ jae @@TimedOut
+ jmp @@PollLoop
+
+@@AxisFlipped:
+ xor esi,esi
+ mov ah,1
+ test al,ah
+ jnz @@StoreCount ; Joystick 1, X axis flipped
+ add esi,4
+ mov ah,2
+ test al,ah
+ jnz @@StoreCount ; Joystick 1, Y axis flipped
+ add esi,4
+ mov ah,4
+ test al,ah
+ jnz @@StoreCount ; Joystick 2, X axis flipped
+ add esi,4 ; Joystick 2, Y axis flipped
+ mov ah,8
+
+@@StoreCount:
+ or bh,ah ; Indicate this axis is active
+ xor bl,ah ; Unmark the channels that just tripped
+ call readTimer ; Returns counter in EAX
+ xchg eax,[lastTick]
+ cmp eax,[lastTick]
+ jb @@3
+ sub eax,[lastTick]
+@@3: add [totalTicks],eax
+ mov eax,[totalTicks]
+ mov [edi+esi],eax ; Record the time this channel flipped
+ cmp bl,0 ; If there are more channels to read,
+ jne @@PollLoop ; keep looping
+
+@@TimedOut:
+ sti
+ call exitTimer ; Stop timer 2 counting
+ movzx eax,bh ; Return the mask of working axes
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int _EVT_readJoyButtons(void);
+;----------------------------------------------------------------------------
+; Function to poll the current joystick buttons
+;----------------------------------------------------------------------------
+cprocstart _EVT_readJoyButtons
+
+ mov dx,0201h
+ in al,dx
+ shr al,4
+ not al
+ and eax,0Fh
+ ret
+
+cprocend
+
+endcodeseg _joy
+
+endif
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_mtrr.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_mtrr.asm
new file mode 100644
index 0000000000..1e0a6966ce
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_mtrr.asm
@@ -0,0 +1,272 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: 16/32 bit Ring 0 device driver
+;*
+;* Description: Assembler support routines for the Memory Type Range Register
+;* (MTRR) module.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _mtrr ; Set up memory model
+
+begdataseg _mtrr
+
+ifdef DOS4GW
+ cextern _PM_haveCauseWay,UINT
+endif
+
+enddataseg _mtrr
+
+begcodeseg _mtrr ; Start of code segment
+
+P586
+
+;----------------------------------------------------------------------------
+; ibool _MTRR_isRing0(void);
+;----------------------------------------------------------------------------
+; Checks to see if we are running at ring 0. This check is only relevant
+; for 32-bit DOS4GW and compatible programs. If we are not running under
+; DOS4GW, then we simply assume we are a ring 0 device driver.
+;----------------------------------------------------------------------------
+cprocnear _MTRR_isRing0
+
+; Are we running under CauseWay?
+
+ifdef DOS4GW
+ enter_c
+ mov ax,cs
+ and eax,3
+ xor eax,3
+ jnz @@Exit
+
+; CauseWay runs the apps at ring 3, but implements support for specific
+; ring 0 instructions that we need to get stuff done under real DOS.
+
+ mov eax,1
+ cmp [UINT _PM_haveCauseWay],0
+ jnz @@Exit
+@@Fail: xor eax,eax
+@@Exit: leave_c
+ ret
+else
+ifdef __SMX32__
+ mov eax,1 ; SMX is ring 0!
+ ret
+else
+ifdef __VXD__
+ mov eax,1 ; VxD is ring 0!
+ ret
+else
+ifdef __NT_DRIVER__
+ mov eax,1 ; NT/W2K is ring 0!
+ ret
+else
+else
+ xor eax,eax ; Assume ring 3 for 32-bit DOS
+ ret
+endif
+endif
+endif
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _MTRR_disableInt(void);
+;----------------------------------------------------------------------------
+; Return processor interrupt status and disable interrupts.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_disableInt
+
+ pushfd ; Put flag word on stack
+ cli ; Disable interrupts!
+ pop eax ; deposit flag word in return register
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _MTRR_restoreInt(ulong ps);
+;----------------------------------------------------------------------------
+; Restore processor interrupt status.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_restoreInt
+
+ ARG ps:ULONG
+
+ push ebp
+ mov ebp,esp ; Set up stack frame
+ mov ecx,[ps]
+ test ecx,200h ; SMP safe interrupt flag restore!
+ jz @@1
+ sti
+@@1: pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _MTRR_saveCR4(void);
+;----------------------------------------------------------------------------
+; Save the value of CR4 and clear the Page Global Enable (bit 7). We also
+; disable and flush the caches.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_saveCR4
+
+ enter_c
+
+; Save value of CR4 and clear Page Global Enable (bit 7)
+
+ mov ebx,cr4
+ mov eax,ebx
+ and al,7Fh
+ mov cr4,eax
+
+; Disable and flush caches
+
+ mov eax,cr0
+ or eax,40000000h
+ wbinvd
+ mov cr0,eax
+ wbinvd
+
+; Return value from CR4
+
+ mov eax,ebx
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _MTRR_restoreCR4(ulong cr4Val)
+;----------------------------------------------------------------------------
+; Save the value of CR4 and clear the Page Global Enable (bit 7). We also
+; disable and flush the caches.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_restoreCR4
+
+ ARG cr4Val:ULONG
+
+ enter_c
+
+; Enable caches
+
+ mov eax,cr0
+ and eax,0BFFFFFFFh
+ mov cr0,eax
+ mov eax,[cr4Val]
+ mov cr4,eax
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uchar _MTRR_getCx86(uchar reg);
+;----------------------------------------------------------------------------
+; Read a Cyrix CPU indexed register
+;----------------------------------------------------------------------------
+cprocstart _MTRR_getCx86
+
+ ARG reg:UCHAR
+
+ enter_c
+ mov al,[reg]
+ out 22h,al
+ in al,23h
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uchar _MTRR_setCx86(uchar reg,uchar val);
+;----------------------------------------------------------------------------
+; Write a Cyrix CPU indexed register
+;----------------------------------------------------------------------------
+cprocstart _MTRR_setCx86
+
+ ARG reg:UCHAR, val:UCHAR
+
+ enter_c
+ mov al,[reg]
+ out 22h,al
+ mov al,[val]
+ out 23h,al
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _MTRR_readMSR(uong reg, ulong FAR *eax, ulong FAR *edx);
+;----------------------------------------------------------------------------
+; Writes the specific Machine Status Register used on the newer Intel
+; Pentium Pro and Pentium II motherboards.
+;----------------------------------------------------------------------------
+cprocnear _MTRR_readMSR
+
+ ARG reg:ULONG, v_eax:DPTR, v_edx:DPTR
+
+ enter_c
+ mov ecx,[reg]
+ rdmsr
+ mov ebx,[v_eax]
+ mov [ebx],eax
+ mov ebx,[v_edx]
+ mov [ebx],edx
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _MTRR_writeMSR(uong reg, ulong eax, ulong edx);
+;----------------------------------------------------------------------------
+; Writes the specific Machine Status Register used on the newer Intel
+; Pentium Pro and Pentium II motherboards.
+;----------------------------------------------------------------------------
+cprocnear _MTRR_writeMSR
+
+ ARG reg:ULONG, v_eax:ULONG, v_edx:ULONG
+
+ enter_c
+ mov ecx,[reg]
+ mov eax,[v_eax]
+ mov edx,[v_edx]
+ wrmsr
+ leave_c
+ ret
+
+cprocend
+
+endcodeseg _mtrr
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/_pcihelp.asm b/board/MAI/bios_emulator/scitech/src/pm/common/_pcihelp.asm
new file mode 100644
index 0000000000..5b8dbcc73a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/_pcihelp.asm
@@ -0,0 +1,358 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: Any
+;*
+;* Description: Helper assembler functions for PCI access module.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pcilib
+
+begcodeseg _pcilib
+
+ifdef flatmodel
+
+;----------------------------------------------------------------------------
+; uchar _ASMAPI _BIOS32_service(
+; ulong service,
+; ulong func,
+; ulong *physBase,
+; ulong *length,
+; ulong *serviceOffset,
+; PCIBIOS_entry entry);
+;----------------------------------------------------------------------------
+; Call the BIOS32 services directory
+;----------------------------------------------------------------------------
+cprocstart _BIOS32_service
+
+ ARG service:ULONG, func:ULONG, physBase:DPTR, len:DPTR, off:DPTR, entry:QWORD
+
+ enter_c
+ mov eax,[service]
+ mov ebx,[func]
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+ mov esi,[physBase]
+ mov [esi],ebx
+ mov esi,[len]
+ mov [esi],ecx
+ mov esi,[off]
+ mov [esi],edx
+ leave_c
+ ret
+
+cprocend
+
+endif
+
+;----------------------------------------------------------------------------
+; ushort _ASMAPI _PCIBIOS_isPresent(ulong i_eax,ulong *o_edx,ushort *oeax,
+; uchar *o_cl,PCIBIOS_entry entry)
+;----------------------------------------------------------------------------
+; Call the PCI BIOS to determine if it is present.
+;----------------------------------------------------------------------------
+cprocstart _PCIBIOS_isPresent
+
+ ARG i_eax:ULONG, o_edx:DPTR, oeax:DPTR, o_cl:DPTR, entry:QWORD
+
+ enter_c
+ mov eax,[i_eax]
+ifdef flatmodel
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+else
+ int 1Ah
+endif
+ _les _si,[o_edx]
+ mov [_ES _si],edx
+ _les _si,[oeax]
+ mov [_ES _si],ax
+ _les _si,[o_cl]
+ mov [_ES _si],cl
+ mov ax,bx
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _PCIBIOS_service(ulong r_eax,ulong r_ebx,ulong r_edi,ulong r_ecx,
+; PCIBIOS_entry entry)
+;----------------------------------------------------------------------------
+; Call the PCI BIOS services, either via the 32-bit protected mode entry
+; point or via the Int 1Ah 16-bit interrupt.
+;----------------------------------------------------------------------------
+cprocstart _PCIBIOS_service
+
+ ARG r_eax:ULONG, r_ebx:ULONG, r_edi:ULONG, r_ecx:ULONG, entry:QWORD
+
+ enter_c
+ mov eax,[r_eax]
+ mov ebx,[r_ebx]
+ mov edi,[r_edi]
+ mov ecx,[r_ecx]
+ifdef flatmodel
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+else
+ int 1Ah
+endif
+ mov eax,ecx
+ifndef flatmodel
+ shld edx,eax,16 ; Return result in DX:AX
+endif
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int _PCIBIOS_getRouting(PCIRoutingOptionsBuffer *buf,PCIBIOS_entry entry);
+;----------------------------------------------------------------------------
+; Get the routing options for PCI devices
+;----------------------------------------------------------------------------
+cprocstart _PCIBIOS_getRouting
+
+ ARG buf:DPTR, entry:QWORD
+
+ enter_c
+ mov eax,0B10Eh
+ mov bx,0
+ _les _di,[buf]
+ifdef flatmodel
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+else
+ int 1Ah
+endif
+ movzx eax,ah
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ibool _PCIBIOS_setIRQ(int busDev,int intPin,int IRQ,PCIBIOS_entry entry);
+;----------------------------------------------------------------------------
+; Change the IRQ routing for the PCI device
+;----------------------------------------------------------------------------
+cprocstart _PCIBIOS_setIRQ
+
+ ARG busDev:UINT, intPin:UINT, IRQ:UINT, entry:QWORD
+
+ enter_c
+ mov eax,0B10Fh
+ mov bx,[USHORT busDev]
+ mov cl,[BYTE intPin]
+ mov ch,[BYTE IRQ]
+ifdef flatmodel
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+else
+ int 1Ah
+endif
+ mov eax,1
+ jnc @@1
+ xor eax,eax ; Function failed!
+@@1: leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _PCIBIOS_specialCycle(int bus,ulong data,PCIBIOS_entry entry);
+;----------------------------------------------------------------------------
+; Generate a special cycle via the PCI BIOS.
+;----------------------------------------------------------------------------
+cprocstart _PCIBIOS_specialCycle
+
+ ARG bus:UINT, data:ULONG, entry:QWORD
+
+ enter_c
+ mov eax,0B106h
+ mov bh,[BYTE bus]
+ mov ecx,[data]
+ifdef flatmodel
+ifdef USE_NASM
+ call far dword [entry]
+else
+ call [FWORD entry]
+endif
+else
+ int 1Ah
+endif
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ushort _PCI_getCS(void)
+;----------------------------------------------------------------------------
+cprocstart _PCI_getCS
+
+ mov ax,cs
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_inpb(int port)
+;----------------------------------------------------------------------------
+; Reads a byte from the specified port
+;----------------------------------------------------------------------------
+cprocstart PM_inpb
+
+ ARG port:UINT
+
+ push _bp
+ mov _bp,_sp
+ xor _ax,_ax
+ mov _dx,[port]
+ in al,dx
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_inpw(int port)
+;----------------------------------------------------------------------------
+; Reads a word from the specified port
+;----------------------------------------------------------------------------
+cprocstart PM_inpw
+
+ ARG port:UINT
+
+ push _bp
+ mov _bp,_sp
+ xor _ax,_ax
+ mov _dx,[port]
+ in ax,dx
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong PM_inpd(int port)
+;----------------------------------------------------------------------------
+; Reads a word from the specified port
+;----------------------------------------------------------------------------
+cprocstart PM_inpd
+
+ ARG port:UINT
+
+ push _bp
+ mov _bp,_sp
+ mov _dx,[port]
+ in eax,dx
+ifndef flatmodel
+ shld edx,eax,16 ; DX:AX = result
+endif
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_outpb(int port,int value)
+;----------------------------------------------------------------------------
+; Write a byte to the specified port.
+;----------------------------------------------------------------------------
+cprocstart PM_outpb
+
+ ARG port:UINT, value:UINT
+
+ push _bp
+ mov _bp,_sp
+ mov _dx,[port]
+ mov _ax,[value]
+ out dx,al
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_outpw(int port,int value)
+;----------------------------------------------------------------------------
+; Write a word to the specified port.
+;----------------------------------------------------------------------------
+cprocstart PM_outpw
+
+ ARG port:UINT, value:UINT
+
+ push _bp
+ mov _bp,_sp
+ mov _dx,[port]
+ mov _ax,[value]
+ out dx,ax
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_outpd(int port,ulong value)
+;----------------------------------------------------------------------------
+; Write a word to the specified port.
+;----------------------------------------------------------------------------
+cprocstart PM_outpd
+
+ ARG port:UINT, value:ULONG
+
+ push _bp
+ mov _bp,_sp
+ mov _dx,[port]
+ mov eax,[value]
+ out dx,eax
+ pop _bp
+ ret
+
+cprocend
+
+endcodeseg _pcilib
+
+ END
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/agp.c b/board/MAI/bios_emulator/scitech/src/pm/common/agp.c
new file mode 100644
index 0000000000..23f7e1e145
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/agp.c
@@ -0,0 +1,190 @@
+/****************************************************************************
+*
+* 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: 32-bit Ring 0 device driver
+*
+* Description: Generic module to implement AGP support functions using the
+* SciTech Nucleus AGP support drivers. If the OS provides
+* native AGP support, this module should *NOT* be used. Instead
+* wrappers should be placed around the OS support functions
+* to implement this functionality.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#ifndef REALMODE
+#include "nucleus/agp.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+static AGP_devCtx *agp;
+static AGP_driverFuncs driver;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+RETURNS:
+Size of AGP aperture in MB on success, 0 on failure.
+
+REMARKS:
+This function initialises the AGP driver in the system and returns the
+size of the available AGP aperture in megabytes.
+****************************************************************************/
+ulong PMAPI PM_agpInit(void)
+{
+ if ((agp = AGP_loadDriver(0)) == NULL)
+ return 0;
+ driver.dwSize = sizeof(driver);
+ if (!agp->QueryFunctions(AGP_GET_DRIVERFUNCS,&driver))
+ return 0;
+ switch (driver.GetApertureSize()) {
+ case agpSize4MB: return 4;
+ case agpSize8MB: return 8;
+ case agpSize16MB: return 16;
+ case agpSize32MB: return 32;
+ case agpSize64MB: return 64;
+ case agpSize128MB: return 128;
+ case agpSize256MB: return 256;
+ case agpSize512MB: return 512;
+ case agpSize1GB: return 1024;
+ case agpSize2GB: return 2048;
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+This function closes down the loaded AGP driver.
+****************************************************************************/
+void PMAPI PM_agpExit(void)
+{
+ AGP_unloadDriver(agp);
+}
+
+/****************************************************************************
+PARAMETERS:
+numPages - Number of memory pages that should be reserved
+type - Type of memory to allocate
+physContext - Returns the physical context handle for the mapping
+physAddr - Returns the physical address for the mapping
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function reserves a range of physical memory addresses on the system
+bus which the AGP controller will respond to. If this function succeeds,
+the AGP controller can respond to the reserved physical address range on
+the bus. However you must first call AGP_commitPhysical to cause this memory
+to actually be committed for use before it can be accessed.
+****************************************************************************/
+ibool PMAPI PM_agpReservePhysical(
+ ulong numPages,
+ int type,
+ void **physContext,
+ PM_physAddr *physAddr)
+{
+ switch (type) {
+ case PM_agpUncached:
+ type = agpUncached;
+ break;
+ case PM_agpWriteCombine:
+ type = agpWriteCombine;
+ break;
+ case PM_agpIntelDCACHE:
+ type = agpIntelDCACHE;
+ break;
+ default:
+ return false;
+ }
+ return driver.ReservePhysical(numPages,type,physContext,physAddr) == nOK;
+}
+
+/****************************************************************************
+PARAMETERS:
+physContext - Physical AGP context to release
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function releases a range of physical memory addresses on the system
+bus which the AGP controller will respond to. All committed memory for
+the physical address range covered by the context will be released.
+****************************************************************************/
+ibool PMAPI PM_agpReleasePhysical(
+ void *physContext)
+{
+ return driver.ReleasePhysical(physContext) == nOK;
+}
+
+/****************************************************************************
+PARAMETERS:
+physContext - Physical AGP context to commit memory for
+numPages - Number of pages to be committed
+startOffset - Offset in pages into the reserved physical context
+physAddr - Returns the physical address of the committed memory
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function commits into the specified physical context that was previously
+reserved by a call to ReservePhysical. You can use the startOffset and
+numPages parameters to only commit portions of the reserved memory range at
+a time.
+****************************************************************************/
+ibool PMAPI PM_agpCommitPhysical(
+ void *physContext,
+ ulong numPages,
+ ulong startOffset,
+ PM_physAddr *physAddr)
+{
+ return driver.CommitPhysical(physContext,numPages,startOffset,physAddr) == nOK;
+}
+
+/****************************************************************************
+PARAMETERS:
+physContext - Physical AGP context to free memory for
+numPages - Number of pages to be freed
+startOffset - Offset in pages into the reserved physical context
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function frees memory previously committed by the CommitPhysical
+function. Note that you can free a portion of a memory range that was
+previously committed if you wish.
+****************************************************************************/
+ibool PMAPI PM_agpFreePhysical(
+ void *physContext,
+ ulong numPages,
+ ulong startOffset)
+{
+ return driver.FreePhysical(physContext,numPages,startOffset) == nOK;
+}
+
+#endif /* !REALMODE */
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/keyboard.c b/board/MAI/bios_emulator/scitech/src/pm/common/keyboard.c
new file mode 100644
index 0000000000..79b4040ac1
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/keyboard.c
@@ -0,0 +1,450 @@
+/****************************************************************************
+*
+* 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: Direct keyboard event handling module. This module contains
+* code to process raw scan code information, convert it to
+* virtual scan codes and do code page translation to ASCII
+* for different international keyboard layouts.
+*
+****************************************************************************/
+
+/*---------------------------- Implementation -----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+scanCode - Keyboard scan code to translate
+table - Code page table to search
+count - Number of entries in the code page table
+
+REMARKS:
+This function translates the scan codes from keyboard scan codes to ASCII
+codes using a binary search on the code page table.
+****************************************************************************/
+static uchar translateScan(
+ uchar scanCode,
+ codepage_entry_t *table,
+ int count)
+{
+ codepage_entry_t *test;
+ int n,pivot,val;
+
+ for (n = count; n > 0; ) {
+ pivot = n >> 1;
+ test = table + pivot;
+ val = scanCode - test->scanCode;
+ if (val < 0)
+ n = pivot;
+ else if (val == 0)
+ return test->asciiCode;
+ else {
+ table = test + 1;
+ n -= pivot + 1;
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+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 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.
+{secret}
+****************************************************************************/
+void _EVT_maskKeyCode(
+ event_t *evt)
+{
+ int ascii,scan = EVT_scanCode(evt->message);
+
+ evt->message &= ~0xFF;
+ if (evt->modifiers & EVT_NUMLOCK) {
+ if ((ascii = translateScan(scan,EVT.codePage->numPad,EVT.codePage->numPadLen)) != 0) {
+ evt->message |= ascii;
+ return;
+ }
+ }
+ if (evt->modifiers & EVT_CTRLSTATE) {
+ evt->message |= translateScan(scan,EVT.codePage->ctrl,EVT.codePage->ctrlLen);
+ return;
+ }
+ if (evt->modifiers & EVT_CAPSLOCK) {
+ if (evt->modifiers & EVT_SHIFTKEY) {
+ if ((ascii = translateScan(scan,EVT.codePage->shiftCaps,EVT.codePage->shiftCapsLen)) != 0) {
+ evt->message |= ascii;
+ return;
+ }
+ }
+ else {
+ if ((ascii = translateScan(scan,EVT.codePage->caps,EVT.codePage->capsLen)) != 0) {
+ evt->message |= ascii;
+ return;
+ }
+ }
+ }
+ if (evt->modifiers & EVT_SHIFTKEY) {
+ if ((ascii = translateScan(scan,EVT.codePage->shift,EVT.codePage->shiftLen)) != 0) {
+ evt->message |= ascii;
+ return;
+ }
+ }
+ evt->message |= translateScan(scan,EVT.codePage->normal,EVT.codePage->normalLen);
+}
+
+/****************************************************************************
+REMARKS:
+Returns true if the key with the specified scan code is being held down.
+****************************************************************************/
+static ibool _EVT_isKeyDown(
+ uchar scanCode)
+{
+ if (scanCode > 0x7F)
+ return false;
+ else
+ return EVT.keyTable[scanCode] != 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+what - Event code
+message - Event message (ASCII code and scan code)
+
+REMARKS:
+Adds a new keyboard event to the event queue. This routine is called from
+within the keyboard interrupt subroutine!
+
+NOTE: Interrupts are OFF when this routine is called by the keyboard ISR,
+ and we leave them OFF the entire time.
+****************************************************************************/
+static void addKeyEvent(
+ uint what,
+ uint message)
+{
+ event_t evt;
+
+ if (EVT.count < EVENTQSIZE) {
+ /* Save information in event record */
+ evt.when = _EVT_getTicks();
+ evt.what = what;
+ evt.message = message | 0x10000UL;
+ evt.where_x = 0;
+ evt.where_y = 0;
+ evt.relative_x = 0;
+ evt.relative_y = 0;
+ evt.modifiers = EVT.keyModifiers;
+ if (evt.what == EVT_KEYREPEAT) {
+ if (EVT.oldKey != -1)
+ EVT.evtq[EVT.oldKey].message += 0x10000UL;
+ else {
+ EVT.oldKey = EVT.freeHead;
+ addEvent(&evt); /* Add to tail of event queue */
+ }
+ }
+ else {
+#ifdef __QNX__
+ _EVT_maskKeyCode(&evt);
+#endif
+ addEvent(&evt); /* Add to tail of event queue */
+ }
+ EVT.oldMove = -1;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+This function waits for the keyboard controller to set the ready-for-write
+bit.
+****************************************************************************/
+static int kbWaitForWriteReady(void)
+{
+ int timeout = 8192;
+ while ((timeout > 0) && (PM_inpb(0x64) & 0x02))
+ timeout--;
+ return (timeout > 0);
+}
+
+/****************************************************************************
+REMARKS:
+This function waits for the keyboard controller to set the ready-for-read
+bit.
+****************************************************************************/
+static int kbWaitForReadReady(void)
+{
+ int timeout = 8192;
+ while ((timeout > 0) && (!(PM_inpb(0x64) & 0x01)))
+ timeout--;
+ return (timeout > 0);
+}
+
+/****************************************************************************
+PARAMETERS:
+data - Data to send to the keyboard
+
+REMARKS:
+This function sends a data byte to the keyboard controller.
+****************************************************************************/
+static int kbSendData(
+ uchar data)
+{
+ int resends = 4;
+ int timeout, temp;
+
+ do {
+ if (!kbWaitForWriteReady())
+ return 0;
+ PM_outpb(0x60,data);
+ timeout = 8192;
+ while (--timeout > 0) {
+ if (!kbWaitForReadReady())
+ return 0;
+ temp = PM_inpb(0x60);
+ if (temp == 0xFA)
+ return 1;
+ if (temp == 0xFE)
+ break;
+ }
+ } while ((resends-- > 0) && (timeout > 0));
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+modifiers - Keyboard modifier flags
+
+REMARKS:
+This function re-programs the LED's on the keyboard to the values stored
+in the passed in modifier flags. If the 'allowLEDS' flag is false, this
+function does nothing.
+****************************************************************************/
+static void setLEDS(
+ uint modifiers)
+{
+ if (EVT.allowLEDS) {
+ if (!kbSendData(0xED) || !kbSendData((modifiers>>9) & 7)) {
+ kbSendData(0xF4);
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Function to process raw scan codes read from the keyboard controller.
+
+NOTE: Interrupts are OFF when this routine is called by the keyboard ISR,
+ and we leave them OFF the entire time.
+{secret}
+****************************************************************************/
+void processRawScanCode(
+ int scan)
+{
+ static int pauseLoop = 0;
+ static int extended = 0;
+ int what;
+
+ if (pauseLoop) {
+ /* Skip scan codes until the pause key sequence has been read */
+ pauseLoop--;
+ }
+ else if (scan == 0xE0) {
+ /* This signals the start of an extended scan code sequence */
+ extended = 1;
+ }
+ else if (scan == 0xE1) {
+ /* The Pause key sends a strange scan code sequence, which is:
+ *
+ * E1 1D 52 E1 9D D2
+ *
+ * However there is never any release code nor any auto-repeat for
+ * this key. For this reason we simply ignore the key and skip the
+ * next 5 scan codes read from the keyboard.
+ */
+ pauseLoop = 5;
+ }
+ else {
+ /* Process the scan code normally (it may be an extended code
+ * however!). Bit 7 means key was released, and bits 0-6 are the
+ * scan code.
+ */
+ what = (scan & 0x80) ? EVT_KEYUP : EVT_KEYDOWN;
+ scan &= 0x7F;
+ if (extended) {
+ extended = 0;
+ if (scan == 0x2A || scan == 0x36) {
+ /* Ignore these extended scan code sequences. These are
+ * used by the keyboard controller to wrap around certain
+ * key sequences for the keypad (and when NUMLOCK is down
+ * internally).
+ */
+ return;
+ }
+
+ /* Convert extended codes for key sequences that we map to
+ * virtual scan codes so the user can detect them in their
+ * code.
+ */
+ switch (scan) {
+ case KB_leftCtrl: scan = KB_rightCtrl; break;
+ case KB_leftAlt: scan = KB_rightAlt; break;
+ case KB_divide: scan = KB_padDivide; break;
+ case KB_enter: scan = KB_padEnter; break;
+ case KB_padTimes: scan = KB_sysReq; break;
+ }
+ }
+ else {
+ /* Convert regular scan codes for key sequences that we map to
+ * virtual scan codes so the user can detect them in their
+ * code.
+ */
+ switch (scan) {
+ case KB_left: scan = KB_padLeft; break;
+ case KB_right: scan = KB_padRight; break;
+ case KB_up: scan = KB_padUp; break;
+ case KB_down: scan = KB_padDown; break;
+ case KB_insert: scan = KB_padInsert; break;
+ case KB_delete: scan = KB_padDelete; break;
+ case KB_home: scan = KB_padHome; break;
+ case KB_end: scan = KB_padEnd; break;
+ case KB_pageUp: scan = KB_padPageUp; break;
+ case KB_pageDown: scan = KB_padPageDown; break;
+ }
+ }
+
+ /* Determine if the key is an UP, DOWN or REPEAT and maintain the
+ * up/down status of all keys in our global key array.
+ */
+ if (what == EVT_KEYDOWN) {
+ if (EVT.keyTable[scan])
+ what = EVT_KEYREPEAT;
+ else
+ EVT.keyTable[scan] = scan;
+ }
+ else {
+ EVT.keyTable[scan] = 0;
+ }
+
+ /* Handle shift key modifiers */
+ if (what != EVT_KEYREPEAT) {
+ switch (scan) {
+ case KB_capsLock:
+ if (what == EVT_KEYDOWN)
+ EVT.keyModifiers ^= EVT_CAPSLOCK;
+ setLEDS(EVT.keyModifiers);
+ break;
+ case KB_numLock:
+ if (what == EVT_KEYDOWN)
+ EVT.keyModifiers ^= EVT_NUMLOCK;
+ setLEDS(EVT.keyModifiers);
+ break;
+ case KB_scrollLock:
+ if (what == EVT_KEYDOWN)
+ EVT.keyModifiers ^= EVT_SCROLLLOCK;
+ setLEDS(EVT.keyModifiers);
+ break;
+ case KB_leftShift:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_LEFTSHIFT;
+ else
+ EVT.keyModifiers |= EVT_LEFTSHIFT;
+ break;
+ case KB_rightShift:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_RIGHTSHIFT;
+ else
+ EVT.keyModifiers |= EVT_RIGHTSHIFT;
+ break;
+ case KB_leftCtrl:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_LEFTCTRL;
+ else
+ EVT.keyModifiers |= EVT_LEFTCTRL;
+ break;
+ case KB_rightCtrl:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_RIGHTCTRL;
+ else
+ EVT.keyModifiers |= EVT_RIGHTCTRL;
+ break;
+ case KB_leftAlt:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_LEFTALT;
+ else
+ EVT.keyModifiers |= EVT_LEFTALT;
+ break;
+ case KB_rightAlt:
+ if (what == EVT_KEYUP)
+ EVT.keyModifiers &= ~EVT_RIGHTALT;
+ else
+ EVT.keyModifiers |= EVT_RIGHTALT;
+ break;
+#ifdef SUPPORT_CTRL_ALT_DEL
+ case KB_delete:
+ if ((EVT.keyModifiers & EVT_CTRLSTATE) && (EVT.keyModifiers & EVT_ALTSTATE))
+ Reboot();
+ break;
+#endif
+ }
+ }
+
+ /* Add the untranslated key code to the event queue. All
+ * translation to ASCII from the key codes occurs when the key
+ * is extracted from the queue, saving time in the low level
+ * interrupt handler.
+ */
+ addKeyEvent(what,scan << 8);
+ }
+}
+
+/****************************************************************************
+DESCRIPTION:
+Enables/disables the update of the keyboard LED status indicators.
+
+HEADER:
+event.h
+
+PARAMETERS:
+enable - True to enable, false to disable
+
+REMARKS:
+Enables the update of the keyboard LED status indicators. Sometimes it may
+be convenient in the application to turn off the updating of the LED
+status indicators (such as if a game is using the CAPSLOCK key for some
+function). Passing in a value of FALSE to this function will turn off all
+the LEDS, and stop updating them when the internal status changes (note
+however that internally we still keep track of the toggle key status!).
+****************************************************************************/
+void EVTAPI EVT_allowLEDS(
+ ibool enable)
+{
+ EVT.allowLEDS = true;
+ if (enable)
+ setLEDS(EVT.keyModifiers);
+ else
+ setLEDS(0);
+ EVT.allowLEDS = enable;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/malloc.c b/board/MAI/bios_emulator/scitech/src/pm/common/malloc.c
new file mode 100644
index 0000000000..83ef22113c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/malloc.c
@@ -0,0 +1,205 @@
+/****************************************************************************
+*
+* 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: Module for implementing the PM library overrideable memory
+* allocator functions.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+void * (*__PM_malloc)(size_t size) = malloc;
+void * (*__PM_calloc)(size_t nelem,size_t size) = calloc;
+void * (*__PM_realloc)(void *ptr,size_t size) = realloc;
+void (*__PM_free)(void *p) = free;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+DESCRIPTION:
+Use local memory allocation routines.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+malloc - Pointer to new malloc routine to use
+calloc - Pointer to new caalloc routine to use
+realloc - Pointer to new realloc routine to use
+free - Pointer to new free routine to use
+
+REMARKS:
+Tells the PM library to use a set of user specified memory allocation
+routines instead of using the normal malloc/calloc/realloc/free standard
+C library functions. This is useful if you wish to use a third party
+debugging malloc library or perhaps a set of faster memory allocation
+functions with the PM library, or any apps that use the PM library (such as
+the MGL). Once you have registered your memory allocation routines, all
+calls to PM_malloc, PM_calloc, PM_realloc and PM_free will be revectored to
+your local memory allocation routines.
+
+This is also useful if you need to keep track of just how much physical
+memory your program has been using. You can use the PM_availableMemory
+function to find out how much physical memory is available when the program
+starts, and then you can use your own local memory allocation routines to
+keep track of how much memory has been used and freed.
+
+NOTE: This function should be called right at the start of your application,
+ before you initialise any other components or libraries.
+
+NOTE: Code compiled into Binary Portable DLL's and Drivers automatically
+ end up calling these functions via the BPD C runtime library.
+
+SEE ALSO:
+PM_malloc, PM_calloc, PM_realloc, PM_free, PM_availableMemory
+****************************************************************************/
+void PMAPI PM_useLocalMalloc(
+ void * (*malloc)(size_t size),
+ void * (*calloc)(size_t nelem,size_t size),
+ void * (*realloc)(void *ptr,size_t size),
+ void (*free)(void *p))
+{
+ __PM_malloc = malloc;
+ __PM_calloc = calloc;
+ __PM_realloc = realloc;
+ __PM_free = free;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Allocate a block of memory.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+size - Size of block to allocate in bytes
+
+RETURNS:
+Pointer to allocated block, or NULL if out of memory.
+
+REMARKS:
+Allocates a block of memory of length size. If you have changed the memory
+allocation routines with the PM_useLocalMalloc function, then calls to this
+function will actually make calls to the local memory allocation routines
+that you have registered.
+
+SEE ALSO:
+PM_calloc, PM_realloc, PM_free, PM_useLocalMalloc
+****************************************************************************/
+void * PMAPI PM_malloc(
+ size_t size)
+{
+ return __PM_malloc(size);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Allocate and clear a large memory block.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+nelem - number of contiguous size-byte units to allocate
+size - size of unit in bytes
+
+RETURNS:
+Pointer to allocated memory if successful, NULL if out of memory.
+
+REMARKS:
+Allocates a block of memory of length (size * nelem), and clears the
+allocated area with zeros (0). If you have changed the memory allocation
+routines with the PM_useLocalMalloc function, then calls to this function
+will actually make calls to the local memory allocation routines that you
+have registered.
+
+SEE ALSO:
+PM_malloc, PM_realloc, PM_free, PM_useLocalMalloc
+****************************************************************************/
+void * PMAPI PM_calloc(
+ size_t nelem,
+ size_t size)
+{
+ return __PM_calloc(nelem,size);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Re-allocate a block of memory
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+ptr - Pointer to block to resize
+size - size of unit in bytes
+
+RETURNS:
+Pointer to allocated memory if successful, NULL if out of memory.
+
+REMARKS:
+This function reallocates a block of memory that has been previously been
+allocated to the new of size. The new size may be smaller or larger than
+the original block of memory. If you have changed the memory allocation
+routines with the PM_useLocalMalloc function, then calls to this function
+will actually make calls to the local memory allocation routines that you
+have registered.
+
+SEE ALSO:
+PM_malloc, PM_calloc, PM_free, PM_useLocalMalloc
+****************************************************************************/
+void * PMAPI PM_realloc(
+ void *ptr,
+ size_t size)
+{
+ return __PM_realloc(ptr,size);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Frees a block of memory.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+p - Pointer to memory block to free
+
+REMARKS:
+Frees a block of memory previously allocated with either PM_malloc,
+PM_calloc or PM_realloc.
+
+SEE ALSO:
+PM_malloc, PM_calloc, PM_realloc, PM_useLocalMalloc
+****************************************************************************/
+void PMAPI PM_free(
+ void *p)
+{
+ __PM_free(p);
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/mtrr.c b/board/MAI/bios_emulator/scitech/src/pm/common/mtrr.c
new file mode 100644
index 0000000000..d6ced6eadc
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/mtrr.c
@@ -0,0 +1,867 @@
+/****************************************************************************
+*
+* 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.
+*
+* ========================================================================
+*
+* Heavily based on code copyright (C) Richard Gooch
+*
+* Language: ANSI C
+* Environment: 32-bit Ring 0 device driver
+*
+* Description: Generic Memory Type Range Register (MTRR) functions to
+* manipulate the MTRR registers on supported CPU's. This code
+* *must* run at ring 0, so you can't normally include this
+* code directly in normal applications (the except is DOS4GW
+* apps which run at ring 0 under real DOS). Thus this code
+* will normally be compiled into a ring 0 device driver for
+* the target operating system.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "ztimerc.h"
+#include "mtrr.h"
+
+#ifndef REALMODE
+
+/*--------------------------- Global variables ----------------------------*/
+
+/* Intel pre-defined MTRR registers */
+
+#define NUM_FIXED_RANGES 88
+#define INTEL_cap_MSR 0x0FE
+#define INTEL_defType_MSR 0x2FF
+#define INTEL_fix64K_00000_MSR 0x250
+#define INTEL_fix16K_80000_MSR 0x258
+#define INTEL_fix16K_A0000_MSR 0x259
+#define INTEL_fix4K_C0000_MSR 0x268
+#define INTEL_fix4K_C8000_MSR 0x269
+#define INTEL_fix4K_D0000_MSR 0x26A
+#define INTEL_fix4K_D8000_MSR 0x26B
+#define INTEL_fix4K_E0000_MSR 0x26C
+#define INTEL_fix4K_E8000_MSR 0x26D
+#define INTEL_fix4K_F0000_MSR 0x26E
+#define INTEL_fix4K_F8000_MSR 0x26F
+
+/* Macros to find the address of a paricular MSR register */
+
+#define INTEL_physBase_MSR(reg) (0x200 + 2 * (reg))
+#define INTEL_physMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+/* Cyrix CPU configuration register indexes */
+#define CX86_CCR0 0xC0
+#define CX86_CCR1 0xC1
+#define CX86_CCR2 0xC2
+#define CX86_CCR3 0xC3
+#define CX86_CCR4 0xE8
+#define CX86_CCR5 0xE9
+#define CX86_CCR6 0xEA
+#define CX86_DIR0 0xFE
+#define CX86_DIR1 0xFF
+#define CX86_ARR_BASE 0xC4
+#define CX86_RCR_BASE 0xDC
+
+/* Structure to maintain machine state while updating MTRR registers */
+
+typedef struct {
+ ulong flags;
+ ulong defTypeLo;
+ ulong defTypeHi;
+ ulong cr4Val;
+ ulong ccr3;
+ } MTRRContext;
+
+static int numMTRR = -1;
+static int cpuFamily,cpuType,cpuStepping;
+static void (*getMTRR)(uint reg,ulong *base,ulong *size,int *type) = NULL;
+static void (*setMTRR)(uint reg,ulong base,ulong size,int type) = NULL;
+static int (*getFreeRegion)(ulong base,ulong size) = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+RETURNS:
+Returns non-zero if we have the write-combining memory type
+****************************************************************************/
+static int MTRR_haveWriteCombine(void)
+{
+ ulong config,dummy;
+
+ switch (cpuFamily) {
+ case CPU_AMD:
+ if (cpuType < CPU_AMDAthlon) {
+ /* AMD K6-2 stepping 8 and later support the MTRR registers.
+ * The earlier K6-2 steppings (300Mhz models) do not
+ * support MTRR's.
+ */
+ if ((cpuType < CPU_AMDK6_2) || (cpuType == CPU_AMDK6_2 && cpuStepping < 8))
+ return 0;
+ return 1;
+ }
+ /* Fall through for AMD Athlon which uses P6 style MTRR's */
+ case CPU_Intel:
+ _MTRR_readMSR(INTEL_cap_MSR,&config,&dummy);
+ return (config & (1 << 10));
+ case CPU_Cyrix:
+ /* Cyrix 6x86 and later support the MTRR registers */
+ if (cpuType < CPU_Cyrix6x86)
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+
+RETURNS:
+The index of the region on success, else -1 on error.
+
+REMARKS:
+Generic function to find the location of a free MTRR register to be used
+for creating a new mapping.
+****************************************************************************/
+static int GENERIC_getFreeRegion(
+ ulong base,
+ ulong size)
+{
+ int i,ltype;
+ ulong lbase,lsize;
+
+ for (i = 0; i < numMTRR; i++) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ if (lsize < 1)
+ return i;
+ }
+ (void)base;
+ (void)size;
+ return -1;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+
+RETURNS:
+The index of the region on success, else -1 on error.
+
+REMARKS:
+Generic function to find the location of a free MTRR register to be used
+for creating a new mapping.
+****************************************************************************/
+static int AMDK6_getFreeRegion(
+ ulong base,
+ ulong size)
+{
+ int i,ltype;
+ ulong lbase,lsize;
+
+ for (i = 0; i < numMTRR; i++) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ if (lsize < 1)
+ return i;
+ }
+ (void)base;
+ (void)size;
+ return -1;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+
+RETURNS:
+The index of the region on success, else -1 on error.
+
+REMARKS:
+Cyrix specific function to find the location of a free MTRR register to be
+used for creating a new mapping.
+****************************************************************************/
+static int CYRIX_getFreeRegion(
+ ulong base,
+ ulong size)
+{
+ int i,ltype;
+ ulong lbase, lsize;
+
+ if (size > 0x2000000UL) {
+ /* If we are to set up a region >32M then look at ARR7 immediately */
+ getMTRR(7,&lbase,&lsize,&ltype);
+ if (lsize < 1)
+ return 7;
+ }
+ else {
+ /* Check ARR0-6 registers */
+ for (i = 0; i < 7; i++) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ if (lsize < 1)
+ return i;
+ }
+ /* Try ARR7 but its size must be at least 256K */
+ getMTRR(7,&lbase,&lsize,&ltype);
+ if ((lsize < 1) && (size >= 0x40000))
+ return i;
+ }
+ (void)base;
+ return -1;
+}
+
+/****************************************************************************
+PARAMETERS:
+c - Place to store the machine context across the call
+
+REMARKS:
+Puts the processor into a state where MTRRs can be safely updated
+****************************************************************************/
+static void MTRR_beginUpdate(
+ MTRRContext *c)
+{
+ c->flags = _MTRR_disableInt();
+ if (cpuFamily != CPU_AMD || (cpuFamily == CPU_AMD && cpuType >= CPU_AMDAthlon)) {
+ switch (cpuFamily) {
+ case CPU_Intel:
+ case CPU_AMD:
+ /* Disable MTRRs, and set the default type to uncached */
+ c->cr4Val = _MTRR_saveCR4();
+ _MTRR_readMSR(INTEL_defType_MSR,&c->defTypeLo,&c->defTypeHi);
+ _MTRR_writeMSR(INTEL_defType_MSR,c->defTypeLo & 0xF300UL,c->defTypeHi);
+ break;
+ case CPU_Cyrix:
+ c->ccr3 = _MTRR_getCx86(CX86_CCR3);
+ _MTRR_setCx86(CX86_CCR3, (uchar)((c->ccr3 & 0x0F) | 0x10));
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+c - Place to restore the machine context from
+
+REMARKS:
+Restores the processor after updating any of the registers
+****************************************************************************/
+static void MTRR_endUpdate(
+ MTRRContext *c)
+{
+ if (cpuFamily != CPU_AMD || (cpuFamily == CPU_AMD && cpuType >= CPU_AMDAthlon)) {
+ PM_flushTLB();
+ switch (cpuFamily) {
+ case CPU_Intel:
+ case CPU_AMD:
+ _MTRR_writeMSR(INTEL_defType_MSR,c->defTypeLo,c->defTypeHi);
+ _MTRR_restoreCR4(c->cr4Val);
+ break;
+ case CPU_Cyrix:
+ _MTRR_setCx86(CX86_CCR3,(uchar)c->ccr3);
+ break;
+ }
+ }
+
+ /* Re-enable interrupts (if enabled previously) */
+ _MTRR_restoreInt(c->flags);
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to read
+base - Place to store the starting physical base address of the region
+size - Place to store the size in bytes of the region
+type - Place to store the type of the MTRR register
+
+REMARKS:
+Intel specific function to read the value of a specific MTRR register.
+****************************************************************************/
+static void INTEL_getMTRR(
+ uint reg,
+ ulong *base,
+ ulong *size,
+ int *type)
+{
+ ulong hi,maskLo,baseLo;
+
+ _MTRR_readMSR(INTEL_physMask_MSR(reg),&maskLo,&hi);
+ if ((maskLo & 0x800) == 0) {
+ /* MTRR is disabled, so it is free */
+ *base = 0;
+ *size = 0;
+ *type = 0;
+ return;
+ }
+ _MTRR_readMSR(INTEL_physBase_MSR(reg),&baseLo,&hi);
+ maskLo = (maskLo & 0xFFFFF000UL);
+ *size = ~(maskLo - 1);
+ *base = (baseLo & 0xFFFFF000UL);
+ *type = (baseLo & 0xFF);
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to set
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+REMARKS:
+Intel specific function to set the value of a specific MTRR register to
+the passed in base, size and type.
+****************************************************************************/
+static void INTEL_setMTRR(
+ uint reg,
+ ulong base,
+ ulong size,
+ int type)
+{
+ MTRRContext c;
+
+ MTRR_beginUpdate(&c);
+ if (size == 0) {
+ /* The invalid bit is kept in the mask, so we simply clear the
+ * relevant mask register to disable a range.
+ */
+ _MTRR_writeMSR(INTEL_physMask_MSR(reg),0,0);
+ }
+ else {
+ _MTRR_writeMSR(INTEL_physBase_MSR(reg),base | type,0);
+ _MTRR_writeMSR(INTEL_physMask_MSR(reg),~(size - 1) | 0x800,0);
+ }
+ MTRR_endUpdate(&c);
+}
+
+/****************************************************************************
+REMARKS:
+Disabled banked write combing for Intel processors. We always disable this
+because it invariably causes problems with older hardware.
+****************************************************************************/
+static void INTEL_disableBankedWriteCombine(void)
+{
+ MTRRContext c;
+
+ MTRR_beginUpdate(&c);
+ _MTRR_writeMSR(INTEL_fix16K_A0000_MSR,0,0);
+ MTRR_endUpdate(&c);
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to set
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+REMARKS:
+Intel specific function to set the value of a specific MTRR register to
+the passed in base, size and type.
+****************************************************************************/
+static void AMD_getMTRR(
+ uint reg,
+ ulong *base,
+ ulong *size,
+ int *type)
+{
+ ulong low,high;
+
+ /* Upper dword is region 1, lower is region 0 */
+ _MTRR_readMSR(0xC0000085, &low, &high);
+ if (reg == 1)
+ low = high;
+
+ /* Find the base and type for the region */
+ *base = low & 0xFFFE0000;
+ *type = 0;
+ if (low & 1)
+ *type = PM_MTRR_UNCACHABLE;
+ if (low & 2)
+ *type = PM_MTRR_WRCOMB;
+ if ((low & 3) == 0) {
+ *size = 0;
+ return;
+ }
+
+ /* This needs a little explaining. The size is stored as an
+ * inverted mask of bits of 128K granularity 15 bits long offset
+ * 2 bits
+ *
+ * So to get a size we do invert the mask and add 1 to the lowest
+ * mask bit (4 as its 2 bits in). This gives us a size we then shift
+ * to turn into 128K blocks
+ *
+ * eg 111 1111 1111 1100 is 512K
+ *
+ * invert 000 0000 0000 0011
+ * +1 000 0000 0000 0100
+ * *128K ...
+ */
+ low = (~low) & 0x0FFFC;
+ *size = (low + 4) << 15;
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to set
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+REMARKS:
+Intel specific function to set the value of a specific MTRR register to
+the passed in base, size and type.
+****************************************************************************/
+static void AMD_setMTRR(
+ uint reg,
+ ulong base,
+ ulong size,
+ int type)
+{
+ ulong low,high,newVal;
+ MTRRContext c;
+
+ MTRR_beginUpdate(&c);
+ _MTRR_readMSR(0xC0000085, &low, &high);
+ if (size == 0) {
+ /* Clear register to disable */
+ if (reg)
+ high = 0;
+ else
+ low = 0;
+ }
+ else {
+ /* Set the register to the base (already shifted for us), the
+ * type (off by one) and an inverted bitmask of the size
+ * The size is the only odd bit. We are fed say 512K
+ * We invert this and we get 111 1111 1111 1011 but
+ * if you subtract one and invert you get the desired
+ * 111 1111 1111 1100 mask
+ */
+ newVal = (((~(size-1)) >> 15) & 0x0001FFFC) | base | (type+1);
+ if (reg)
+ high = newVal;
+ else
+ low = newVal;
+ }
+
+ /* The writeback rule is quite specific. See the manual. Its
+ * disable local interrupts, write back the cache, set the MTRR
+ */
+ PM_flushTLB();
+ _MTRR_writeMSR(0xC0000085, low, high);
+ MTRR_endUpdate(&c);
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to set
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+REMARKS:
+Intel specific function to set the value of a specific MTRR register to
+the passed in base, size and type.
+****************************************************************************/
+static void CYRIX_getMTRR(
+ uint reg,
+ ulong *base,
+ ulong *size,
+ int *type)
+{
+ MTRRContext c;
+ uchar arr = CX86_ARR_BASE + reg*3;
+ uchar rcr,shift;
+
+ /* Save flags and disable interrupts */
+ MTRR_beginUpdate(&c);
+ ((uchar*)base)[3] = _MTRR_getCx86(arr);
+ ((uchar*)base)[2] = _MTRR_getCx86((uchar)(arr+1));
+ ((uchar*)base)[1] = _MTRR_getCx86((uchar)(arr+2));
+ rcr = _MTRR_getCx86((uchar)(CX86_RCR_BASE + reg));
+ MTRR_endUpdate(&c);
+
+ /* Enable interrupts if it was enabled previously */
+ shift = ((uchar*)base)[1] & 0x0f;
+ *base &= 0xFFFFF000UL;
+
+ /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
+ * Note: shift==0xF means 4G, this is unsupported.
+ */
+ if (shift)
+ *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift;
+ else
+ *size = 0;
+
+ /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
+ if (reg < 7) {
+ switch (rcr) {
+ case 1: *type = PM_MTRR_UNCACHABLE; break;
+ case 8: *type = PM_MTRR_WRBACK; break;
+ case 9: *type = PM_MTRR_WRCOMB; break;
+ case 24:
+ default: *type = PM_MTRR_WRTHROUGH; break;
+ }
+ }
+ else {
+ switch (rcr) {
+ case 0: *type = PM_MTRR_UNCACHABLE; break;
+ case 8: *type = PM_MTRR_WRCOMB; break;
+ case 9: *type = PM_MTRR_WRBACK; break;
+ case 25:
+ default: *type = PM_MTRR_WRTHROUGH; break;
+ }
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - MTRR register to set
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+REMARKS:
+Intel specific function to set the value of a specific MTRR register to
+the passed in base, size and type.
+****************************************************************************/
+static void CYRIX_setMTRR(
+ uint reg,
+ ulong base,
+ ulong size,
+ int type)
+{
+ MTRRContext c;
+ uchar arr = CX86_ARR_BASE + reg*3;
+ uchar arr_type,arr_size;
+
+ /* Count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
+ size >>= (reg < 7 ? 12 : 18);
+ size &= 0x7FFF; /* Make sure arr_size <= 14 */
+ for (arr_size = 0; size; arr_size++, size >>= 1)
+ ;
+ if (reg < 7) {
+ switch (type) {
+ case PM_MTRR_UNCACHABLE: arr_type = 1; break;
+ case PM_MTRR_WRCOMB: arr_type = 9; break;
+ case PM_MTRR_WRTHROUGH: arr_type = 24; break;
+ default: arr_type = 8; break;
+ }
+ }
+ else {
+ switch (type) {
+ case PM_MTRR_UNCACHABLE: arr_type = 0; break;
+ case PM_MTRR_WRCOMB: arr_type = 8; break;
+ case PM_MTRR_WRTHROUGH: arr_type = 25; break;
+ default: arr_type = 9; break;
+ }
+ }
+ MTRR_beginUpdate(&c);
+ _MTRR_setCx86((uchar)arr, ((uchar*)&base)[3]);
+ _MTRR_setCx86((uchar)(arr+1), ((uchar*)&base)[2]);
+ _MTRR_setCx86((uchar)(arr+2), (uchar)((((uchar*)&base)[1]) | arr_size));
+ _MTRR_setCx86((uchar)(CX86_RCR_BASE + reg), (uchar)arr_type);
+ MTRR_endUpdate(&c);
+}
+
+/****************************************************************************
+REMARKS:
+On Cyrix 6x86(MX) and MII the ARR3 is special: it has connection
+with the SMM (System Management Mode) mode. So we need the following:
+Check whether SMI_LOCK (CCR3 bit 0) is set
+ if it is set, ARR3 cannot be changed (it cannot be changed until the
+ next processor reset)
+ if it is reset, then we can change it, set all the needed bits:
+ - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
+ - disable access to SMM memory (CCR1 bit 2 reset)
+ - disable SMM mode (CCR1 bit 1 reset)
+ - disable write protection of ARR3 (CCR6 bit 1 reset)
+ - (maybe) disable ARR3
+Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
+****************************************************************************/
+static void CYRIX_initARR(void)
+{
+ MTRRContext c;
+ uchar ccr[7];
+ int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
+
+ /* Begin updating */
+ MTRR_beginUpdate(&c);
+
+ /* Save all CCRs locally */
+ ccr[0] = _MTRR_getCx86(CX86_CCR0);
+ ccr[1] = _MTRR_getCx86(CX86_CCR1);
+ ccr[2] = _MTRR_getCx86(CX86_CCR2);
+ ccr[3] = (uchar)c.ccr3;
+ ccr[4] = _MTRR_getCx86(CX86_CCR4);
+ ccr[5] = _MTRR_getCx86(CX86_CCR5);
+ ccr[6] = _MTRR_getCx86(CX86_CCR6);
+ if (ccr[3] & 1)
+ ccrc[3] = 1;
+ else {
+ /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
+ * access to SMM memory through ARR3 (bit 7).
+ */
+ if (ccr[6] & 0x02) {
+ ccr[6] &= 0xFD;
+ ccrc[6] = 1; /* Disable write protection of ARR3. */
+ _MTRR_setCx86(CX86_CCR6,ccr[6]);
+ }
+ }
+
+ /* If we changed CCR1 in memory, change it in the processor, too. */
+ if (ccrc[1])
+ _MTRR_setCx86(CX86_CCR1,ccr[1]);
+
+ /* Enable ARR usage by the processor */
+ if (!(ccr[5] & 0x20)) {
+ ccr[5] |= 0x20;
+ ccrc[5] = 1;
+ _MTRR_setCx86(CX86_CCR5,ccr[5]);
+ }
+
+ /* We are finished updating */
+ MTRR_endUpdate(&c);
+}
+
+/****************************************************************************
+REMARKS:
+Initialise the MTRR module, by detecting the processor type and determining
+if the processor supports the MTRR functionality.
+****************************************************************************/
+void MTRR_init(void)
+{
+ int i,cpu,ltype;
+ ulong eax,edx,lbase,lsize;
+
+ /* Check that we have a compatible CPU */
+ if (numMTRR == -1) {
+ numMTRR = 0;
+ if (!_MTRR_isRing0())
+ return;
+ cpu = CPU_getProcessorType();
+ cpuFamily = cpu & CPU_familyMask;
+ cpuType = cpu & CPU_mask;
+ cpuStepping = (cpu & CPU_steppingMask) >> CPU_steppingShift;
+ switch (cpuFamily) {
+ case CPU_Intel:
+ /* Intel Pentium Pro and later support the MTRR registers */
+ if (cpuType < CPU_PentiumPro)
+ return;
+ _MTRR_readMSR(INTEL_cap_MSR,&eax,&edx);
+ numMTRR = eax & 0xFF;
+ getMTRR = INTEL_getMTRR;
+ setMTRR = INTEL_setMTRR;
+ getFreeRegion = GENERIC_getFreeRegion;
+ INTEL_disableBankedWriteCombine();
+ break;
+ case CPU_AMD:
+ /* AMD K6-2 and later support the MTRR registers */
+ if ((cpuType < CPU_AMDK6_2) || (cpuType == CPU_AMDK6_2 && cpuStepping < 8))
+ return;
+ if (cpuType < CPU_AMDAthlon) {
+ numMTRR = 2; /* AMD CPU's have 2 MTRR's */
+ getMTRR = AMD_getMTRR;
+ setMTRR = AMD_setMTRR;
+ getFreeRegion = AMDK6_getFreeRegion;
+
+ /* For some reason some IBM systems with K6-2 processors
+ * have write combined enabled for the system BIOS
+ * region from 0xE0000 to 0xFFFFFF. We need *both* MTRR's
+ * for our own graphics drivers, so if we detect any
+ * regions below the 1Meg boundary, we remove them
+ * so we can use this MTRR register ourselves.
+ */
+ for (i = 0; i < numMTRR; i++) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ if (lbase < 0x100000)
+ setMTRR(i,0,0,0);
+ }
+ }
+ else {
+ /* AMD Athlon uses P6 style MTRR's */
+ _MTRR_readMSR(INTEL_cap_MSR,&eax,&edx);
+ numMTRR = eax & 0xFF;
+ getMTRR = INTEL_getMTRR;
+ setMTRR = INTEL_setMTRR;
+ getFreeRegion = GENERIC_getFreeRegion;
+ INTEL_disableBankedWriteCombine();
+ }
+ break;
+ case CPU_Cyrix:
+ /* Cyrix 6x86 and later support the MTRR registers */
+ if (cpuType < CPU_Cyrix6x86 || cpuType >= CPU_CyrixMediaGX)
+ return;
+ numMTRR = 8; /* Cyrix CPU's have 8 ARR's */
+ getMTRR = CYRIX_getMTRR;
+ setMTRR = CYRIX_setMTRR;
+ getFreeRegion = CYRIX_getFreeRegion;
+ CYRIX_initARR();
+ break;
+ default:
+ return;
+ }
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+RETURNS:
+Error code describing the result.
+
+REMARKS:
+Function to enable write combining for the specified region of memory.
+****************************************************************************/
+int MTRR_enableWriteCombine(
+ ulong base,
+ ulong size,
+ uint type)
+{
+ int i;
+ int ltype;
+ ulong lbase,lsize,last;
+
+ /* Check that we have a CPU that supports MTRR's and type is valid */
+ if (numMTRR <= 0) {
+ if (!_MTRR_isRing0())
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+ return PM_MTRR_NOT_SUPPORTED;
+ }
+ if (type >= PM_MTRR_MAX)
+ return PM_MTRR_ERR_PARAMS;
+
+ /* If the type is WC, check that this processor supports it */
+ if (!MTRR_haveWriteCombine())
+ return PM_MTRR_ERR_NOWRCOMB;
+
+ /* Adjust the boundaries depending on the CPU type */
+ switch (cpuFamily) {
+ case CPU_AMD:
+ if (cpuType < CPU_AMDAthlon) {
+ /* Apply the K6 block alignment and size rules. In order:
+ * o Uncached or gathering only
+ * o 128K or bigger block
+ * o Power of 2 block
+ * o base suitably aligned to the power
+ */
+ if (type > PM_MTRR_WRCOMB && (size < (1 << 17) || (size & ~(size-1))-size || (base & (size-1))))
+ return PM_MTRR_ERR_NOT_ALIGNED;
+ break;
+ }
+ /* Fall through for AMD Athlon which uses P6 style MTRR's */
+ case CPU_Intel:
+ case CPU_Cyrix:
+ if ((base & 0xFFF) || (size & 0xFFF)) {
+ /* Base and size must be multiples of 4Kb */
+ return PM_MTRR_ERR_NOT_4KB_ALIGNED;
+ }
+ if (base < 0x100000) {
+ /* Base must be >= 1Mb */
+ return PM_MTRR_ERR_BELOW_1MB;
+ }
+
+ /* Check upper bits of base and last are equal and lower bits
+ * are 0 for base and 1 for last
+ */
+ last = base + size - 1;
+ for (lbase = base; !(lbase & 1) && (last & 1); lbase = lbase >> 1, last = last >> 1)
+ ;
+ if (lbase != last) {
+ /* Base is not aligned on the correct boundary */
+ return PM_MTRR_ERR_NOT_ALIGNED;
+ }
+ break;
+ default:
+ return PM_MTRR_NOT_SUPPORTED;
+ }
+
+ /* Search for existing MTRR */
+ for (i = 0; i < numMTRR; ++i) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ if (lbase == 0 && lsize == 0)
+ continue;
+ if (base > lbase + (lsize-1))
+ continue;
+ if ((base < lbase) && (base+size-1 < lbase))
+ continue;
+
+ /* Check that we don't overlap an existing region */
+ if (type != PM_MTRR_UNCACHABLE) {
+ if ((base < lbase) || (base+size-1 > lbase+lsize-1))
+ return PM_MTRR_ERR_OVERLAP;
+ }
+ else if (base == lbase && size == lsize) {
+ /* The region already exists so leave it alone */
+ return PM_MTRR_ERR_OK;
+ }
+
+ /* New region is enclosed by an existing region, so only allow
+ * a new type to be created if we are setting a region to be
+ * uncacheable (such as MMIO registers within a framebuffer).
+ */
+ if (ltype != (int)type) {
+ if (type == PM_MTRR_UNCACHABLE)
+ continue;
+ return PM_MTRR_ERR_TYPE_MISMATCH;
+ }
+ return PM_MTRR_ERR_OK;
+ }
+
+ /* Search for an empty MTRR */
+ if ((i = getFreeRegion(base,size)) < 0)
+ return PM_MTRR_ERR_NONE_FREE;
+ setMTRR(i,base,size,type);
+ return PM_MTRR_ERR_OK;
+}
+
+/****************************************************************************
+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)
+{
+ int i,ltype;
+ ulong lbase,lsize;
+
+ /* Check that we have a CPU that supports MTRR's and type is valid */
+ if (numMTRR <= 0) {
+ if (!_MTRR_isRing0())
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+ return PM_MTRR_NOT_SUPPORTED;
+ }
+
+ /* Enumerate all existing MTRR's */
+ for (i = 0; i < numMTRR; ++i) {
+ getMTRR(i,&lbase,&lsize,&ltype);
+ callback(lbase,lsize,ltype);
+ }
+ return PM_MTRR_ERR_OK;
+}
+#endif
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/pcilib.c b/board/MAI/bios_emulator/scitech/src/pm/common/pcilib.c
new file mode 100644
index 0000000000..8dd6dd13e3
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/pcilib.c
@@ -0,0 +1,747 @@
+/****************************************************************************
+*
+* 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: Module for interfacing to the PCI bus and configuration
+* space registers.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "pcilib.h"
+#if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__)
+#include <string.h>
+#endif
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+#pragma pack(1)
+
+/* Length of the memory mapping for the PCI BIOS */
+
+#define BIOS_LIMIT (128 * 1024L - 1)
+
+/* Macros for accessing the PCI BIOS functions from 32-bit protected mode */
+
+#define BIOS32_SIGNATURE (((ulong)'_' << 0) + ((ulong)'3' << 8) + ((ulong)'2' << 16) + ((ulong)'_' << 24))
+#define PCI_SIGNATURE (((ulong)'P' << 0) + ((ulong)'C' << 8) + ((ulong)'I' << 16) + ((ulong)' ' << 24))
+#define PCI_SERVICE (((ulong)'$' << 0) + ((ulong)'P' << 8) + ((ulong)'C' << 16) + ((ulong)'I' << 24))
+#define PCI_BIOS_PRESENT 0xB101
+#define FIND_PCI_DEVICE 0xB102
+#define FIND_PCI_CLASS 0xB103
+#define GENERATE_SPECIAL 0xB106
+#define READ_CONFIG_BYTE 0xB108
+#define READ_CONFIG_WORD 0xB109
+#define READ_CONFIG_DWORD 0xB10A
+#define WRITE_CONFIG_BYTE 0xB10B
+#define WRITE_CONFIG_WORD 0xB10C
+#define WRITE_CONFIG_DWORD 0xB10D
+#define GET_IRQ_ROUTING_OPT 0xB10E
+#define SET_PCI_IRQ 0xB10F
+
+/* This is the standard structure used to identify the entry point to the
+ * BIOS32 Service Directory, as documented in PCI 2.1 BIOS Specicition.
+ */
+
+typedef union {
+ struct {
+ ulong signature; /* _32_ */
+ ulong entry; /* 32 bit physical address */
+ uchar revision; /* Revision level, 0 */
+ uchar length; /* Length in paragraphs should be 01 */
+ uchar checksum; /* All bytes must add up to zero */
+ uchar reserved[5]; /* Must be zero */
+ } fields;
+ char chars[16];
+ } PCI_bios32;
+
+/* Structure for a far pointer to call the PCI BIOS services with */
+
+typedef struct {
+ ulong address;
+ ushort segment;
+ } PCIBIOS_entry;
+
+/* Macros to copy a structure that includes dwSize members */
+
+#define COPY_STRUCTURE(d,s) memcpy(d,s,MIN((s)->dwSize,(d)->dwSize))
+
+#pragma pack()
+
+/*--------------------------- Global variables ----------------------------*/
+
+static uchar *BIOSImage = NULL; /* BIOS image mapping */
+static int PCIBIOSVersion = -1;/* PCI BIOS version */
+static PCIBIOS_entry PCIEntry; /* PCI services entry point */
+static ulong PCIPhysEntry = 0; /* Physical address */
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* External assembler helper functions */
+
+uchar _ASMAPI _BIOS32_service(ulong service,ulong function,ulong *physBase,ulong *length,ulong *serviceOffset,PCIBIOS_entry entry);
+ushort _ASMAPI _PCIBIOS_isPresent(ulong i_eax,ulong *o_edx,ushort *o_ax,uchar *o_cl,PCIBIOS_entry entry);
+ulong _ASMAPI _PCIBIOS_service(ulong r_eax,ulong r_ebx,ulong r_edi,ulong r_ecx,PCIBIOS_entry entry);
+int _ASMAPI _PCIBIOS_getRouting(PCIRoutingOptionsBuffer *buf,PCIBIOS_entry entry);
+ibool _ASMAPI _PCIBIOS_setIRQ(int busDev,int intPin,int IRQ,PCIBIOS_entry entry);
+ulong _ASMAPI _PCIBIOS_specialCycle(int bus,ulong data,PCIBIOS_entry entry);
+ushort _ASMAPI _PCI_getCS(void);
+
+/****************************************************************************
+REMARKS:
+This functions returns the physical address of the PCI BIOS entry point.
+****************************************************************************/
+ulong _ASMAPI PCIBIOS_getEntry(void)
+{ return PCIPhysEntry; }
+
+/****************************************************************************
+PARAMETERS:
+hwType - Place to store the PCI hardware access mechanism flags
+lastBus - Place to store the index of the last PCI bus in the system
+
+RETURNS:
+Version number of the PCI BIOS found.
+
+REMARKS:
+This function determines if the PCI BIOS is present in the system, and if
+so returns the information returned by the PCI BIOS detect function.
+****************************************************************************/
+static int PCIBIOS_detect(
+ uchar *hwType,
+ uchar *lastBus)
+{
+ ulong signature;
+ ushort stat,version;
+
+#ifndef __16BIT__
+ PCIBIOS_entry BIOSEntry = {0};
+ uchar *BIOSEnd;
+ PCI_bios32 *BIOSDir;
+ ulong physBase,length,offset;
+
+ /* Bail if we have already detected no BIOS is present */
+ if (PCIBIOSVersion == 0)
+ return 0;
+
+ /* First scan the memory from 0xE0000 to 0xFFFFF looking for the
+ * BIOS32 service directory, so we can determine if we can call it
+ * from 32-bit protected mode.
+ */
+ if (PCIBIOSVersion == -1) {
+ PCIBIOSVersion = 0;
+ BIOSImage = PM_mapPhysicalAddr(0xE0000,BIOS_LIMIT,false);
+ if (!BIOSImage)
+ return 0;
+ BIOSEnd = BIOSImage + 0x20000;
+ for (BIOSDir = (PCI_bios32*)BIOSImage; BIOSDir < (PCI_bios32*)BIOSEnd; BIOSDir++) {
+ uchar sum;
+ int i,length;
+
+ if (BIOSDir->fields.signature != BIOS32_SIGNATURE)
+ continue;
+ length = BIOSDir->fields.length * 16;
+ if (!length)
+ continue;
+ for (sum = i = 0; i < length ; i++)
+ sum += BIOSDir->chars[i];
+ if (sum != 0)
+ continue;
+ BIOSEntry.address = (ulong)BIOSImage + (BIOSDir->fields.entry - 0xE0000);
+ BIOSEntry.segment = _PCI_getCS();
+ break;
+ }
+
+ /* If we found the BIOS32 directory, call it to get the address of the
+ * PCI services.
+ */
+ if (BIOSEntry.address == 0)
+ return 0;
+ if (_BIOS32_service(PCI_SERVICE,0,&physBase,&length,&offset,BIOSEntry) != 0)
+ return 0;
+ PCIPhysEntry = physBase + offset;
+ PCIEntry.address = (ulong)BIOSImage + (PCIPhysEntry - 0xE0000);
+ PCIEntry.segment = _PCI_getCS();
+ }
+#endif
+ /* We found the BIOS entry, so now do the version check */
+ version = _PCIBIOS_isPresent(PCI_BIOS_PRESENT,&signature,&stat,lastBus,PCIEntry);
+ if (version > 0 && ((stat >> 8) == 0) && signature == PCI_SIGNATURE) {
+ *hwType = stat & 0xFF;
+ return PCIBIOSVersion = version;
+ }
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to check against
+index - Index of the current device to check
+
+RETURNS:
+True if the device is a duplicate, false if not.
+
+REMARKS:
+This function goes through the list of all devices preceeding the newly
+found device in the info structure, and checks that the device is not a
+duplicate of a previous device. Some devices incorrectly enumerate
+themselves at different function addresses so we check here to exclude
+those cases.
+****************************************************************************/
+static ibool CheckDuplicate(
+ PCIDeviceInfo *info,
+ PCIDeviceInfo *prev)
+{
+ /* Ignore devices with a vendor ID of 0 */
+ if (info->VendorID == 0)
+ return true;
+
+ /* NOTE: We only check against the current device on
+ * the bus to ensure that we do not exclude
+ * multiple controllers of the same device ID.
+ */
+ if (info->slot.p.Bus == prev->slot.p.Bus &&
+ info->slot.p.Device == prev->slot.p.Device &&
+ info->DeviceID == prev->DeviceID)
+ return true;
+ return false;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to fill in
+maxDevices - Maximum number of of devices to enumerate into array
+
+RETURNS:
+Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
+
+REMARKS:
+Function to enumerate all available devices on the PCI bus into an array
+of configuration information blocks.
+****************************************************************************/
+static int PCI_enumerateMech1(
+ PCIDeviceInfo info[])
+{
+ int bus,device,function,i,numFound = 0;
+ ulong *lp,tmp;
+ PCIslot slot = {{0,0,0,0,0,0,1}};
+ PCIDeviceInfo pci,prev = {0};
+
+ /* Try PCI access mechanism 1 */
+ PM_outpb(0xCFB,0x01);
+ tmp = PM_inpd(0xCF8);
+ PM_outpd(0xCF8,slot.i);
+ if ((PM_inpd(0xCF8) == slot.i) && (PM_inpd(0xCFC) != 0xFFFFFFFFUL)) {
+ /* PCI access mechanism 1 - the preferred mechanism */
+ for (bus = 0; bus < 8; bus++) {
+ slot.p.Bus = bus;
+ for (device = 0; device < 32; device++) {
+ slot.p.Device = device;
+ for (function = 0; function < 8; function++) {
+ slot.p.Function = function;
+ slot.p.Register = 0;
+ PM_outpd(0xCF8,slot.i);
+ if (PM_inpd(0xCFC) != 0xFFFFFFFFUL) {
+ memset(&pci,0,sizeof(pci));
+ pci.dwSize = sizeof(pci);
+ pci.mech1 = 1;
+ pci.slot = slot;
+ lp = (ulong*)&(pci.VendorID);
+ for (i = 0; i < NUM_PCI_REG; i++, lp++) {
+ slot.p.Register = i;
+ PM_outpd(0xCF8,slot.i);
+ *lp = PM_inpd(0xCFC);
+ }
+ if (!CheckDuplicate(&pci,&prev)) {
+ if (info)
+ COPY_STRUCTURE(&info[numFound],&pci);
+ ++numFound;
+ }
+ prev = pci;
+ }
+ }
+ }
+ }
+
+ /* Disable PCI config cycle on exit */
+ PM_outpd(0xCF8,0);
+ return numFound;
+ }
+ PM_outpd(0xCF8,tmp);
+
+ /* No hardware access mechanism 1 found */
+ return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to fill in
+maxDevices - Maximum number of of devices to enumerate into array
+
+RETURNS:
+Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
+
+REMARKS:
+Function to enumerate all available devices on the PCI bus into an array
+of configuration information blocks.
+****************************************************************************/
+static int PCI_enumerateMech2(
+ PCIDeviceInfo info[])
+{
+ int bus,device,function,i,numFound = 0;
+ ushort deviceIO;
+ ulong *lp;
+ PCIslot slot = {{0,0,0,0,0,0,1}};
+ PCIDeviceInfo pci,prev = {0};
+
+ /* Try PCI access mechanism 2 */
+ PM_outpb(0xCFB,0x00);
+ PM_outpb(0xCF8,0x00);
+ PM_outpb(0xCFA,0x00);
+ if (PM_inpb(0xCF8) == 0x00 && PM_inpb(0xCFB) == 0x00) {
+ /* PCI access mechanism 2 - the older mechanism for legacy busses */
+ for (bus = 0; bus < 2; bus++) {
+ slot.p.Bus = bus;
+ PM_outpb(0xCFA,(uchar)bus);
+ for (device = 0; device < 16; device++) {
+ slot.p.Device = device;
+ deviceIO = 0xC000 + (device << 8);
+ for (function = 0; function < 8; function++) {
+ slot.p.Function = function;
+ slot.p.Register = 0;
+ PM_outpb(0xCF8,(uchar)((function << 1) | 0x10));
+ if (PM_inpd(deviceIO) != 0xFFFFFFFFUL) {
+ memset(&pci,0,sizeof(pci));
+ pci.dwSize = sizeof(pci);
+ pci.mech1 = 0;
+ pci.slot = slot;
+ lp = (ulong*)&(pci.VendorID);
+ for (i = 0; i < NUM_PCI_REG; i++, lp++) {
+ slot.p.Register = i;
+ *lp = PM_inpd(deviceIO + (i << 2));
+ }
+ if (!CheckDuplicate(&pci,&prev)) {
+ if (info)
+ COPY_STRUCTURE(&info[numFound],&pci);
+ ++numFound;
+ }
+ prev = pci;
+ }
+ }
+ }
+ }
+
+ /* Disable PCI config cycle on exit */
+ PM_outpb(0xCF8,0);
+ return numFound;
+ }
+
+ /* No hardware access mechanism 2 found */
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+This functions reads a configuration dword via the PCI BIOS.
+****************************************************************************/
+static ulong PCIBIOS_readDWORD(
+ int index,
+ ulong slot)
+{
+ return (ulong)_PCIBIOS_service(READ_CONFIG_DWORD,slot >> 8,index,0,PCIEntry);
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to fill in
+maxDevices - Maximum number of of devices to enumerate into array
+
+RETURNS:
+Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
+
+REMARKS:
+Function to enumerate all available devices on the PCI bus into an array
+of configuration information blocks.
+****************************************************************************/
+static int PCI_enumerateBIOS(
+ PCIDeviceInfo info[])
+{
+ uchar hwType,lastBus;
+ int bus,device,function,i,numFound = 0;
+ ulong *lp;
+ PCIslot slot = {{0,0,0,0,0,0,1}};
+ PCIDeviceInfo pci,prev = {0};
+
+ if (PCIBIOS_detect(&hwType,&lastBus)) {
+ /* PCI BIOS access - the ultimate fallback */
+ for (bus = 0; bus <= lastBus; bus++) {
+ slot.p.Bus = bus;
+ for (device = 0; device < 32; device++) {
+ slot.p.Device = device;
+ for (function = 0; function < 8; function++) {
+ slot.p.Function = function;
+ if (PCIBIOS_readDWORD(0,slot.i) != 0xFFFFFFFFUL) {
+ memset(&pci,0,sizeof(pci));
+ pci.dwSize = sizeof(pci);
+ pci.mech1 = 2;
+ pci.slot = slot;
+ lp = (ulong*)&(pci.VendorID);
+ for (i = 0; i < NUM_PCI_REG; i++, lp++)
+ *lp = PCIBIOS_readDWORD(i << 2,slot.i);
+ if (!CheckDuplicate(&pci,&prev)) {
+ if (info)
+ COPY_STRUCTURE(&info[numFound],&pci);
+ ++numFound;
+ }
+ prev = pci;
+ }
+ }
+ }
+ }
+ }
+
+ /* Return number of devices found */
+ return numFound;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to fill in
+maxDevices - Maximum number of of devices to enumerate into array
+
+RETURNS:
+Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
+
+REMARKS:
+Function to enumerate all available devices on the PCI bus into an array
+of configuration information blocks.
+****************************************************************************/
+int _ASMAPI PCI_enumerate(
+ PCIDeviceInfo info[])
+{
+ int numFound;
+
+ /* First try via the direct access mechanisms which are faster if we
+ * have them (nearly always). The BIOS is used as a fallback, and for
+ * stuff we can't do directly.
+ */
+ if ((numFound = PCI_enumerateMech1(info)) == 0) {
+ if ((numFound = PCI_enumerateMech2(info)) == 0) {
+ if ((numFound = PCI_enumerateBIOS(info)) == 0)
+ return 0;
+ }
+ }
+ return numFound;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - Array of PCIDeviceInfo structures to fill in
+maxDevices - Maximum number of of devices to enumerate into array
+
+RETURNS:
+Number of PCI devices found and enumerated on the PCI bus, 0 if not PCI.
+
+REMARKS:
+Function to enumerate all available devices on the PCI bus into an array
+of configuration information blocks.
+****************************************************************************/
+int _ASMAPI PCI_getNumDevices(void)
+{
+ return PCI_enumerate(NULL);
+}
+
+/****************************************************************************
+PARAMETERS:
+bar - Base address to measure
+pci - PCI device to access
+
+RETURNS:
+Size of the PCI base address in bytes
+
+REMARKS:
+This function measures the size of the PCI base address register in bytes,
+by writing all F's to the register, and reading the value back. The size
+of the base address is determines by the bits that are hardwired to zero's.
+****************************************************************************/
+ulong _ASMAPI PCI_findBARSize(
+ int bar,
+ PCIDeviceInfo *pci)
+{
+ ulong base,size = 0;
+
+ base = PCI_accessReg(bar,0,PCI_READ_DWORD,pci);
+ if (base && !(base & 0x1)) {
+ /* For some strange reason some devices don't properly decode
+ * their base address registers (Intel PCI/PCI bridges!), and
+ * we read completely bogus values. We check for that here
+ * and clear out those BAR's.
+ *
+ * We check for that here because at least the low 12 bits
+ * of the address range must be zeros, since the page size
+ * on IA32 processors is always 4Kb.
+ */
+ if ((base & 0xFFF) == 0) {
+ PCI_accessReg(bar,0xFFFFFFFF,PCI_WRITE_DWORD,pci);
+ size = PCI_accessReg(bar,0,PCI_READ_DWORD,pci) & ~0xFF;
+ size = ~size+1;
+ PCI_accessReg(bar,base,PCI_WRITE_DWORD,pci);
+ }
+ }
+ pci->slot.p.Register = 0;
+ return size;
+}
+
+/****************************************************************************
+PARAMETERS:
+index - DWORD index of the register to access
+value - Value to write to the register for write access
+func - Function to implement
+
+RETURNS:
+The value read from the register for read operations
+
+REMARKS:
+The function code are defined as follows
+
+code - function
+0 - Read BYTE
+1 - Read WORD
+2 - Read DWORD
+3 - Write BYTE
+4 - Write WORD
+5 - Write DWORD
+****************************************************************************/
+ulong _ASMAPI PCI_accessReg(
+ int index,
+ ulong value,
+ int func,
+ PCIDeviceInfo *info)
+{
+ int iobase;
+
+ if (info->mech1 == 2) {
+ /* Use PCI BIOS access since we dont have direct hardware access */
+ switch (func) {
+ case PCI_READ_BYTE:
+ return (uchar)_PCIBIOS_service(READ_CONFIG_BYTE,info->slot.i >> 8,index,0,PCIEntry);
+ case PCI_READ_WORD:
+ return (ushort)_PCIBIOS_service(READ_CONFIG_WORD,info->slot.i >> 8,index,0,PCIEntry);
+ case PCI_READ_DWORD:
+ return (ulong)_PCIBIOS_service(READ_CONFIG_DWORD,info->slot.i >> 8,index,0,PCIEntry);
+ case PCI_WRITE_BYTE:
+ _PCIBIOS_service(WRITE_CONFIG_BYTE,info->slot.i >> 8,index,value,PCIEntry);
+ break;
+ case PCI_WRITE_WORD:
+ _PCIBIOS_service(WRITE_CONFIG_WORD,info->slot.i >> 8,index,value,PCIEntry);
+ break;
+ case PCI_WRITE_DWORD:
+ _PCIBIOS_service(WRITE_CONFIG_DWORD,info->slot.i >> 8,index,value,PCIEntry);
+ break;
+ }
+ }
+ else {
+ /* Use direct hardware access mechanisms */
+ if (info->mech1) {
+ /* PCI access mechanism 1 */
+ iobase = 0xCFC + (index & 3);
+ info->slot.p.Register = index >> 2;
+ PM_outpd(0xCF8,info->slot.i);
+ }
+ else {
+ /* PCI access mechanism 2 */
+ PM_outpb(0xCF8,(uchar)((info->slot.p.Function << 1) | 0x10));
+ PM_outpb(0xCFA,(uchar)info->slot.p.Bus);
+ iobase = 0xC000 + (info->slot.p.Device << 8) + index;
+ }
+ switch (func) {
+ case PCI_READ_BYTE:
+ case PCI_READ_WORD:
+ case PCI_READ_DWORD: value = PM_inpd(iobase); break;
+ case PCI_WRITE_BYTE: PM_outpb(iobase,(uchar)value); break;
+ case PCI_WRITE_WORD: PM_outpw(iobase,(ushort)value); break;
+ case PCI_WRITE_DWORD: PM_outpd(iobase,(ulong)value); break;
+ }
+ PM_outpd(0xCF8,0);
+ }
+ return value;
+}
+
+/****************************************************************************
+PARAMETERS:
+numDevices - Number of devices to query info for
+
+RETURNS:
+0 on success, -1 on error, number of devices to enumerate if numDevices = 0
+
+REMARKS:
+This function reads the PCI routing information. If you pass a value of
+0 for numDevices, this function will return with the number of devices
+needed in the routing buffer that will be filled in by the BIOS.
+****************************************************************************/
+ibool _ASMAPI PCI_getIRQRoutingOptions(
+ int numDevices,
+ PCIRouteInfo *buffer)
+{
+ PCIRoutingOptionsBuffer buf;
+ int ret;
+
+ if (PCIPhysEntry) {
+ buf.BufferSize = numDevices * sizeof(PCIRouteInfo);
+ buf.DataBuffer = buffer;
+ if ((ret = _PCIBIOS_getRouting(&buf,PCIEntry)) == 0x89)
+ return buf.BufferSize / sizeof(PCIRouteInfo);
+ if (ret != 0)
+ return -1;
+ return 0;
+ }
+
+ /* We currently only support this via the PCI BIOS functions */
+ return -1;
+}
+
+/****************************************************************************
+PARAMETERS:
+info - PCI device information for the specified device
+intPin - Value to store in the PCI InterruptPin register
+IRQ - New ISA IRQ to map the PCI interrupt to (0-15)
+
+RETURNS:
+True on success, or false if this function failed.
+
+REMARKS:
+This function changes the PCI IRQ routing for the specified device to the
+desired PCI interrupt and the desired ISA bus compatible IRQ. This function
+may not be supported by the PCI BIOS, in which case this function will
+fail.
+****************************************************************************/
+ibool _ASMAPI PCI_setHardwareIRQ(
+ PCIDeviceInfo *info,
+ uint intPin,
+ uint IRQ)
+{
+ if (PCIPhysEntry) {
+ if (_PCIBIOS_setIRQ(info->slot.i >> 8,intPin,IRQ,PCIEntry)) {
+ info->u.type0.InterruptPin = intPin;
+ info->u.type0.InterruptLine = IRQ;
+ return true;
+ }
+ return false;
+ }
+
+ /* We currently only support this via the PCI BIOS functions */
+ return false;
+}
+
+/****************************************************************************
+PARAMETERS:
+bus - Bus number to generate the special cycle for
+specialCycleData - Data to send for the special cyle
+
+REMARKS:
+This function generates a special cycle on the specified bus using with
+the specified data.
+****************************************************************************/
+void _ASMAPI PCI_generateSpecialCyle(
+ uint bus,
+ ulong specialCycleData)
+{
+ if (PCIPhysEntry)
+ _PCIBIOS_specialCycle(bus,specialCycleData,PCIEntry);
+ /* We currently only support this via the PCI BIOS functions */
+}
+
+/****************************************************************************
+PARAMETERS:
+info - PCI device information block for device to access
+index - Index of register to start reading from
+dst - Place to store the values read from configuration space
+count - Count of bytes to read from configuration space
+
+REMARKS:
+This function is used to read a block of PCI configuration space registers
+from the configuration space into the passed in data block. This function
+will properly handle reading non-DWORD aligned data from the configuration
+space correctly.
+****************************************************************************/
+void _ASMAPI PCI_readRegBlock(
+ PCIDeviceInfo *info,
+ int index,
+ void *dst,
+ int count)
+{
+ uchar *pb;
+ ulong *pd;
+ int i;
+ int startCount = (index & 3);
+ int middleCount = (count - startCount) >> 2;
+ int endCount = count - middleCount * 4 - startCount;
+
+ for (i = 0,pb = dst; i < startCount; i++, index++) {
+ *pb++ = (uchar)PCI_accessReg(index,0,PCI_READ_BYTE,info);
+ }
+ for (i = 0,pd = (ulong*)pb; i < middleCount; i++, index += 4) {
+ *pd++ = (ulong)PCI_accessReg(index,0,PCI_READ_DWORD,info);
+ }
+ for (i = 0,pb = (uchar*)pd; i < endCount; i++, index++) {
+ *pb++ = (uchar)PCI_accessReg(index,0,PCI_READ_BYTE,info);
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+info - PCI device information block for device to access
+index - Index of register to start reading from
+dst - Place to store the values read from configuration space
+count - Count of bytes to read from configuration space
+
+REMARKS:
+This function is used to write a block of PCI configuration space registers
+to the configuration space from the passed in data block. This function
+will properly handle writing non-DWORD aligned data to the configuration
+space correctly.
+****************************************************************************/
+void _ASMAPI PCI_writeRegBlock(
+ PCIDeviceInfo *info,
+ int index,
+ void *src,
+ int count)
+{
+ uchar *pb;
+ ulong *pd;
+ int i;
+ int startCount = (index & 3);
+ int middleCount = (count - startCount) >> 2;
+ int endCount = count - middleCount * 4 - startCount;
+
+ for (i = 0,pb = src; i < startCount; i++, index++) {
+ PCI_accessReg(index,*pb++,PCI_WRITE_BYTE,info);
+ }
+ for (i = 0,pd = (ulong*)pb; i < middleCount; i++, index += 4) {
+ PCI_accessReg(index,*pd++,PCI_WRITE_DWORD,info);
+ }
+ for (i = 0,pb = (uchar*)pd; i < endCount; i++, index++) {
+ PCI_accessReg(index,*pb++,PCI_WRITE_BYTE,info);
+ }
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/unixio.c b/board/MAI/bios_emulator/scitech/src/pm/common/unixio.c
new file mode 100644
index 0000000000..04aa47002b
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/unixio.c
@@ -0,0 +1,306 @@
+/****************************************************************************
+*
+* 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: Module containing Unix I/O functions.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* {secret} */
+typedef struct {
+ DIR *d;
+ char path[PM_MAX_PATH];
+ char mask[PM_MAX_PATH];
+ } PM_findHandle;
+
+/****************************************************************************
+REMARKS:
+Internal function to convert the find data to the generic interface.
+****************************************************************************/
+static void convertFindData(
+ PM_findData *findData,
+ struct dirent *blk,
+ const char *path)
+{
+ ulong dwSize = findData->dwSize;
+ struct stat st;
+ char filename[PM_MAX_PATH];
+
+ memset(findData,0,findData->dwSize);
+ findData->dwSize = dwSize;
+ strcpy(filename,path);
+ PM_backslash(filename);
+ strcat(filename,blk->d_name);
+ stat(filename,&st);
+ if (!(st.st_mode & S_IWRITE))
+ findData->attrib |= PM_FILE_READONLY;
+ if (st.st_mode & S_IFDIR)
+ findData->attrib |= PM_FILE_DIRECTORY;
+ findData->sizeLo = st.st_size;
+ findData->sizeHi = 0;
+ strncpy(findData->name,blk->d_name,PM_MAX_PATH);
+ findData->name[PM_MAX_PATH-1] = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Determines if a file name matches the passed in pattern.
+****************************************************************************/
+static ibool filematch(
+ char *pattern,
+ char *dirpath,
+ struct dirent *dire)
+{
+ struct stat st;
+ int i = 0,j = 0,lastchar = '\0';
+ char fullpath[PM_MAX_PATH];
+
+ strcpy(fullpath,dirpath);
+ PM_backslash(fullpath);
+ strcat(fullpath, dire->d_name);
+ if (stat(fullpath, &st) != 0)
+ return false;
+ for (; i < (int)strlen(dire->d_name) && j < (int)strlen(pattern); i++, j++) {
+ if (pattern[j] == '*' && lastchar != '\\') {
+ if (pattern[j+1] == '\0')
+ return true;
+ while (dire->d_name[i++] != pattern[j+1]) {
+ if (dire->d_name[i] == '\0')
+ return false;
+ }
+ i -= 2;
+ }
+ else if (dire->d_name[i] != pattern[j] &&
+ !(pattern[j] == '?' && lastchar != '\\'))
+ return false;
+ lastchar = pattern[i];
+ }
+ if (j == (int)strlen(pattern) && i == (int)strlen(dire->d_name))
+ return true;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+void * PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ PM_findHandle *d;
+ struct dirent *dire;
+ char name[PM_MAX_PATH];
+ char ext[PM_MAX_PATH];
+
+ if ((d = PM_malloc(sizeof(*d))) == NULL)
+ return PM_FILE_INVALID;
+ PM_splitpath(filename,NULL,d->path,name,ext);
+ strcpy(d->mask,name);
+ strcat(d->mask,ext);
+ if (strlen(d->path) == 0)
+ strcpy(d->path, ".");
+ if (d->path[strlen(d->path)-1] == '/')
+ d->path[strlen(d->path)-1] = 0;
+ if ((d->d = opendir(d->path)) != NULL) {
+ while ((dire = readdir(d->d)) != NULL) {
+ if (filematch(d->mask,d->path,dire)) {
+ convertFindData(findData,dire,d->path);
+ return d;
+ }
+ }
+ closedir(d->d);
+ }
+ PM_free(d);
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ void *handle,
+ PM_findData *findData)
+{
+ PM_findHandle *d = handle;
+ struct dirent *dire;
+
+ while ((dire = readdir(d->d)) != NULL) {
+ if (filematch(d->mask,d->path,dire)) {
+ convertFindData(findData,dire,d->path);
+ return true;
+ }
+ }
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ void *handle)
+{
+ PM_findHandle *d = handle;
+
+ closedir(d->d);
+ free(d);
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ if (drive == 3)
+ return true;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ (void)drive;
+ getcwd(dir,len);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+ struct stat st;
+ mode_t mode;
+
+ stat(filename,&st);
+ mode = st.st_mode;
+ if (attrib & PM_FILE_READONLY)
+ mode &= ~S_IWRITE;
+ else
+ mode |= S_IWRITE;
+ chmod(filename,mode);
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file attributes for a specific file.
+****************************************************************************/
+uint PMAPI PM_getFileAttr(
+ const char *filename)
+{
+ struct stat st;
+
+ stat(filename,&st);
+ if (st.st_mode & S_IWRITE)
+ return 0;
+ return PM_FILE_READONLY;
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+ return mkdir(filename,0x1FF) == 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+ return rmdir(filename) == 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_getFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this!
+ (void)filename;
+ (void)gmTime;
+ (void)time;
+ PM_fatalError("PM_getFileTime not implemented yet!");
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_setFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this!
+ (void)filename;
+ (void)gmTime;
+ (void)time;
+ PM_fatalError("PM_setFileTime not implemented yet!");
+ return false;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/common/vgastate.c b/board/MAI/bios_emulator/scitech/src/pm/common/vgastate.c
new file mode 100644
index 0000000000..3be14e81eb
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/common/vgastate.c
@@ -0,0 +1,377 @@
+/****************************************************************************
+*
+* 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: Any
+*
+* Description: Functions to save and restore the VGA hardware state.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#if defined(__WIN32_VXD__) || defined(__NT_DRIVER__)
+#include "sdd/sddhelp.h"
+#else
+#include <string.h>
+#endif
+
+/*--------------------------- Global variables ----------------------------*/
+
+/* VGA index register ports */
+#define CRT_I 0x3D4 /* CRT Controller Index */
+#define ATT_IW 0x3C0 /* Attribute Controller Index & Data */
+#define GRA_I 0x3CE /* Graphics Controller Index */
+#define SEQ_I 0x3C4 /* Sequencer Index */
+
+/* VGA data register ports */
+#define CRT_D 0x3D5 /* CRT Controller Data Register */
+#define ATT_R 0x3C1 /* Attribute Controller Data Read Register */
+#define GRA_D 0x3CF /* Graphics Controller Data Register */
+#define SEQ_D 0x3C5 /* Sequencer Data Register */
+#define MIS_R 0x3CC /* Misc Output Read Register */
+#define MIS_W 0x3C2 /* Misc Output Write Register */
+#define IS1_R 0x3DA /* Input Status Register 1 */
+#define PEL_IW 0x3C8 /* PEL Write Index */
+#define PEL_IR 0x3C7 /* PEL Read Index */
+#define PEL_D 0x3C9 /* PEL Data Register */
+
+/* standard VGA indexes max counts */
+#define CRT_C 24 /* 24 CRT Controller Registers */
+#define ATT_C 21 /* 21 Attribute Controller Registers */
+#define GRA_C 9 /* 9 Graphics Controller Registers */
+#define SEQ_C 5 /* 5 Sequencer Registers */
+#define MIS_C 1 /* 1 Misc Output Register */
+#define PAL_C 768 /* 768 Palette Registers */
+#define FONT_C 8192 /* Total size of character generator RAM */
+
+/* VGA registers saving indexes */
+#define CRT 0 /* CRT Controller Registers start */
+#define ATT (CRT+CRT_C) /* Attribute Controller Registers start */
+#define GRA (ATT+ATT_C) /* Graphics Controller Registers start */
+#define SEQ (GRA+GRA_C) /* Sequencer Registers */
+#define MIS (SEQ+SEQ_C) /* General Registers */
+#define PAL (MIS+MIS_C) /* VGA Palette Registers */
+#define FONT (PAL+PAL_C) /* VGA font data */
+
+/* Macros for port I/O with arguments reversed */
+
+#define _port_out(v,p) PM_outpb(p,(uchar)(v))
+#define _port_in(p) PM_inpb(p)
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Returns the size of the VGA state buffer.
+****************************************************************************/
+int PMAPI PM_getVGAStateSize(void)
+{
+ return CRT_C + ATT_C + GRA_C + SEQ_C + MIS_C + PAL_C + FONT_C;
+}
+
+/****************************************************************************
+REMARKS:
+Delay for a short period of time.
+****************************************************************************/
+static void vga_delay(void)
+{
+ int i;
+
+ /* For the loop here we program the POST register. The length of this
+ * delay is dependant only on ISA bus speed, but it is enough for
+ * what we need.
+ */
+ for (i = 0; i <= 10; i++)
+ PM_outpb(0x80, 0);
+}
+
+/****************************************************************************
+PARAMETERS:
+port - I/O port to read value from
+index - Port index to read
+
+RETURNS:
+Byte read from 'port' register 'index'.
+****************************************************************************/
+static ushort vga_rdinx(
+ ushort port,
+ ushort index)
+{
+ PM_outpb(port,(uchar)index);
+ return PM_inpb(port+1);
+}
+
+/****************************************************************************
+PARAMETERS:
+port - I/O port to write to
+index - Port index to write
+value - Byte to write to port
+
+REMARKS:
+Writes a byte value to the 'port' register 'index'.
+****************************************************************************/
+static void vga_wrinx(
+ ushort port,
+ ushort index,
+ ushort value)
+{
+ PM_outpb(port,(uchar)index);
+ PM_outpb(port+1,(uchar)value);
+}
+
+/****************************************************************************
+REMARKS:
+Save the color palette values
+****************************************************************************/
+static void vga_savepalette(
+ uchar *pal)
+{
+ int i;
+
+ _port_out(0, PEL_IR);
+ for (i = 0; i < 768; i++) {
+ vga_delay();
+ *pal++ = _port_in(PEL_D);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Restore the color palette values
+****************************************************************************/
+static void vga_restorepalette(
+ const uchar *pal)
+{
+ int i;
+
+ /* restore saved palette */
+ _port_out(0, PEL_IW);
+ for (i = 0; i < 768; i++) {
+ vga_delay();
+ _port_out(*pal++, PEL_D);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Read the font data from the VGA character generator RAM
+****************************************************************************/
+static void vga_saveFont(
+ uchar *data)
+{
+ uchar *A0000Ptr = PM_getA0000Pointer();
+ uchar save[7];
+
+ /* Enable access to character generator RAM */
+ save[0] = (uchar)vga_rdinx(SEQ_I,0x00);
+ save[1] = (uchar)vga_rdinx(SEQ_I,0x02);
+ save[2] = (uchar)vga_rdinx(SEQ_I,0x04);
+ save[3] = (uchar)vga_rdinx(SEQ_I,0x00);
+ save[4] = (uchar)vga_rdinx(GRA_I,0x04);
+ save[5] = (uchar)vga_rdinx(GRA_I,0x05);
+ save[6] = (uchar)vga_rdinx(GRA_I,0x06);
+ vga_wrinx(SEQ_I,0x00,0x01);
+ vga_wrinx(SEQ_I,0x02,0x04);
+ vga_wrinx(SEQ_I,0x04,0x07);
+ vga_wrinx(SEQ_I,0x00,0x03);
+ vga_wrinx(GRA_I,0x04,0x02);
+ vga_wrinx(GRA_I,0x05,0x00);
+ vga_wrinx(GRA_I,0x06,0x00);
+
+ /* Copy character generator RAM */
+ memcpy(data,A0000Ptr,FONT_C);
+
+ /* Restore VGA state */
+ vga_wrinx(SEQ_I,0x00,save[0]);
+ vga_wrinx(SEQ_I,0x02,save[1]);
+ vga_wrinx(SEQ_I,0x04,save[2]);
+ vga_wrinx(SEQ_I,0x00,save[3]);
+ vga_wrinx(GRA_I,0x04,save[4]);
+ vga_wrinx(GRA_I,0x05,save[5]);
+ vga_wrinx(GRA_I,0x06,save[6]);
+}
+
+/****************************************************************************
+REMARKS:
+Downloads the font data to the VGA character generator RAM
+****************************************************************************/
+static void vga_restoreFont(
+ const uchar *data)
+{
+ uchar *A0000Ptr = PM_getA0000Pointer();
+
+ /* Enable access to character generator RAM */
+ vga_wrinx(SEQ_I,0x00,0x01);
+ vga_wrinx(SEQ_I,0x02,0x04);
+ vga_wrinx(SEQ_I,0x04,0x07);
+ vga_wrinx(SEQ_I,0x00,0x03);
+ vga_wrinx(GRA_I,0x04,0x02);
+ vga_wrinx(GRA_I,0x05,0x00);
+ vga_wrinx(GRA_I,0x06,0x00);
+
+ /* Copy font back to character generator RAM */
+ memcpy(A0000Ptr,data,FONT_C);
+}
+
+/****************************************************************************
+REMARKS:
+Save the state of all VGA compatible registers
+****************************************************************************/
+void PMAPI PM_saveVGAState(
+ void *stateBuf)
+{
+ uchar *regs = stateBuf;
+ int i;
+
+ /* Save state of VGA registers */
+ for (i = 0; i < CRT_C; i++) {
+ _port_out(i, CRT_I);
+ regs[CRT + i] = _port_in(CRT_D);
+ }
+ for (i = 0; i < ATT_C; i++) {
+ _port_in(IS1_R);
+ vga_delay();
+ _port_out(i, ATT_IW);
+ vga_delay();
+ regs[ATT + i] = _port_in(ATT_R);
+ vga_delay();
+ }
+ for (i = 0; i < GRA_C; i++) {
+ _port_out(i, GRA_I);
+ regs[GRA + i] = _port_in(GRA_D);
+ }
+ for (i = 0; i < SEQ_C; i++) {
+ _port_out(i, SEQ_I);
+ regs[SEQ + i] = _port_in(SEQ_D);
+ }
+ regs[MIS] = _port_in(MIS_R);
+
+ /* Save the VGA palette values */
+ vga_savepalette(&regs[PAL]);
+
+ /* Save the VGA character generator RAM */
+ vga_saveFont(&regs[FONT]);
+
+ /* Turn the VGA display back on */
+ PM_vgaUnblankDisplay();
+}
+
+/****************************************************************************
+REMARKS:
+Retore the state of all VGA compatible registers
+****************************************************************************/
+void PMAPI PM_restoreVGAState(
+ const void *stateBuf)
+{
+ const uchar *regs = stateBuf;
+ int i;
+
+ /* Blank the display before we start the restore */
+ PM_vgaBlankDisplay();
+
+ /* Restore the VGA character generator RAM */
+ vga_restoreFont(&regs[FONT]);
+
+ /* Restore the VGA palette values */
+ vga_restorepalette(&regs[PAL]);
+
+ /* Restore the state of the VGA compatible registers */
+ _port_out(regs[MIS], MIS_W);
+
+ /* Delay to allow clock change to settle */
+ for (i = 0; i < 10; i++)
+ vga_delay();
+
+ /* Synchronous reset on */
+ _port_out(0x00,SEQ_I);
+ _port_out(0x01,SEQ_D);
+
+ /* Write seqeuencer registers */
+ _port_out(1, SEQ_I);
+ _port_out(regs[SEQ + 1] | 0x20, SEQ_D);
+ for (i = 2; i < SEQ_C; i++) {
+ _port_out(i, SEQ_I);
+ _port_out(regs[SEQ + i], SEQ_D);
+ }
+
+ /* Synchronous reset off */
+ _port_out(0x00,SEQ_I);
+ _port_out(0x03,SEQ_D);
+
+ /* Deprotect CRT registers 0-7 and write CRTC */
+ _port_out(0x11, CRT_I);
+ _port_out(_port_in(CRT_D) & 0x7F, CRT_D);
+ for (i = 0; i < CRT_C; i++) {
+ _port_out(i, CRT_I);
+ _port_out(regs[CRT + i], CRT_D);
+ }
+ for (i = 0; i < GRA_C; i++) {
+ _port_out(i, GRA_I);
+ _port_out(regs[GRA + i], GRA_D);
+ }
+ for (i = 0; i < ATT_C; i++) {
+ _port_in(IS1_R); /* reset flip-flop */
+ vga_delay();
+ _port_out(i, ATT_IW);
+ vga_delay();
+ _port_out(regs[ATT + i], ATT_IW);
+ vga_delay();
+ }
+
+ /* Ensure the VGA screen is turned on */
+ PM_vgaUnblankDisplay();
+}
+
+/****************************************************************************
+REMARKS:
+Disables the VGA display for screen output making it blank.
+****************************************************************************/
+void PMAPI PM_vgaBlankDisplay(void)
+{
+ /* Turn screen off */
+ _port_out(0x01, SEQ_I);
+ _port_out(_port_in(SEQ_D) | 0x20, SEQ_D);
+
+ /* Disable video output */
+ _port_in(IS1_R);
+ vga_delay();
+ _port_out(0x00, ATT_IW);
+}
+
+/****************************************************************************
+REMARKS:
+Enables the VGA display for screen output.
+****************************************************************************/
+void PMAPI PM_vgaUnblankDisplay(void)
+{
+ /* Turn screen back on */
+ _port_out(0x01, SEQ_I);
+ _port_out(_port_in(SEQ_D) & 0xDF, SEQ_D);
+
+ /* Enable video output */
+ _port_in(IS1_R);
+ vga_delay();
+ _port_out(0x20, ATT_IW);
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/cpuinfo.c
new file mode 100644
index 0000000000..e2446a4397
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/cpuinfo.c
@@ -0,0 +1,808 @@
+/****************************************************************************
+*
+* 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: Main module to implement the Zen Timer support functions.
+*
+****************************************************************************/
+
+#include "ztimer.h"
+#include "pmapi.h"
+#include "oshdr.h"
+#if !defined(__WIN32_VXD__) && !defined(__OS2_VDD__) && !defined(__NT_DRIVER__)
+#include <stdio.h>
+#include <string.h>
+#endif
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* External Intel assembler functions */
+#ifdef __INTEL__
+/* {secret} */
+ibool _ASMAPI _CPU_haveCPUID(void);
+/* {secret} */
+ibool _ASMAPI _CPU_check80386(void);
+/* {secret} */
+ibool _ASMAPI _CPU_check80486(void);
+/* {secret} */
+uint _ASMAPI _CPU_checkCPUID(void);
+/* {secret} */
+uint _ASMAPI _CPU_getCPUIDModel(void);
+/* {secret} */
+uint _ASMAPI _CPU_getCPUIDStepping(void);
+/* {secret} */
+uint _ASMAPI _CPU_getCPUIDFeatures(void);
+/* {secret} */
+uint _ASMAPI _CPU_getCacheSize(void);
+/* {secret} */
+uint _ASMAPI _CPU_have3DNow(void);
+/* {secret} */
+ibool _ASMAPI _CPU_checkClone(void);
+/* {secret} */
+void _ASMAPI _CPU_readTimeStamp(CPU_largeInteger *time);
+/* {secret} */
+void _ASMAPI _CPU_runBSFLoop(ulong iterations);
+/* {secret} */
+ulong _ASMAPI _CPU_mulDiv(ulong a,ulong b,ulong c);
+/* {secret} */
+void ZTimerQuickInit(void);
+#define CPU_HaveMMX 0x00800000
+#define CPU_HaveRDTSC 0x00000010
+#define CPU_HaveSSE 0x02000000
+#endif
+
+#if defined(__SMX32__)
+#include "smx/cpuinfo.c"
+#elif defined(__RTTARGET__)
+#include "rttarget/cpuinfo.c"
+#elif defined(__REALDOS__)
+#include "dos/cpuinfo.c"
+#elif defined(__NT_DRIVER__)
+#include "ntdrv/cpuinfo.c"
+#elif defined(__WIN32_VXD__)
+#include "vxd/cpuinfo.c"
+#elif defined(__WINDOWS32__)
+#include "win32/cpuinfo.c"
+#elif defined(__OS2_VDD__)
+#include "vdd/cpuinfo.c"
+#elif defined(__OS2__)
+#include "os2/cpuinfo.c"
+#elif defined(__LINUX__)
+#include "linux/cpuinfo.c"
+#elif defined(__QNX__)
+#include "qnx/cpuinfo.c"
+#elif defined(__BEOS__)
+#include "beos/cpuinfo.c"
+#else
+#error CPU library not ported to this platform yet!
+#endif
+
+/*------------------------ Public interface routines ----------------------*/
+
+/****************************************************************************
+REMARKS:
+Read an I/O port location.
+****************************************************************************/
+static uchar rdinx(
+ int port,
+ int index)
+{
+ PM_outpb(port,(uchar)index);
+ return PM_inpb(port+1);
+}
+
+/****************************************************************************
+REMARKS:
+Write an I/O port location.
+****************************************************************************/
+static void wrinx(
+ ushort port,
+ ushort index,
+ ushort value)
+{
+ PM_outpb(port,(uchar)index);
+ PM_outpb(port+1,(uchar)value);
+}
+
+/****************************************************************************
+REMARKS:
+Enables the Cyrix CPUID instruction to properly detect MediaGX and 6x86
+processors.
+****************************************************************************/
+static void _CPU_enableCyrixCPUID(void)
+{
+ uchar ccr3;
+
+ PM_init();
+ ccr3 = rdinx(0x22,0xC3);
+ wrinx(0x22,0xC3,(uchar)(ccr3 | 0x10));
+ wrinx(0x22,0xE8,(uchar)(rdinx(0x22,0xE8) | 0x80));
+ wrinx(0x22,0xC3,ccr3);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns the type of processor in the system.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+Numerical identifier for the installed processor
+
+REMARKS:
+Returns the type of processor in the system. Note that if the CPU is an
+unknown Pentium family processor that we don't have an enumeration for,
+the return value will be greater than or equal to the value of CPU_UnkPentium
+(depending on the value returned by the CPUID instruction).
+
+SEE ALSO:
+CPU_getProcessorSpeed, CPU_haveMMX, CPU_getProcessorName
+****************************************************************************/
+uint ZAPI CPU_getProcessorType(void)
+{
+#if defined(__INTEL__)
+ uint cpu,vendor,model,cacheSize;
+ static ibool firstTime = true;
+
+ if (_CPU_haveCPUID()) {
+ cpu = _CPU_checkCPUID();
+ vendor = cpu & ~CPU_mask;
+ if (vendor == CPU_Intel) {
+ /* Check for Intel processors */
+ switch (cpu & CPU_mask) {
+ case 4: cpu = CPU_i486; break;
+ case 5: cpu = CPU_Pentium; break;
+ case 6:
+ if ((model = _CPU_getCPUIDModel()) == 1)
+ cpu = CPU_PentiumPro;
+ else if (model <= 6) {
+ cacheSize = _CPU_getCacheSize();
+ if ((model == 5 && cacheSize == 0) ||
+ (model == 5 && cacheSize == 256) ||
+ (model == 6 && cacheSize == 128))
+ cpu = CPU_Celeron;
+ else
+ cpu = CPU_PentiumII;
+ }
+ else if (model >= 7) {
+ /* Model 7 == Pentium III */
+ /* Model 8 == Celeron/Pentium III Coppermine */
+ cacheSize = _CPU_getCacheSize();
+ if ((model == 8 && cacheSize == 128))
+ cpu = CPU_Celeron;
+ else
+ cpu = CPU_PentiumIII;
+ }
+ break;
+ default:
+ cpu = CPU_UnkIntel;
+ }
+ }
+ else if (vendor == CPU_Cyrix) {
+ /* Check for Cyrix processors */
+ switch (cpu & CPU_mask) {
+ case 4:
+ if ((model = _CPU_getCPUIDModel()) == 4)
+ cpu = CPU_CyrixMediaGX;
+ else
+ cpu = CPU_UnkCyrix;
+ break;
+ case 5:
+ if ((model = _CPU_getCPUIDModel()) == 2)
+ cpu = CPU_Cyrix6x86;
+ else if (model == 4)
+ cpu = CPU_CyrixMediaGXm;
+ else
+ cpu = CPU_UnkCyrix;
+ break;
+ case 6:
+ if ((model = _CPU_getCPUIDModel()) <= 1)
+ cpu = CPU_Cyrix6x86MX;
+ else
+ cpu = CPU_UnkCyrix;
+ break;
+ default:
+ cpu = CPU_UnkCyrix;
+ }
+ }
+ else if (vendor == CPU_AMD) {
+ /* Check for AMD processors */
+ switch (cpu & CPU_mask) {
+ case 4:
+ if ((model = _CPU_getCPUIDModel()) == 0)
+ cpu = CPU_AMDAm5x86;
+ else
+ cpu = CPU_AMDAm486;
+ break;
+ case 5:
+ if ((model = _CPU_getCPUIDModel()) <= 3)
+ cpu = CPU_AMDK5;
+ else if (model <= 7)
+ cpu = CPU_AMDK6;
+ else if (model == 8)
+ cpu = CPU_AMDK6_2;
+ else if (model == 9)
+ cpu = CPU_AMDK6_III;
+ else if (model == 13) {
+ if (_CPU_getCPUIDStepping() <= 3)
+ cpu = CPU_AMDK6_IIIplus;
+ else
+ cpu = CPU_AMDK6_2plus;
+ }
+ else
+ cpu = CPU_UnkAMD;
+ break;
+ case 6:
+ if ((model = _CPU_getCPUIDModel()) == 3)
+ cpu = CPU_AMDDuron;
+ else
+ cpu = CPU_AMDAthlon;
+ break;
+ default:
+ cpu = CPU_UnkAMD;
+ }
+ }
+ else if (vendor == CPU_IDT) {
+ /* Check for IDT WinChip processors */
+ switch (cpu & CPU_mask) {
+ case 5:
+ if ((model = _CPU_getCPUIDModel()) <= 4)
+ cpu = CPU_WinChipC6;
+ else if (model == 8)
+ cpu = CPU_WinChip2;
+ else
+ cpu = CPU_UnkIDT;
+ break;
+ default:
+ cpu = CPU_UnkIDT;
+ }
+ }
+ else {
+ /* Assume a Pentium compatible Intel clone */
+ cpu = CPU_Pentium;
+ }
+ return cpu | vendor | (_CPU_getCPUIDStepping() << CPU_steppingShift);
+ }
+ else {
+ if (_CPU_check80386())
+ cpu = CPU_i386;
+ else if (_CPU_check80486()) {
+ /* If we get here we may have a Cyrix processor so we can try
+ * enabling the CPUID instruction and trying again.
+ */
+ if (firstTime) {
+ firstTime = false;
+ _CPU_enableCyrixCPUID();
+ return CPU_getProcessorType();
+ }
+ cpu = CPU_i486;
+ }
+ else
+ cpu = CPU_Pentium;
+ if (!_CPU_checkClone())
+ return cpu | CPU_Intel;
+ return cpu;
+ }
+#elif defined(__ALPHA__)
+ return CPU_Alpha;
+#elif defined(__MIPS__)
+ return CPU_Mips;
+#elif defined(__PPC__)
+ return CPU_PowerPC;
+#endif
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns true if the processor supports Intel MMX extensions.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+True if MMX is available, false if not.
+
+REMARKS:
+This function determines if the processor supports the Intel MMX extended
+instruction set.
+
+SEE ALSO:
+CPU_getProcessorType, CPU_getProcessorSpeed, CPU_have3DNow, CPU_haveSSE,
+CPU_getProcessorName
+****************************************************************************/
+ibool ZAPI CPU_haveMMX(void)
+{
+#ifdef __INTEL__
+ if (_CPU_haveCPUID())
+ return (_CPU_getCPUIDFeatures() & CPU_HaveMMX) != 0;
+ return false;
+#else
+ return false;
+#endif
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns true if the processor supports AMD 3DNow! extensions.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+True if 3DNow! is available, false if not.
+
+REMARKS:
+This function determines if the processor supports the AMD 3DNow! extended
+instruction set.
+
+SEE ALSO:
+CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_haveSSE,
+CPU_getProcessorName
+****************************************************************************/
+ibool ZAPI CPU_have3DNow(void)
+{
+#ifdef __INTEL__
+ if (_CPU_haveCPUID())
+ return _CPU_have3DNow();
+ return false;
+#else
+ return false;
+#endif
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns true if the processor supports Intel KNI extensions.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+True if Intel KNI is available, false if not.
+
+REMARKS:
+This function determines if the processor supports the Intel KNI extended
+instruction set.
+
+SEE ALSO:
+CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_have3DNow,
+CPU_getProcessorName
+****************************************************************************/
+ibool ZAPI CPU_haveSSE(void)
+{
+#ifdef __INTEL__
+ if (_CPU_haveCPUID())
+ return (_CPU_getCPUIDFeatures() & CPU_HaveSSE) != 0;
+ return false;
+#else
+ return false;
+#endif
+}
+
+/****************************************************************************
+RETURNS:
+True if the RTSC instruction is available, false if not.
+
+REMARKS:
+This function determines if the processor supports the Intel RDTSC
+instruction, for high precision timing. If the processor is not an Intel or
+Intel clone CPU, this function will always return false.
+
+DESCRIPTION:
+Returns true if the processor supports RDTSC extensions.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+True if RTSC is available, false if not.
+
+REMARKS:
+This function determines if the processor supports the RDTSC instruction
+for reading the processor time stamp counter.
+
+SEE ALSO:
+CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_have3DNow,
+CPU_getProcessorName
+****************************************************************************/
+ibool ZAPI CPU_haveRDTSC(void)
+{
+#ifdef __INTEL__
+ if (_CPU_haveCPUID())
+ return (_CPU_getCPUIDFeatures() & CPU_HaveRDTSC) != 0;
+ return false;
+#else
+ return false;
+#endif
+}
+
+#ifdef __INTEL__
+
+#define ITERATIONS 16000
+#define SAMPLINGS 2
+#define INNER_LOOPS 400
+
+/****************************************************************************
+REMARKS:
+If processor does not support time stamp reading, but is at least a 386 or
+above, utilize method of timing a loop of BSF instructions which take a
+known number of cycles to run on i386(tm), i486(tm), and Pentium(R)
+processors.
+****************************************************************************/
+static ulong GetBSFCpuSpeed(
+ ulong cycles)
+{
+ CPU_largeInteger t0,t1,count_freq;
+ ulong ticks; /* Microseconds elapsed during test */
+ ulong current; /* Variable to store time elapsed */
+ int i,j,iPriority;
+ ulong lowest = (ulong)-1;
+
+ iPriority = SetMaxThreadPriority();
+ GetCounterFrequency(&count_freq);
+ for (i = 0; i < SAMPLINGS; i++) {
+ GetCounter(&t0);
+ for (j = 0; j < INNER_LOOPS; j++)
+ _CPU_runBSFLoop(ITERATIONS);
+ GetCounter(&t1);
+ current = t1.low - t0.low;
+ if (current < lowest)
+ lowest = current;
+ }
+ RestoreThreadPriority(iPriority);
+
+ /* Compute frequency */
+ ticks = _CPU_mulDiv(lowest,1000000,count_freq.low);
+ if ((ticks % count_freq.low) > (count_freq.low/2))
+ ticks++; /* Round up if necessary */
+ if (ticks == 0)
+ return 0;
+ return ((cycles*INNER_LOOPS)/ticks);
+}
+
+#define TOLERANCE 1
+
+/****************************************************************************
+REMARKS:
+On processors supporting the Read Time Stamp opcode, compare elapsed
+time on the High-Resolution Counter with elapsed cycles on the Time
+Stamp Register.
+
+The inner loop runs up to 20 times oruntil the average of the previous
+three calculated frequencies is within 1 MHz of each of the individual
+calculated frequencies. This resampling increases the accuracy of the
+results since outside factors could affect this calculation.
+****************************************************************************/
+static ulong GetRDTSCCpuSpeed(
+ ibool accurate)
+{
+ CPU_largeInteger t0,t1,s0,s1,count_freq;
+ u64 stamp0, stamp1, ticks0, ticks1;
+ u64 total_cycles, cycles, hz, freq;
+ u64 total_ticks, ticks;
+ int tries,iPriority;
+ ulong maxCount;
+
+ PM_set64_32(total_cycles,0);
+ PM_set64_32(total_ticks,0);
+ maxCount = accurate ? 600000 : 30000;
+ iPriority = SetMaxThreadPriority();
+ GetCounterFrequency(&count_freq);
+ PM_set64(freq,count_freq.high,count_freq.low);
+ for (tries = 0; tries < 3; tries++) {
+ /* Loop until 100 ticks have passed since last read of hi-res
+ * counter. This accounts for overhead later.
+ */
+ GetCounter(&t0);
+ t1.low = t0.low;
+ t1.high = t0.high;
+ while ((t1.low - t0.low) < 100) {
+ GetCounter(&t1);
+ _CPU_readTimeStamp(&s0);
+ }
+
+ /* Loop until 30000 ticks have passed since last read of hi-res counter.
+ * This allows for elapsed time for sampling. For a hi-res frequency
+ * of 1MHz, this is about 0.03 of a second. The frequency reported
+ * by the OS dependent code should be tuned to provide a good
+ * sample period depending on the accuracy of the OS timers (ie:
+ * if the accuracy is lower, lower the frequency to spend more time
+ * in the inner loop to get better accuracy).
+ */
+ t0.low = t1.low;
+ t0.high = t1.high;
+ while ((t1.low - t0.low) < maxCount) {
+ GetCounter(&t1);
+ _CPU_readTimeStamp(&s1);
+ }
+
+ /* Find the difference during the timing loop */
+ PM_set64(stamp0,s0.high,s0.low);
+ PM_set64(stamp1,s1.high,s1.low);
+ PM_set64(ticks0,t0.high,t0.low);
+ PM_set64(ticks1,t1.high,t1.low);
+ PM_sub64(cycles,stamp1,stamp0);
+ PM_sub64(ticks,ticks1,ticks0);
+
+ /* Sum up the results */
+ PM_add64(total_ticks,total_ticks,ticks);
+ PM_add64(total_cycles,total_cycles,cycles);
+ }
+ RestoreThreadPriority(iPriority);
+
+ /* Compute frequency in Hz */
+ PM_mul64(hz,total_cycles,freq);
+ PM_div64(hz,hz,total_ticks);
+ return PM_64to32(hz);
+}
+
+#endif /* __INTEL__ */
+
+/****************************************************************************
+DESCRIPTION:
+Returns the speed of the processor in MHz.
+
+HEADER:
+ztimer.h
+
+PARAMETERS:
+accurate - True of the speed should be measured accurately
+
+RETURNS:
+Processor speed in MHz.
+
+REMARKS:
+This function returns the speed of the CPU in MHz. Note that if the speed
+cannot be determined, this function will return 0.
+
+If the accurate parameter is set to true, this function will spend longer
+profiling the speed of the CPU, and will not round the CPU speed that is
+reported. This is important for highly accurate timing using the Pentium
+RDTSC instruction, but it does take a lot longer for the profiling to
+produce accurate results.
+
+SEE ALSO:
+CPU_getProcessorSpeedInHz, CPU_getProcessorType, CPU_haveMMX,
+CPU_getProcessorName
+****************************************************************************/
+ulong ZAPI CPU_getProcessorSpeed(
+ ibool accurate)
+{
+#if defined(__INTEL__)
+ /* Number of cycles needed to execute a single BSF instruction on i386+
+ * processors.
+ */
+ ulong cpuSpeed;
+ uint i;
+ static ulong intel_cycles[] = {
+ 115,47,43,
+ };
+ static ulong cyrix_cycles[] = {
+ 38,38,52,52,
+ };
+ static ulong amd_cycles[] = {
+ 49,
+ };
+ static ulong known_speeds[] = {
+ 1000,950,900,850,800,750,700,650,600,550,500,450,433,400,350,
+ 333,300,266,233,200,166,150,133,120,100,90,75,66,60,50,33,20,0,
+ };
+
+ if (CPU_haveRDTSC()) {
+ cpuSpeed = (GetRDTSCCpuSpeed(accurate) + 500000) / 1000000;
+ }
+ else {
+ int type = CPU_getProcessorType();
+ int processor = type & CPU_mask;
+ int vendor = type & CPU_familyMask;
+ if (vendor == CPU_Intel)
+ cpuSpeed = GetBSFCpuSpeed(ITERATIONS * intel_cycles[processor - CPU_i386]);
+ else if (vendor == CPU_Cyrix)
+ cpuSpeed = GetBSFCpuSpeed(ITERATIONS * cyrix_cycles[processor - CPU_Cyrix6x86]);
+ else if (vendor == CPU_AMD)
+ cpuSpeed = GetBSFCpuSpeed(ITERATIONS * amd_cycles[0]);
+ else
+ return 0;
+ }
+
+ /* Now normalise the results given known processors speeds, if the
+ * speed we measure is within 2MHz of the expected values
+ */
+ if (!accurate) {
+ for (i = 0; known_speeds[i] != 0; i++) {
+ if (cpuSpeed >= (known_speeds[i]-3) && cpuSpeed <= (known_speeds[i]+3)) {
+ return known_speeds[i];
+ }
+ }
+ }
+ return cpuSpeed;
+#else
+ return 0;
+#endif
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns the speed of the processor in Hz.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+Accurate processor speed in Hz.
+
+REMARKS:
+This function returns the accurate speed of the CPU in Hz. Note that if the
+speed cannot be determined, this function will return 0.
+
+This function is similar to the CPU_getProcessorSpeed function, except that
+it attempts to accurately measure the CPU speed in Hz. This is used
+internally in the Zen Timer libraries to provide accurate real world timing
+information. This is important for highly accurate timing using the Pentium
+RDTSC instruction, but it does take a lot longer for the profiling to
+produce accurate results.
+
+SEE ALSO:
+CPU_getProcessorSpeed, CPU_getProcessorType, CPU_haveMMX,
+CPU_getProcessorName
+****************************************************************************/
+ulong ZAPI CPU_getProcessorSpeedInHZ(
+ ibool accurate)
+{
+#if defined(__INTEL__)
+ if (CPU_haveRDTSC()) {
+ return GetRDTSCCpuSpeed(accurate);
+ }
+ return CPU_getProcessorSpeed(false) * 1000000;
+#else
+ return 0;
+#endif
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns a string defining the speed and name of the processor.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+Processor name string.
+
+REMARKS:
+This function returns an English string describing the speed and name of the
+CPU.
+
+SEE ALSO:
+CPU_getProcessorType, CPU_haveMMX, CPU_getProcessorName
+****************************************************************************/
+char * ZAPI CPU_getProcessorName(void)
+{
+#if defined(__INTEL__)
+ static int cpu,speed = -1;
+ static char name[80];
+
+ if (speed == -1) {
+ cpu = CPU_getProcessorType();
+ speed = CPU_getProcessorSpeed(false);
+ }
+ sprintf(name,"%d MHz ", speed);
+ switch (cpu & CPU_mask) {
+ case CPU_i386:
+ strcat(name,"Intel i386 processor");
+ break;
+ case CPU_i486:
+ strcat(name,"Intel i486 processor");
+ break;
+ case CPU_Pentium:
+ strcat(name,"Intel Pentium processor");
+ break;
+ case CPU_PentiumPro:
+ strcat(name,"Intel Pentium Pro processor");
+ break;
+ case CPU_PentiumII:
+ strcat(name,"Intel Pentium II processor");
+ break;
+ case CPU_Celeron:
+ strcat(name,"Intel Celeron processor");
+ break;
+ case CPU_PentiumIII:
+ strcat(name,"Intel Pentium III processor");
+ break;
+ case CPU_UnkIntel:
+ strcat(name,"Unknown Intel processor");
+ break;
+ case CPU_Cyrix6x86:
+ strcat(name,"Cyrix 6x86 processor");
+ break;
+ case CPU_Cyrix6x86MX:
+ strcat(name,"Cyrix 6x86MX processor");
+ break;
+ case CPU_CyrixMediaGX:
+ strcat(name,"Cyrix MediaGX processor");
+ break;
+ case CPU_CyrixMediaGXm:
+ strcat(name,"Cyrix MediaGXm processor");
+ break;
+ case CPU_UnkCyrix:
+ strcat(name,"Unknown Cyrix processor");
+ break;
+ case CPU_AMDAm486:
+ strcat(name,"AMD Am486 processor");
+ break;
+ case CPU_AMDAm5x86:
+ strcat(name,"AMD Am5x86 processor");
+ break;
+ case CPU_AMDK5:
+ strcat(name,"AMD K5 processor");
+ break;
+ case CPU_AMDK6:
+ strcat(name,"AMD K6 processor");
+ break;
+ case CPU_AMDK6_2:
+ strcat(name,"AMD K6-2 processor");
+ break;
+ case CPU_AMDK6_III:
+ strcat(name,"AMD K6-III processor");
+ break;
+ case CPU_AMDK6_2plus:
+ strcat(name,"AMD K6-2+ processor");
+ break;
+ case CPU_AMDK6_IIIplus:
+ strcat(name,"AMD K6-III+ processor");
+ break;
+ case CPU_UnkAMD:
+ strcat(name,"Unknown AMD processor");
+ break;
+ case CPU_AMDAthlon:
+ strcat(name,"AMD Athlon processor");
+ break;
+ case CPU_AMDDuron:
+ strcat(name,"AMD Duron processor");
+ break;
+ case CPU_WinChipC6:
+ strcat(name,"IDT WinChip C6 processor");
+ break;
+ case CPU_WinChip2:
+ strcat(name,"IDT WinChip 2 processor");
+ break;
+ case CPU_UnkIDT:
+ strcat(name,"Unknown IDT processor");
+ break;
+ default:
+ strcat(name,"Unknown processor");
+ }
+ if (CPU_haveMMX())
+ strcat(name," with MMX(R)");
+ if (CPU_have3DNow())
+ strcat(name,", 3DNow!(R)");
+ if (CPU_haveSSE())
+ strcat(name,", SSE(R)");
+ return name;
+#else
+ return "Unknown";
+#endif
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/debug.c b/board/MAI/bios_emulator/scitech/src/pm/debug.c
new file mode 100644
index 0000000000..d86e3e6a0d
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/debug.c
@@ -0,0 +1,107 @@
+/****************************************************************************
+*
+* 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: Main module containing debug checking features.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#ifdef __WIN32_VXD__
+#include "vxdfile.h"
+#elif defined(__NT_DRIVER__)
+#include "ntdriver.h"
+#elif defined(__OS2_VDD__)
+#include "vddfile.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+/*---------------------------- Global variables ---------------------------*/
+
+/* {secret} */
+void (*_CHK_fail)(int fatal,const char *msg,const char *cond,const char *file,int line) = _CHK_defaultFail;
+static char logFile[256] = "";
+
+/*----------------------------- Implementation ----------------------------*/
+
+#ifdef CHECKED
+void _CHK_defaultFail(
+ int fatal,
+ const char *msg,
+ const char *cond,
+ const char *file,
+ int line)
+{
+ FILE *f;
+ char buf[256];
+
+ if (logFile[0] == 0) {
+ strcpy(logFile,PM_getNucleusPath());
+ PM_backslash(logFile);
+ strcat(logFile,"scitech.log");
+ }
+ if ((f = fopen(logFile,"a+")) != NULL) {
+#if defined(__WIN32_VXD__) || defined(__OS2_VDD__) || defined(__NT_DRIVER__)
+ sprintf(buf,msg,cond,file,line);
+ fwrite(buf,1,strlen(buf),f);
+#else
+ fprintf(f,msg,cond,file,line);
+#endif
+ fclose(f);
+ }
+ if (fatal) {
+ sprintf(buf,"Check failed: check '%s' for details", logFile);
+ PM_fatalError(buf);
+ }
+}
+#endif
+
+/****************************************************************************
+DESCRIPTION:
+Sets the location of the debug log file.
+
+HEADER:
+pmapi.h
+
+PARAMETERS:
+logFilePath - Full file and path name to debug log file.
+
+REMARKS:
+Sets the name and location of the debug log file. The debug log file is
+created and written to when runtime checks, warnings and failure conditions
+are logged to disk when code is compiled in CHECKED mode. By default the
+log file is called 'scitech.log' and goes into the current SciTech Nucleus
+path for the application. You can use this function to set the filename
+and location of the debug log file to your own application specific
+directory.
+****************************************************************************/
+void PMAPI PM_setDebugLog(
+ const char *logFilePath)
+{
+ strcpy(logFile,logFilePath);
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/_event.asm b/board/MAI/bios_emulator/scitech/src/pm/dos/_event.asm
new file mode 100644
index 0000000000..36dcaab67b
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/_event.asm
@@ -0,0 +1,194 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler
+;* Environment: IBM PC (MS DOS)
+;*
+;* Description: Assembly language support routines for the event module.
+;*
+;****************************************************************************
+
+ ideal
+
+include "scitech.mac" ; Memory model macros
+
+ifdef flatmodel
+
+header _event ; Set up memory model
+
+begdataseg _event
+
+ cextern _EVT_biosPtr,DPTR
+
+ifdef USE_NASM
+%define KB_HEAD WORD esi+01Ah ; Keyboard buffer head in BIOS data area
+%define KB_TAIL WORD esi+01Ch ; Keyboard buffer tail in BIOS data area
+%define KB_START WORD esi+080h ; Start of keyboard buffer in BIOS data area
+%define KB_END WORD esi+082h ; End of keyboard buffer in BIOS data area
+else
+KB_HEAD EQU WORD esi+01Ah ; Keyboard buffer head in BIOS data area
+KB_TAIL EQU WORD esi+01Ch ; Keyboard buffer tail in BIOS data area
+KB_START EQU WORD esi+080h ; Start of keyboard buffer in BIOS data area
+KB_END EQU WORD esi+082h ; End of keyboard buffer in BIOS data area
+endif
+
+enddataseg _event
+
+begcodeseg _event ; Start of code segment
+
+ cpublic _EVT_codeStart
+
+;----------------------------------------------------------------------------
+; int _EVT_getKeyCode(void)
+;----------------------------------------------------------------------------
+; Returns the key code for the next available key by extracting it from
+; the BIOS keyboard buffer.
+;----------------------------------------------------------------------------
+cprocstart _EVT_getKeyCode
+
+ enter_c
+
+ mov esi,[_EVT_biosPtr]
+ xor ebx,ebx
+ xor eax,eax
+ mov bx,[KB_HEAD]
+ cmp bx,[KB_TAIL]
+ jz @@Done
+ xor eax,eax
+ mov ax,[esi+ebx] ; EAX := character from keyboard buffer
+ inc _bx
+ inc _bx
+ cmp bx,[KB_END] ; Hit the end of the keyboard buffer?
+ jl @@1
+ mov bx,[KB_START]
+@@1: mov [KB_HEAD],bx ; Update keyboard buffer head pointer
+
+@@Done: leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _EVT_pumpMessages(void)
+;----------------------------------------------------------------------------
+; This function would normally do nothing, however due to strange bugs
+; in the Windows 3.1 and OS/2 DOS boxes, we don't get any hardware keyboard
+; interrupts unless we periodically call the BIOS keyboard functions. Hence
+; this function gets called every time that we check for events, and works
+; around this problem (in essence it tells the DOS VDM to pump the
+; keyboard events to our program ;-).
+;
+; Note that this bug is not present under Win 9x DOS boxes.
+;----------------------------------------------------------------------------
+cprocstart _EVT_pumpMessages
+
+ mov ah,11h ; Function - Check keyboard status
+ int 16h ; Call BIOS
+
+ mov ax, 0Bh ; Reset Move Mouse
+ int 33h
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int _EVT_disableInt(void);
+;----------------------------------------------------------------------------
+; Return processor interrupt status and disable interrupts.
+;----------------------------------------------------------------------------
+cprocstart _EVT_disableInt
+
+ pushf ; Put flag word on stack
+ cli ; Disable interrupts!
+ pop eax ; deposit flag word in return register
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _EVT_restoreInt(int ps);
+;----------------------------------------------------------------------------
+; Restore processor interrupt status.
+;----------------------------------------------------------------------------
+cprocstart _EVT_restoreInt
+
+ ARG ps:UINT
+
+ push ebp
+ mov ebp,esp ; Set up stack frame
+ push [DWORD ps]
+ popf ; Restore processor status (and interrupts)
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int EVT_rdinx(int port,int index)
+;----------------------------------------------------------------------------
+; Reads an indexed register value from an I/O port.
+;----------------------------------------------------------------------------
+cprocstart EVT_rdinx
+
+ ARG port:UINT, index:UINT
+
+ push ebp
+ mov ebp,esp
+ mov edx,[port]
+ mov al,[BYTE index]
+ out dx,al
+ inc dx
+ in al,dx
+ movzx eax,al
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void EVT_wrinx(int port,int index,int value)
+;----------------------------------------------------------------------------
+; Writes an indexed register value to an I/O port.
+;----------------------------------------------------------------------------
+cprocstart EVT_wrinx
+
+ ARG port:UINT, index:UINT, value:UINT
+
+ push ebp
+ mov ebp,esp
+ mov edx,[port]
+ mov al,[BYTE index]
+ mov ah,[BYTE value]
+ out dx,ax
+ pop ebp
+ ret
+
+cprocend
+
+ cpublic _EVT_codeEnd
+
+endcodeseg _event
+
+endif
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/_lztimer.asm b/board/MAI/bios_emulator/scitech/src/pm/dos/_lztimer.asm
new file mode 100644
index 0000000000..a4a9c7916e
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/_lztimer.asm
@@ -0,0 +1,438 @@
+;****************************************************************************
+;*
+;* 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: NASM or TASM Assembler
+;* Environment: IBM PC (MS DOS)
+;*
+;* Description: Uses the 8253 timer and the BIOS time-of-day count to time
+;* the performance of code that takes less than an hour to
+;* execute.
+;*
+;* The routines in this package only works with interrupts
+;* enabled, and in fact will explicitly turn interrupts on
+;* in order to ensure we get accurate results from the timer.
+;*
+;* Externally 'C' callable routines:
+;*
+;* LZ_timerOn: Saves the BIOS time of day count and starts the
+;* long period Zen Timer.
+;*
+;* LZ_timerLap: Latches the current count, and keeps the timer running
+;*
+;* LZ_timerOff: Stops the long-period Zen Timer and saves the timer
+;* count and the BIOS time of day count.
+;*
+;* LZ_timerCount: Returns an unsigned long representing the timed count
+;* in microseconds. If more than an hour passed during
+;* the timing interval, LZ_timerCount will return the
+;* value 0xFFFFFFFF (an invalid count).
+;*
+;* Note: If either more than an hour passes between calls to LZ_timerOn
+;* and LZ_timerOff, an error is reported. For timing code that takes
+;* more than a few minutes to execute, use the low resolution
+;* Ultra Long Period Zen Timer code, which should be accurate
+;* enough for most purposes.
+;*
+;* Note: Each block of code being timed should ideally be run several
+;* times, with at least two similar readings required to
+;* establish a true measurement, in order to eliminate any
+;* variability caused by interrupts.
+;*
+;* Note: Interrupts must not be disabled for more than 54 ms at a
+;* stretch during the timing interval. Because interrupts are
+;* enabled, key, mice, and other devices that generate interrupts
+;* should not be used during the timing interval.
+;*
+;* Note: Any extra code running off the timer interrupt (such as
+;* some memory resident utilities) will increase the time
+;* measured by the Zen Timer.
+;*
+;* Note: These routines can introduce inaccuracies of up to a few
+;* tenths of a second into the system clock count for each
+;* code section being timed. Consequently, it's a good idea to
+;* reboot at the conclusion of timing sessions. (The
+;* battery-backed clock, if any, is not affected by the Zen
+;* timer.)
+;*
+;* All registers and all flags are preserved by all routines, except
+;* interrupts which are always turned on
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac"
+
+;****************************************************************************
+;
+; Equates used by long period Zen Timer
+;
+;****************************************************************************
+
+; Base address of 8253 timer chip
+
+BASE_8253 equ 40h
+
+; The address of the timer 0 count registers in the 8253
+
+TIMER_0_8253 equ BASE_8253 + 0
+
+; The address of the mode register in the 8253
+
+MODE_8253 equ BASE_8253 + 3
+
+; The address of the BIOS timer count variable in the BIOS data area.
+
+TIMER_COUNT equ 6Ch
+
+; Macro to delay briefly to ensure that enough time has elapsed between
+; successive I/O accesses so that the device being accessed can respond
+; to both accesses even on a very fast PC.
+
+ifdef USE_NASM
+%macro DELAY 0
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+%endmacro
+else
+macro DELAY
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+endm
+endif
+
+header _lztimer
+
+begdataseg _lztimer
+
+ cextern _ZTimerBIOSPtr,DPTR
+
+StartBIOSCount dd 0 ; Starting BIOS count dword
+EndBIOSCount dd 0 ; Ending BIOS count dword
+EndTimedCount dw 0 ; Timer 0 count at the end of timing period
+
+enddataseg _lztimer
+
+begcodeseg _lztimer ; Start of code segment
+
+;----------------------------------------------------------------------------
+; void LZ_timerOn(void);
+;----------------------------------------------------------------------------
+; Starts the Long period Zen timer counting.
+;----------------------------------------------------------------------------
+cprocstart LZ_timerOn
+
+; Set the timer 0 of the 8253 to mode 2 (divide-by-N), to cause
+; linear counting rather than count-by-two counting. Also stops
+; timer 0 until the timer count is loaded, except on PS/2 computers.
+
+ mov al,00110100b ; mode 2
+ out MODE_8253,al
+
+; Set the timer count to 0, so we know we won't get another timer
+; interrupt right away. Note: this introduces an inaccuracy of up to 54 ms
+; in the system clock count each time it is executed.
+
+ DELAY
+ sub al,al
+ out TIMER_0_8253,al ; lsb
+ DELAY
+ out TIMER_0_8253,al ; msb
+
+; Store the timing start BIOS count
+
+ use_es
+ifdef flatmodel
+ mov ebx,[_ZTimerBIOSPtr]
+else
+ les bx,[_ZTimerBIOSPtr]
+endif
+ cli ; No interrupts while we grab the count
+ mov eax,[_ES _bx+TIMER_COUNT]
+ sti
+ mov [StartBIOSCount],eax
+ unuse_es
+
+; Set the timer count to 0 again to start the timing interval.
+
+ mov al,00110100b ; set up to load initial
+ out MODE_8253,al ; timer count
+ DELAY
+ sub al,al
+ out TIMER_0_8253,al ; load count lsb
+ DELAY
+ out TIMER_0_8253,al ; load count msb
+
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void LZ_timerOff(void);
+;----------------------------------------------------------------------------
+; Stops the long period Zen timer and saves count.
+;----------------------------------------------------------------------------
+cprocstart LZ_timerOff
+
+; Latch the timer count.
+
+ mov al,00000000b ; latch timer 0
+ out MODE_8253,al
+ cli ; Stop the BIOS count
+
+; Read the BIOS count. (Since interrupts are disabled, the BIOS
+; count won't change).
+
+ use_es
+ifdef flatmodel
+ mov ebx,[_ZTimerBIOSPtr]
+else
+ les bx,[_ZTimerBIOSPtr]
+endif
+ mov eax,[_ES _bx+TIMER_COUNT]
+ mov [EndBIOSCount],eax
+ unuse_es
+
+; Read out the count we latched earlier.
+
+ in al,TIMER_0_8253 ; least significant byte
+ DELAY
+ mov ah,al
+ in al,TIMER_0_8253 ; most significant byte
+ xchg ah,al
+ neg ax ; Convert from countdown remaining
+ ; to elapsed count
+ mov [EndTimedCount],ax
+ sti ; Let the BIOS count continue
+
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; unsigned long LZ_timerLap(void)
+;----------------------------------------------------------------------------
+; Latches the current count and converts it to a microsecond timing value,
+; but leaves the timer still running. We dont check for and overflow,
+; where the time has gone over an hour in this routine, since we want it
+; to execute as fast as possible.
+;----------------------------------------------------------------------------
+cprocstart LZ_timerLap
+
+ push ebx ; Save EBX for 32 bit code
+
+; Latch the timer count.
+
+ mov al,00000000b ; latch timer 0
+ out MODE_8253,al
+ cli ; Stop the BIOS count
+
+; Read the BIOS count. (Since interrupts are disabled, the BIOS
+; count wont change).
+
+ use_es
+ifdef flatmodel
+ mov ebx,[_ZTimerBIOSPtr]
+else
+ les bx,[_ZTimerBIOSPtr]
+endif
+ mov eax,[_ES _bx+TIMER_COUNT]
+ mov [EndBIOSCount],eax
+ unuse_es
+
+; Read out the count we latched earlier.
+
+ in al,TIMER_0_8253 ; least significant byte
+ DELAY
+ mov ah,al
+ in al,TIMER_0_8253 ; most significant byte
+ xchg ah,al
+ neg ax ; Convert from countdown remaining
+ ; to elapsed count
+ mov [EndTimedCount],ax
+ sti ; Let the BIOS count continue
+
+; See if a midnight boundary has passed and adjust the finishing BIOS
+; count by the number of ticks in 24 hours. We wont be able to detect
+; more than 24 hours, but at least we can time across a midnight
+; boundary
+
+ mov eax,[EndBIOSCount] ; Is end < start?
+ cmp eax,[StartBIOSCount]
+ jae @@CalcBIOSTime ; No, calculate the time taken
+
+; Adjust the finishing time by adding the number of ticks in 24 hours
+; (1573040).
+
+ add [DWORD EndBIOSCount],1800B0h
+
+; Convert the BIOS time to microseconds
+
+@@CalcBIOSTime:
+ mov ax,[WORD EndBIOSCount]
+ sub ax,[WORD StartBIOSCount]
+ mov dx,54925 ; Number of microseconds each
+ ; BIOS count represents.
+ mul dx
+ mov bx,ax ; set aside BIOS count in
+ mov cx,dx ; microseconds
+
+; Convert timer count to microseconds
+
+ push _si
+ mov ax,[EndTimedCount]
+ mov si,8381
+ mul si
+ mov si,10000
+ div si ; * 0.8381 = * 8381 / 10000
+ pop _si
+
+; Add the timer and BIOS counts together to get an overall time in
+; microseconds.
+
+ add ax,bx
+ adc cx,0
+ifdef flatmodel
+ shl ecx,16
+ mov cx,ax
+ mov eax,ecx ; EAX := timer count
+else
+ mov dx,cx
+endif
+ pop ebx ; Restore EBX for 32 bit code
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; unsigned long LZ_timerCount(void);
+;----------------------------------------------------------------------------
+; Returns an unsigned long representing the net time in microseconds.
+;
+; If an hour has passed while timing, we return 0xFFFFFFFF as the count
+; (which is not a possible count in itself).
+;----------------------------------------------------------------------------
+cprocstart LZ_timerCount
+
+ push ebx ; Save EBX for 32 bit code
+
+; See if a midnight boundary has passed and adjust the finishing BIOS
+; count by the number of ticks in 24 hours. We wont be able to detect
+; more than 24 hours, but at least we can time across a midnight
+; boundary
+
+ mov eax,[EndBIOSCount] ; Is end < start?
+ cmp eax,[StartBIOSCount]
+ jae @@CheckForHour ; No, check for hour passing
+
+; Adjust the finishing time by adding the number of ticks in 24 hours
+; (1573040).
+
+ add [DWORD EndBIOSCount],1800B0h
+
+; See if more than an hour passed during timing. If so, notify the user.
+
+@@CheckForHour:
+ mov ax,[WORD StartBIOSCount+2]
+ cmp ax,[WORD EndBIOSCount+2]
+ jz @@CalcBIOSTime ; Hour count didn't change, so
+ ; everything is fine
+
+ inc ax
+ cmp ax,[WORD EndBIOSCount+2]
+ jnz @@TestTooLong ; Two hour boundaries passed, so the
+ ; results are no good
+ mov ax,[WORD EndBIOSCount]
+ cmp ax,[WORD StartBIOSCount]
+ jb @@CalcBIOSTime ; a single hour boundary passed. That's
+ ; OK, so long as the total time wasn't
+ ; more than an hour.
+
+; Over an hour elapsed passed during timing, which renders
+; the results invalid. Notify the user. This misses the case where a
+; multiple of 24 hours has passed, but we'll rely on the perspicacity of
+; the user to detect that case :-).
+
+@@TestTooLong:
+ifdef flatmodel
+ mov eax,0FFFFFFFFh
+else
+ mov ax,0FFFFh
+ mov dx,0FFFFh
+endif
+ jmp short @@Done
+
+; Convert the BIOS time to microseconds
+
+@@CalcBIOSTime:
+ mov ax,[WORD EndBIOSCount]
+ sub ax,[WORD StartBIOSCount]
+ mov dx,54925 ; Number of microseconds each
+ ; BIOS count represents.
+ mul dx
+ mov bx,ax ; set aside BIOS count in
+ mov cx,dx ; microseconds
+
+; Convert timer count to microseconds
+
+ push _si
+ mov ax,[EndTimedCount]
+ mov si,8381
+ mul si
+ mov si,10000
+ div si ; * 0.8381 = * 8381 / 10000
+ pop _si
+
+; Add the timer and BIOS counts together to get an overall time in
+; microseconds.
+
+ add ax,bx
+ adc cx,0
+ifdef flatmodel
+ shl ecx,16
+ mov cx,ax
+ mov eax,ecx ; EAX := timer count
+else
+ mov dx,cx
+endif
+
+@@Done: pop ebx ; Restore EBX for 32 bit code
+ ret
+
+cprocend
+
+cprocstart LZ_disable
+ cli
+ ret
+cprocend
+
+cprocstart LZ_enable
+ sti
+ ret
+cprocend
+
+endcodeseg _lztimer
+
+ END
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/_pm.asm b/board/MAI/bios_emulator/scitech/src/pm/dos/_pm.asm
new file mode 100644
index 0000000000..42b5cf3692
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/_pm.asm
@@ -0,0 +1,656 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: IBM PC Real mode and 16/32 bit protected mode
+;*
+;* Description: Low level assembly support for the PM library specific to
+;* MSDOS.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pmdos ; Set up memory model
+
+begdataseg _pmdos
+
+ifndef flatmodel
+
+struc rmregs_s
+ax dw ?
+ax_high dw ?
+bx dw ?
+bx_high dw ?
+cx dw ?
+cx_high dw ?
+dx dw ?
+dx_high dw ?
+si dw ?
+si_high dw ?
+di dw ?
+di_high dw ?
+cflag dw ?
+cflag_high dw ?
+ends rmregs_s
+RMREGS = (rmregs_s PTR es:bx)
+
+struc rmsregs_s
+es dw ?
+cs dw ?
+ss dw ?
+ds dw ?
+ends rmsregs_s
+RMSREGS = (rmsregs_s PTR es:bx)
+
+endif ; !flatmodel
+
+ifdef flatmodel
+ cextern _PM_savedDS,USHORT
+ cextern _PM_VXD_off,UINT
+ cextern _PM_VXD_sel,UINT
+ifdef DOS4GW
+ cextern _PM_haveCauseWay,UINT
+endif
+endif
+intel_id db "GenuineIntel" ; Intel vendor ID
+
+PMHELP_GETPDB EQU 0026h
+PMHELP_FLUSHTLB EQU 0027h
+
+enddataseg _pmdos
+
+P586
+
+begcodeseg _pmdos ; Start of code segment
+
+ifndef flatmodel
+
+;----------------------------------------------------------------------------
+; void PM_callRealMode(unsigned s,unsigned o, RMREGS *regs,
+; RMSREGS *sregs)
+;----------------------------------------------------------------------------
+; Calls a real mode procedure, loading the appropriate registers values
+; from the passed in structures. Only the DS and ES register are loaded
+; from the SREGS structure.
+;----------------------------------------------------------------------------
+cprocstart PM_callRealMode
+
+ ARG s:WORD, o:WORD, regs:DWORD, sregs:DWORD
+
+ LOCAL addr:DWORD, bxVal:WORD, esVal:WORD, flags:WORD = LocalSize
+
+ enter_c
+ push ds
+ push es
+
+ mov ax,[o] ; Build the address to call in 'addr'
+ mov [WORD addr],ax
+ mov ax,[s]
+ mov [WORD addr+2],ax
+
+ les bx,[sregs]
+ mov ax,[RMSREGS.ds]
+ mov ds,ax ; DS := passed in value
+ mov ax,[RMSREGS.es]
+ mov [esVal],ax
+ les bx,[regs]
+ mov ax,[RMREGS.bx]
+ mov [bxVal],ax
+ mov ax,[RMREGS.ax] ; AX := passed in value
+ mov cx,[RMREGS.cx] ; CX := passed in value
+ mov dx,[RMREGS.dx] ; DX := passed in value
+ mov si,[RMREGS.si] ; SI := passed in value
+ mov di,[RMREGS.di] ; DI := passed in value
+ push bp
+ push [esVal]
+ pop es ; ES := passed in value
+ mov bx,[bxVal] ; BX := passed in value
+
+ call [addr] ; Call the specified routine
+
+ pushf ; Save flags for later
+ pop [flags]
+
+ pop bp
+ push es
+ pop [esVal]
+ push bx
+ pop [bxVal]
+ les bx,[sregs]
+ push ds
+ pop [RMSREGS.ds] ; Save value of DS
+ push [esVal]
+ pop [RMSREGS.es] ; Save value of ES
+ les bx,[regs]
+ mov [RMREGS.ax],ax ; Save value of AX
+ mov [RMREGS.cx],cx ; Save value of CX
+ mov [RMREGS.dx],dx ; Save value of DX
+ mov [RMREGS.si],si ; Save value of SI
+ mov [RMREGS.di],di ; Save value of DI
+ mov ax,[flags] ; Return flags
+ and ax,1h ; Isolate carry flag
+ mov [RMREGS.cflag],ax ; Save carry flag status
+ mov ax,[bxVal]
+ mov [RMREGS.bx],ax ; Save value of BX
+
+ pop es
+ pop ds
+ leave_c
+ ret
+
+cprocend
+
+endif
+
+;----------------------------------------------------------------------------
+; void PM_segread(PMSREGS *sregs)
+;----------------------------------------------------------------------------
+; Read the current value of all segment registers
+;----------------------------------------------------------------------------
+cprocstartdll16 PM_segread
+
+ ARG sregs:DPTR
+
+ enter_c
+
+ mov ax,es
+ _les _si,[sregs]
+ mov [_ES _si],ax
+ mov [_ES _si+2],cs
+ mov [_ES _si+4],ss
+ mov [_ES _si+6],ds
+ mov [_ES _si+8],fs
+ mov [_ES _si+10],gs
+
+ leave_c
+ ret
+
+cprocend
+
+; Create a table of the 256 different interrupt calls that we can jump
+; into
+
+ifdef USE_NASM
+
+%assign intno 0
+
+intTable:
+%rep 256
+ db 0CDh
+ db intno
+%assign intno intno + 1
+ ret
+ nop
+%endrep
+
+else
+
+intno = 0
+
+intTable:
+ REPT 256
+ db 0CDh
+ db intno
+intno = intno + 1
+ ret
+ nop
+ ENDM
+
+endif
+
+;----------------------------------------------------------------------------
+; _PM_genInt - Generate the appropriate interrupt
+;----------------------------------------------------------------------------
+cprocnear _PM_genInt
+
+ push _ax ; Save _ax
+ push _bx ; Save _bx
+ifdef flatmodel
+ mov ebx,[UINT esp+12] ; EBX := interrupt number
+else
+ mov bx,sp ; Make sure ESP is zeroed
+ mov bx,[UINT ss:bx+6] ; BX := interrupt number
+endif
+ mov _ax,offset intTable ; Point to interrupt generation table
+ shl _bx,2 ; _BX := index into table
+ add _ax,_bx ; _AX := pointer to interrupt code
+ifdef flatmodel
+ xchg eax,[esp+4] ; Restore eax, and set for int
+else
+ mov bx,sp
+ xchg ax,[ss:bx+2] ; Restore ax, and set for int
+endif
+ pop _bx ; restore _bx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_int386x(int intno, PMREGS *in, PMREGS *out,PMSREGS *sregs)
+;----------------------------------------------------------------------------
+; Issues a software interrupt in protected mode. This routine has been
+; written to allow user programs to load CS and DS with different values
+; other than the default.
+;----------------------------------------------------------------------------
+cprocstartdll16 PM_int386x
+
+ ARG intno:UINT, inptr:DPTR, outptr:DPTR, sregs:DPTR
+
+ LOCAL flags:UINT, sv_ds:UINT, sv_esi:ULONG = LocalSize
+
+ enter_c
+ push ds
+ push es ; Save segment registers
+ push fs
+ push gs
+
+ _lds _si,[sregs] ; DS:_SI -> Load segment registers
+ mov es,[_si]
+ mov bx,[_si+6]
+ mov [sv_ds],_bx ; Save value of user DS on stack
+ mov fs,[_si+8]
+ mov gs,[_si+10]
+
+ _lds _si,[inptr] ; Load CPU registers
+ mov eax,[_si]
+ mov ebx,[_si+4]
+ mov ecx,[_si+8]
+ mov edx,[_si+12]
+ mov edi,[_si+20]
+ mov esi,[_si+16]
+
+ push ds ; Save value of DS
+ push _bp ; Some interrupts trash this!
+ clc ; Generate the interrupt
+ push [UINT intno]
+ mov ds,[WORD sv_ds] ; Set value of user's DS selector
+ call _PM_genInt
+ pop _bp ; Pop intno from stack (flags unchanged)
+ pop _bp ; Restore value of stack frame pointer
+ pop ds ; Restore value of DS
+
+ pushf ; Save flags for later
+ pop [UINT flags]
+ push esi ; Save ESI for later
+ pop [DWORD sv_esi]
+ push ds ; Save DS for later
+ pop [UINT sv_ds]
+
+ _lds _si,[outptr] ; Save CPU registers
+ mov [_si],eax
+ mov [_si+4],ebx
+ mov [_si+8],ecx
+ mov [_si+12],edx
+ push [DWORD sv_esi]
+ pop [DWORD _si+16]
+ mov [_si+20],edi
+
+ mov _bx,[flags] ; Return flags
+ and ebx,1h ; Isolate carry flag
+ mov [_si+24],ebx ; Save carry flag status
+
+ _lds _si,[sregs] ; Save segment registers
+ mov [_si],es
+ mov _bx,[sv_ds]
+ mov [_si+6],bx ; Get returned DS from stack
+ mov [_si+8],fs
+ mov [_si+10],gs
+
+ pop gs ; Restore segment registers
+ pop fs
+ pop es
+ pop ds
+ leave_c
+ ret
+
+cprocend
+
+ifndef flatmodel
+_PM_savedDS dw _DATA ; Saved value of DS
+endif
+
+;----------------------------------------------------------------------------
+; void PM_saveDS(void)
+;----------------------------------------------------------------------------
+; Save the value of DS into a section of the code segment, so that we can
+; quickly load this value at a later date in the PM_loadDS() routine from
+; inside interrupt handlers etc. The method to do this is different
+; depending on the DOS extender being used.
+;----------------------------------------------------------------------------
+cprocstartdll16 PM_saveDS
+
+ifdef flatmodel
+ mov [_PM_savedDS],ds ; Store away in data segment
+endif
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_loadDS(void)
+;----------------------------------------------------------------------------
+; Routine to load the DS register with the default value for the current
+; DOS extender. Only the DS register is loaded, not the ES register, so
+; if you wish to call C code, you will need to also load the ES register
+; in 32 bit protected mode.
+;----------------------------------------------------------------------------
+cprocstartdll16 PM_loadDS
+
+ mov ds,[cs:_PM_savedDS] ; We can access the proper DS through CS
+ ret
+
+cprocend
+
+ifdef flatmodel
+
+;----------------------------------------------------------------------------
+; ibool DPMI_allocateCallback(void (*pmcode)(), void *rmregs, long *RMCB)
+;----------------------------------------------------------------------------
+cprocstart _DPMI_allocateCallback
+
+ ARG pmcode:CPTR, rmregs:DPTR, RMCB:DPTR
+
+ enter_c
+ push ds
+ push es
+
+ push cs
+ pop ds
+ mov esi,[pmcode] ; DS:ESI -> protected mode code to call
+ mov edi,[rmregs] ; ES:EDI -> real mode register buffer
+ mov ax,303h ; AX := allocate realmode callback function
+ int 31h
+ mov eax,0 ; Return failure!
+ jc @@Fail
+
+ mov eax,[RMCB]
+ shl ecx,16
+ mov cx,dx
+ mov [es:eax],ecx ; Return real mode address
+ mov eax,1 ; Return success!
+
+@@Fail: pop es
+ pop ds
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void DPMI_freeCallback(long RMCB)
+;----------------------------------------------------------------------------
+cprocstart _DPMI_freeCallback
+
+ ARG RMCB:ULONG
+
+ enter_c
+
+ mov cx,[WORD RMCB+2]
+ mov dx,[WORD RMCB] ; CX:DX := real mode callback
+ mov ax,304h
+ int 31h
+
+ leave_c
+ ret
+
+cprocend
+
+endif
+
+; Macro to delay briefly to ensure that enough time has elapsed between
+; successive I/O accesses so that the device being accessed can respond
+; to both accesses even on a very fast PC.
+
+ifdef USE_NASM
+%macro DELAY 0
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+%endmacro
+%macro IODELAYN 1
+%rep %1
+ DELAY
+%endrep
+%endmacro
+else
+macro DELAY
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+endm
+macro IODELAYN N
+ rept N
+ DELAY
+ endm
+endm
+endif
+
+;----------------------------------------------------------------------------
+; uchar _PM_readCMOS(int index)
+;----------------------------------------------------------------------------
+; Read the value of a specific CMOS register. We do this with both
+; normal interrupts and NMI disabled.
+;----------------------------------------------------------------------------
+cprocstart _PM_readCMOS
+
+ ARG index:UINT
+
+ push _bp
+ mov _bp,_sp
+ pushfd
+ mov al,[BYTE index]
+ or al,80h ; Add disable NMI flag
+ cli
+ out 70h,al
+ IODELAYN 5
+ in al,71h
+ mov ah,al
+ xor al,al
+ IODELAYN 5
+ out 70h,al ; Re-enable NMI
+ sti
+ mov al,ah ; Return value in AL
+ popfd
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_writeCMOS(int index,uchar value)
+;----------------------------------------------------------------------------
+; Read the value of a specific CMOS register. We do this with both
+; normal interrupts and NMI disabled.
+;----------------------------------------------------------------------------
+cprocstart _PM_writeCMOS
+
+ ARG index:UINT, value:UCHAR
+
+ push _bp
+ mov _bp,_sp
+ pushfd
+ mov al,[BYTE index]
+ or al,80h ; Add disable NMI flag
+ cli
+ out 70h,al
+ IODELAYN 5
+ mov al,[value]
+ out 71h,al
+ xor al,al
+ IODELAYN 5
+ out 70h,al ; Re-enable NMI
+ sti
+ popfd
+ pop _bp
+ ret
+
+cprocend
+
+ifdef flatmodel
+
+;----------------------------------------------------------------------------
+; int _PM_pagingEnabled(void)
+;----------------------------------------------------------------------------
+; Returns 1 if paging is enabled, 0 if not or -1 if not at ring 0
+;----------------------------------------------------------------------------
+cprocstart _PM_pagingEnabled
+
+ mov eax,-1
+ifdef DOS4GW
+ mov cx,cs
+ and ecx,3
+ jz @@Ring0
+ cmp [UINT _PM_haveCauseWay],0
+ jnz @@Ring0
+ jmp @@Exit
+
+@@Ring0:
+ mov eax,cr0 ; Load CR0
+ shr eax,31 ; Isolate paging enabled bit
+endif
+@@Exit: ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; _PM_getPDB - Return the Page Table Directory Base address
+;----------------------------------------------------------------------------
+cprocstart _PM_getPDB
+
+ifdef DOS4GW
+ mov ax,cs
+ and eax,3
+ jz @@Ring0
+ cmp [UINT _PM_haveCauseWay],0
+ jnz @@Ring0
+endif
+
+; Call VxD if running at ring 3 in a DOS box
+
+ cmp [WORD _PM_VXD_sel],0
+ jz @@Fail
+ mov eax,PMHELP_GETPDB
+ifdef USE_NASM
+ call far dword [_PM_VXD_off]
+else
+ call [FCPTR _PM_VXD_off]
+endif
+ ret
+
+@@Ring0:
+ifdef DOS4GW
+ mov eax,cr3
+ and eax,0FFFFF000h
+ ret
+endif
+@@Fail: xor eax,eax
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_flushTLB - Flush the Translation Lookaside buffer
+;----------------------------------------------------------------------------
+cprocstart PM_flushTLB
+
+ mov ax,cs
+ and eax,3
+ jz @@Ring0
+ifdef DOS4GW
+ cmp [UINT _PM_haveCauseWay],0
+ jnz @@Ring0
+endif
+
+; Call VxD if running at ring 3 in a DOS box
+
+ cmp [WORD _PM_VXD_sel],0
+ jz @@Fail
+ mov eax,PMHELP_FLUSHTLB
+ifdef USE_NASM
+ call far dword [_PM_VXD_off]
+else
+ call [FCPTR _PM_VXD_off]
+endif
+ ret
+
+@@Ring0:
+ifdef DOS4GW
+ wbinvd ; Flush the CPU cache
+ mov eax,cr3
+ mov cr3,eax ; Flush the TLB
+endif
+@@Fail: ret
+
+cprocend
+
+endif
+
+;----------------------------------------------------------------------------
+; void _PM_VxDCall(VXD_regs far *r,uint off,uint sel);
+;----------------------------------------------------------------------------
+cprocstart _PM_VxDCall
+
+ ARG r:DPTR, off:UINT, sel:UINT
+
+ enter_c
+
+; Load all registers from the registers structure
+
+ mov ebx,[r]
+ mov eax,[ebx+0]
+ mov ecx,[ebx+8]
+ mov edx,[ebx+12]
+ mov esi,[ebx+16]
+ mov edi,[ebx+20]
+ mov ebx,[ebx+4] ; Trashes BX structure pointer!
+
+; Call the VxD entry point (on stack)
+
+ifdef USE_NASM
+ call far dword [off]
+else
+ call [FCPTR off]
+endif
+
+; Save all registers back in the structure
+
+ push ebx ; Push EBX onto stack for later
+ mov ebx,[r]
+ mov [ebx+0],eax
+ mov [ebx+8],ecx
+ mov [ebx+12],edx
+ mov [ebx+16],esi
+ mov [ebx+20],edi
+ pop [DWORD ebx+4] ; Save value of EBX from stack
+
+ leave_c
+ ret
+
+cprocend
+
+endcodeseg _pmdos
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/_pmdos.asm b/board/MAI/bios_emulator/scitech/src/pm/dos/_pmdos.asm
new file mode 100644
index 0000000000..5c741f346c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/_pmdos.asm
@@ -0,0 +1,1105 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: IBM PC Real mode and 16/32 bit protected mode
+;*
+;* Description: Low level assembly support for the PM library specific to
+;* MSDOS interrupt handling.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pmdos ; Set up memory model
+
+; Define the size of our local stacks. For real mode code they cant be
+; that big, but for 32 bit protected mode code we can make them nice and
+; large so that complex C functions can be used.
+
+ifdef flatmodel
+MOUSE_STACK EQU 4096
+TIMER_STACK EQU 4096
+KEY_STACK EQU 1024
+INT10_STACK EQU 1024
+IRQ_STACK EQU 1024
+else
+MOUSE_STACK EQU 1024
+TIMER_STACK EQU 512
+KEY_STACK EQU 256
+INT10_STACK EQU 256
+IRQ_STACK EQU 256
+endif
+
+ifdef USE_NASM
+
+; Macro to load DS and ES registers with correct value.
+
+%imacro LOAD_DS 0
+%ifdef flatmodel
+ mov ds,[cs:_PM_savedDS]
+ mov es,[cs:_PM_savedDS]
+%else
+ push ax
+ mov ax,_DATA
+ mov ds,ax
+ pop ax
+%endif
+%endmacro
+
+; Note that interrupts we disable interrupts during the following stack
+; %imacro for correct operation, but we do not enable them again. Normally
+; these %imacros are used within interrupt handlers so interrupts should
+; already be off. We turn them back on explicitly later if the user code
+; needs them to be back on.
+
+; Macro to switch to a new local stack.
+
+%imacro NEWSTK 1
+ cli
+ mov [seg_%1],ss
+ mov [ptr_%1],_sp
+ mov [TempSeg],ds
+ mov ss,[TempSeg]
+ mov _sp,offset %1
+%endmacro
+
+; %imacro to switch back to the old stack.
+
+%imacro RESTSTK 1
+ cli
+ mov ss,[seg_%1]
+ mov _sp,[ptr_%1]
+%endmacro
+
+; %imacro to swap the current stack with the one saved away.
+
+%imacro SWAPSTK 1
+ cli
+ mov ax,ss
+ xchg ax,[seg_%1]
+ mov ss,ax
+ xchg _sp,[ptr_%1]
+%endmacro
+
+else
+
+; Macro to load DS and ES registers with correct value.
+
+MACRO LOAD_DS
+ifdef flatmodel
+ mov ds,[cs:_PM_savedDS]
+ mov es,[cs:_PM_savedDS]
+else
+ push ax
+ mov ax,_DATA
+ mov ds,ax
+ pop ax
+endif
+ENDM
+
+; Note that interrupts we disable interrupts during the following stack
+; macro for correct operation, but we do not enable them again. Normally
+; these macros are used within interrupt handlers so interrupts should
+; already be off. We turn them back on explicitly later if the user code
+; needs them to be back on.
+
+; Macro to switch to a new local stack.
+
+MACRO NEWSTK stkname
+ cli
+ mov [seg_&stkname&],ss
+ mov [ptr_&stkname&],_sp
+ mov [TempSeg],ds
+ mov ss,[TempSeg]
+ mov _sp,offset stkname
+ENDM
+
+; Macro to switch back to the old stack.
+
+MACRO RESTSTK stkname
+ cli
+ mov ss,[seg_&stkname&]
+ mov _sp,[ptr_&stkname&]
+ENDM
+
+; Macro to swap the current stack with the one saved away.
+
+MACRO SWAPSTK stkname
+ cli
+ mov ax,ss
+ xchg ax,[seg_&stkname&]
+ mov ss,ax
+ xchg _sp,[ptr_&stkname&]
+ENDM
+
+endif
+
+begdataseg _pmdos
+
+ifdef flatmodel
+ cextern _PM_savedDS,USHORT
+endif
+ cextern _PM_critHandler,CPTR
+ cextern _PM_breakHandler,CPTR
+ cextern _PM_timerHandler,CPTR
+ cextern _PM_rtcHandler,CPTR
+ cextern _PM_keyHandler,CPTR
+ cextern _PM_key15Handler,CPTR
+ cextern _PM_mouseHandler,CPTR
+ cextern _PM_int10Handler,CPTR
+
+ cextern _PM_ctrlCPtr,DPTR
+ cextern _PM_ctrlBPtr,DPTR
+ cextern _PM_critPtr,DPTR
+
+ cextern _PM_prevTimer,FCPTR
+ cextern _PM_prevRTC,FCPTR
+ cextern _PM_prevKey,FCPTR
+ cextern _PM_prevKey15,FCPTR
+ cextern _PM_prevBreak,FCPTR
+ cextern _PM_prevCtrlC,FCPTR
+ cextern _PM_prevCritical,FCPTR
+ cextern _PM_prevRealTimer,ULONG
+ cextern _PM_prevRealRTC,ULONG
+ cextern _PM_prevRealKey,ULONG
+ cextern _PM_prevRealKey15,ULONG
+ cextern _PM_prevRealInt10,ULONG
+
+cpublic _PM_pmdosDataStart
+
+; Allocate space for all of the local stacks that we need. These stacks
+; are not very large, but should be large enough for most purposes
+; (generally you want to handle these interrupts quickly, simply storing
+; the information for later and then returning). If you need bigger
+; stacks then change the appropriate value in here.
+
+ ALIGN 4
+ dclb MOUSE_STACK ; Space for local stack (small)
+MsStack: ; Stack starts at end!
+ptr_MsStack DUINT 0 ; Place to store old stack offset
+seg_MsStack dw 0 ; Place to store old stack segment
+
+ ALIGN 4
+ dclb INT10_STACK ; Space for local stack (small)
+Int10Stack: ; Stack starts at end!
+ptr_Int10Stack DUINT 0 ; Place to store old stack offset
+seg_Int10Stack dw 0 ; Place to store old stack segment
+
+ ALIGN 4
+ dclb TIMER_STACK ; Space for local stack (small)
+TmStack: ; Stack starts at end!
+ptr_TmStack DUINT 0 ; Place to store old stack offset
+seg_TmStack dw 0 ; Place to store old stack segment
+
+ ALIGN 4
+ dclb TIMER_STACK ; Space for local stack (small)
+RtcStack: ; Stack starts at end!
+ptr_RtcStack DUINT 0 ; Place to store old stack offset
+seg_RtcStack dw 0 ; Place to store old stack segment
+RtcInside dw 0 ; Are we still handling current interrupt
+
+ ALIGN 4
+ dclb KEY_STACK ; Space for local stack (small)
+KyStack: ; Stack starts at end!
+ptr_KyStack DUINT 0 ; Place to store old stack offset
+seg_KyStack dw 0 ; Place to store old stack segment
+KyInside dw 0 ; Are we still handling current interrupt
+
+ ALIGN 4
+ dclb KEY_STACK ; Space for local stack (small)
+Ky15Stack: ; Stack starts at end!
+ptr_Ky15Stack DUINT 0 ; Place to store old stack offset
+seg_Ky15Stack dw 0 ; Place to store old stack segment
+
+TempSeg dw 0 ; Place to store stack segment
+
+cpublic _PM_pmdosDataEnd
+
+enddataseg _pmdos
+
+begcodeseg _pmdos ; Start of code segment
+
+cpublic _PM_pmdosCodeStart
+
+;----------------------------------------------------------------------------
+; PM_mouseISR - Mouse interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Interrupt subroutine called by the mouse driver upon interrupts, to
+; dispatch control to high level C based subroutines. Interrupts are on
+; when we call the user code.
+;
+; It is _extremely_ important to save the state of the extended registers
+; as these may well be trashed by the routines called from here and not
+; restored correctly by the mouse interface module.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. For mouse handlers this is not a
+; problem, as the mouse driver arbitrates calls to the user mouse
+; handler for us.
+;
+; Entry: AX - Condition mask giving reason for call
+; BX - Mouse button state
+; CX - Horizontal cursor coordinate
+; DX - Vertical cursor coordinate
+; SI - Horizontal mickey value
+; DI - Vertical mickey value
+;
+;----------------------------------------------------------------------------
+ifdef DJGPP
+cprocstart _PM_mouseISR
+else
+cprocfar _PM_mouseISR
+endif
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+ NEWSTK MsStack ; Switch to local stack
+
+; Call the installed high level C code routine
+
+ clrhi dx ; Clear out high order values
+ clrhi cx
+ clrhi bx
+ clrhi ax
+ sgnhi si
+ sgnhi di
+
+ push _di
+ push _si
+ push _dx
+ push _cx
+ push _bx
+ push _ax
+ sti ; Enable interrupts
+ call [CPTR _PM_mouseHandler]
+ _add sp,12,24
+
+ RESTSTK MsStack ; Restore previous stack
+
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ ret ; We are done!!
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_timerISR - Timer interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the timer interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. Make sure your C code executes as
+; quickly as possible, since a timer overrun will simply hang the
+; system.
+;----------------------------------------------------------------------------
+cprocfar _PM_timerISR
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+
+ NEWSTK TmStack ; Switch to local stack
+ call [CPTR _PM_timerHandler]
+ RESTSTK TmStack ; Restore previous stack
+
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_chainPrevTimer - Chain to previous timer interrupt and return
+;----------------------------------------------------------------------------
+; Chains to the previous timer interrupt routine and returns control
+; back to the high level interrupt handler.
+;----------------------------------------------------------------------------
+cprocstart PM_chainPrevTimer
+
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealTimer]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+ ret
+else
+ SWAPSTK TmStack ; Swap back to previous stack
+ pushf ; Save state of interrupt flag
+ pushf ; Push flags on stack to simulate interrupt
+ifdef USE_NASM
+ call far dword [_PM_prevTimer]
+else
+ call [_PM_prevTimer]
+endif
+ popf ; Restore state of interrupt flag
+ SWAPSTK TmStack ; Swap back to C stack again
+ ret
+endif
+
+cprocend
+
+; Macro to delay briefly to ensure that enough time has elapsed between
+; successive I/O accesses so that the device being accessed can respond
+; to both accesses even on a very fast PC.
+
+ifdef USE_NASM
+%macro DELAY 0
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+%endmacro
+%macro IODELAYN 1
+%rep %1
+ DELAY
+%endrep
+%endmacro
+else
+macro DELAY
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+endm
+macro IODELAYN N
+ rept N
+ DELAY
+ endm
+endm
+endif
+
+;----------------------------------------------------------------------------
+; PM_rtcISR - Real time clock interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the timer interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. Make sure your C code executes as
+; quickly as possible, since a timer overrun will simply hang the
+; system.
+;----------------------------------------------------------------------------
+cprocfar _PM_rtcISR
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+; Clear priority interrupt controller and re-enable interrupts so we
+; dont lock things up for long.
+
+ mov al,20h
+ out 0A0h,al
+ out 020h,al
+
+; Clear real-time clock timeout
+
+ in al,70h ; Read CMOS index register
+ push _ax ; and save for later
+ IODELAYN 3
+ mov al,0Ch
+ out 70h,al
+ IODELAYN 5
+ in al,71h
+
+; Call the C interrupt handler function
+
+ LOAD_DS ; Load DS register
+ cmp [BYTE RtcInside],1 ; Check for mutual exclusion
+ je @@Exit
+ mov [BYTE RtcInside],1
+ NEWSTK RtcStack ; Switch to local stack
+ sti ; Re-enable interrupts
+ call [CPTR _PM_rtcHandler]
+ RESTSTK RtcStack ; Restore previous stack
+ mov [BYTE RtcInside],0
+
+@@Exit: pop _ax
+ out 70h,al ; Restore CMOS index register
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+ifdef flatmodel
+;----------------------------------------------------------------------------
+; PM_irqISRTemplate - Hardware interrupt handler IRQ template
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for any interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. Make sure your C code executes as
+; quickly as possible.
+;----------------------------------------------------------------------------
+cprocfar _PM_irqISRTemplate
+
+ push ebx
+ mov ebx,0 ; Relocation adjustment factor
+ jmp __IRQEntry
+
+; Global variables stored in the IRQ thunk code segment
+
+_CHandler dd 0 ; Pointer to C interrupt handler
+_PrevIRQ dd 0 ; Previous IRQ handler
+ dd 0
+_IRQ dd 0 ; IRQ we are hooked for
+ptr_IRQStack DUINT 0 ; Place to store old stack offset
+seg_IRQStack dw 0 ; Place to store old stack segment
+_Inside db 0 ; Mutual exclusion flag
+ ALIGN 4
+ dclb IRQ_STACK ; Space for local stack
+_IRQStack: ; Stack starts at end!
+
+; Check for and reject spurious IRQ 7 signals
+
+__IRQEntry:
+ cmp [BYTE cs:ebx+_IRQ],7 ; Spurious IRQs occur only on IRQ 7
+ jmp @@ValidIRQ
+ push eax
+ mov al,1011b ; OCW3: read ISR
+ out 20h,al ; (Intel Peripheral Components, 1991,
+ in al,20h ; p. 3-188)
+ shl al,1 ; Set C = bit 7 (IRQ 7) of ISR register
+ pop eax
+ jc @@ValidIRQ
+ iret ; Return from interrupt
+
+; Save all registers for duration of IRQ handler
+
+@@ValidIRQ:
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+ LOAD_DS ; Load DS register
+
+; Send an EOI to the PIC
+
+ mov al,20h ; Send EOI to PIC
+ cmp [BYTE ebx+_IRQ],8 ; Clear PIC1 first if IRQ >= 8
+ jb @@1
+ out 0A0h,al
+@@1: out 20h,al
+
+; Check for mutual exclusion
+
+ cmp [BYTE ebx+_Inside],1
+ je @@ChainOldHandler
+ mov [BYTE ebx+_Inside],1
+
+; Call the C interrupt handler function
+
+ mov [ebx+seg_IRQStack],ss ; Switch to local stack
+ mov [ebx+ptr_IRQStack],esp
+ mov [TempSeg],ds
+ mov ss,[TempSeg]
+ lea esp,[ebx+_IRQStack]
+ sti ; Re-enable interrupts
+ push ebx
+ call [DWORD ebx+_CHandler]
+ pop ebx
+ cli
+ mov ss,[ebx+seg_IRQStack] ; Restore previous stack
+ mov esp,[ebx+ptr_IRQStack]
+ or eax,eax
+ jz @@ChainOldHandler ; Chain if not handled for shared IRQ
+
+@@Exit: mov [BYTE ebx+_Inside],0
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ pop ebx
+ iret ; Return from interrupt
+
+@@ChainOldHandler:
+ cmp [DWORD ebx+_PrevIRQ],0
+ jz @@Exit
+ mov [BYTE ebx+_Inside],0
+ mov eax,[DWORD ebx+_PrevIRQ]
+ mov ebx,[DWORD ebx+_PrevIRQ+4]
+ mov [DWORD _PrevIRQ],eax
+ mov [DWORD _PrevIRQ+4],ebx
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ pop ebx
+ jmp [cs:_PrevIRQ] ; Chain to previous IRQ handler
+
+cprocend
+cpublic _PM_irqISRTemplateEnd
+endif
+
+;----------------------------------------------------------------------------
+; PM_keyISR - keyboard interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the keyboard interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. However we ensure within this routine
+; mutual exclusion to the keyboard handling routine.
+;----------------------------------------------------------------------------
+cprocfar _PM_keyISR
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+
+ cmp [BYTE KyInside],1 ; Check for mutual exclusion
+ je @@Reissued
+
+ mov [BYTE KyInside],1
+ NEWSTK KyStack ; Switch to local stack
+ call [CPTR _PM_keyHandler] ; Call C code
+ RESTSTK KyStack ; Restore previous stack
+ mov [BYTE KyInside],0
+
+@@Exit: popad ; Restore all extended registers
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+; When the BIOS keyboard handler needs to change the SHIFT status lights
+; on the keyboard, in the process of doing this the keyboard controller
+; re-issues another interrupt, while the current handler is still executing.
+; If we recieve another interrupt while still handling the current one,
+; then simply chain directly to the previous handler.
+;
+; Note that for most DOS extenders, the real mode interrupt handler that we
+; install takes care of this for us.
+
+@@Reissued:
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealKey]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+else
+ pushf
+ifdef USE_NASM
+ call far dword [_PM_prevKey]
+else
+ call [_PM_prevKey]
+endif
+endif
+ jmp @@Exit
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_chainPrevkey - Chain to previous key interrupt and return
+;----------------------------------------------------------------------------
+; Chains to the previous key interrupt routine and returns control
+; back to the high level interrupt handler.
+;----------------------------------------------------------------------------
+cprocstart PM_chainPrevKey
+
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealKey]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+ ret
+else
+
+; YIKES! For some strange reason, when execution returns from the
+; previous keyboard handler, interrupts are re-enabled!! Since we expect
+; interrupts to remain off during the duration of our handler, this can
+; cause havoc. However our stack macros always turn off interrupts, so they
+; will be off when we exit this routine. Obviously there is a tiny weeny
+; window when interrupts will be enabled, but there is nothing we can
+; do about this.
+
+ SWAPSTK KyStack ; Swap back to previous stack
+ pushf ; Push flags on stack to simulate interrupt
+ifdef USE_NASM
+ call far dword [_PM_prevKey]
+else
+ call [_PM_prevKey]
+endif
+ SWAPSTK KyStack ; Swap back to C stack again
+ ret
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_key15ISR - Int 15h keyboard interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; This routine gets called if we have been called to handle the Int 15h
+; keyboard interrupt callout from real mode.
+;
+; Entry: AX - Hardware scan code to process
+; Exit: AX - Hardware scan code to process (0 to ignore)
+;----------------------------------------------------------------------------
+cprocfar _PM_key15ISR
+
+ push ds
+ push es
+ LOAD_DS
+ cmp ah,4Fh
+ jnz @@NotOurs ; Quit if not keyboard callout
+
+ pushad
+ cld ; Clear direction flag
+ xor ah,ah ; AX := scan code
+ NEWSTK Ky15Stack ; Switch to local stack
+ push _ax
+ call [CPTR _PM_key15Handler] ; Call C code
+ _add sp,2,4
+ RESTSTK Ky15Stack ; Restore previous stack
+ test ax,ax
+ jz @@1
+ stc ; Set carry to process as normal
+ jmp @@2
+@@1: clc ; Clear carry to ignore scan code
+@@2: popad
+ jmp @@Exit ; We are done
+
+@@NotOurs:
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealKey15]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+else
+ pushf
+ifdef USE_NASM
+ call far dword [_PM_prevKey15]
+else
+ call [_PM_prevKey15]
+endif
+endif
+@@Exit: pop es
+ pop ds
+ifdef flatmodel
+ retf 4
+else
+ retf 2
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_breakISR - Control Break interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the Ctrl-Break interrupt. We simply set
+; the Ctrl-Break flag to a 1 and leave (note that this is accessed through
+; a far pointer, as it may well be located in conventional memory).
+;----------------------------------------------------------------------------
+cprocfar _PM_breakISR
+
+ sti
+ push ds ; Save value of DS
+ push es
+ push _bx
+
+ LOAD_DS ; Load DS register
+ifdef flatmodel
+ mov ebx,[_PM_ctrlBPtr]
+else
+ les bx,[_PM_ctrlBPtr]
+endif
+ mov [UINT _ES _bx],1
+
+; Run alternate break handler code if installed
+
+ cmp [CPTR _PM_breakHandler],0
+ je @@Exit
+
+ pushad
+ mov _ax,1
+ push _ax
+ call [CPTR _PM_breakHandler] ; Call C code
+ pop _ax
+ popad
+
+@@Exit: pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_ctrlBreakHit(int clearFlag)
+;----------------------------------------------------------------------------
+; Returns the current state of the Ctrl-Break flag and possibly clears it.
+;----------------------------------------------------------------------------
+cprocstart PM_ctrlBreakHit
+
+ ARG clearFlag:UINT
+
+ enter_c
+ pushf ; Save interrupt status
+ push es
+ifdef flatmodel
+ mov ebx,[_PM_ctrlBPtr]
+else
+ les bx,[_PM_ctrlBPtr]
+endif
+ cli ; No interrupts thanks!
+ mov _ax,[_ES _bx]
+ test [BYTE clearFlag],1
+ jz @@Done
+ mov [UINT _ES _bx],0
+
+@@Done: pop es
+ popf ; Restore interrupt status
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_ctrlCISR - Control Break interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the Ctrl-C interrupt. We simply set
+; the Ctrl-C flag to a 1 and leave (note that this is accessed through
+; a far pointer, as it may well be located in conventional memory).
+;----------------------------------------------------------------------------
+cprocfar _PM_ctrlCISR
+
+ sti
+ push ds ; Save value of DS
+ push es
+ push _bx
+
+ LOAD_DS ; Load DS register
+ifdef flatmodel
+ mov ebx,[_PM_ctrlCPtr]
+else
+ les bx,[_PM_ctrlCPtr]
+endif
+ mov [UINT _ES _bx],1
+
+; Run alternate break handler code if installed
+
+ cmp [CPTR _PM_breakHandler],0
+ je @@Exit
+
+ pushad
+ mov _ax,0
+ push _ax
+ call [CPTR _PM_breakHandler] ; Call C code
+ pop _ax
+ popad
+
+@@Exit: pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+ iretd
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_ctrlCHit(int clearFlag)
+;----------------------------------------------------------------------------
+; Returns the current state of the Ctrl-C flag and possibly clears it.
+;----------------------------------------------------------------------------
+cprocstart PM_ctrlCHit
+
+ ARG clearFlag:UINT
+
+ enter_c
+ pushf ; Save interrupt status
+ push es
+ifdef flatmodel
+ mov ebx,[_PM_ctrlCPtr]
+else
+ les bx,[_PM_ctrlCPtr]
+endif
+ cli ; No interrupts thanks!
+ mov _ax,[_ES _bx]
+ test [BYTE clearFlag],1
+ jz @@Done
+ mov [UINT _ES _bx],0
+
+@@Done:
+ pop es
+ popf ; Restore interrupt status
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_criticalISR - Control Error handler interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Interrupt handler for the MSDOS Critical Error interrupt, to dispatch
+; control to high level C based subroutines. We save the state of all
+; registers in this routine, and switch to a local stack. We also pass
+; the values of the AX and DI registers to the as pointers, so that the
+; values can be modified before returning to MSDOS.
+;----------------------------------------------------------------------------
+cprocfar _PM_criticalISR
+
+ sti
+ push ds ; Save value of DS
+ push es
+ push _bx ; Save register values changed
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+ifdef flatmodel
+ mov ebx,[_PM_critPtr]
+else
+ les bx,[_PM_critPtr]
+endif
+ mov [_ES _bx],ax
+ mov [_ES _bx+2],di
+
+; Run alternate critical handler code if installed
+
+ cmp [CPTR _PM_critHandler],0
+ je @@NoAltHandler
+
+ pushad
+ push _di
+ push _ax
+ call [CPTR _PM_critHandler] ; Call C code
+ _add sp,4,8
+ popad
+
+ pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+@@NoAltHandler:
+ mov ax,3 ; Tell MSDOS to fail the operation
+ pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_criticalError(int *axVal,int *diVal,int clearFlag)
+;----------------------------------------------------------------------------
+; Returns the current state of the critical error flags, and the values that
+; MSDOS passed in the AX and DI registers to our handler.
+;----------------------------------------------------------------------------
+cprocstart PM_criticalError
+
+ ARG axVal:DPTR, diVal:DPTR, clearFlag:UINT
+
+ enter_c
+ pushf ; Save interrupt status
+ push es
+ifdef flatmodel
+ mov ebx,[_PM_critPtr]
+else
+ les bx,[_PM_critPtr]
+endif
+ cli ; No interrupts thanks!
+ xor _ax,_ax
+ xor _di,_di
+ mov ax,[_ES _bx]
+ mov di,[_ES _bx+2]
+ test [BYTE clearFlag],1
+ jz @@NoClear
+ mov [ULONG _ES _bx],0
+@@NoClear:
+ _les _bx,[axVal]
+ mov [_ES _bx],_ax
+ _les _bx,[diVal]
+ mov [_ES _bx],_di
+ pop es
+ popf ; Restore interrupt status
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setMouseHandler(int mask, PM_mouseHandler mh)
+;----------------------------------------------------------------------------
+cprocstart _PM_setMouseHandler
+
+ ARG mouseMask:UINT
+
+ enter_c
+ push es
+
+ mov ax,0Ch ; AX := Function 12 - install interrupt sub
+ mov _cx,[mouseMask] ; CX := mouse mask
+ mov _dx,offset _PM_mouseISR
+ push cs
+ pop es ; ES:_DX -> mouse handler
+ int 33h ; Call mouse driver
+
+ pop es
+ leave_c
+ ret
+
+cprocend
+
+ifdef flatmodel
+
+;----------------------------------------------------------------------------
+; void PM_mousePMCB(void)
+;----------------------------------------------------------------------------
+; Mouse realmode callback routine. Upon entry to this routine, we recieve
+; the following from the DPMI server:
+;
+; Entry: DS:_SI -> Real mode stack at time of call
+; ES:_DI -> Real mode register data structure
+; SS:_SP -> Locked protected mode stack to use
+;----------------------------------------------------------------------------
+cprocfar _PM_mousePMCB
+
+ pushad
+ mov eax,[es:_di+1Ch] ; Load register values from real mode
+ mov ebx,[es:_di+10h]
+ mov ecx,[es:_di+18h]
+ mov edx,[es:_di+14h]
+ mov esi,[es:_di+04h]
+ mov edi,[es:_di]
+ call _PM_mouseISR ; Call the mouse handler
+ popad
+
+ mov ax,[ds:_si]
+ mov [es:_di+2Ah],ax ; Plug in return IP address
+ mov ax,[ds:_si+2]
+ mov [es:_di+2Ch],ax ; Plug in return CS value
+ add [WORD es:_di+2Eh],4 ; Remove return address from stack
+ iret ; Go back to real mode!
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_int10PMCB(void)
+;----------------------------------------------------------------------------
+; int10 realmode callback routine. Upon entry to this routine, we recieve
+; the following from the DPMI server:
+;
+; Entry: DS:ESI -> Real mode stack at time of call
+; ES:EDI -> Real mode register data structure
+; SS:ESP -> Locked protected mode stack to use
+;----------------------------------------------------------------------------
+cprocfar _PM_int10PMCB
+
+ pushad
+ push ds
+ push es
+ push fs
+
+ pushfd
+ pop eax
+ mov [es:edi+20h],ax ; Save return flag status
+ mov ax,[ds:esi]
+ mov [es:edi+2Ah],ax ; Plug in return IP address
+ mov ax,[ds:esi+2]
+ mov [es:edi+2Ch],ax ; Plug in return CS value
+ add [WORD es:edi+2Eh],4 ; Remove return address from stack
+
+; Call the install int10 handler in protected mode. This function gets called
+; with DS set to the current data selector, and ES:EDI pointing the the
+; real mode DPMI register structure at the time of the interrupt. The
+; handle must be written in assembler to be able to extract the real mode
+; register values from the structure
+
+ push es
+ pop fs ; FS:EDI -> real mode registers
+ LOAD_DS
+ NEWSTK Int10Stack ; Switch to local stack
+
+ call [_PM_int10Handler]
+
+ RESTSTK Int10Stack ; Restore previous stack
+ pop fs
+ pop es
+ pop ds
+ popad
+ iret ; Go back to real mode!
+
+cprocend
+
+endif
+
+cpublic _PM_pmdosCodeEnd
+
+endcodeseg _pmdos
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/_vflat.asm b/board/MAI/bios_emulator/scitech/src/pm/dos/_vflat.asm
new file mode 100644
index 0000000000..34985a9d8b
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/_vflat.asm
@@ -0,0 +1,652 @@
+;****************************************************************************
+;*
+;* 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.
+;*
+;* ========================================================================
+;*
+;* Based on original code Copyright 1994 Otto Chrons
+;*
+;* Language: 80386 Assembler, TASM 4.0 or later
+;* Environment: IBM PC 32 bit protected mode
+;*
+;* Description: Low level page fault handler for virtual linear framebuffers.
+;*
+;****************************************************************************
+
+ IDEAL
+ JUMPS
+
+include "scitech.mac" ; Memory model macros
+
+header _vflat ; Set up memory model
+
+VFLAT_START EQU 0F0000000h
+VFLAT_END EQU 0F03FFFFFh
+PAGE_PRESENT EQU 1
+PAGE_NOTPRESENT EQU 0
+PAGE_READ EQU 0
+PAGE_WRITE EQU 2
+
+ifdef DOS4GW
+
+;----------------------------------------------------------------------------
+; DOS4G/W flat linear framebuffer emulation.
+;----------------------------------------------------------------------------
+
+begdataseg _vflat
+
+; Near pointers to the page directory base and our page tables. All of
+; this memory is always located in the first Mb of DOS memory.
+
+PDBR dd 0 ; Page directory base register (CR3)
+accessPageAddr dd 0
+accessPageTable dd 0
+
+; CauseWay page directory & 1st page table linear addresses.
+
+CauseWayDIRLinear dd 0
+CauseWay1stLinear dd 0
+
+; Place to store a copy of the original Page Table Directory before we
+; intialised our virtual buffer code.
+
+pageDirectory: resd 1024 ; Saved page table directory
+
+ValidCS dw 0 ; Valid CS for page faults
+Ring0CS dw 0 ; Our ring 0 code selector
+LastPage dd 0 ; Last page we mapped in
+BankFuncBuf: resb 101 ; Place to store bank switch code
+BankFuncPtr dd offset BankFuncBuf
+
+INT14Gate:
+INT14Offset dd 0 ; eip of original vector
+INT14Selector dw 0 ; cs of original vector
+
+ cextern _PM_savedDS,USHORT
+ cextern VF_haveCauseWay,BOOL
+
+enddataseg _vflat
+
+begcodeseg _vflat ; Start of code segment
+
+ cextern VF_malloc,FPTR
+
+;----------------------------------------------------------------------------
+; PF_handler64k - Page fault handler for 64k banks
+;----------------------------------------------------------------------------
+; The handler below is a 32 bit ring 0 page fault handler. It receives
+; control immediately after any page fault or after an IRQ6 (hardware
+; interrupt). This provides the fastest possible handling of page faults
+; since it jump directly here. If this is a page fault, the number
+; immediately on the stack will be an error code, at offset 4 will be
+; the eip of the faulting instruction, at offset 8 will be the cs of the
+; faulting instruction. If it is a hardware interrupt, it will not have
+; the error code and the eflags will be at offset 8.
+;----------------------------------------------------------------------------
+cprocfar PF_handler64k
+
+; Check if this is a processor exeception or a page fault
+
+ push eax
+ mov ax,[cs:ValidCS] ; Use CS override to access data
+ cmp [ss:esp+12],ax ; Is this a page fault?
+ jne @@ToOldHandler ; Nope, jump to the previous handler
+
+; Get address of page fault and check if within our handlers range
+
+ mov eax,cr2 ; EBX has page fault linear address
+ cmp eax,VFLAT_START ; Is the fault less than ours?
+ jb @@ToOldHandler ; Yep, go to previous handler
+ cmp eax,VFLAT_END ; Is the fault more than ours?
+ jae @@ToOldHandler ; Yep, go to previous handler
+
+; This is our page fault, so we need to handle it
+
+ pushad
+ push ds
+ push es
+ mov ebx,eax ; EBX := page fault address
+ and ebx,invert 0FFFFh ; Mask to 64k bank boundary
+ mov ds,[cs:_PM_savedDS]; Load segment registers
+ mov es,[cs:_PM_savedDS]
+
+; Map in the page table for our virtual framebuffer area for modification
+
+ mov edi,[PDBR] ; EDI points to page directory
+ mov edx,ebx ; EDX = linear address
+ shr edx,22 ; EDX = offset to page directory
+ mov edx,[edx*4+edi] ; EDX = physical page table address
+ mov eax,edx
+ mov edx,[accessPageTable]
+ or eax,7
+ mov [edx],eax
+ mov eax,cr3
+ mov cr3,eax ; Update page table cache
+
+; Mark all pages valid for the new page fault area
+
+ mov esi,ebx ; ESI := linear address for page
+ shr esi,10
+ and esi,0FFFh ; Offset into page table
+ add esi,[accessPageAddr]
+ifdef USE_NASM
+%assign off 0
+%rep 16
+ or [DWORD esi+off],0000000001h ; Enable pages
+%assign off off+4
+%endrep
+else
+off = 0
+REPT 16
+ or [DWORD esi+off],0000000001h ; Enable pages
+off = off+4
+ENDM
+endif
+
+; Mark all pages invalid for the previously mapped area
+
+ xchg esi,[LastPage] ; Save last page for next page fault
+ test esi,esi
+ jz @@DoneMapping ; Dont update if first time round
+ifdef USE_NASM
+%assign off 0
+%rep 16
+ or [DWORD esi+off],0FFFFFFFEh ; Disable pages
+%assign off off+4
+%endrep
+else
+off = 0
+REPT 16
+ and [DWORD esi+off],0FFFFFFFEh ; Disable pages
+off = off+4
+ENDM
+endif
+
+@@DoneMapping:
+ mov eax,cr3
+ mov cr3,eax ; Flush the TLB
+
+; Now program the new SuperVGA starting bank address
+
+ mov eax,ebx ; EAX := page fault address
+ shr eax,16
+ and eax,0FFh ; Mask to 0-255
+ call [BankFuncPtr] ; Call the bank switch function
+
+ pop es
+ pop ds
+ popad
+ pop eax
+ add esp,4 ; Pop the error code from stack
+ iretd ; Return to faulting instruction
+
+@@ToOldHandler:
+ pop eax
+ifdef USE_NASM
+ jmp far dword [cs:INT14Gate]; Chain to previous handler
+else
+ jmp [FWORD cs:INT14Gate]; Chain to previous handler
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PF_handler4k - Page fault handler for 4k banks
+;----------------------------------------------------------------------------
+; The handler below is a 32 bit ring 0 page fault handler. It receives
+; control immediately after any page fault or after an IRQ6 (hardware
+; interrupt). This provides the fastest possible handling of page faults
+; since it jump directly here. If this is a page fault, the number
+; immediately on the stack will be an error code, at offset 4 will be
+; the eip of the faulting instruction, at offset 8 will be the cs of the
+; faulting instruction. If it is a hardware interrupt, it will not have
+; the error code and the eflags will be at offset 8.
+;----------------------------------------------------------------------------
+cprocfar PF_handler4k
+
+; Fill in when we have tested all the 64Kb code
+
+ifdef USE_NASM
+ jmp far dword [cs:INT14Gate]; Chain to previous handler
+else
+ jmp [FWORD cs:INT14Gate]; Chain to previous handler
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void InstallFaultHandler(void *baseAddr,int bankSize)
+;----------------------------------------------------------------------------
+; Installes the page fault handler directly int the interrupt descriptor
+; table for maximum performance. This of course requires ring 0 access,
+; but none of this stuff will run without ring 0!
+;----------------------------------------------------------------------------
+cprocstart InstallFaultHandler
+
+ ARG baseAddr:ULONG, bankSize:UINT
+
+ enter_c
+
+ mov [DWORD LastPage],0 ; No pages have been mapped
+ mov ax,cs
+ mov [ValidCS],ax ; Save CS value for page faults
+
+; Put address of our page fault handler into the IDT directly
+
+ sub esp,6 ; Allocate space on stack
+ifdef USE_NASM
+ sidt [ss:esp] ; Store pointer to IDT
+else
+ sidt [FWORD ss:esp] ; Store pointer to IDT
+endif
+ pop ax ; add esp,2
+ pop eax ; Absolute address of IDT
+ add eax,14*8 ; Point to Int #14
+
+; Note that Interrupt gates do not have the high and low word of the
+; offset in adjacent words in memory, there are 4 bytes separating them.
+
+ mov ecx,[eax] ; Get cs and low 16 bits of offset
+ mov edx,[eax+6] ; Get high 16 bits of offset in dx
+ shl edx,16
+ mov dx,cx ; edx has offset
+ mov [INT14Offset],edx ; Save offset
+ shr ecx,16
+ mov [INT14Selector],cx ; Save original cs
+ mov [eax+2],cs ; Install new cs
+ mov edx,offset PF_handler64k
+ cmp [UINT bankSize],4
+ jne @@1
+ mov edx,offset PF_handler4k
+@@1: mov [eax],dx ; Install low word of offset
+ shr edx,16
+ mov [eax+6],dx ; Install high word of offset
+
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void RemoveFaultHandler(void)
+;----------------------------------------------------------------------------
+; Closes down the virtual framebuffer services and restores the previous
+; page fault handler.
+;----------------------------------------------------------------------------
+cprocstart RemoveFaultHandler
+
+ enter_c
+
+; Remove page fault handler from IDT
+
+ sub esp,6 ; Allocate space on stack
+ifdef USE_NASM
+ sidt [ss:esp] ; Store pointer to IDT
+else
+ sidt [FWORD ss:esp] ; Store pointer to IDT
+endif
+
+ pop ax ; add esp,2
+ pop eax ; Absolute address of IDT
+ add eax,14*8 ; Point to Int #14
+ mov cx,[INT14Selector]
+ mov [eax+2],cx ; Restore original CS
+ mov edx,[INT14Offset]
+ mov [eax],dx ; Install low word of offset
+ shr edx,16
+ mov [eax+6],dx ; Install high word of offset
+
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void InstallBankFunc(int codeLen,void *bankFunc)
+;----------------------------------------------------------------------------
+; Installs the bank switch function by relocating it into our data segment
+; and making it into a callable function. We do it this way to make the
+; code identical to the way that the VflatD devices work under Windows.
+;----------------------------------------------------------------------------
+cprocstart InstallBankFunc
+
+ ARG codeLen:UINT, bankFunc:DPTR
+
+ enter_c
+
+ mov esi,[bankFunc] ; Copy the code into buffer
+ mov edi,offset BankFuncBuf
+ mov ecx,[codeLen]
+ rep movsb
+ mov [BYTE edi],0C3h ; Terminate the function with a near ret
+
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int InitPaging(void)
+;----------------------------------------------------------------------------
+; Initializes paging system. If paging is not enabled, builds a page table
+; directory and page tables for physical memory
+;
+; Exit: 0 - Successful
+; -1 - Couldn't initialize paging mechanism
+;----------------------------------------------------------------------------
+cprocstart InitPaging
+
+ push ebx
+ push ecx
+ push edx
+ push esi
+ push edi
+
+; Are we running under CauseWay?
+
+ mov ax,0FFF9h
+ int 31h
+ jc @@NotCauseway
+ cmp ecx,"CAUS"
+ jnz @@NotCauseway
+ cmp edx,"EWAY"
+ jnz @@NotCauseway
+
+ mov [BOOL VF_haveCauseWay],1
+ mov [CauseWayDIRLinear],esi
+ mov [CauseWay1stLinear],edi
+
+; Check for DPMI
+
+ mov ax,0ff00h
+ push es
+ int 31h
+ pop es
+ shr edi,2
+ and edi,3
+ cmp edi,2
+ jz @@ErrExit ; Not supported under DPMI
+
+ mov eax,[CauseWayDIRLinear]
+ jmp @@CopyCR3
+
+@@NotCauseway:
+ mov ax,cs
+ test ax,3 ; Which ring are we running
+ jnz @@ErrExit ; Needs zero ring to access
+ ; page tables (CR3)
+ mov eax,cr0 ; Load CR0
+ test eax,80000000h ; Is paging enabled?
+ jz @@ErrExit ; No, we must have paging!
+
+ mov eax,cr3 ; Load directory address
+ and eax,0FFFFF000h
+
+@@CopyCR3:
+ mov [PDBR],eax ; Save it
+ mov esi,eax
+ mov edi,offset pageDirectory
+ mov ecx,1024
+ cld
+ rep movsd ; Copy the original page table directory
+ cmp [DWORD accessPageAddr],0; Check if we have allocated page
+ jne @@HaveRealMem ; table already (we cant free it)
+
+ mov eax,0100h ; DPMI DOS allocate
+ mov ebx,8192/16
+ int 31h ; Allocate 8192 bytes
+ and eax,0FFFFh
+ shl eax,4 ; EAX points to newly allocated memory
+ add eax,4095
+ and eax,0FFFFF000h ; Page align
+ mov [accessPageAddr],eax
+
+@@HaveRealMem:
+ mov eax,[accessPageAddr] ; EAX -> page table in 1st Mb
+ shr eax,12
+ and eax,3FFh ; Page table offset
+ shl eax,2
+ cmp [BOOL VF_haveCauseWay],0
+ jz @@NotCW0
+ mov ebx,[CauseWay1stLinear]
+ jmp @@Put1st
+
+@@NotCW0:
+ mov ebx,[PDBR]
+ mov ebx,[ebx]
+ and ebx,0FFFFF000h ; Page table for 1st megabyte
+
+@@Put1st:
+ add eax,ebx
+ mov [accessPageTable],eax
+ sub eax,eax ; No error
+ jmp @@Exit
+
+@@ErrExit:
+ mov eax,-1
+
+@@Exit: pop edi
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void ClosePaging(void)
+;----------------------------------------------------------------------------
+; Closes the paging system
+;----------------------------------------------------------------------------
+cprocstart ClosePaging
+
+ push eax
+ push ecx
+ push edx
+ push esi
+ push edi
+
+ mov eax,[accessPageAddr]
+ call AccessPage ; Restore AccessPage mapping
+ mov edi,[PDBR]
+ mov esi,offset pageDirectory
+ mov ecx,1024
+ cld
+ rep movsd ; Restore the original page table directory
+
+@@Exit: pop edi
+ pop esi
+ pop edx
+ pop ecx
+ pop eax
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; long AccessPage(long phys)
+;----------------------------------------------------------------------------
+; Maps a known page to given physical memory
+; Entry: EAX - Physical memory
+; Exit: EAX - Linear memory address of mapped phys mem
+;----------------------------------------------------------------------------
+cprocstatic AccessPage
+
+ push edx
+ mov edx,[accessPageTable]
+ or eax,7
+ mov [edx],eax
+ mov eax,cr3
+ mov cr3,eax ; Update page table cache
+ mov eax,[accessPageAddr]
+ pop edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; long GetPhysicalAddress(long linear)
+;----------------------------------------------------------------------------
+; Returns the physical address of linear address
+; Entry: EAX - Linear address to convert
+; Exit: EAX - Physical address
+;----------------------------------------------------------------------------
+cprocstatic GetPhysicalAddress
+
+ push ebx
+ push edx
+ mov edx,eax
+ shr edx,22 ; EDX is the directory offset
+ mov ebx,[PDBR]
+ mov edx,[edx*4+ebx] ; Load page table address
+ push eax
+ mov eax,edx
+ call AccessPage ; Access the page table
+ mov edx,eax
+ pop eax
+ shr eax,12
+ and eax,03FFh ; EAX offset into page table
+ mov eax,[edx+eax*4] ; Load physical address
+ and eax,0FFFFF000h
+ pop edx
+ pop ebx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void CreatePageTable(long pageDEntry)
+;----------------------------------------------------------------------------
+; Creates a page table for specific address (4MB)
+; Entry: EAX - Page directory entry (top 10-bits of address)
+;----------------------------------------------------------------------------
+cprocstatic CreatePageTable
+
+ push ebx
+ push ecx
+ push edx
+ push edi
+ mov ebx,eax ; Save address
+ mov eax,8192
+ push eax
+ call VF_malloc ; Allocate page table directory
+ add esp,4
+ add eax,0FFFh
+ and eax,0FFFFF000h ; Page align (4KB)
+ mov edi,eax ; Save page table linear address
+ sub eax,eax ; Fill with zero
+ mov ecx,1024
+ cld
+ rep stosd ; Clear page table
+ sub edi,4096
+ mov eax,edi
+ call GetPhysicalAddress
+ mov edx,[PDBR]
+ or eax,7 ; Present/write/user bit
+ mov [edx+ebx*4],eax ; Save physical address into page directory
+ mov eax,cr3
+ mov cr3,eax ; Update page table cache
+ pop edi
+ pop edx
+ pop ecx
+ pop ebx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void MapPhysical2Linear(ulong pAddr, ulong lAddr, int pages, int flags);
+;----------------------------------------------------------------------------
+; Maps physical memory into linear memory
+; Entry: pAddr - Physical address
+; lAddr - Linear address
+; pages - Number of 4K pages to map
+; flags - Page flags
+; bit 0 = present
+; bit 1 = Read(0)/Write(1)
+;----------------------------------------------------------------------------
+cprocstart MapPhysical2Linear
+
+ ARG pAddr:ULONG, lAddr:ULONG, pages:UINT, pflags:UINT
+
+ enter_c
+
+ and [ULONG pAddr],0FFFFF000h; Page boundary
+ and [ULONG lAddr],0FFFFF000h; Page boundary
+ mov ecx,[pflags]
+ and ecx,11b ; Just two bits
+ or ecx,100b ; Supervisor bit
+ mov [pflags],ecx
+
+ mov edx,[lAddr]
+ shr edx,22 ; EDX = Directory
+ mov esi,[PDBR]
+ mov edi,[pages] ; EDI page count
+ mov ebx,[lAddr]
+
+@@CreateLoop:
+ mov ecx,[esi+edx*4] ; Load page table address
+ test ecx,1 ; Is it present?
+ jnz @@TableOK
+ mov eax,edx
+ call CreatePageTable ; Create a page table
+@@TableOK:
+ mov eax,ebx
+ shr eax,12
+ and eax,3FFh
+ sub eax,1024
+ neg eax ; EAX = page count in this table
+ inc edx ; Next table
+ mov ebx,0 ; Next time we'll map 1K pages
+ sub edi,eax ; Subtract mapped pages from page count
+ jns @@CreateLoop ; Create more tables if necessary
+
+ mov ecx,[pages] ; ECX = Page count
+ mov esi,[lAddr]
+ shr esi,12 ; Offset part isn't needed
+ mov edi,[pAddr]
+@@MappingLoop:
+ mov eax,esi
+ shr eax,10 ; EAX = offset to page directory
+ mov ebx,[PDBR]
+ mov eax,[eax*4+ebx] ; EAX = page table address
+ call AccessPage
+ mov ebx,esi
+ and ebx,3FFh ; EBX = offset to page table
+ mov edx,edi
+ add edi,4096 ; Next physical address
+ inc esi ; Next linear page
+ or edx,[pflags] ; Update flags...
+ mov [eax+ebx*4],edx ; Store page table entry
+ loop @@MappingLoop
+ mov eax,cr3
+ mov cr3,eax ; Update page table cache
+
+ leave_c
+ ret
+
+cprocend
+
+endcodeseg _vflat
+
+endif
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/dos/cpuinfo.c
new file mode 100644
index 0000000000..ee117c78e9
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/cpuinfo.c
@@ -0,0 +1,72 @@
+/****************************************************************************
+*
+* 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: DOS
+*
+* Description: MSDOS specific code for the CPU detection module.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* External timing function */
+
+void __ZTimerInit(void);
+
+/****************************************************************************
+REMARKS:
+Do nothing for DOS because we don't have thread priorities.
+****************************************************************************/
+#define SetMaxThreadPriority() 0
+
+/****************************************************************************
+REMARKS:
+Do nothing for DOS because we don't have thread priorities.
+****************************************************************************/
+#define RestoreThreadPriority(i) (void)(i)
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ ulong resolution;
+
+ __ZTimerInit();
+ ULZTimerResolution(&resolution);
+ freq->low = (ulong)(10000000000.0 / resolution);
+ freq->high = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ (t)->low = ULZReadTime() * 10000L; \
+ (t)->high = 0; \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/event.c b/board/MAI/bios_emulator/scitech/src/pm/dos/event.c
new file mode 100644
index 0000000000..12ecb298bc
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/event.c
@@ -0,0 +1,494 @@
+/****************************************************************************
+*
+* 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: 32-bit DOS
+*
+* Description: 32-bit DOS implementation for the SciTech cross platform
+* event library.
+*
+****************************************************************************/
+
+/*--------------------------- Global variables ----------------------------*/
+
+ibool _VARAPI _EVT_useEvents = true; /* True to use event handling */
+ibool _VARAPI _EVT_installed = 0; /* Event handers installed? */
+uchar _VARAPI *_EVT_biosPtr = NULL; /* Pointer to the BIOS data area */
+static ibool haveMouse = false; /* True if we have a mouse */
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* External assembler functions */
+
+void EVTAPI _EVT_pollJoystick(void);
+uint EVTAPI _EVT_disableInt(void);
+uint EVTAPI _EVT_restoreInt(uint flags);
+void EVTAPI _EVT_codeStart(void);
+void EVTAPI _EVT_codeEnd(void);
+void EVTAPI _EVT_cCodeStart(void);
+void EVTAPI _EVT_cCodeEnd(void);
+int EVTAPI _EVT_getKeyCode(void);
+void EVTAPI _EVT_pumpMessages(void);
+int EVTAPI EVT_rdinx(int port,int index);
+void EVTAPI EVT_wrinx(int port,int index,int value);
+
+#ifdef NO_KEYBOARD_INTERRUPT
+/****************************************************************************
+REMARKS:
+This function is used to pump all keyboard messages from the BIOS keyboard
+handler into our event queue. This can be used to avoid using the
+installable keyboard handler if this is causing problems.
+****************************************************************************/
+static void EVTAPI _EVT_pumpMessages(void)
+{
+ RMREGS regs;
+ uint key,ps;
+
+ /* Since the keyboard ISR has not been installed if NO_IDE_BUG has
+ * been defined, we first check for any pending keyboard events
+ * here, and if there are some insert them into the event queue to
+ * be picked up later - what a kludge.
+ */
+ while ((key = _EVT_getKeyCode()) != 0) {
+ ps = _EVT_disableInt();
+ addKeyEvent(EVT_KEYDOWN, key);
+ _EVT_restoreInt(ps);
+ }
+
+ regs.x.ax = 0x0B; // Reset Move Mouse
+ PM_int86(0x33,&regs,&regs);
+}
+#endif
+
+/****************************************************************************
+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)
+{
+ return (ulong)PM_getLong(_EVT_biosPtr+0x6C) * 55UL;
+}
+
+/****************************************************************************
+REMARKS:
+Reboots the machine from DOS (warm boot)
+****************************************************************************/
+static void Reboot(void)
+{
+ PMREGS regs;
+ PMSREGS sregs;
+
+ ushort *rebootType = PM_mapRealPointer(0x40,0x72);
+ *rebootType = 0x1234;
+ PM_callRealMode(0xFFFF,0x0000,&regs,&sregs);
+}
+
+/****************************************************************************
+REMARKS:
+Include generic raw scancode keyboard module.
+****************************************************************************/
+#define SUPPORT_CTRL_ALT_DEL
+#include "common/keyboard.c"
+
+/****************************************************************************
+REMARKS:
+This function fools the DOS mouse driver into thinking that it is running
+in graphics mode, rather than text mode so we always get virtual coordinates
+correctly rather than character coordinates.
+****************************************************************************/
+int _EVT_foolMouse(void)
+{
+ int oldmode = PM_getByte(_EVT_biosPtr+0x49);
+ PM_setByte(_EVT_biosPtr+0x49,0x10);
+ oldmode |= (EVT_rdinx(0x3C4,0x2) << 8);
+ return oldmode;
+}
+
+/****************************************************************************
+REMARKS:
+This function unfools the DOS mouse driver after we have finished calling it.
+****************************************************************************/
+void _EVT_unfoolMouse(
+ int oldmode)
+{
+ PM_setByte(_EVT_biosPtr+0x49,oldmode);
+
+ /* Some mouse drivers reset the plane mask register for VGA plane 4
+ * modes, which screws up the display on some VGA compatible controllers
+ * in SuperVGA modes. We reset the value back again in here to solve
+ * the problem.
+ */
+ EVT_wrinx(0x3C4,0x2,oldmode >> 8);
+}
+
+/****************************************************************************
+REMARKS:
+Determines if we have a mouse attached and functioning.
+****************************************************************************/
+static ibool detectMouse(void)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+ uchar *p;
+ ibool retval;
+
+ regs.x.ax = 0x3533; /* Get interrupt vector 0x33 */
+ PM_int86x(0x21,&regs,&regs,&sregs);
+
+ /* Check that interrupt vector 0x33 is not a zero, and that the first
+ * instruction in the interrupt vector is not an IRET instruction
+ */
+ p = PM_mapRealPointer(sregs.es, regs.x.bx);
+ retval = ((sregs.es != 0) || (regs.x.bx != 0)) && (PM_getByte(p) != 207);
+ return retval;
+}
+
+/****************************************************************************
+PARAMETERS:
+what - Event code
+message - Event message
+x,y - Mouse 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.
+
+NOTE: Interrupts MUST be OFF while this routine is called to ensure we have
+ mutually exclusive access to our internal data structures for
+ interrupt driven systems (like under DOS).
+****************************************************************************/
+static void addMouseEvent(
+ uint what,
+ uint message,
+ int x,
+ int y,
+ int mickeyX,
+ int mickeyY,
+ uint but_stat)
+{
+ event_t evt;
+
+ if (EVT.count < EVENTQSIZE) {
+ /* Save information in event record. */
+ evt.when = _EVT_getTicks();
+ evt.what = what;
+ evt.message = message;
+ evt.modifiers = but_stat;
+ evt.where_x = x; /* Save mouse event position */
+ evt.where_y = y;
+ evt.relative_x = mickeyX;
+ evt.relative_y = mickeyY;
+ evt.modifiers |= EVT.keyModifiers;
+ addEvent(&evt); /* Add to tail of event queue */
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+mask - Event mask
+butstate - Button state
+x - Mouse x coordinate
+y - Mouse y coordinate
+
+REMARKS:
+Mouse event handling routine. This gets called when a mouse event occurs,
+and we call the addMouseEvent() routine to add the appropriate mouse event
+to the event queue.
+
+Note: Interrupts are ON when this routine is called by the mouse driver code.
+****************************************************************************/
+static void EVTAPI mouseISR(
+ uint mask,
+ uint butstate,
+ int x,
+ int y,
+ int mickeyX,
+ int mickeyY)
+{
+ uint ps;
+ uint buttonMask;
+
+ if (mask & 1) {
+ /* Save the current mouse coordinates */
+ EVT.mx = x; EVT.my = y;
+
+ /* If the last event was a movement event, then modify the last
+ * event rather than post a new one, so that the queue will not
+ * become saturated. Before we modify the data structures, we
+ * MUST ensure that interrupts are off.
+ */
+ ps = _EVT_disableInt();
+ if (EVT.oldMove != -1) {
+ EVT.evtq[EVT.oldMove].where_x = x; /* Modify existing one */
+ EVT.evtq[EVT.oldMove].where_y = y;
+ EVT.evtq[EVT.oldMove].relative_x += mickeyX;
+ EVT.evtq[EVT.oldMove].relative_y += mickeyY;
+ }
+ else {
+ EVT.oldMove = EVT.freeHead; /* Save id of this move event */
+ addMouseEvent(EVT_MOUSEMOVE,0,x,y,mickeyX,mickeyY,butstate);
+ }
+ _EVT_restoreInt(ps);
+ }
+ if (mask & 0x2A) {
+ ps = _EVT_disableInt();
+ buttonMask = 0;
+ if (mask & 2) buttonMask |= EVT_LEFTBMASK;
+ if (mask & 8) buttonMask |= EVT_RIGHTBMASK;
+ if (mask & 32) buttonMask |= EVT_MIDDLEBMASK;
+ addMouseEvent(EVT_MOUSEDOWN,buttonMask,x,y,0,0,butstate);
+ EVT.oldMove = -1;
+ _EVT_restoreInt(ps);
+ }
+ if (mask & 0x54) {
+ ps = _EVT_disableInt();
+ buttonMask = 0;
+ if (mask & 2) buttonMask |= EVT_LEFTBMASK;
+ if (mask & 8) buttonMask |= EVT_RIGHTBMASK;
+ if (mask & 32) buttonMask |= EVT_MIDDLEBMASK;
+ addMouseEvent(EVT_MOUSEUP,buttonMask,x,y,0,0,butstate);
+ EVT.oldMove = -1;
+ _EVT_restoreInt(ps);
+ }
+ EVT.oldKey = -1;
+}
+
+/****************************************************************************
+REMARKS:
+Keyboard interrupt handler function.
+
+NOTE: Interrupts are OFF when this routine is called by the keyboard ISR,
+ and we leave them OFF the entire time.
+****************************************************************************/
+static void EVTAPI keyboardISR(void)
+{
+ processRawScanCode(PM_inpb(0x60));
+ PM_outpb(0x20,0x20);
+}
+
+/****************************************************************************
+REMARKS:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort()
+{
+ EVT_exit();
+ PM_fatalError("Unhandled exception!");
+}
+
+/****************************************************************************
+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;
+
+ PM_init();
+ EVT.mouseMove = mouseMove;
+ _EVT_biosPtr = PM_getBIOSPointer();
+ EVT_resume();
+
+ /* Grab all characters pending in the keyboard buffer and stuff
+ * them into our event buffer. This allows us to pick up any keypresses
+ * while the program is initialising.
+ */
+ while ((i = _EVT_getKeyCode()) != 0)
+ addKeyEvent(EVT_KEYDOWN,i);
+}
+
+/****************************************************************************
+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 EVTAPI EVT_resume(void)
+{
+ static int locked = 0;
+ int stat;
+ uchar mods;
+ PM_lockHandle lh; /* Unused in DOS */
+
+ if (_EVT_useEvents) {
+ /* Initialise the event queue and enable our interrupt handlers */
+ initEventQueue();
+#ifndef NO_KEYBOARD_INTERRUPT
+ PM_setKeyHandler(keyboardISR);
+#endif
+#ifndef NO_MOUSE_INTERRUPT
+ if ((haveMouse = detectMouse()) != 0) {
+ int oldmode = _EVT_foolMouse();
+ PM_setMouseHandler(0xFFFF,mouseISR);
+ _EVT_unfoolMouse(oldmode);
+ }
+#endif
+
+ /* Read the keyboard modifier flags from the BIOS to get the
+ * correct initialisation state. The only state we care about is
+ * the correct toggle state flags such as SCROLLLOCK, NUMLOCK and
+ * CAPSLOCK.
+ */
+ EVT.keyModifiers = 0;
+ mods = PM_getByte(_EVT_biosPtr+0x17);
+ if (mods & 0x10)
+ EVT.keyModifiers |= EVT_SCROLLLOCK;
+ if (mods & 0x20)
+ EVT.keyModifiers |= EVT_NUMLOCK;
+ if (mods & 0x40)
+ EVT.keyModifiers |= EVT_CAPSLOCK;
+
+ /* Lock all of the code and data used by our protected mode interrupt
+ * handling routines, so that it will continue to work correctly
+ * under real mode.
+ */
+ if (!locked) {
+ /* It is difficult to ensure that we lock our global data, so we
+ * do this by taking the address of a variable locking all data
+ * 2Kb on either side. This should properly cover the global data
+ * used by the module (the other alternative is to declare the
+ * variables in assembler, in which case we know it will be
+ * correct).
+ */
+ stat = !PM_lockDataPages(&EVT,sizeof(EVT),&lh);
+ stat |= !PM_lockDataPages(&_EVT_biosPtr,sizeof(_EVT_biosPtr),&lh);
+ stat |= !PM_lockCodePages((__codePtr)_EVT_cCodeStart,(int)_EVT_cCodeEnd-(int)_EVT_cCodeStart,&lh);
+ stat |= !PM_lockCodePages((__codePtr)_EVT_codeStart,(int)_EVT_codeEnd-(int)_EVT_codeStart,&lh);
+ if (stat) {
+ PM_fatalError("Page locking services failed - interrupt handling not safe!");
+ exit(1);
+ }
+ locked = 1;
+ }
+
+ /* Catch program termination signals so we can clean up properly */
+ signal(SIGABRT, _EVT_abort);
+ signal(SIGFPE, _EVT_abort);
+ signal(SIGINT, _EVT_abort);
+ _EVT_installed = true;
+ }
+}
+
+/****************************************************************************
+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)
+{
+ RMREGS regs;
+
+ if (haveMouse) {
+ int oldmode = _EVT_foolMouse();
+ PM_resetMouseDriver(1);
+ regs.x.ax = 7; /* Mouse function 7 - Set horizontal min and max */
+ regs.x.cx = 0;
+ regs.x.dx = xRes;
+ PM_int86(0x33,&regs,&regs);
+ regs.x.ax = 8; /* Mouse function 8 - Set vertical min and max */
+ regs.x.cx = 0;
+ regs.x.dx = yRes;
+ PM_int86(0x33,&regs,&regs);
+ _EVT_unfoolMouse(oldmode);
+ }
+}
+
+/****************************************************************************
+REMARKS
+Modifes the mouse coordinates as necessary if scaling to OS coordinates,
+and sets the OS mouse cursor position.
+****************************************************************************/
+void _EVT_setMousePos(
+ int *x,
+ int *y)
+{
+ RMREGS regs;
+
+ if (haveMouse) {
+ int oldmode = _EVT_foolMouse();
+ regs.x.ax = 4; /* Mouse function 4 - Set mouse position */
+ regs.x.cx = *x; /* New horizontal coordinate */
+ regs.x.dx = *y; /* New vertical coordinate */
+ PM_int86(0x33,&regs,&regs);
+ _EVT_unfoolMouse(oldmode);
+ }
+}
+
+/****************************************************************************
+REMARKS
+Suspends all of our event handling operations. This is also used to
+de-install the event handling code.
+****************************************************************************/
+void EVTAPI EVT_suspend(void)
+{
+ uchar mods;
+
+ if (_EVT_installed) {
+ /* Restore the interrupt handlers */
+ PM_restoreKeyHandler();
+ if (haveMouse)
+ PM_restoreMouseHandler();
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+
+ /* Set the keyboard modifier flags in the BIOS to our values */
+ EVT_allowLEDS(true);
+ mods = PM_getByte(_EVT_biosPtr+0x17) & ~0x70;
+ if (EVT.keyModifiers & EVT_SCROLLLOCK)
+ mods |= 0x10;
+ if (EVT.keyModifiers & EVT_NUMLOCK)
+ mods |= 0x20;
+ if (EVT.keyModifiers & EVT_CAPSLOCK)
+ mods |= 0x40;
+ PM_setByte(_EVT_biosPtr+0x17,mods);
+
+ /* Flag that we are no longer installed */
+ _EVT_installed = false;
+ }
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVTAPI EVT_exit(void)
+{
+ EVT_suspend();
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/dos/oshdr.h
new file mode 100644
index 0000000000..35e8e00f72
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/oshdr.h
@@ -0,0 +1,29 @@
+/****************************************************************************
+*
+* 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: 32-bit DOS
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/pm.c b/board/MAI/bios_emulator/scitech/src/pm/dos/pm.c
new file mode 100644
index 0000000000..71acd6894e
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/pm.c
@@ -0,0 +1,2243 @@
+/****************************************************************************
+*
+* 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: 16/32 bit DOS
+*
+* 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 "ztimerc.h"
+#include "mtrr.h"
+#include "pm_help.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dos.h>
+#include <conio.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#include <sys/nearptr.h>
+#include <sys/stat.h>
+#else
+#include <direct.h>
+#endif
+#ifdef __BORLANDC__
+#pragma warn -par
+#endif
+
+/*--------------------------- Global variables ----------------------------*/
+
+typedef struct {
+ int oldMode;
+ int old50Lines;
+ } DOS_stateBuf;
+
+#define MAX_RM_BLOCKS 10
+
+static struct {
+ void *p;
+ uint tag;
+ } rmBlocks[MAX_RM_BLOCKS];
+
+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 */
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+ushort _VARAPI _PM_savedDS = 0;
+#ifdef DOS4GW
+static ulong PDB = 0,*pPDB = NULL;
+#endif
+#ifndef REALMODE
+static char VXD_name[] = PMHELP_NAME;
+static char VXD_module[] = PMHELP_MODULE;
+static char VXD_DDBName[] = PMHELP_DDBNAME;
+static uint VXD_version = -1;
+static uint VXD_loadOff = 0;
+static uint VXD_loadSel = 0;
+uint _VARAPI _PM_VXD_off = 0;
+uint _VARAPI _PM_VXD_sel = 0;
+int _VARAPI _PM_haveCauseWay = -1;
+
+/* Memory mapping cache */
+
+#define MAX_MEMORY_MAPPINGS 100
+typedef struct {
+ ulong physical;
+ ulong linear;
+ ulong limit;
+ } mmapping;
+static mmapping maps[MAX_MEMORY_MAPPINGS] = {0};
+static int numMaps = 0;
+
+/* Page sized block cache */
+
+#define PAGES_PER_BLOCK 100
+#define FREELIST_NEXT(p) (*(void**)(p))
+typedef struct pageblock {
+ struct pageblock *next;
+ struct pageblock *prev;
+ void *freeListStart;
+ void *freeList;
+ void *freeListEnd;
+ int freeCount;
+ } pageblock;
+static pageblock *pageBlocks = NULL;
+#endif
+
+/* Start of all page tables in CauseWay */
+
+#define CW_PAGE_TABLE_START (1024UL*4096UL*1023UL)
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* External assembler functions */
+
+ulong _ASMAPI _PM_getPDB(void);
+int _ASMAPI _PM_pagingEnabled(void);
+void _ASMAPI _PM_VxDCall(VXD_regs *regs,uint off,uint sel);
+
+#ifndef REALMODE
+/****************************************************************************
+REMARKS:
+Exit function to unload the dynamically loaded VxD
+****************************************************************************/
+static void UnloadVxD(void)
+{
+ PMSREGS sregs;
+ VXD_regs r;
+
+ r.eax = 2;
+ r.ebx = 0;
+ r.edx = (uint)VXD_module;
+ PM_segread(&sregs);
+#ifdef __16BIT__
+ r.ds = ((ulong)VXD_module) >> 16;
+#else
+ r.ds = sregs.ds;
+#endif
+ r.es = sregs.es;
+ _PM_VxDCall(&r,VXD_loadOff,VXD_loadSel);
+}
+
+/****************************************************************************
+REMARKS:
+External function to call the PMHELP helper VxD.
+****************************************************************************/
+void PMAPI PM_VxDCall(
+ VXD_regs *regs)
+{
+ if (_PM_VXD_sel != 0 || _PM_VXD_off != 0)
+ _PM_VxDCall(regs,_PM_VXD_off,_PM_VXD_sel);
+}
+
+/****************************************************************************
+RETURNS:
+BCD coded version number of the VxD, or 0 if not loaded (ie: 0x202 - 2.2)
+
+REMARKS:
+This function gets the version number for the VxD that we have connected to.
+****************************************************************************/
+uint PMAPI PMHELP_getVersion(void)
+{
+ VXD_regs r;
+
+ /* Call the helper VxD to determine the version number */
+ if (_PM_VXD_sel != 0 || _PM_VXD_off != 0) {
+ memset(&r,0,sizeof(r));
+ r.eax = API_NUM(PMHELP_GETVER);
+ _PM_VxDCall(&r,_PM_VXD_off,_PM_VXD_sel);
+ return VXD_version = (uint)r.eax;
+ }
+ return VXD_version = 0;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Connects to the helper VxD and returns the version number
+
+RETURNS:
+True if the VxD was found and loaded, false otherwise.
+
+REMARKS:
+This function connects to the VxD (loading it if it is dynamically loadable)
+and returns the version number of the VxD.
+****************************************************************************/
+static ibool PMHELP_connect(void)
+{
+ PMREGS regs;
+ PMSREGS sregs;
+ VXD_regs r;
+
+ /* Bail early if we have alread connected */
+ if (VXD_version != -1)
+ return VXD_version != 0;
+
+ /* Get the static SDDHELP.VXD entry point if available */
+ PM_segread(&sregs);
+ regs.x.ax = 0x1684;
+ regs.x.bx = SDDHELP_DeviceID;
+ regs.x.di = 0;
+ sregs.es = 0;
+ PM_int386x(0x2F,&regs,&regs,&sregs);
+ _PM_VXD_sel = sregs.es;
+ _PM_VXD_off = regs.x.di;
+ if (_PM_VXD_sel != 0 || _PM_VXD_off != 0) {
+ if (PMHELP_getVersion() >= PMHELP_VERSION)
+ return true;
+ }
+
+ /* If we get here, then either SDDHELP.VXD is not loaded, or it is an
+ * earlier version. In this case try to dynamically load the PMHELP.VXD
+ * helper VxD instead.
+ */
+ PM_segread(&sregs);
+ regs.x.ax = 0x1684;
+ regs.x.bx = VXDLDR_DeviceID;
+ regs.x.di = 0;
+ sregs.es = 0;
+ PM_int386x(0x2F,&regs,&regs,&sregs);
+ VXD_loadSel = sregs.es;
+ VXD_loadOff = regs.x.di;
+ if (VXD_loadSel == 0 && VXD_loadOff == 0)
+ return VXD_version = 0;
+ r.eax = 1;
+ r.ebx = 0;
+ r.edx = (uint)VXD_name;
+ PM_segread(&sregs);
+ r.ds = sregs.ds;
+ r.es = sregs.es;
+ _PM_VxDCall(&r,VXD_loadOff,VXD_loadSel);
+ if (r.eax != 0)
+ return VXD_version = 0;
+
+ /* Get the dynamic VxD entry point so we can call it */
+ atexit(UnloadVxD);
+ PM_segread(&sregs);
+ regs.x.ax = 0x1684;
+ regs.x.bx = 0;
+ regs.e.edi = (uint)VXD_DDBName;
+ PM_int386x(0x2F,&regs,&regs,&sregs);
+ _PM_VXD_sel = sregs.es;
+ _PM_VXD_off = regs.x.di;
+ if (_PM_VXD_sel == 0 && _PM_VXD_off == 0)
+ return VXD_version = 0;
+ if (PMHELP_getVersion() >= PMHELP_VERSION)
+ return true;
+ return VXD_version = 0;
+}
+#endif
+
+/****************************************************************************
+REMARKS:
+Initialise the PM library. First we try to connect to a static SDDHELP.VXD
+helper VxD, and check that it is a version we can use. If not we try to
+dynamically load the PMHELP.VXD helper VxD
+****************************************************************************/
+void PMAPI PM_init(void)
+{
+#ifndef REALMODE
+ PMREGS regs;
+
+ /* Check if we are running under CauseWay under real DOS */
+ if (_PM_haveCauseWay == -1) {
+ /* Check if we are running under DPMI in which case we will not be
+ * able to use our special ring 0 CauseWay functions.
+ */
+ _PM_haveCauseWay = false;
+ regs.x.ax = 0xFF00;
+ PM_int386(0x31,&regs,&regs);
+ if (regs.x.cflag || !(regs.e.edi & 8)) {
+ /* We are not under DPMI, so now check if CauseWay is active */
+ regs.x.ax = 0xFFF9;
+ PM_int386(0x31,&regs,&regs);
+ if (!regs.x.cflag && regs.e.ecx == 0x43415553 && regs.e.edx == 0x45574159)
+ _PM_haveCauseWay = true;
+ }
+
+ /* Now connect to PMHELP.VXD and initialise MTRR module */
+ if (!PMHELP_connect())
+ MTRR_init();
+ }
+#endif
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+RETURNS:
+Error code describing the result.
+
+REMARKS:
+Function to enable write combining for the specified region of memory.
+****************************************************************************/
+int PMAPI PM_enableWriteCombine(
+ ulong base,
+ ulong size,
+ uint type)
+{
+#ifndef REALMODE
+ VXD_regs regs;
+
+ if (PMHELP_connect()) {
+ memset(&regs,0,sizeof(regs));
+ regs.eax = API_NUM(PMHELP_ENABLELFBCOMB);
+ regs.ebx = base;
+ regs.ecx = size;
+ regs.edx = type;
+ _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
+ return regs.eax;
+ }
+ return MTRR_enableWriteCombine(base,size,type);
+#else
+ return PM_MTRR_NOT_SUPPORTED;
+#endif
+}
+
+ibool PMAPI PM_haveBIOSAccess(void)
+{ return true; }
+
+long PMAPI PM_getOSType(void)
+{ return _OS_DOS; }
+
+int PMAPI PM_getModeType(void)
+{
+#if defined(REALMODE)
+ return PM_realMode;
+#elif defined(PM286)
+ return PM_286;
+#elif defined(PM386)
+ return PM_386;
+#endif
+}
+
+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);
+ 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;
+}
+
+int PMAPI PM_int386(int intno, PMREGS *in, PMREGS *out)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+ return PM_int386x(intno,in,out,&sregs);
+}
+
+/* Routines to set and get the real mode interrupt vectors, by making
+ * direct real mode calls to DOS and bypassing the DOS extenders API.
+ * This is the safest way to handle this, as some servers try to be
+ * smart about changing real mode vectors.
+ */
+
+void PMAPI _PM_getRMvect(int intno, long *realisr)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+
+ PM_saveDS();
+ regs.h.ah = 0x35;
+ regs.h.al = intno;
+ PM_int86x(0x21, &regs, &regs, &sregs);
+ *realisr = ((long)sregs.es << 16) | regs.x.bx;
+}
+
+void PMAPI _PM_setRMvect(int intno, long realisr)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+
+ PM_saveDS();
+ regs.h.ah = 0x25;
+ regs.h.al = intno;
+ sregs.ds = (int)(realisr >> 16);
+ regs.x.dx = (int)(realisr & 0xFFFF);
+ PM_int86x(0x21, &regs, &regs, &sregs);
+}
+
+void PMAPI _PM_addRealModeBlock(void *mem,uint tag)
+{
+ int i;
+
+ for (i = 0; i < MAX_RM_BLOCKS; i++) {
+ if (rmBlocks[i].p == NULL) {
+ rmBlocks[i].p = mem;
+ rmBlocks[i].tag = tag;
+ return;
+ }
+ }
+ PM_fatalError("To many real mode memory block allocations!");
+}
+
+uint PMAPI _PM_findRealModeBlock(void *mem)
+{
+ int i;
+
+ for (i = 0; i < MAX_RM_BLOCKS; i++) {
+ if (rmBlocks[i].p == mem)
+ return rmBlocks[i].tag;
+ }
+ PM_fatalError("Could not find prior real mode memory block allocation!");
+ return 0;
+}
+
+char * PMAPI PM_getCurrentPath(
+ char *path,
+ int maxLen)
+{
+ return getcwd(path,maxLen);
+}
+
+char PMAPI PM_getBootDrive(void)
+{ return 'C'; }
+
+const char * PMAPI PM_getVBEAFPath(void)
+{ return "c:\\"; }
+
+const char * PMAPI PM_getNucleusPath(void)
+{
+ static char path[256];
+ char *env;
+
+ if ((env = getenv("NUCLEUS_PATH")) != NULL)
+ return env;
+ if ((env = getenv("WINBOOTDIR")) != NULL) {
+ /* Running in a Windows 9x DOS box or DOS mode */
+ strcpy(path,env);
+ strcat(path,"\\system\\nucleus");
+ return path;
+ }
+ if ((env = getenv("SystemRoot")) != NULL) {
+ /* Running in an NT/2K DOS box */
+ strcpy(path,env);
+ strcat(path,"\\system32\\nucleus");
+ return path;
+ }
+ return "c:\\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)
+{ return "DOS"; }
+
+const char * PMAPI PM_getMachineName(void)
+{ return "DOS"; }
+
+int PMAPI PM_kbhit(void)
+{
+ return kbhit();
+}
+
+int PMAPI PM_getch(void)
+{
+ return getch();
+}
+
+PM_HWND PMAPI PM_openConsole(PM_HWND hwndUser,int device,int xRes,int yRes,int bpp,ibool fullScreen)
+{
+ /* Not used for DOS */
+ (void)hwndUser;
+ (void)device;
+ (void)xRes;
+ (void)yRes;
+ (void)bpp;
+ (void)fullScreen;
+ return 0;
+}
+
+int PMAPI PM_getConsoleStateSize(void)
+{
+ return sizeof(DOS_stateBuf);
+}
+
+void PMAPI PM_saveConsoleState(void *stateBuf,PM_HWND hwndConsole)
+{
+ RMREGS regs;
+ DOS_stateBuf *sb = stateBuf;
+
+ /* Save the old video mode state */
+ regs.h.ah = 0x0F;
+ PM_int86(0x10,&regs,&regs);
+ sb->oldMode = regs.h.al & 0x7F;
+ sb->old50Lines = false;
+ if (sb->oldMode == 0x3) {
+ regs.x.ax = 0x1130;
+ regs.x.bx = 0;
+ regs.x.dx = 0;
+ PM_int86(0x10,&regs,&regs);
+ sb->old50Lines = (regs.h.dl == 42 || regs.h.dl == 49);
+ }
+ (void)hwndConsole;
+}
+
+void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
+{
+ /* Not used for DOS */
+ (void)saveState;
+}
+
+void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND hwndConsole)
+{
+ RMREGS regs;
+ const DOS_stateBuf *sb = stateBuf;
+
+ /* Retore 50 line mode if set */
+ if (sb->old50Lines) {
+ regs.x.ax = 0x1112;
+ regs.x.bx = 0;
+ PM_int86(0x10,&regs,&regs);
+ }
+ (void)hwndConsole;
+}
+
+void PMAPI PM_closeConsole(PM_HWND hwndConsole)
+{
+ /* Not used for DOS */
+ (void)hwndConsole;
+}
+
+void PMAPI PM_setOSCursorLocation(int x,int y)
+{
+ uchar *_biosPtr = PM_getBIOSPointer();
+ PM_setByte(_biosPtr+0x50,x);
+ PM_setByte(_biosPtr+0x51,y);
+}
+
+void PMAPI PM_setOSScreenWidth(int width,int height)
+{
+ uchar *_biosPtr = PM_getBIOSPointer();
+ PM_setWord(_biosPtr+0x4A,width);
+ PM_setWord(_biosPtr+0x4C,width*2);
+ PM_setByte(_biosPtr+0x84,height-1);
+ if (height > 25) {
+ PM_setWord(_biosPtr+0x60,0x0607);
+ PM_setByte(_biosPtr+0x85,0x08);
+ }
+ else {
+ PM_setWord(_biosPtr+0x60,0x0D0E);
+ PM_setByte(_biosPtr+0x85,0x016);
+ }
+}
+
+void * PMAPI PM_mallocShared(long size)
+{
+ return PM_malloc(size);
+}
+
+void PMAPI PM_freeShared(void *ptr)
+{
+ PM_free(ptr);
+}
+
+#define GetRMVect(intno,isr) *(isr) = ((ulong*)rmZeroPtr)[intno]
+#define SetRMVect(intno,isr) ((ulong*)rmZeroPtr)[intno] = (isr)
+
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *mappedBIOS,
+ ulong BIOSLen)
+{
+ static int firstTime = true;
+ static uchar *rmZeroPtr;
+ long Current10,Current6D,Current42;
+ RMREGS regs;
+ RMSREGS sregs;
+
+ /* Create a zero memory mapping for us to use */
+ if (firstTime) {
+ rmZeroPtr = PM_mapPhysicalAddr(0,0x7FFF,true);
+ firstTime = false;
+ }
+
+ /* Remap the secondary BIOS to 0xC0000 physical */
+ if (BIOSPhysAddr != 0xC0000L || BIOSLen > 32768) {
+ /* DOS cannot virtually remap the BIOS, so we can only work if all
+ * the secondary controllers are identical, and we then use the
+ * BIOS on the first controller for all the remaining controllers.
+ *
+ * For OS'es that do virtual memory, and remapping of 0xC0000
+ * physical (perhaps a copy on write mapping) should be all that
+ * is needed.
+ */
+ return false;
+ }
+
+ /* Save current handlers of int 10h and 6Dh */
+ GetRMVect(0x10,&Current10);
+ GetRMVect(0x6D,&Current6D);
+
+ /* POST the secondary BIOS */
+ GetRMVect(0x42,&Current42);
+ SetRMVect(0x10,Current42); /* Restore int 10h to STD-BIOS */
+ regs.x.ax = axVal;
+ PM_callRealMode(0xC000,0x0003,&regs,&sregs);
+
+ /* Restore current handlers */
+ SetRMVect(0x10,Current10);
+ SetRMVect(0x6D,Current6D);
+
+ /* Second the primary BIOS mappin 1:1 for 0xC0000 physical */
+ if (BIOSPhysAddr != 0xC0000L) {
+ /* DOS does not support this */
+ (void)mappedBIOS;
+ }
+ return true;
+}
+
+void PMAPI PM_sleep(ulong milliseconds)
+{
+ ulong microseconds = milliseconds * 1000L;
+ LZTimerObject tm;
+
+ LZTimerOnExt(&tm);
+ while (LZTimerLapExt(&tm) < microseconds)
+ ;
+ LZTimerOffExt(&tm);
+}
+
+int PMAPI PM_getCOMPort(int port)
+{
+ switch (port) {
+ case 0: return 0x3F8;
+ case 1: return 0x2F8;
+ }
+ return 0;
+}
+
+int PMAPI PM_getLPTPort(int port)
+{
+ switch (port) {
+ case 0: return 0x3BC;
+ case 1: return 0x378;
+ case 2: return 0x278;
+ }
+ return 0;
+}
+
+PM_MODULE PMAPI PM_loadLibrary(
+ const char *szDLLName)
+{
+ (void)szDLLName;
+ return NULL;
+}
+
+void * PMAPI PM_getProcAddress(
+ PM_MODULE hModule,
+ const char *szProcName)
+{
+ (void)hModule;
+ (void)szProcName;
+ return NULL;
+}
+
+void PMAPI PM_freeLibrary(
+ PM_MODULE hModule)
+{
+ (void)hModule;
+}
+
+int PMAPI PM_setIOPL(
+ int level)
+{
+ return level;
+}
+
+/****************************************************************************
+REMARKS:
+Internal function to convert the find data to the generic interface.
+****************************************************************************/
+static void convertFindData(
+ PM_findData *findData,
+ struct find_t *blk)
+{
+ ulong dwSize = findData->dwSize;
+
+ memset(findData,0,findData->dwSize);
+ findData->dwSize = dwSize;
+ if (blk->attrib & _A_RDONLY)
+ findData->attrib |= PM_FILE_READONLY;
+ if (blk->attrib & _A_SUBDIR)
+ findData->attrib |= PM_FILE_DIRECTORY;
+ if (blk->attrib & _A_ARCH)
+ findData->attrib |= PM_FILE_ARCHIVE;
+ if (blk->attrib & _A_HIDDEN)
+ findData->attrib |= PM_FILE_HIDDEN;
+ if (blk->attrib & _A_SYSTEM)
+ findData->attrib |= PM_FILE_SYSTEM;
+ findData->sizeLo = blk->size;
+ strncpy(findData->name,blk->name,PM_MAX_PATH);
+ findData->name[PM_MAX_PATH-1] = 0;
+}
+
+#define FIND_MASK (_A_RDONLY | _A_ARCH | _A_SUBDIR | _A_HIDDEN | _A_SYSTEM)
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+void * PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ struct find_t *blk;
+
+ if ((blk = PM_malloc(sizeof(*blk))) == NULL)
+ return PM_FILE_INVALID;
+ if (_dos_findfirst((char*)filename,FIND_MASK,blk) == 0) {
+ convertFindData(findData,blk);
+ return blk;
+ }
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ void *handle,
+ PM_findData *findData)
+{
+ struct find_t *blk = handle;
+
+ if (_dos_findnext(blk) == 0) {
+ convertFindData(findData,blk);
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ void *handle)
+{
+ PM_free(handle);
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ RMREGS regs;
+ regs.h.dl = (uchar)(drive - 'A' + 1);
+ regs.h.ah = 0x36; // Get disk information service
+ PM_int86(0x21,&regs,&regs);
+ return regs.x.ax != 0xFFFF; // AX = 0xFFFF if disk is invalid
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ uint oldDrive,maxDrives;
+ _dos_getdrive(&oldDrive);
+ _dos_setdrive(drive,&maxDrives);
+ getcwd(dir,len);
+ _dos_setdrive(oldDrive,&maxDrives);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+#if defined(TNT) && defined(_MSC_VER)
+ DWORD attr = 0;
+
+ if (attrib & PM_FILE_READONLY)
+ attr |= FILE_ATTRIBUTE_READONLY;
+ if (attrib & PM_FILE_ARCHIVE)
+ attr |= FILE_ATTRIBUTE_ARCHIVE;
+ if (attrib & PM_FILE_HIDDEN)
+ attr |= FILE_ATTRIBUTE_HIDDEN;
+ if (attrib & PM_FILE_SYSTEM)
+ attr |= FILE_ATTRIBUTE_SYSTEM;
+ SetFileAttributes((LPSTR)filename, attr);
+#else
+ uint attr = 0;
+
+ if (attrib & PM_FILE_READONLY)
+ attr |= _A_RDONLY;
+ if (attrib & PM_FILE_ARCHIVE)
+ attr |= _A_ARCH;
+ if (attrib & PM_FILE_HIDDEN)
+ attr |= _A_HIDDEN;
+ if (attrib & PM_FILE_SYSTEM)
+ attr |= _A_SYSTEM;
+ _dos_setfileattr(filename,attr);
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+#ifdef __GNUC__
+ return mkdir(filename,S_IRUSR) == 0;
+#else
+ return mkdir(filename) == 0;
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+ return rmdir(filename) == 0;
+}
+
+/*-------------------------------------------------------------------------*/
+/* Generic DPMI routines common to 16/32 bit code */
+/*-------------------------------------------------------------------------*/
+
+#ifndef REALMODE
+ulong PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit)
+{
+ PMREGS r;
+ int i;
+ ulong baseAddr,baseOfs,roundedLimit;
+
+ /* We can't map memory below 1Mb, but the linear address are already
+ * mapped 1:1 for this memory anyway so we just return the base address.
+ */
+ if (physAddr < 0x100000L)
+ return physAddr;
+
+ /* Search table of existing mappings to see if we have already mapped
+ * a region of memory that will serve this purpose. We do this because
+ * DPMI 0.9 does not allow us to free physical memory mappings, and if
+ * the mappings get re-used in the program we want to avoid allocating
+ * more mappings than necessary.
+ */
+ for (i = 0; i < numMaps; i++) {
+ if (maps[i].physical == physAddr && maps[i].limit == limit)
+ return maps[i].linear;
+ }
+
+ /* Find a free slot in our physical memory mapping table */
+ for (i = 0; i < numMaps; i++) {
+ if (maps[i].limit == 0)
+ break;
+ }
+ if (i == numMaps) {
+ i = numMaps++;
+ if (i == MAX_MEMORY_MAPPINGS)
+ return NULL;
+ }
+
+ /* Round the physical address to a 4Kb boundary and the limit to a
+ * 4Kb-1 boundary before passing the values to DPMI as some extenders
+ * will fail the calls unless this is the case. If we round the
+ * physical address, then we also add an extra offset into the address
+ * that we return.
+ */
+ baseOfs = physAddr & 4095;
+ baseAddr = physAddr & ~4095;
+ roundedLimit = ((limit+baseOfs+1+4095) & ~4095)-1;
+ r.x.ax = 0x800;
+ r.x.bx = baseAddr >> 16;
+ r.x.cx = baseAddr & 0xFFFF;
+ r.x.si = roundedLimit >> 16;
+ r.x.di = roundedLimit & 0xFFFF;
+ PM_int386(0x31, &r, &r);
+ if (r.x.cflag)
+ return 0xFFFFFFFFUL;
+ maps[i].physical = physAddr;
+ maps[i].limit = limit;
+ maps[i].linear = ((ulong)r.x.bx << 16) + r.x.cx + baseOfs;
+ return maps[i].linear;
+}
+
+int PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr)
+{
+ PMREGS r;
+
+ r.x.ax = 7; /* DPMI set selector base address */
+ r.x.bx = sel;
+ r.x.cx = linAddr >> 16;
+ r.x.dx = linAddr & 0xFFFF;
+ PM_int386(0x31, &r, &r);
+ if (r.x.cflag)
+ return 0;
+ return 1;
+}
+
+ulong PMAPI DPMI_getSelectorBase(ushort sel)
+{
+ PMREGS r;
+
+ r.x.ax = 6; /* DPMI get selector base address */
+ r.x.bx = sel;
+ PM_int386(0x31, &r, &r);
+ return ((ulong)r.x.cx << 16) + r.x.dx;
+}
+
+int PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit)
+{
+ PMREGS r;
+
+ r.x.ax = 8; /* DPMI set selector limit */
+ r.x.bx = sel;
+ r.x.cx = limit >> 16;
+ r.x.dx = limit & 0xFFFF;
+ PM_int386(0x31, &r, &r);
+ if (r.x.cflag)
+ return 0;
+ return 1;
+}
+
+uint PMAPI DPMI_createSelector(ulong base,ulong limit)
+{
+ uint sel;
+ PMREGS r;
+
+ /* Allocate 1 descriptor */
+ r.x.ax = 0;
+ r.x.cx = 1;
+ PM_int386(0x31, &r, &r);
+ if (r.x.cflag) return 0;
+ sel = r.x.ax;
+
+ /* Set the descriptor access rights (for a 32 bit page granular
+ * segment).
+ */
+ if (limit >= 0x10000L) {
+ r.x.ax = 9;
+ r.x.bx = sel;
+ r.x.cx = 0x40F3;
+ PM_int386(0x31, &r, &r);
+ }
+
+ /* Map physical memory and create selector */
+ if ((base = DPMI_mapPhysicalToLinear(base,limit)) == 0xFFFFFFFFUL)
+ return 0;
+ if (!DPMI_setSelectorBase(sel,base))
+ return 0;
+ if (!DPMI_setSelectorLimit(sel,limit))
+ return 0;
+ return sel;
+}
+
+void PMAPI DPMI_freeSelector(uint sel)
+{
+ PMREGS r;
+
+ r.x.ax = 1;
+ r.x.bx = sel;
+ PM_int386(0x31, &r, &r);
+}
+
+int PMAPI DPMI_lockLinearPages(ulong linear,ulong len)
+{
+ PMREGS r;
+
+ r.x.ax = 0x600; /* DPMI Lock Linear Region */
+ r.x.bx = (linear >> 16); /* Linear address in BX:CX */
+ r.x.cx = (linear & 0xFFFF);
+ r.x.si = (len >> 16); /* Length in SI:DI */
+ r.x.di = (len & 0xFFFF);
+ PM_int386(0x31, &r, &r);
+ return (!r.x.cflag);
+}
+
+int PMAPI DPMI_unlockLinearPages(ulong linear,ulong len)
+{
+ PMREGS r;
+
+ r.x.ax = 0x601; /* DPMI Unlock Linear Region */
+ r.x.bx = (linear >> 16); /* Linear address in BX:CX */
+ r.x.cx = (linear & 0xFFFF);
+ r.x.si = (len >> 16); /* Length in SI:DI */
+ r.x.di = (len & 0xFFFF);
+ PM_int386(0x31, &r, &r);
+ return (!r.x.cflag);
+}
+
+/****************************************************************************
+REMARKS:
+Adjust the page table caching bits directly. Requires ring 0 access and
+only works with DOS4GW and compatible extenders (CauseWay also works since
+it has direct support for the ring 0 instructions we need from ring 3). Will
+not work in a DOS box, but we call into the ring 0 helper VxD so we should
+never get here in a DOS box anyway (assuming the VxD is present). If we
+do get here and we are in windows, this code will be skipped.
+****************************************************************************/
+static void PM_adjustPageTables(
+ ulong linear,
+ ulong limit,
+ ibool isCached)
+{
+#ifdef DOS4GW
+ int startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
+ ulong andMask,orMask,pageTable,*pPageTable;
+
+ andMask = ~0x18;
+ orMask = (isCached) ? 0x00 : 0x18;
+ if (_PM_pagingEnabled() == 1 && (PDB = _PM_getPDB()) != 0) {
+ if (_PM_haveCauseWay) {
+ /* CauseWay is a little different in the page table handling.
+ * The code that we use for DOS4G/W does not appear to work
+ * with CauseWay correctly as it does not appear to allow us
+ * to map the page tables directly. Instead we can directly
+ * access the page table entries in extended memory where
+ * CauseWay always locates them (starting at 1024*4096*1023)
+ */
+ startPage = (linear >> 12);
+ endPage = ((linear+limit) >> 12);
+ pPageTable = (ulong*)CW_PAGE_TABLE_START;
+ for (iPage = startPage; iPage <= endPage; iPage++)
+ pPageTable[iPage] = (pPageTable[iPage] & andMask) | orMask;
+ }
+ else {
+ pPDB = (ulong*)DPMI_mapPhysicalToLinear(PDB,0xFFF);
+ if (pPDB) {
+ startPDB = (linear >> 22) & 0x3FF;
+ startPage = (linear >> 12) & 0x3FF;
+ endPDB = ((linear+limit) >> 22) & 0x3FF;
+ endPage = ((linear+limit) >> 12) & 0x3FF;
+ for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
+ pageTable = pPDB[iPDB] & ~0xFFF;
+ pPageTable = (ulong*)DPMI_mapPhysicalToLinear(pageTable,0xFFF);
+ start = (iPDB == startPDB) ? startPage : 0;
+ end = (iPDB == endPDB) ? endPage : 0x3FF;
+ for (iPage = start; iPage <= end; iPage++)
+ pPageTable[iPage] = (pPageTable[iPage] & andMask) | orMask;
+ }
+ }
+ }
+ PM_flushTLB();
+ }
+#endif
+}
+
+void * PMAPI DPMI_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{
+ PMSREGS sregs;
+ ulong linAddr;
+ ulong DSBaseAddr;
+
+ /* Get the base address for the default DS selector */
+ PM_segread(&sregs);
+ DSBaseAddr = DPMI_getSelectorBase(sregs.ds);
+ if ((base < 0x100000) && (DSBaseAddr == 0)) {
+ /* DS is zero based, so we can directly access the first 1Mb of
+ * system memory (like under DOS4GW).
+ */
+ return (void*)base;
+ }
+
+ /* Map the memory to a linear address using DPMI function 0x800 */
+ if ((linAddr = DPMI_mapPhysicalToLinear(base,limit)) == 0xFFFFFFFF) {
+ if (base >= 0x100000)
+ return NULL;
+ /* If the linear address mapping fails but we are trying to
+ * map an area in the first 1Mb of system memory, then we must
+ * be running under a Windows or OS/2 DOS box. Under these
+ * environments we can use the segment wrap around as a fallback
+ * measure, as this does work properly.
+ */
+ linAddr = base;
+ }
+
+ /* Now expand the default DS selector to 4Gb so we can access it */
+ if (!DPMI_setSelectorLimit(sregs.ds,0xFFFFFFFFUL))
+ return NULL;
+
+ /* Finally enable caching for the page tables that we just mapped in,
+ * since DOS4GW and PMODE/W create the page table entries without
+ * caching enabled which hurts the performance of the linear framebuffer
+ * as it disables write combining on Pentium Pro and above processors.
+ *
+ * For those processors cache disabling is better handled through the
+ * MTRR registers anyway (we can write combine a region but disable
+ * caching) so that MMIO register regions do not screw up.
+ */
+ if (DSBaseAddr == 0)
+ PM_adjustPageTables(linAddr,limit,isCached);
+
+ /* Now return the base address of the memory into the default DS */
+ return (void*)(linAddr - DSBaseAddr);
+}
+
+#if defined(PM386)
+
+/* Some DOS extender implementations do not directly support calling a
+ * real mode procedure from protected mode. However we can simulate what
+ * we need temporarily hooking the INT 6Ah vector with a small real mode
+ * stub that will call our real mode code for us.
+ */
+
+static uchar int6AHandler[] = {
+ 0x00,0x00,0x00,0x00, /* __PMODE_callReal variable */
+ 0xFB, /* sti */
+ 0x2E,0xFF,0x1E,0x00,0x00, /* call [cs:__PMODE_callReal] */
+ 0xCF, /* iretf */
+ };
+static uchar *crPtr = NULL; /* Pointer to of int 6A handler */
+static uint crRSeg,crROff; /* Real mode seg:offset of handler */
+
+void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
+ RMSREGS *sregs)
+{
+ uchar *p;
+ uint oldSeg,oldOff;
+
+ if (!crPtr) {
+ /* Allocate and copy the memory block only once */
+ crPtr = PM_allocRealSeg(sizeof(int6AHandler), &crRSeg, &crROff);
+ memcpy(crPtr,int6AHandler,sizeof(int6AHandler));
+ }
+ PM_setWord(crPtr,off); /* Plug in address to call */
+ PM_setWord(crPtr+2,seg);
+ p = PM_mapRealPointer(0,0x6A * 4);
+ oldOff = PM_getWord(p); /* Save old handler address */
+ oldSeg = PM_getWord(p+2);
+ PM_setWord(p,crROff+4); /* Hook 6A handler */
+ PM_setWord(p+2,crRSeg);
+ PM_int86x(0x6A, in, in, sregs); /* Call real mode code */
+ PM_setWord(p,oldOff); /* Restore old handler */
+ PM_setWord(p+2,oldSeg);
+}
+
+#endif /* PM386 */
+
+#endif /* !REALMODE */
+
+/****************************************************************************
+REMARKS:
+Allocates a block of locked, physically contiguous memory. The memory
+may be required to be below the 16Meg boundary.
+****************************************************************************/
+void * PMAPI PM_allocLockedMem(
+ uint size,
+ ulong *physAddr,
+ ibool contiguous,
+ ibool below16Meg)
+{
+ uchar *p,*roundedP;
+ uint r_seg,r_off;
+ uint roundedSize = (size + 4 + 0xFFF) & ~0xFFF;
+ PM_lockHandle lh; /* Unused in DOS */
+#ifndef REALMODE
+ VXD_regs regs;
+
+ /* If we have connected to our helper VxD in a Windows DOS box, use the
+ * helper VxD services to allocate the memory that we need.
+ */
+ if (VXD_version) {
+ memset(&regs,0,sizeof(regs));
+ regs.eax = API_NUM(PMHELP_ALLOCLOCKED);
+ regs.ebx = size;
+ regs.ecx = (ulong)physAddr;
+ regs.edx = contiguous | (below16Meg << 8);
+ _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
+ return (void*)regs.eax;
+ }
+
+ /* If the memory is not contiguous, we simply need to allocate it
+ * using regular memory allocation services, and lock it down
+ * in memory.
+ *
+ * For contiguous memory blocks, the only way to guarantee contiguous physical
+ * memory addresses under DOS is to allocate the memory below the
+ * 1Meg boundary as real mode memory.
+ *
+ * Note that we must page align the memory block, and we also must
+ * keep track of the non-aligned pointer so we can properly free
+ * it later. Hence we actually allocate 4 bytes more than the
+ * size rounded up to the next 4K boundary.
+ */
+ if (!contiguous)
+ p = PM_malloc(roundedSize);
+ else
+#endif
+ p = PM_allocRealSeg(roundedSize,&r_seg,&r_off);
+ if (p == NULL)
+ return NULL;
+ roundedP = (void*)(((ulong)p + 0xFFF) & ~0xFFF);
+ *((ulong*)(roundedP + size)) = (ulong)p;
+ PM_lockDataPages(roundedP,size,&lh);
+ if ((*physAddr = PM_getPhysicalAddr(roundedP)) == 0xFFFFFFFF) {
+ PM_freeLockedMem(roundedP,size,contiguous);
+ return NULL;
+ }
+
+ /* Disable caching for the memory since it is probably a DMA buffer */
+#ifndef REALMODE
+ PM_adjustPageTables((ulong)roundedP,size-1,false);
+#endif
+ return roundedP;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of locked memory.
+****************************************************************************/
+void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous)
+{
+#ifndef REALMODE
+ VXD_regs regs;
+ PM_lockHandle lh; /* Unused in DOS */
+
+ if (!p)
+ return;
+ if (VXD_version) {
+ memset(&regs,0,sizeof(regs));
+ regs.eax = API_NUM(PMHELP_FREELOCKED);
+ regs.ebx = (ulong)p;
+ regs.ecx = size;
+ regs.edx = contiguous;
+ _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
+ return;
+ }
+ PM_unlockDataPages(p,size,&lh);
+ if (!contiguous)
+ free(*((void**)((uchar*)p + size)));
+ else
+#endif
+ PM_freeRealSeg(*((void**)((char*)p + size)));
+}
+
+#ifndef REALMODE
+/****************************************************************************
+REMARKS:
+Allocates a new block of pages for the page block manager.
+****************************************************************************/
+static pageblock *PM_addNewPageBlock(void)
+{
+ int i,size;
+ pageblock *newBlock;
+ char *p,*next;
+
+ /* Allocate memory for the new page block, and add to head of list */
+ size = PAGES_PER_BLOCK * PM_PAGE_SIZE + (PM_PAGE_SIZE-1) + sizeof(pageblock);
+ if ((newBlock = PM_malloc(size)) == NULL)
+ return NULL;
+ newBlock->prev = NULL;
+ newBlock->next = pageBlocks;
+ if (pageBlocks)
+ pageBlocks->prev = newBlock;
+ pageBlocks = newBlock;
+
+ /* Initialise the page aligned free list for the page block */
+ newBlock->freeCount = PAGES_PER_BLOCK;
+ newBlock->freeList = p = (char*)(((ulong)(newBlock + 1) + (PM_PAGE_SIZE-1)) & ~(PM_PAGE_SIZE-1));
+ newBlock->freeListStart = newBlock->freeList;
+ newBlock->freeListEnd = p + (PAGES_PER_BLOCK-1) * PM_PAGE_SIZE;
+ for (i = 0; i < PAGES_PER_BLOCK; i++,p = next)
+ FREELIST_NEXT(p) = next = p + PM_PAGE_SIZE;
+ FREELIST_NEXT(p - PM_PAGE_SIZE) = NULL;
+ return newBlock;
+}
+#endif
+
+/****************************************************************************
+REMARKS:
+Allocates a page aligned and page sized block of memory
+****************************************************************************/
+void * PMAPI PM_allocPage(
+ ibool locked)
+{
+#ifndef REALMODE
+ VXD_regs regs;
+ pageblock *block;
+ void *p;
+ PM_lockHandle lh; /* Unused in DOS */
+
+ /* Call the helper VxD for this service if we are running in a DOS box */
+ if (VXD_version) {
+ memset(&regs,0,sizeof(regs));
+ regs.eax = API_NUM(PMHELP_ALLOCPAGE);
+ regs.ebx = locked;
+ _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
+ return (void*)regs.eax;
+ }
+
+ /* Scan the block list looking for any free blocks. Allocate a new
+ * page block if no free blocks are found.
+ */
+ for (block = pageBlocks; block != NULL; block = block->next) {
+ if (block->freeCount)
+ break;
+ }
+ if (block == NULL && (block = PM_addNewPageBlock()) == NULL)
+ return NULL;
+ block->freeCount--;
+ p = block->freeList;
+ block->freeList = FREELIST_NEXT(p);
+ if (locked)
+ PM_lockDataPages(p,PM_PAGE_SIZE,&lh);
+ return p;
+#else
+ return NULL;
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Free a page aligned and page sized block of memory
+****************************************************************************/
+void PMAPI PM_freePage(
+ void *p)
+{
+#ifndef REALMODE
+ VXD_regs regs;
+ pageblock *block;
+
+ /* Call the helper VxD for this service if we are running in a DOS box */
+ if (VXD_version) {
+ memset(&regs,0,sizeof(regs));
+ regs.eax = API_NUM(PMHELP_FREEPAGE);
+ regs.ebx = (ulong)p;
+ _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
+ return;
+ }
+
+ /* First find the page block that this page belongs to */
+ for (block = pageBlocks; block != NULL; block = block->next) {
+ if (p >= block->freeListStart && p <= block->freeListEnd)
+ break;
+ }
+ CHECK(block != NULL);
+
+ /* Now free the block by adding it to the free list */
+ FREELIST_NEXT(p) = block->freeList;
+ block->freeList = p;
+ if (++block->freeCount == PAGES_PER_BLOCK) {
+ /* If all pages in the page block are now free, free the entire
+ * page block itself.
+ */
+ if (block == pageBlocks) {
+ /* Delete from head */
+ pageBlocks = block->next;
+ if (block->next)
+ block->next->prev = NULL;
+ }
+ else {
+ /* Delete from middle of list */
+ CHECK(block->prev != NULL);
+ block->prev->next = block->next;
+ if (block->next)
+ block->next->prev = block->prev;
+ }
+ PM_free(block);
+ }
+#else
+ (void)p;
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+/* DOS Real Mode support. */
+/*-------------------------------------------------------------------------*/
+
+#ifdef REALMODE
+
+#ifndef MK_FP
+#define MK_FP(s,o) ( (void far *)( ((ulong)(s) << 16) + \
+ (ulong)(o) ))
+#endif
+
+void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
+{ return MK_FP(r_seg,r_off); }
+
+void * PMAPI PM_getBIOSPointer(void)
+{
+ return MK_FP(0x40,0);
+}
+
+void * PMAPI PM_getA0000Pointer(void)
+{
+ return MK_FP(0xA000,0);
+}
+
+void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{
+ uint sel = base >> 4;
+ uint off = base & 0xF;
+ limit = limit;
+ return MK_FP(sel,off);
+}
+
+void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
+{ ptr = ptr; }
+
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{
+ return ((((ulong)p >> 16) << 4) + (ushort)p);
+}
+
+ibool PMAPI PM_getPhysicalAddrRange(void *p,ulong length,ulong *physAddress)
+{ return false; }
+
+void * PMAPI PM_mapToProcess(void *base,ulong limit)
+{ return (void*)base; }
+
+void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
+{
+ /* Call malloc() to allocate the memory for us */
+ void *p = PM_malloc(size);
+ *r_seg = FP_SEG(p);
+ *r_off = FP_OFF(p);
+ return p;
+}
+
+void PMAPI PM_freeRealSeg(void *mem)
+{
+ if (mem) PM_free(mem);
+}
+
+int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
+{
+ return PM_int386(intno,in,out);
+}
+
+int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
+ RMSREGS *sregs)
+{
+ return PM_int386x(intno,in,out,sregs);
+}
+
+void PMAPI PM_availableMemory(ulong *physical,ulong *total)
+{
+ PMREGS regs;
+
+ regs.h.ah = 0x48;
+ regs.x.bx = 0xFFFF;
+ PM_int86(0x21,&regs,&regs);
+ *physical = *total = regs.x.bx * 16UL;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* Phar Lap TNT DOS Extender support. */
+/*-------------------------------------------------------------------------*/
+
+#ifdef TNT
+
+#include <pldos32.h>
+#include <pharlap.h>
+#include <hw386.h>
+
+static uchar *zeroPtr = NULL;
+
+void * PMAPI PM_getBIOSPointer(void)
+{
+ if (!zeroPtr)
+ zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
+ return (void*)(zeroPtr + 0x400);
+}
+
+void * PMAPI PM_getA0000Pointer(void)
+{
+ static void *bankPtr;
+ if (!bankPtr)
+ bankPtr = PM_mapPhysicalAddr(0xA0000,0xFFFF,true);
+ return bankPtr;
+}
+
+void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{
+ CONFIG_INF config;
+ ULONG offset;
+ int err;
+ ulong baseAddr,baseOfs,newLimit;
+ VXD_regs regs;
+
+ /* If we have connected to our helper VxD in a Windows DOS box, use
+ * the helper VxD services to map memory instead of the DPMI services.
+ * We do this because the helper VxD can properly disable caching
+ * where necessary, which we can only do directly here if we are
+ * running at ring 0 (ie: under real DOS).
+ */
+ if (VXD_version == -1)
+ PM_init();
+ if (VXD_version) {
+ memset(&regs,0,sizeof(regs));
+ regs.eax = API_NUM(PMHELP_MAPPHYS);
+ regs.ebx = base;
+ regs.ecx = limit;
+ regs.edx = isCached;
+ _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
+ return (void*)regs.eax;
+ }
+
+ /* Round the physical address to a 4Kb boundary and the limit to a
+ * 4Kb-1 boundary before passing the values to TNT. 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;
+ newLimit = ((limit+baseOfs+1+4095) & ~4095)-1;
+ _dx_config_inf(&config, (UCHAR*)&config);
+ err = _dx_map_phys(config.c_ds_sel,baseAddr,(newLimit + 4095) / 4096,&offset);
+ if (err == 130) {
+ /* If the TNT function failed, we are running in a DPMI environment
+ * and this function does not work. However we know how to handle
+ * DPMI properly, so we use our generic DPMI functions to do
+ * what the TNT runtime libraries can't.
+ */
+ return DPMI_mapPhysicalAddr(base,limit,isCached);
+ }
+ if (err == 0)
+ return (void*)(offset + baseOfs);
+ return NULL;
+}
+
+void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
+{
+}
+
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{ return 0xFFFFFFFFUL; }
+
+ibool PMAPI PM_getPhysicalAddrRange(void *p,ulong length,ulong *physAddress)
+{ return false; }
+
+void * PMAPI PM_mapToProcess(void *base,ulong limit)
+{ return (void*)base; }
+
+void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
+{
+ if (!zeroPtr)
+ zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF);
+ return (void*)(zeroPtr + MK_PHYS(r_seg,r_off));
+}
+
+void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
+{
+ USHORT addr,t;
+ void *p;
+
+ if (_dx_real_alloc((size + 0xF) >> 4,&addr,&t) != 0)
+ return 0;
+ *r_seg = addr; /* Real mode segment address */
+ *r_off = 0; /* Real mode segment offset */
+ p = PM_mapRealPointer(*r_seg,*r_off);
+ _PM_addRealModeBlock(p,addr);
+ return p;
+}
+
+void PMAPI PM_freeRealSeg(void *mem)
+{
+ if (mem) _dx_real_free(_PM_findRealModeBlock(mem));
+}
+
+#define INDPMI(reg) rmregs.reg = regs->reg
+#define OUTDPMI(reg) regs->reg = rmregs.reg
+
+void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
+{
+ SWI_REGS rmregs;
+
+ memset(&rmregs, 0, sizeof(rmregs));
+ INDPMI(eax); INDPMI(ebx); INDPMI(ecx); INDPMI(edx); INDPMI(esi); INDPMI(edi);
+
+ _dx_real_int(intno,&rmregs);
+
+ OUTDPMI(eax); OUTDPMI(ebx); OUTDPMI(ecx); OUTDPMI(edx); OUTDPMI(esi); OUTDPMI(edi);
+ regs->flags = rmregs.flags;
+}
+
+#define IN(reg) rmregs.reg = in->e.reg
+#define OUT(reg) out->e.reg = rmregs.reg
+
+int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
+{
+ SWI_REGS rmregs;
+
+ memset(&rmregs, 0, sizeof(rmregs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+
+ _dx_real_int(intno,&rmregs);
+
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ out->x.cflag = rmregs.flags & 0x1;
+ return out->x.ax;
+}
+
+int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
+ RMSREGS *sregs)
+{
+ SWI_REGS rmregs;
+
+ memset(&rmregs, 0, sizeof(rmregs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ rmregs.es = sregs->es;
+ rmregs.ds = sregs->ds;
+
+ _dx_real_int(intno,&rmregs);
+
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ sregs->es = rmregs.es;
+ sregs->cs = rmregs.cs;
+ sregs->ss = rmregs.ss;
+ sregs->ds = rmregs.ds;
+ out->x.cflag = rmregs.flags & 0x1;
+ return out->x.ax;
+}
+
+void PMAPI PM_availableMemory(ulong *physical,ulong *total)
+{
+ PMREGS r;
+ uint data[25];
+
+ r.x.ax = 0x2520; /* Get free memory info */
+ r.x.bx = 0;
+ r.e.edx = (uint)data;
+ PM_int386(0x21, &r, &r);
+ *physical = data[21] * 4096;
+ *total = data[23] * 4096;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* Symantec C++ DOSX and FlashTek X-32/X-32VM support */
+/*-------------------------------------------------------------------------*/
+
+#if defined(DOSX) || defined(X32VM)
+
+#ifdef X32VM
+#include <x32.h>
+
+#define _x386_mk_protected_ptr(p) _x32_mk_protected_ptr((void*)p)
+#define _x386_free_protected_ptr(p) _x32_free_protected_ptr(p)
+#define _x386_zero_base_ptr _x32_zero_base_ptr
+#else
+extern void *_x386_zero_base_ptr;
+#endif
+
+void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
+{
+ return (void*)((ulong)_x386_zero_base_ptr + MK_PHYS(r_seg,r_off));
+}
+
+void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
+{
+ PMREGS r;
+
+ r.h.ah = 0x48; /* DOS function 48h - allocate mem */
+ r.x.bx = (size + 0xF) >> 4; /* Number of paragraphs to allocate */
+ PM_int386(0x21, &r, &r); /* Call DOS extender */
+ if (r.x.cflag)
+ return 0; /* Could not allocate the memory */
+ *r_seg = r.e.eax;
+ *r_off = 0;
+ return PM_mapRealPointer(*r_seg,*r_off);
+}
+
+void PMAPI PM_freeRealSeg(void *mem)
+{
+ /* Cannot de-allocate this memory */
+ mem = mem;
+}
+
+#pragma pack(1)
+
+typedef struct {
+ ushort intno;
+ ushort ds;
+ ushort es;
+ ushort fs;
+ ushort gs;
+ ulong eax;
+ ulong edx;
+ } _RMREGS;
+
+#pragma pack()
+
+#define IN(reg) regs.e.reg = in->e.reg
+#define OUT(reg) out->e.reg = regs.e.reg
+
+int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
+{
+ _RMREGS rmregs;
+ PMREGS regs;
+ PMSREGS pmsregs;
+
+ rmregs.intno = intno;
+ rmregs.eax = in->e.eax;
+ rmregs.edx = in->e.edx;
+ IN(ebx); IN(ecx); IN(esi); IN(edi);
+ regs.x.ax = 0x2511;
+ regs.e.edx = (uint)(&rmregs);
+ PM_segread(&pmsregs);
+ PM_int386x(0x21,&regs,&regs,&pmsregs);
+
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(esi); OUT(edi);
+ out->x.dx = rmregs.edx;
+ out->x.cflag = regs.x.cflag;
+ return out->x.ax;
+}
+
+int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out, RMSREGS *sregs)
+{
+ _RMREGS rmregs;
+ PMREGS regs;
+ PMSREGS pmsregs;
+
+ rmregs.intno = intno;
+ rmregs.eax = in->e.eax;
+ rmregs.edx = in->e.edx;
+ rmregs.es = sregs->es;
+ rmregs.ds = sregs->ds;
+ IN(ebx); IN(ecx); IN(esi); IN(edi);
+ regs.x.ax = 0x2511;
+ regs.e.edx = (uint)(&rmregs);
+ PM_segread(&pmsregs);
+ PM_int386x(0x21,&regs,&regs,&pmsregs);
+
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(esi); OUT(edi);
+ sregs->es = rmregs.es;
+ sregs->ds = rmregs.ds;
+ out->x.dx = rmregs.edx;
+ out->x.cflag = regs.x.cflag;
+ return out->x.ax;
+}
+
+void * PMAPI PM_getBIOSPointer(void)
+{
+ return (void*)((ulong)_x386_zero_base_ptr + 0x400);
+}
+
+void * PMAPI PM_getA0000Pointer(void)
+{
+ return (void*)((ulong)_x386_zero_base_ptr + 0xA0000);
+}
+
+void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{
+ VXD_regs regs;
+
+ /* If we have connected to our helper VxD in a Windows DOS box, use
+ * the helper VxD services to map memory instead of the DPMI services.
+ * We do this because the helper VxD can properly disable caching
+ * where necessary, which we can only do directly here if we are
+ * running at ring 0 (ie: under real DOS).
+ */
+ if (VXD_version == -1)
+ PM_init();
+ if (VXD_version) {
+ memset(&regs,0,sizeof(regs));
+ regs.eax = API_NUM(PMHELP_MAPPHYS);
+ regs.ebx = base;
+ regs.ecx = limit;
+ regs.edx = isCached;
+ _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
+ return (void*)regs.eax;
+ }
+
+ if (base > 0x100000)
+ return _x386_map_physical_address((void*)base,limit);
+ return (void*)((ulong)_x386_zero_base_ptr + base);
+}
+
+void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
+{
+ /* Mapping cannot be freed */
+}
+
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{ return 0xFFFFFFFFUL; }
+
+ibool PMAPI PM_getPhysicalAddrRange(void *p,ulong length,ulong *physAddress)
+{ return false; }
+
+void * PMAPI PM_mapToProcess(void *base,ulong limit)
+{ return (void*)base; }
+
+ulong _cdecl _X32_getPhysMem(void);
+
+void PMAPI PM_availableMemory(ulong *physical,ulong *total)
+{
+ PMREGS regs;
+
+ /* Get total memory available, including virtual memory */
+ regs.x.ax = 0x350B;
+ PM_int386(0x21,&regs,&regs);
+ *total = regs.e.eax;
+
+ /* Get physical memory available */
+ *physical = _X32_getPhysMem();
+ if (*physical > *total)
+ *physical = *total;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* Borland's DPMI32, Watcom DOS4GW and DJGPP DPMI support routines */
+/*-------------------------------------------------------------------------*/
+
+#if defined(DPMI32) || defined(DOS4GW) || defined(DJGPP)
+
+void * PMAPI PM_getBIOSPointer(void)
+{
+ return PM_mapPhysicalAddr(0x400,0xFFFF,true);
+}
+
+void * PMAPI PM_getA0000Pointer(void)
+{
+ return PM_mapPhysicalAddr(0xA0000,0xFFFF,true);
+}
+
+void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{
+ VXD_regs regs;
+
+#ifdef DJGPP
+ /* Enable near pointers for DJGPP V2 */
+ __djgpp_nearptr_enable();
+#endif
+ /* If we have connected to our helper VxD in a Windows DOS box, use
+ * the helper VxD services to map memory instead of the DPMI services.
+ * We do this because the helper VxD can properly disable caching
+ * where necessary, which we can only do directly here if we are
+ * running at ring 0 (ie: under real DOS).
+ */
+ if (VXD_version == -1)
+ PM_init();
+ if (VXD_version) {
+ memset(&regs,0,sizeof(regs));
+ regs.eax = API_NUM(PMHELP_MAPPHYS);
+ regs.ebx = base;
+ regs.ecx = limit;
+ regs.edx = isCached;
+ _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
+ return (void*)regs.eax;
+ }
+ return DPMI_mapPhysicalAddr(base,limit,isCached);
+}
+
+void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
+{
+ /* Mapping cannot be freed */
+ (void)ptr;
+ (void)limit;
+}
+
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{
+ ulong physAddr;
+ if (!PM_getPhysicalAddrRange(p,1,&physAddr))
+ return 0xFFFFFFFF;
+ return physAddr | ((ulong)p & 0xFFF);
+}
+
+ibool PMAPI PM_getPhysicalAddrRange(
+ void *p,
+ ulong length,
+ ulong *physAddress)
+{
+ VXD_regs regs;
+ ulong pte;
+ PMSREGS sregs;
+ ulong DSBaseAddr;
+
+ /* If we have connected to our helper VxD in a Windows DOS box, use the
+ * helper VxD services to find the physical address of an address.
+ */
+ if (VXD_version) {
+ memset(&regs,0,sizeof(regs));
+ regs.eax = API_NUM(PMHELP_GETPHYSICALADDRRANGE);
+ regs.ebx = (ulong)p;
+ regs.ecx = (ulong)length;
+ regs.edx = (ulong)physAddress;
+ _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);
+ return regs.eax;
+ }
+
+ /* Find base address for default DS selector */
+ PM_segread(&sregs);
+ DSBaseAddr = DPMI_getSelectorBase(sregs.ds);
+
+ /* Otherwise directly access the page tables to determine the
+ * physical memory address. Note that we touch the memory before
+ * calling, otherwise the memory may not be paged in correctly.
+ */
+ pte = *((ulong*)p);
+#ifdef DOS4GW
+ if (_PM_pagingEnabled() == 0) {
+ int count;
+ ulong linAddr = (ulong)p;
+
+ /* When paging is disabled physical=linear */
+ for (count = (length+0xFFF) >> 12; count > 0; count--) {
+ *physAddress++ = linAddr;
+ linAddr += 4096;
+ }
+ return true;
+ }
+ else if ((PDB = _PM_getPDB()) != 0 && DSBaseAddr == 0) {
+ int startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
+ ulong pageTable,*pPageTable,linAddr = (ulong)p;
+ ulong limit = length-1;
+
+ pPDB = (ulong*)DPMI_mapPhysicalToLinear(PDB,0xFFF);
+ if (pPDB) {
+ startPDB = (linAddr >> 22) & 0x3FFL;
+ startPage = (linAddr >> 12) & 0x3FFL;
+ endPDB = ((linAddr+limit) >> 22) & 0x3FFL;
+ endPage = ((linAddr+limit) >> 12) & 0x3FFL;
+ for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
+ pageTable = pPDB[iPDB] & ~0xFFFL;
+ pPageTable = (ulong*)DPMI_mapPhysicalToLinear(pageTable,0xFFF);
+ start = (iPDB == startPDB) ? startPage : 0;
+ end = (iPDB == endPDB) ? endPage : 0x3FFL;
+ for (iPage = start; iPage <= end; iPage++)
+ *physAddress++ = (pPageTable[iPage] & ~0xFFF);
+ }
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+void * PMAPI PM_mapToProcess(void *base,ulong limit)
+{
+ (void)limit;
+ return (void*)base;
+}
+
+void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
+{
+ static uchar *zeroPtr = NULL;
+
+ if (!zeroPtr)
+ zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
+ return (void*)(zeroPtr + MK_PHYS(r_seg,r_off));
+}
+
+void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
+{
+ PMREGS r;
+ void *p;
+
+ r.x.ax = 0x100; /* DPMI allocate DOS memory */
+ r.x.bx = (size + 0xF) >> 4; /* number of paragraphs */
+ PM_int386(0x31, &r, &r);
+ if (r.x.cflag)
+ return NULL; /* DPMI call failed */
+ *r_seg = r.x.ax; /* Real mode segment */
+ *r_off = 0;
+ p = PM_mapRealPointer(*r_seg,*r_off);
+ _PM_addRealModeBlock(p,r.x.dx);
+ return p;
+}
+
+void PMAPI PM_freeRealSeg(void *mem)
+{
+ PMREGS r;
+
+ if (mem) {
+ r.x.ax = 0x101; /* DPMI free DOS memory */
+ r.x.dx = _PM_findRealModeBlock(mem);/* DX := selector from 0x100 */
+ PM_int386(0x31, &r, &r);
+ }
+}
+
+static DPMI_handler_t DPMI_int10 = NULL;
+
+void PMAPI DPMI_setInt10Handler(DPMI_handler_t handler)
+{
+ DPMI_int10 = handler;
+}
+
+void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
+{
+ PMREGS r;
+ PMSREGS sr;
+
+ if (intno == 0x10 && DPMI_int10) {
+ if (DPMI_int10(regs))
+ return;
+ }
+ PM_segread(&sr);
+ r.x.ax = 0x300; /* DPMI issue real interrupt */
+ r.h.bl = intno;
+ r.h.bh = 0;
+ r.x.cx = 0;
+ sr.es = sr.ds;
+ r.e.edi = (uint)regs;
+ PM_int386x(0x31, &r, &r, &sr); /* Issue the interrupt */
+}
+
+#define IN(reg) rmregs.reg = in->e.reg
+#define OUT(reg) out->e.reg = rmregs.reg
+
+int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
+{
+ DPMI_regs rmregs;
+
+ memset(&rmregs, 0, sizeof(rmregs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+
+ DPMI_int86(intno,&rmregs); /* DPMI issue real interrupt */
+
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ out->x.cflag = rmregs.flags & 0x1;
+ return out->x.ax;
+}
+
+int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
+ RMSREGS *sregs)
+{
+ DPMI_regs rmregs;
+
+ memset(&rmregs, 0, sizeof(rmregs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ rmregs.es = sregs->es;
+ rmregs.ds = sregs->ds;
+
+ DPMI_int86(intno,&rmregs); /* DPMI issue real interrupt */
+
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ sregs->es = rmregs.es;
+ sregs->cs = rmregs.cs;
+ sregs->ss = rmregs.ss;
+ sregs->ds = rmregs.ds;
+ out->x.cflag = rmregs.flags & 0x1;
+ return out->x.ax;
+}
+
+#pragma pack(1)
+
+typedef struct {
+ uint LargestBlockAvail;
+ uint MaxUnlockedPage;
+ uint LargestLockablePage;
+ uint LinAddrSpace;
+ uint NumFreePagesAvail;
+ uint NumPhysicalPagesFree;
+ uint TotalPhysicalPages;
+ uint FreeLinAddrSpace;
+ uint SizeOfPageFile;
+ uint res[3];
+ } MemInfo;
+
+#pragma pack()
+
+void PMAPI PM_availableMemory(ulong *physical,ulong *total)
+{
+ PMREGS r;
+ PMSREGS sr;
+ MemInfo memInfo;
+
+ PM_segread(&sr);
+ r.x.ax = 0x500; /* DPMI get free memory info */
+ sr.es = sr.ds;
+ r.e.edi = (uint)&memInfo;
+ PM_int386x(0x31, &r, &r, &sr); /* Issue the interrupt */
+ *physical = memInfo.NumPhysicalPagesFree * 4096;
+ *total = memInfo.LargestBlockAvail;
+ if (*total < *physical)
+ *physical = *total;
+}
+
+#endif
+
+#ifndef __16BIT__
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display banks.
+****************************************************************************/
+void PMAPI PM_setBankA(
+ int bank)
+{
+ DPMI_regs regs;
+ memset(&regs, 0, sizeof(regs));
+ regs.eax = 0x4F05;
+ regs.ebx = 0x0000;
+ regs.edx = bank;
+ DPMI_int86(0x10,&regs);
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display banks.
+****************************************************************************/
+void PMAPI PM_setBankAB(
+ int bank)
+{
+ DPMI_regs regs;
+ memset(&regs, 0, sizeof(regs));
+ regs.eax = 0x4F05;
+ regs.ebx = 0x0000;
+ regs.edx = bank;
+ DPMI_int86(0x10,&regs);
+ regs.eax = 0x4F05;
+ regs.ebx = 0x0001;
+ regs.edx = bank;
+ DPMI_int86(0x10,&regs);
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display start address.
+****************************************************************************/
+void PMAPI PM_setCRTStart(
+ int x,
+ int y,
+ int waitVRT)
+{
+ DPMI_regs regs;
+ memset(&regs, 0, sizeof(regs));
+ regs.eax = 0x4F07;
+ regs.ebx = waitVRT;
+ regs.ecx = x;
+ regs.edx = y;
+ DPMI_int86(0x10,&regs);
+}
+
+#endif
+
+/****************************************************************************
+REMARKS:
+Function to get the file attributes for a specific file.
+****************************************************************************/
+uint PMAPI PM_getFileAttr(
+ const char *filename)
+{
+ // TODO: Implement this!
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_getFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this!
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_setFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this!
+ return false;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/pmdos.c b/board/MAI/bios_emulator/scitech/src/pm/dos/pmdos.c
new file mode 100644
index 0000000000..74f8427a1c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/pmdos.c
@@ -0,0 +1,1637 @@
+/****************************************************************************
+*
+* 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: 16/32 bit DOS
+*
+* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dos.h>
+
+/*--------------------------- Global variables ----------------------------*/
+
+#ifndef REALMODE
+static int globalDataStart;
+#endif
+
+PM_criticalHandler _VARAPI _PM_critHandler = NULL;
+PM_breakHandler _VARAPI _PM_breakHandler = NULL;
+PM_intHandler _VARAPI _PM_timerHandler = NULL;
+PM_intHandler _VARAPI _PM_rtcHandler = NULL;
+PM_intHandler _VARAPI _PM_keyHandler = NULL;
+PM_key15Handler _VARAPI _PM_key15Handler = NULL;
+PM_mouseHandler _VARAPI _PM_mouseHandler = NULL;
+PM_intHandler _VARAPI _PM_int10Handler = NULL;
+int _VARAPI _PM_mouseMask;
+
+uchar * _VARAPI _PM_ctrlCPtr; /* Location of Ctrl-C flag */
+uchar * _VARAPI _PM_ctrlBPtr; /* Location of Ctrl-Break flag */
+uchar * _VARAPI _PM_critPtr; /* Location of Critical error Bf*/
+PMFARPTR _VARAPI _PM_prevTimer = PMNULL; /* Previous timer handler */
+PMFARPTR _VARAPI _PM_prevRTC = PMNULL; /* Previous RTC handler */
+PMFARPTR _VARAPI _PM_prevKey = PMNULL; /* Previous key handler */
+PMFARPTR _VARAPI _PM_prevKey15 = PMNULL; /* Previous key15 handler */
+PMFARPTR _VARAPI _PM_prevBreak = PMNULL; /* Previous break handler */
+PMFARPTR _VARAPI _PM_prevCtrlC = PMNULL; /* Previous CtrlC handler */
+PMFARPTR _VARAPI _PM_prevCritical = PMNULL; /* Previous critical handler */
+long _VARAPI _PM_prevRealTimer; /* Previous real mode timer */
+long _VARAPI _PM_prevRealRTC; /* Previous real mode RTC */
+long _VARAPI _PM_prevRealKey; /* Previous real mode key */
+long _VARAPI _PM_prevRealKey15; /* Previous real mode key15 */
+long _VARAPI _PM_prevRealInt10; /* Previous real mode int 10h */
+static uchar _PM_oldCMOSRegA; /* CMOS register A contents */
+static uchar _PM_oldCMOSRegB; /* CMOS register B contents */
+static uchar _PM_oldRTCPIC2; /* Mask value for RTC IRQ8 */
+
+/* Structure to maintain information about hardware interrupt handlers,
+ * include a copy of the hardware IRQ assembler thunk (one for each
+ * hooked interrupt handler).
+ */
+
+typedef struct {
+ uchar IRQ;
+ uchar IRQVect;
+ uchar prevPIC;
+ uchar prevPIC2;
+ PMFARPTR prevHandler;
+ long prevRealhandler;
+ uchar thunk[1];
+ /* IRQ assembler thunk follows ... */
+ } _PM_IRQHandle;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* Globals for locking interrupt handlers in _pmdos.asm */
+
+#ifndef REALMODE
+extern int _VARAPI _PM_pmdosDataStart;
+extern int _VARAPI _PM_pmdosDataEnd;
+extern int _VARAPI _PM_DMADataStart;
+extern int _VARAPI _PM_DMADataEnd;
+void _ASMAPI _PM_pmdosCodeStart(void);
+void _ASMAPI _PM_pmdosCodeEnd(void);
+void _ASMAPI _PM_DMACodeStart(void);
+void _ASMAPI _PM_DMACodeEnd(void);
+#endif
+
+/* Protected mode interrupt handlers, also called by PM callbacks below */
+
+void _ASMAPI _PM_timerISR(void);
+void _ASMAPI _PM_rtcISR(void);
+void _ASMAPI _PM_irqISRTemplate(void);
+void _ASMAPI _PM_irqISRTemplateEnd(void);
+void _ASMAPI _PM_keyISR(void);
+void _ASMAPI _PM_key15ISR(void);
+void _ASMAPI _PM_breakISR(void);
+void _ASMAPI _PM_ctrlCISR(void);
+void _ASMAPI _PM_criticalISR(void);
+void _ASMAPI _PM_mouseISR(void);
+void _ASMAPI _PM_int10PMCB(void);
+
+/* Protected mode DPMI callback handlers */
+
+void _ASMAPI _PM_mousePMCB(void);
+
+/* Routine to install a mouse handler function */
+
+void _ASMAPI _PM_setMouseHandler(int mask);
+
+/* Routine to allocate DPMI real mode callback routines */
+
+ibool _ASMAPI _DPMI_allocateCallback(void (_ASMAPI *pmcode)(),void *rmregs,long *RMCB);
+void _ASMAPI _DPMI_freeCallback(long RMCB);
+
+/* DPMI helper functions in PMLITE.C */
+
+ulong PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit);
+int PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr);
+ulong PMAPI DPMI_getSelectorBase(ushort sel);
+int PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit);
+uint PMAPI DPMI_createSelector(ulong base,ulong limit);
+void PMAPI DPMI_freeSelector(uint sel);
+int PMAPI DPMI_lockLinearPages(ulong linear,ulong len);
+int PMAPI DPMI_unlockLinearPages(ulong linear,ulong len);
+
+/* Functions to read and write CMOS registers */
+
+uchar PMAPI _PM_readCMOS(int index);
+void PMAPI _PM_writeCMOS(int index,uchar value);
+
+/*-------------------------------------------------------------------------*/
+/* Generic routines common to all environments */
+/*-------------------------------------------------------------------------*/
+
+void PMAPI PM_resetMouseDriver(int hardReset)
+{
+ RMREGS regs;
+ PM_mouseHandler oldHandler = _PM_mouseHandler;
+
+ PM_restoreMouseHandler();
+ regs.x.ax = hardReset ? 0 : 33;
+ PM_int86(0x33, &regs, &regs);
+ if (oldHandler)
+ PM_setMouseHandler(_PM_mouseMask, oldHandler);
+}
+
+void PMAPI PM_setRealTimeClockFrequency(int frequency)
+{
+ static short convert[] = {
+ 8192,
+ 4096,
+ 2048,
+ 1024,
+ 512,
+ 256,
+ 128,
+ 64,
+ 32,
+ 16,
+ 8,
+ 4,
+ 2,
+ -1,
+ };
+ int i;
+
+ /* First clear any pending RTC timeout if not cleared */
+ _PM_readCMOS(0x0C);
+ if (frequency == 0) {
+ /* Disable RTC timout */
+ _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,_PM_oldCMOSRegB & 0x0F);
+ }
+ else {
+ /* Convert frequency value to RTC clock indexes */
+ for (i = 0; convert[i] != -1; i++) {
+ if (convert[i] == frequency)
+ break;
+ }
+
+ /* Set RTC timout value and enable timeout */
+ _PM_writeCMOS(0x0A,0x20 | (i+3));
+ _PM_writeCMOS(0x0B,(_PM_oldCMOSRegB & 0x0F) | 0x40);
+ }
+}
+
+#ifndef REALMODE
+
+static void PMAPI lockPMHandlers(void)
+{
+ static int locked = 0;
+ int stat;
+ PM_lockHandle lh; /* Unused in DOS */
+
+ /* Lock all of the code and data used by our protected mode interrupt
+ * handling routines, so that it will continue to work correctly
+ * under real mode.
+ */
+ if (!locked) {
+ PM_saveDS();
+ stat = !PM_lockDataPages(&globalDataStart-2048,4096,&lh);
+ stat |= !PM_lockDataPages(&_PM_pmdosDataStart,(int)&_PM_pmdosDataEnd - (int)&_PM_pmdosDataStart,&lh);
+ stat |= !PM_lockCodePages((__codePtr)_PM_pmdosCodeStart,(int)_PM_pmdosCodeEnd-(int)_PM_pmdosCodeStart,&lh);
+ stat |= !PM_lockDataPages(&_PM_DMADataStart,(int)&_PM_DMADataEnd - (int)&_PM_DMADataStart,&lh);
+ stat |= !PM_lockCodePages((__codePtr)_PM_DMACodeStart,(int)_PM_DMACodeEnd-(int)_PM_DMACodeStart,&lh);
+ if (stat) {
+ printf("Page locking services failed - interrupt handling not safe!\n");
+ exit(1);
+ }
+ locked = 1;
+ }
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* DOS Real Mode support. */
+/*-------------------------------------------------------------------------*/
+
+#ifdef REALMODE
+
+#ifndef MK_FP
+#define MK_FP(s,o) ( (void far *)( ((ulong)(s) << 16) + \
+ (ulong)(o) ))
+#endif
+
+int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
+{
+ PM_saveDS();
+ _PM_mouseHandler = mh;
+ _PM_setMouseHandler(_PM_mouseMask = mask);
+ return 1;
+}
+
+void PMAPI PM_restoreMouseHandler(void)
+{
+ union REGS regs;
+
+ if (_PM_mouseHandler) {
+ regs.x.ax = 33;
+ int86(0x33, &regs, &regs);
+ _PM_mouseHandler = NULL;
+ }
+}
+
+void PMAPI PM_setTimerHandler(PM_intHandler th)
+{
+ _PM_getRMvect(0x8, (long*)&_PM_prevTimer);
+ _PM_timerHandler = th;
+ _PM_setRMvect(0x8, (long)_PM_timerISR);
+}
+
+void PMAPI PM_restoreTimerHandler(void)
+{
+ if (_PM_timerHandler) {
+ _PM_setRMvect(0x8, (long)_PM_prevTimer);
+ _PM_timerHandler = NULL;
+ }
+}
+
+ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
+{
+ /* Save the old CMOS real time clock values */
+ _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
+ _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
+
+ /* Set the real time clock interrupt handler */
+ _PM_getRMvect(0x70, (long*)&_PM_prevRTC);
+ _PM_rtcHandler = th;
+ _PM_setRMvect(0x70, (long)_PM_rtcISR);
+
+ /* Program the real time clock default frequency */
+ PM_setRealTimeClockFrequency(frequency);
+
+ /* Unmask IRQ8 in the PIC2 */
+ _PM_oldRTCPIC2 = PM_inpb(0xA1);
+ PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE);
+ return true;
+}
+
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ if (_PM_rtcHandler) {
+ /* Restore CMOS registers and mask RTC clock */
+ _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
+ PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE));
+
+ /* Restore the interrupt vector */
+ _PM_setRMvect(0x70, (long)_PM_prevRTC);
+ _PM_rtcHandler = NULL;
+ }
+}
+
+void PMAPI PM_setKeyHandler(PM_intHandler kh)
+{
+ _PM_getRMvect(0x9, (long*)&_PM_prevKey);
+ _PM_keyHandler = kh;
+ _PM_setRMvect(0x9, (long)_PM_keyISR);
+}
+
+void PMAPI PM_restoreKeyHandler(void)
+{
+ if (_PM_keyHandler) {
+ _PM_setRMvect(0x9, (long)_PM_prevKey);
+ _PM_keyHandler = NULL;
+ }
+}
+
+void PMAPI PM_setKey15Handler(PM_key15Handler kh)
+{
+ _PM_getRMvect(0x15, (long*)&_PM_prevKey15);
+ _PM_key15Handler = kh;
+ _PM_setRMvect(0x15, (long)_PM_key15ISR);
+}
+
+void PMAPI PM_restoreKey15Handler(void)
+{
+ if (_PM_key15Handler) {
+ _PM_setRMvect(0x15, (long)_PM_prevKey15);
+ _PM_key15Handler = NULL;
+ }
+}
+
+void PMAPI PM_installAltBreakHandler(PM_breakHandler bh)
+{
+ static int ctrlCFlag,ctrlBFlag;
+
+ _PM_ctrlCPtr = (uchar*)&ctrlCFlag;
+ _PM_ctrlBPtr = (uchar*)&ctrlBFlag;
+ _PM_getRMvect(0x1B, (long*)&_PM_prevBreak);
+ _PM_getRMvect(0x23, (long*)&_PM_prevCtrlC);
+ _PM_breakHandler = bh;
+ _PM_setRMvect(0x1B, (long)_PM_breakISR);
+ _PM_setRMvect(0x23, (long)_PM_ctrlCISR);
+}
+
+void PMAPI PM_installBreakHandler(void)
+{
+ PM_installAltBreakHandler(NULL);
+}
+
+void PMAPI PM_restoreBreakHandler(void)
+{
+ if (_PM_prevBreak) {
+ _PM_setRMvect(0x1B, (long)_PM_prevBreak);
+ _PM_setRMvect(0x23, (long)_PM_prevCtrlC);
+ _PM_prevBreak = NULL;
+ _PM_breakHandler = NULL;
+ }
+}
+
+void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch)
+{
+ static short critBuf[2];
+
+ _PM_critPtr = (uchar*)critBuf;
+ _PM_getRMvect(0x24, (long*)&_PM_prevCritical);
+ _PM_critHandler = ch;
+ _PM_setRMvect(0x24, (long)_PM_criticalISR);
+}
+
+void PMAPI PM_installCriticalHandler(void)
+{
+ PM_installAltCriticalHandler(NULL);
+}
+
+void PMAPI PM_restoreCriticalHandler(void)
+{
+ if (_PM_prevCritical) {
+ _PM_setRMvect(0x24, (long)_PM_prevCritical);
+ _PM_prevCritical = NULL;
+ _PM_critHandler = NULL;
+ }
+}
+
+int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ p = p; len = len; /* Do nothing for real mode */
+ return 1;
+}
+
+int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ p = p; len = len; /* Do nothing for real mode */
+ return 1;
+}
+
+int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ p = p; len = len; /* Do nothing for real mode */
+ return 1;
+}
+
+int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ p = p; len = len; /* Do nothing for real mode */
+ return 1;
+}
+
+void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
+{
+ long t;
+ _PM_getRMvect(intno,&t);
+ *isr = (void*)t;
+}
+
+void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
+{
+ PM_saveDS();
+ _PM_setRMvect(intno,(long)isr);
+}
+
+void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
+{
+ _PM_setRMvect(intno,(long)isr);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* Phar Lap TNT DOS Extender support. */
+/*-------------------------------------------------------------------------*/
+
+#ifdef TNT
+
+#include <pldos32.h>
+#include <pharlap.h>
+#include <hw386.h>
+
+static long prevRealBreak; /* Previous real mode break handler */
+static long prevRealCtrlC; /* Previous real mode CtrlC handler */
+static long prevRealCritical; /* Prev real mode critical handler */
+static uchar *mousePtr;
+
+/* The following real mode routine is used to call a 32 bit protected
+ * mode FAR function from real mode. We use this for passing up control
+ * from the real mode mouse callback to our protected mode code.
+ */
+
+static UCHAR realHandler[] = { /* Real mode code generic handler */
+ 0x00,0x00,0x00,0x00, /* __PM_callProtp */
+ 0x00,0x00, /* __PM_protCS */
+ 0x00,0x00,0x00,0x00, /* __PM_protHandler */
+ 0x66,0x60, /* pushad */
+ 0x1E, /* push ds */
+ 0x6A,0x00, /* push 0 */
+ 0x6A,0x00, /* push 0 */
+ 0x2E,0xFF,0x36,0x04,0x00, /* push [cs:__PM_protCS] */
+ 0x66,0x2E,0xFF,0x36,0x06,0x00, /* push [cs:__PM_protHandler] */
+ 0x2E,0xFF,0x1E,0x00,0x00, /* call [cs:__PM_callProtp] */
+ 0x83,0xC4,0x0A, /* add sp,10 */
+ 0x1F, /* pop ds */
+ 0x66,0x61, /* popad */
+ 0xCB, /* retf */
+ };
+
+/* The following functions installs the above realmode callback mechanism
+ * in real mode memory for calling the protected mode routine.
+ */
+
+uchar * installCallback(void (PMAPI *pmCB)(),uint *rseg, uint *roff)
+{
+ CONFIG_INF config;
+ REALPTR realBufAdr,callProtp;
+ ULONG bufSize;
+ FARPTR protBufAdr;
+ uchar *p;
+
+ /* Get address of real mode routine to call up to protected mode */
+ _dx_rmlink_get(&callProtp, &realBufAdr, &bufSize, &protBufAdr);
+ _dx_config_inf(&config, (UCHAR*)&config);
+
+ /* Fill in the values in the real mode code segment so that it will
+ * call the correct routine.
+ */
+ *((REALPTR*)&realHandler[0]) = callProtp;
+ *((USHORT*)&realHandler[4]) = config.c_cs_sel;
+ *((ULONG*)&realHandler[6]) = (ULONG)pmCB;
+
+ /* Copy the real mode handler to real mode memory */
+ if ((p = PM_allocRealSeg(sizeof(realHandler),rseg,roff)) == NULL)
+ return NULL;
+ memcpy(p,realHandler,sizeof(realHandler));
+
+ /* Skip past global variabls in real mode code segment */
+ *roff += 0x0A;
+ return p;
+}
+
+int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+ uint rseg,roff;
+
+ lockPMHandlers(); /* Ensure our handlers are locked */
+
+ if ((mousePtr = installCallback(_PM_mouseISR, &rseg, &roff)) == NULL)
+ return 0;
+ _PM_mouseHandler = mh;
+
+ /* Install the real mode mouse handler */
+ sregs.es = rseg;
+ regs.x.dx = roff;
+ regs.x.cx = _PM_mouseMask = mask;
+ regs.x.ax = 0xC;
+ PM_int86x(0x33, &regs, &regs, &sregs);
+ return 1;
+}
+
+void PMAPI PM_restoreMouseHandler(void)
+{
+ RMREGS regs;
+
+ if (_PM_mouseHandler) {
+ regs.x.ax = 33;
+ PM_int86(0x33, &regs, &regs);
+ PM_freeRealSeg(mousePtr);
+ _PM_mouseHandler = NULL;
+ }
+}
+
+void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
+{
+ FARPTR ph;
+
+ _dx_pmiv_get(intno, &ph);
+ isr->sel = FP_SEL(ph);
+ isr->off = FP_OFF(ph);
+}
+
+void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
+{
+ CONFIG_INF config;
+ FARPTR ph;
+
+ PM_saveDS();
+ _dx_config_inf(&config, (UCHAR*)&config);
+ FP_SET(ph,(uint)isr,config.c_cs_sel);
+ _dx_pmiv_set(intno,ph);
+}
+
+void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
+{
+ FARPTR ph;
+
+ FP_SET(ph,isr.off,isr.sel);
+ _dx_pmiv_set(intno,ph);
+}
+
+static void getISR(int intno, PMFARPTR *pmisr, long *realisr)
+{
+ PM_getPMvect(intno,pmisr);
+ _PM_getRMvect(intno, realisr);
+}
+
+static void restoreISR(int intno, PMFARPTR pmisr, long realisr)
+{
+ _PM_setRMvect(intno,realisr);
+ PM_restorePMvect(intno,pmisr);
+}
+
+static void setISR(int intno, void (PMAPI *isr)())
+{
+ CONFIG_INF config;
+ FARPTR ph;
+
+ lockPMHandlers(); /* Ensure our handlers are locked */
+
+ _dx_config_inf(&config, (UCHAR*)&config);
+ FP_SET(ph,(uint)isr,config.c_cs_sel);
+ _dx_apmiv_set(intno,ph);
+}
+
+void PMAPI PM_setTimerHandler(PM_intHandler th)
+{
+ getISR(0x8, &_PM_prevTimer, &_PM_prevRealTimer);
+ _PM_timerHandler = th;
+ setISR(0x8, _PM_timerISR);
+}
+
+void PMAPI PM_restoreTimerHandler(void)
+{
+ if (_PM_timerHandler) {
+ restoreISR(0x8, _PM_prevTimer, _PM_prevRealTimer);
+ _PM_timerHandler = NULL;
+ }
+}
+
+ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
+{
+ /* Save the old CMOS real time clock values */
+ _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
+ _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
+
+ /* Set the real time clock interrupt handler */
+ getISR(0x70, &_PM_prevRTC, &_PM_prevRealRTC);
+ _PM_rtcHandler = th;
+ setISR(0x70, _PM_rtcISR);
+
+ /* Program the real time clock default frequency */
+ PM_setRealTimeClockFrequency(frequency);
+
+ /* Unmask IRQ8 in the PIC2 */
+ _PM_oldRTCPIC2 = PM_inpb(0xA1);
+ PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE);
+ return true;
+}
+
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ if (_PM_rtcHandler) {
+ /* Restore CMOS registers and mask RTC clock */
+ _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
+ PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE));
+
+ /* Restore the interrupt vector */
+ restoreISR(0x70, _PM_prevRTC, _PM_prevRealRTC);
+ _PM_rtcHandler = NULL;
+ }
+}
+
+void PMAPI PM_setKeyHandler(PM_intHandler kh)
+{
+ getISR(0x9, &_PM_prevKey, &_PM_prevRealKey);
+ _PM_keyHandler = kh;
+ setISR(0x9, _PM_keyISR);
+}
+
+void PMAPI PM_restoreKeyHandler(void)
+{
+ if (_PM_keyHandler) {
+ restoreISR(0x9, _PM_prevKey, _PM_prevRealKey);
+ _PM_keyHandler = NULL;
+ }
+}
+
+void PMAPI PM_setKey15Handler(PM_key15Handler kh)
+{
+ getISR(0x15, &_PM_prevKey15, &_PM_prevRealKey15);
+ _PM_key15Handler = kh;
+ setISR(0x15, _PM_key15ISR);
+}
+
+void PMAPI PM_restoreKey15Handler(void)
+{
+ if (_PM_key15Handler) {
+ restoreISR(0x15, _PM_prevKey15, _PM_prevRealKey15);
+ _PM_key15Handler = NULL;
+ }
+}
+
+void PMAPI PM_installAltBreakHandler(PM_breakHandler bh)
+{
+ static int ctrlCFlag,ctrlBFlag;
+
+ _PM_ctrlCPtr = (uchar*)&ctrlCFlag;
+ _PM_ctrlBPtr = (uchar*)&ctrlBFlag;
+ getISR(0x1B, &_PM_prevBreak, &prevRealBreak);
+ getISR(0x23, &_PM_prevCtrlC, &prevRealCtrlC);
+ _PM_breakHandler = bh;
+ setISR(0x1B, _PM_breakISR);
+ setISR(0x23, _PM_ctrlCISR);
+}
+
+void PMAPI PM_installBreakHandler(void)
+{
+ PM_installAltBreakHandler(NULL);
+}
+
+void PMAPI PM_restoreBreakHandler(void)
+{
+ if (_PM_prevBreak.sel) {
+ restoreISR(0x1B, _PM_prevBreak, prevRealBreak);
+ restoreISR(0x23, _PM_prevCtrlC, prevRealCtrlC);
+ _PM_prevBreak.sel = 0;
+ _PM_breakHandler = NULL;
+ }
+}
+
+void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch)
+{
+ static short critBuf[2];
+
+ _PM_critPtr = (uchar*)critBuf;
+ getISR(0x24, &_PM_prevCritical, &prevRealCritical);
+ _PM_critHandler = ch;
+ setISR(0x24, _PM_criticalISR);
+}
+
+void PMAPI PM_installCriticalHandler(void)
+{
+ PM_installAltCriticalHandler(NULL);
+}
+
+void PMAPI PM_restoreCriticalHandler(void)
+{
+ if (_PM_prevCritical.sel) {
+ restoreISR(0x24, _PM_prevCritical, prevRealCritical);
+ _PM_prevCritical.sel = 0;
+ _PM_critHandler = NULL;
+ }
+}
+
+int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ return (_dx_lock_pgsn(p,len) == 0);
+}
+
+int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ return (_dx_ulock_pgsn(p,len) == 0);
+}
+
+int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ CONFIG_INF config;
+ FARPTR fp;
+
+ _dx_config_inf(&config, (UCHAR*)&config);
+ FP_SET(fp,p,config.c_cs_sel);
+ return (_dx_lock_pgs(fp,len) == 0);
+}
+
+int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ CONFIG_INF config;
+ FARPTR fp;
+
+ _dx_config_inf(&config, (UCHAR*)&config);
+ FP_SET(fp,p,config.c_cs_sel);
+ return (_dx_ulock_pgs(fp,len) == 0);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* Symantec C++ DOSX and FlashTek X-32/X-32VM support */
+/*-------------------------------------------------------------------------*/
+
+#if defined(DOSX) || defined(X32VM)
+
+#ifdef X32VM
+#include <x32.h>
+#endif
+
+static long prevRealBreak; /* Previous real mode break handler */
+static long prevRealCtrlC; /* Previous real mode CtrlC handler */
+static long prevRealCritical; /* Prev real mode critical handler */
+
+static uint mouseSel = 0,mouseOff;
+
+/* The following real mode routine is used to call a 32 bit protected
+ * mode FAR function from real mode. We use this for passing up control
+ * from the real mode mouse callback to our protected mode code.
+ */
+
+static char realHandler[] = { /* Real mode code generic handler */
+ 0x00,0x00,0x00,0x00, /* __PM_callProtp */
+ 0x00,0x00, /* __PM_protCS */
+ 0x00,0x00,0x00,0x00, /* __PM_protHandler */
+ 0x1E, /* push ds */
+ 0x6A,0x00, /* push 0 */
+ 0x6A,0x00, /* push 0 */
+ 0x2E,0xFF,0x36,0x04,0x00, /* push [cs:__PM_protCS] */
+ 0x66,0x2E,0xFF,0x36,0x06,0x00, /* push [cs:__PM_protHandler] */
+ 0x2E,0xFF,0x1E,0x00,0x00, /* call [cs:__PM_callProtp] */
+ 0x83,0xC4,0x0A, /* add sp,10 */
+ 0x1F, /* pop ds */
+ 0xCB, /* retf */
+ };
+
+/* The following functions installs the above realmode callback mechanism
+ * in real mode memory for calling the protected mode routine.
+ */
+
+int installCallback(void (PMAPI *pmCB)(),uint *psel, uint *poff,
+ uint *rseg, uint *roff)
+{
+ PMREGS regs;
+ PMSREGS sregs;
+
+ regs.x.ax = 0x250D;
+ PM_segread(&sregs);
+ PM_int386x(0x21,&regs,&regs,&sregs); /* Get RM callback address */
+
+ /* Fill in the values in the real mode code segment so that it will
+ * call the correct routine.
+ */
+ *((ulong*)&realHandler[0]) = regs.e.eax;
+ *((ushort*)&realHandler[4]) = sregs.cs;
+ *((ulong*)&realHandler[6]) = (ulong)pmCB;
+
+ /* Copy the real mode handler to real mode memory (only allocate the
+ * buffer once since we cant dealloate it with X32).
+ */
+ if (*psel == 0) {
+ if (!PM_allocRealSeg(sizeof(realHandler),psel,poff,rseg,roff))
+ return 0;
+ }
+ PM_memcpyfn(*psel,*poff,realHandler,sizeof(realHandler));
+
+ /* Skip past global variables in real mode code segment */
+ *roff += 0x0A;
+ return 1;
+}
+
+int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+ uint rseg,roff;
+
+ lockPMHandlers(); /* Ensure our handlers are locked */
+
+ if (!installCallback(_PM_mouseISR, &mouseSel, &mouseOff, &rseg, &roff))
+ return 0;
+ _PM_mouseHandler = mh;
+
+ /* Install the real mode mouse handler */
+ sregs.es = rseg;
+ regs.x.dx = roff;
+ regs.x.cx = _PM_mouseMask = mask;
+ regs.x.ax = 0xC;
+ PM_int86x(0x33, &regs, &regs, &sregs);
+ return 1;
+}
+
+void PMAPI PM_restoreMouseHandler(void)
+{
+ RMREGS regs;
+
+ if (_PM_mouseHandler) {
+ regs.x.ax = 33;
+ PM_int86(0x33, &regs, &regs);
+ _PM_mouseHandler = NULL;
+ }
+}
+
+void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
+{
+ PMREGS regs;
+ PMSREGS sregs;
+
+ PM_segread(&sregs);
+ regs.x.ax = 0x2502; /* Get PM interrupt vector */
+ regs.x.cx = intno;
+ PM_int386x(0x21, &regs, &regs, &sregs);
+ isr->sel = sregs.es;
+ isr->off = regs.e.ebx;
+}
+
+void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
+{
+ PMFARPTR pmisr;
+ PMSREGS sregs;
+
+ PM_saveDS();
+ PM_segread(&sregs);
+ pmisr.sel = sregs.cs;
+ pmisr.off = (uint)isr;
+ PM_restorePMvect(intno, pmisr);
+}
+
+void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
+{
+ PMREGS regs;
+ PMSREGS sregs;
+
+ PM_segread(&sregs);
+ regs.x.ax = 0x2505; /* Set PM interrupt vector */
+ regs.x.cx = intno;
+ sregs.ds = isr.sel;
+ regs.e.edx = isr.off;
+ PM_int386x(0x21, &regs, &regs, &sregs);
+}
+
+static void getISR(int intno, PMFARPTR *pmisr, long *realisr)
+{
+ PM_getPMvect(intno,pmisr);
+ _PM_getRMvect(intno,realisr);
+}
+
+static void restoreISR(int intno, PMFARPTR pmisr, long realisr)
+{
+ PMREGS regs;
+ PMSREGS sregs;
+
+ PM_segread(&sregs);
+ regs.x.ax = 0x2507; /* Set real and PM vectors */
+ regs.x.cx = intno;
+ sregs.ds = pmisr.sel;
+ regs.e.edx = pmisr.off;
+ regs.e.ebx = realisr;
+ PM_int386x(0x21, &regs, &regs, &sregs);
+}
+
+static void setISR(int intno, void *isr)
+{
+ PMREGS regs;
+ PMSREGS sregs;
+
+ lockPMHandlers(); /* Ensure our handlers are locked */
+
+ PM_segread(&sregs);
+ regs.x.ax = 0x2506; /* Hook real and protected vectors */
+ regs.x.cx = intno;
+ sregs.ds = sregs.cs;
+ regs.e.edx = (uint)isr;
+ PM_int386x(0x21, &regs, &regs, &sregs);
+}
+
+void PMAPI PM_setTimerHandler(PM_intHandler th)
+{
+ getISR(0x8, &_PM_prevTimer, &_PM_prevRealTimer);
+ _PM_timerHandler = th;
+ setISR(0x8, _PM_timerISR);
+}
+
+void PMAPI PM_restoreTimerHandler(void)
+{
+ if (_PM_timerHandler) {
+ restoreISR(0x8, _PM_prevTimer, _PM_prevRealTimer);
+ _PM_timerHandler = NULL;
+ }
+}
+
+ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
+{
+ /* Save the old CMOS real time clock values */
+ _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
+ _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
+
+ /* Set the real time clock interrupt handler */
+ getISR(0x70, &_PM_prevRTC, &_PM_prevRealRTC);
+ _PM_rtcHandler = th;
+ setISR(0x70, _PM_rtcISR);
+
+ /* Program the real time clock default frequency */
+ PM_setRealTimeClockFrequency(frequency);
+
+ /* Unmask IRQ8 in the PIC2 */
+ _PM_oldRTCPIC2 = PM_inpb(0xA1);
+ PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE);
+ return true;
+}
+
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ if (_PM_rtcHandler) {
+ /* Restore CMOS registers and mask RTC clock */
+ _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
+ PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE));
+
+ /* Restore the interrupt vector */
+ restoreISR(0x70, _PM_prevRTC, _PM_prevRealRTC);
+ _PM_rtcHandler = NULL;
+ }
+}
+
+void PMAPI PM_setKeyHandler(PM_intHandler kh)
+{
+ getISR(0x9, &_PM_prevKey, &_PM_prevRealKey);
+ _PM_keyHandler = kh;
+ setISR(0x9, _PM_keyISR);
+}
+
+void PMAPI PM_restoreKeyHandler(void)
+{
+ if (_PM_keyHandler) {
+ restoreISR(0x9, _PM_prevKey, _PM_prevRealKey);
+ _PM_keyHandler = NULL;
+ }
+}
+
+void PMAPI PM_setKey15Handler(PM_key15Handler kh)
+{
+ getISR(0x15, &_PM_prevKey15, &_PM_prevRealKey15);
+ _PM_key15Handler = kh;
+ setISR(0x15, _PM_key15ISR);
+}
+
+void PMAPI PM_restoreKey15Handler(void)
+{
+ if (_PM_key15Handler) {
+ restoreISR(0x15, _PM_prevKey15, _PM_prevRealKey15);
+ _PM_key15Handler = NULL;
+ }
+}
+
+void PMAPI PM_installAltBreakHandler(PM_breakHandler bh)
+{
+ static int ctrlCFlag,ctrlBFlag;
+
+ _PM_ctrlCPtr = (uchar*)&ctrlCFlag;
+ _PM_ctrlBPtr = (uchar*)&ctrlBFlag;
+ getISR(0x1B, &_PM_prevBreak, &prevRealBreak);
+ getISR(0x23, &_PM_prevCtrlC, &prevRealCtrlC);
+ _PM_breakHandler = bh;
+ setISR(0x1B, _PM_breakISR);
+ setISR(0x23, _PM_ctrlCISR);
+}
+
+void PMAPI PM_installBreakHandler(void)
+{
+ PM_installAltBreakHandler(NULL);
+}
+
+void PMAPI PM_restoreBreakHandler(void)
+{
+ if (_PM_prevBreak.sel) {
+ restoreISR(0x1B, _PM_prevBreak, prevRealBreak);
+ restoreISR(0x23, _PM_prevCtrlC, prevRealCtrlC);
+ _PM_prevBreak.sel = 0;
+ _PM_breakHandler = NULL;
+ }
+}
+
+void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch)
+{
+ static short critBuf[2];
+
+ _PM_critPtr = (uchar*)critBuf;
+ getISR(0x24, &_PM_prevCritical, &prevRealCritical);
+ _PM_critHandler = ch;
+ setISR(0x24, _PM_criticalISR);
+}
+
+void PMAPI PM_installCriticalHandler(void)
+{
+ PM_installAltCriticalHandler(NULL);
+}
+
+void PMAPI PM_restoreCriticalHandler(void)
+{
+ if (_PM_prevCritical.sel) {
+ restoreISR(0x24, _PM_prevCritical, prevRealCritical);
+ _PM_prevCritical.sel = 0;
+ _PM_critHandler = NULL;
+ }
+}
+
+int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ return (_x386_memlock(p,len) == 0);
+}
+
+int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ return (_x386_memunlock(p,len) == 0);
+}
+
+int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ return (_x386_memlock(p,len) == 0);
+}
+
+int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ return (_x386_memunlock(p,len) == 0);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* Borland's DPMI32 DOS Power Pack Extender support. */
+/*-------------------------------------------------------------------------*/
+
+#ifdef DPMI32
+#define GENERIC_DPMI32 /* Use generic 32 bit DPMI routines */
+
+void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
+{
+ PMREGS regs;
+
+ regs.x.ax = 0x204;
+ regs.h.bl = intno;
+ PM_int386(0x31,&regs,&regs);
+ isr->sel = regs.x.cx;
+ isr->off = regs.e.edx;
+}
+
+void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
+{
+ PMSREGS sregs;
+ PMREGS regs;
+
+ PM_saveDS();
+ regs.x.ax = 0x205; /* Set protected mode vector */
+ regs.h.bl = intno;
+ PM_segread(&sregs);
+ regs.x.cx = sregs.cs;
+ regs.e.edx = (uint)isr;
+ PM_int386(0x31,&regs,&regs);
+}
+
+void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
+{
+ PMREGS regs;
+
+ regs.x.ax = 0x205;
+ regs.h.bl = intno;
+ regs.x.cx = isr.sel;
+ regs.e.edx = isr.off;
+ PM_int386(0x31,&regs,&regs);
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* Watcom C/C++ with Rational DOS/4GW support. */
+/*-------------------------------------------------------------------------*/
+
+#ifdef DOS4GW
+#define GENERIC_DPMI32 /* Use generic 32 bit DPMI routines */
+
+#define MOUSE_SUPPORTED /* DOS4GW directly supports mouse */
+
+/* We use the normal DOS services to save and restore interrupts handlers
+ * for Watcom C++, because using the direct DPMI functions does not
+ * appear to work properly. At least if we use the DPMI functions, we
+ * dont get the auto-passup feature that we need to correctly trap
+ * real and protected mode interrupts without installing Bi-model
+ * interrupt handlers.
+ */
+
+void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
+{
+ PMREGS regs;
+ PMSREGS sregs;
+
+ PM_segread(&sregs);
+ regs.h.ah = 0x35;
+ regs.h.al = intno;
+ PM_int386x(0x21,&regs,&regs,&sregs);
+ isr->sel = sregs.es;
+ isr->off = regs.e.ebx;
+}
+
+void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
+{
+ PMREGS regs;
+ PMSREGS sregs;
+
+ PM_saveDS();
+ PM_segread(&sregs);
+ regs.h.ah = 0x25;
+ regs.h.al = intno;
+ sregs.ds = sregs.cs;
+ regs.e.edx = (uint)isr;
+ PM_int386x(0x21,&regs,&regs,&sregs);
+}
+
+void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
+{
+ PMREGS regs;
+ PMSREGS sregs;
+
+ PM_segread(&sregs);
+ regs.h.ah = 0x25;
+ regs.h.al = intno;
+ sregs.ds = isr.sel;
+ regs.e.edx = isr.off;
+ PM_int386x(0x21,&regs,&regs,&sregs);
+}
+
+int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
+{
+ lockPMHandlers(); /* Ensure our handlers are locked */
+
+ _PM_mouseHandler = mh;
+ _PM_setMouseHandler(_PM_mouseMask = mask);
+ return 1;
+}
+
+void PMAPI PM_restoreMouseHandler(void)
+{
+ PMREGS regs;
+
+ if (_PM_mouseHandler) {
+ regs.x.ax = 33;
+ PM_int386(0x33, &regs, &regs);
+ _PM_mouseHandler = NULL;
+ }
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* DJGPP port of GNU C++ support. */
+/*-------------------------------------------------------------------------*/
+
+#ifdef DJGPP
+#define GENERIC_DPMI32 /* Use generic 32 bit DPMI routines */
+
+void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
+{
+ PMREGS regs;
+
+ regs.x.ax = 0x204;
+ regs.h.bl = intno;
+ PM_int386(0x31,&regs,&regs);
+ isr->sel = regs.x.cx;
+ isr->off = regs.e.edx;
+}
+
+void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
+{
+ PMSREGS sregs;
+ PMREGS regs;
+
+ PM_saveDS();
+ regs.x.ax = 0x205; /* Set protected mode vector */
+ regs.h.bl = intno;
+ PM_segread(&sregs);
+ regs.x.cx = sregs.cs;
+ regs.e.edx = (uint)isr;
+ PM_int386(0x31,&regs,&regs);
+}
+
+void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
+{
+ PMREGS regs;
+
+ regs.x.ax = 0x205;
+ regs.h.bl = intno;
+ regs.x.cx = isr.sel;
+ regs.e.edx = isr.off;
+ PM_int386(0x31,&regs,&regs);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* Generic 32 bit DPMI routines */
+/*-------------------------------------------------------------------------*/
+
+#if defined(GENERIC_DPMI32)
+
+static long prevRealBreak; /* Previous real mode break handler */
+static long prevRealCtrlC; /* Previous real mode CtrlC handler */
+static long prevRealCritical; /* Prev real mode critical handler */
+
+#ifndef MOUSE_SUPPORTED
+
+/* The following real mode routine is used to call a 32 bit protected
+ * mode FAR function from real mode. We use this for passing up control
+ * from the real mode mouse callback to our protected mode code.
+ */
+
+static long mouseRMCB; /* Mouse real mode callback address */
+static uchar *mousePtr;
+static char mouseRegs[0x32]; /* Real mode regs for mouse callback */
+static uchar mouseHandler[] = {
+ 0x00,0x00,0x00,0x00, /* _realRMCB */
+ 0x2E,0xFF,0x1E,0x00,0x00, /* call [cs:_realRMCB] */
+ 0xCB, /* retf */
+ };
+
+int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+ uint rseg,roff;
+
+ lockPMHandlers(); /* Ensure our handlers are locked */
+
+ /* Copy the real mode handler to real mode memory */
+ if ((mousePtr = PM_allocRealSeg(sizeof(mouseHandler),&rseg,&roff)) == NULL)
+ return 0;
+ memcpy(mousePtr,mouseHandler,sizeof(mouseHandler));
+ if (!_DPMI_allocateCallback(_PM_mousePMCB, mouseRegs, &mouseRMCB))
+ PM_fatalError("Unable to allocate real mode callback!\n");
+ PM_setLong(mousePtr,mouseRMCB);
+
+ /* Install the real mode mouse handler */
+ _PM_mouseHandler = mh;
+ sregs.es = rseg;
+ regs.x.dx = roff+4;
+ regs.x.cx = _PM_mouseMask = mask;
+ regs.x.ax = 0xC;
+ PM_int86x(0x33, &regs, &regs, &sregs);
+ return 1;
+}
+
+void PMAPI PM_restoreMouseHandler(void)
+{
+ RMREGS regs;
+
+ if (_PM_mouseHandler) {
+ regs.x.ax = 33;
+ PM_int86(0x33, &regs, &regs);
+ PM_freeRealSeg(mousePtr);
+ _DPMI_freeCallback(mouseRMCB);
+ _PM_mouseHandler = NULL;
+ }
+}
+
+#endif
+
+static void getISR(int intno, PMFARPTR *pmisr, long *realisr)
+{
+ PM_getPMvect(intno,pmisr);
+ _PM_getRMvect(intno,realisr);
+}
+
+static void restoreISR(int intno, PMFARPTR pmisr, long realisr)
+{
+ _PM_setRMvect(intno,realisr);
+ PM_restorePMvect(intno,pmisr);
+}
+
+static void setISR(int intno, void (* PMAPI pmisr)())
+{
+ lockPMHandlers(); /* Ensure our handlers are locked */
+ PM_setPMvect(intno,pmisr);
+}
+
+void PMAPI PM_setTimerHandler(PM_intHandler th)
+{
+ getISR(0x8, &_PM_prevTimer, &_PM_prevRealTimer);
+ _PM_timerHandler = th;
+ setISR(0x8, _PM_timerISR);
+}
+
+void PMAPI PM_restoreTimerHandler(void)
+{
+ if (_PM_timerHandler) {
+ restoreISR(0x8, _PM_prevTimer, _PM_prevRealTimer);
+ _PM_timerHandler = NULL;
+ }
+}
+
+ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
+{
+ /* Save the old CMOS real time clock values */
+ _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
+ _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
+
+ /* Set the real time clock interrupt handler */
+ getISR(0x70, &_PM_prevRTC, &_PM_prevRealRTC);
+ _PM_rtcHandler = th;
+ setISR(0x70, _PM_rtcISR);
+
+ /* Program the real time clock default frequency */
+ PM_setRealTimeClockFrequency(frequency);
+
+ /* Unmask IRQ8 in the PIC2 */
+ _PM_oldRTCPIC2 = PM_inpb(0xA1);
+ PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE);
+ return true;
+}
+
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ if (_PM_rtcHandler) {
+ /* Restore CMOS registers and mask RTC clock */
+ _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
+ PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE));
+
+ /* Restore the interrupt vector */
+ restoreISR(0x70, _PM_prevRTC, _PM_prevRealRTC);
+ _PM_rtcHandler = NULL;
+ }
+}
+
+PM_IRQHandle PMAPI PM_setIRQHandler(
+ int IRQ,
+ PM_irqHandler ih)
+{
+ int thunkSize,PICmask,chainPrevious;
+ ulong offsetAdjust;
+ _PM_IRQHandle *handle;
+
+ thunkSize = (ulong)_PM_irqISRTemplateEnd - (ulong)_PM_irqISRTemplate;
+ if ((handle = PM_malloc(sizeof(_PM_IRQHandle) + thunkSize)) == NULL)
+ return NULL;
+ handle->IRQ = IRQ;
+ handle->prevPIC = PM_inpb(0x21);
+ handle->prevPIC2 = PM_inpb(0xA1);
+ if (IRQ < 8) {
+ handle->IRQVect = (IRQ + 8);
+ PICmask = (1 << IRQ);
+ chainPrevious = ((handle->prevPIC & PICmask) == 0);
+ }
+ else {
+ handle->IRQVect = (0x60 + IRQ + 8);
+ PICmask = ((1 << IRQ) | 0x4);
+ chainPrevious = ((handle->prevPIC2 & (PICmask >> 8)) == 0);
+ }
+
+ /* Copy and setup the assembler thunk */
+ offsetAdjust = (ulong)handle->thunk - (ulong)_PM_irqISRTemplate;
+ memcpy(handle->thunk,_PM_irqISRTemplate,thunkSize);
+ *((ulong*)&handle->thunk[2]) = offsetAdjust;
+ *((ulong*)&handle->thunk[11+0]) = (ulong)ih;
+ if (chainPrevious) {
+ *((ulong*)&handle->thunk[11+4]) = handle->prevHandler.off;
+ *((ulong*)&handle->thunk[11+8]) = handle->prevHandler.sel;
+ }
+ else {
+ *((ulong*)&handle->thunk[11+4]) = 0;
+ *((ulong*)&handle->thunk[11+8]) = 0;
+ }
+ *((ulong*)&handle->thunk[11+12]) = IRQ;
+
+ /* Set the real time clock interrupt handler */
+ getISR(handle->IRQVect, &handle->prevHandler, &handle->prevRealhandler);
+ setISR(handle->IRQVect, (PM_intHandler)handle->thunk);
+
+ /* Unmask the IRQ in the PIC */
+ PM_outpb(0xA1,handle->prevPIC2 & ~(PICmask >> 8));
+ PM_outpb(0x21,handle->prevPIC & ~PICmask);
+ return handle;
+}
+
+void PMAPI PM_restoreIRQHandler(
+ PM_IRQHandle irqHandle)
+{
+ int PICmask;
+ _PM_IRQHandle *handle = irqHandle;
+
+ /* Restore PIC mask for the interrupt */
+ if (handle->IRQ < 8)
+ PICmask = (1 << handle->IRQ);
+ else
+ PICmask = ((1 << handle->IRQ) | 0x4);
+ PM_outpb(0xA1,(PM_inpb(0xA1) & ~(PICmask >> 8)) | (handle->prevPIC2 & (PICmask >> 8)));
+ PM_outpb(0x21,(PM_inpb(0x21) & ~PICmask) | (handle->prevPIC & PICmask));
+
+ /* Restore the interrupt vector */
+ restoreISR(handle->IRQVect, handle->prevHandler, handle->prevRealhandler);
+
+ /* Finally free the thunk */
+ PM_free(handle);
+}
+
+void PMAPI PM_setKeyHandler(PM_intHandler kh)
+{
+ getISR(0x9, &_PM_prevKey, &_PM_prevRealKey);
+ _PM_keyHandler = kh;
+ setISR(0x9, _PM_keyISR);
+}
+
+void PMAPI PM_restoreKeyHandler(void)
+{
+ if (_PM_keyHandler) {
+ restoreISR(0x9, _PM_prevKey, _PM_prevRealKey);
+ _PM_keyHandler = NULL;
+ }
+}
+
+void PMAPI PM_setKey15Handler(PM_key15Handler kh)
+{
+ getISR(0x15, &_PM_prevKey15, &_PM_prevRealKey15);
+ _PM_key15Handler = kh;
+ setISR(0x15, _PM_key15ISR);
+}
+
+void PMAPI PM_restoreKey15Handler(void)
+{
+ if (_PM_key15Handler) {
+ restoreISR(0x15, _PM_prevKey15, _PM_prevRealKey15);
+ _PM_key15Handler = NULL;
+ }
+}
+
+/* Real mode Ctrl-C and Ctrl-Break handler. This handler simply sets a
+ * flag in the real mode code segment and exit. We save the location
+ * of this flag in real mode memory so that both the real mode and
+ * protected mode code will be modifying the same flags.
+ */
+
+#ifndef DOS4GW
+static uchar ctrlHandler[] = {
+ 0x00,0x00,0x00,0x00, /* ctrlBFlag */
+ 0x66,0x2E,0xC7,0x06,0x00,0x00,
+ 0x01,0x00,0x00,0x00, /* mov [cs:ctrlBFlag],1 */
+ 0xCF, /* iretf */
+ };
+#endif
+
+void PMAPI PM_installAltBreakHandler(PM_breakHandler bh)
+{
+#ifndef DOS4GW
+ uint rseg,roff;
+#else
+ static int ctrlCFlag,ctrlBFlag;
+
+ _PM_ctrlCPtr = (uchar*)&ctrlCFlag;
+ _PM_ctrlBPtr = (uchar*)&ctrlBFlag;
+#endif
+
+ getISR(0x1B, &_PM_prevBreak, &prevRealBreak);
+ getISR(0x23, &_PM_prevCtrlC, &prevRealCtrlC);
+ _PM_breakHandler = bh;
+ setISR(0x1B, _PM_breakISR);
+ setISR(0x23, _PM_ctrlCISR);
+
+#ifndef DOS4GW
+ /* Hook the real mode vectors for these handlers, as these are not
+ * normally reflected by the DPMI server up to protected mode
+ */
+ _PM_ctrlBPtr = PM_allocRealSeg(sizeof(ctrlHandler)*2, &rseg, &roff);
+ memcpy(_PM_ctrlBPtr,ctrlHandler,sizeof(ctrlHandler));
+ memcpy(_PM_ctrlBPtr+sizeof(ctrlHandler),ctrlHandler,sizeof(ctrlHandler));
+ _PM_ctrlCPtr = _PM_ctrlBPtr + sizeof(ctrlHandler);
+ _PM_setRMvect(0x1B,((long)rseg << 16) | (roff+4));
+ _PM_setRMvect(0x23,((long)rseg << 16) | (roff+sizeof(ctrlHandler)+4));
+#endif
+}
+
+void PMAPI PM_installBreakHandler(void)
+{
+ PM_installAltBreakHandler(NULL);
+}
+
+void PMAPI PM_restoreBreakHandler(void)
+{
+ if (_PM_prevBreak.sel) {
+ restoreISR(0x1B, _PM_prevBreak, prevRealBreak);
+ restoreISR(0x23, _PM_prevCtrlC, prevRealCtrlC);
+ _PM_prevBreak.sel = 0;
+ _PM_breakHandler = NULL;
+#ifndef DOS4GW
+ PM_freeRealSeg(_PM_ctrlBPtr);
+#endif
+ }
+}
+
+/* Real mode Critical Error handler. This handler simply saves the AX and
+ * DI values in the real mode code segment and exits. We save the location
+ * of this flag in real mode memory so that both the real mode and
+ * protected mode code will be modifying the same flags.
+ */
+
+#ifndef DOS4GW
+static uchar criticalHandler[] = {
+ 0x00,0x00, /* axCode */
+ 0x00,0x00, /* diCode */
+ 0x2E,0xA3,0x00,0x00, /* mov [cs:axCode],ax */
+ 0x2E,0x89,0x3E,0x02,0x00, /* mov [cs:diCode],di */
+ 0xB8,0x03,0x00, /* mov ax,3 */
+ 0xCF, /* iretf */
+ };
+#endif
+
+void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch)
+{
+#ifndef DOS4GW
+ uint rseg,roff;
+#else
+ static short critBuf[2];
+
+ _PM_critPtr = (uchar*)critBuf;
+#endif
+
+ getISR(0x24, &_PM_prevCritical, &prevRealCritical);
+ _PM_critHandler = ch;
+ setISR(0x24, _PM_criticalISR);
+
+#ifndef DOS4GW
+ /* Hook the real mode vector, as this is not normally reflected by the
+ * DPMI server up to protected mode.
+ */
+ _PM_critPtr = PM_allocRealSeg(sizeof(criticalHandler)*2, &rseg, &roff);
+ memcpy(_PM_critPtr,criticalHandler,sizeof(criticalHandler));
+ _PM_setRMvect(0x24,((long)rseg << 16) | (roff+4));
+#endif
+}
+
+void PMAPI PM_installCriticalHandler(void)
+{
+ PM_installAltCriticalHandler(NULL);
+}
+
+void PMAPI PM_restoreCriticalHandler(void)
+{
+ if (_PM_prevCritical.sel) {
+ restoreISR(0x24, _PM_prevCritical, prevRealCritical);
+ PM_freeRealSeg(_PM_critPtr);
+ _PM_prevCritical.sel = 0;
+ _PM_critHandler = NULL;
+ }
+}
+
+int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+ return DPMI_lockLinearPages((uint)p + DPMI_getSelectorBase(sregs.ds),len);
+}
+
+int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+ return DPMI_unlockLinearPages((uint)p + DPMI_getSelectorBase(sregs.ds),len);
+}
+
+int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+ return DPMI_lockLinearPages((uint)p + DPMI_getSelectorBase(sregs.cs),len);
+}
+
+int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+ return DPMI_unlockLinearPages((uint)p + DPMI_getSelectorBase(sregs.cs),len);
+}
+
+#endif
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/dos/vflat.c
new file mode 100644
index 0000000000..2e78e25a8b
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/vflat.c
@@ -0,0 +1,251 @@
+/****************************************************************************
+*
+* 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: 32-bit DOS
+*
+* Description: Main C module for the VFlat framebuffer routines. The page
+* fault handler is always installed to handle up to a 4Mb
+* framebuffer with a window size of 4Kb or 64Kb in size.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include <stdlib.h>
+#include <dos.h>
+
+/*-------------------------------------------------------------------------*/
+/* DOS4G/W, PMODE/W and CauseWay support. */
+/*-------------------------------------------------------------------------*/
+
+#if defined(DOS4GW)
+
+#define VFLAT_START_ADDR 0xF0000000U
+#define VFLAT_END_ADDR 0xF03FFFFFU
+#define VFLAT_LIMIT (VFLAT_END_ADDR - VFLAT_START_ADDR)
+#define PAGE_PRESENT 1
+#define PAGE_NOTPRESENT 0
+#define PAGE_READ 0
+#define PAGE_WRITE 2
+
+PRIVATE ibool installed = false;
+PRIVATE ibool haveDPMI = false;
+PUBLIC ibool _ASMAPI VF_haveCauseWay = false;
+PUBLIC uchar * _ASMAPI VF_zeroPtr = NULL;
+
+/* Low level assembler code */
+
+int _ASMAPI InitPaging(void);
+void _ASMAPI ClosePaging(void);
+void _ASMAPI MapPhysical2Linear(ulong pAddr, ulong lAddr, int pages, int flags);
+void _ASMAPI InstallFaultHandler(ulong baseAddr,int bankSize);
+void _ASMAPI RemoveFaultHandler(void);
+void _ASMAPI InstallBankFunc(int codeLen,void *bankFunc);
+
+void * _ASMAPI VF_malloc(uint size)
+{ return PM_malloc(size); }
+
+void _ASMAPI VF_free(void *p)
+{ PM_free(p); }
+
+PRIVATE ibool CheckDPMI(void)
+/****************************************************************************
+*
+* Function: CheckDPMI
+* Returns: True if we are running under DPMI
+*
+****************************************************************************/
+{
+ PMREGS regs;
+
+ if (haveDPMI)
+ return true;
+
+ /* Check if we are running under DPMI in which case we will not be
+ * able to install our page fault handlers. We can however use the
+ * DVA.386 or VFLATD.386 virtual device drivers if they are present.
+ */
+ regs.x.ax = 0xFF00;
+ PM_int386(0x31,&regs,&regs);
+ if (!regs.x.cflag && (regs.e.edi & 8))
+ return (haveDPMI = true);
+ return false;
+}
+
+ibool PMAPI VF_available(void)
+/****************************************************************************
+*
+* Function: VF_available
+* Returns: True if virtual buffer is available, false if not.
+*
+****************************************************************************/
+{
+ if (!VF_zeroPtr)
+ VF_zeroPtr = PM_mapPhysicalAddr(0,0xFFFFFFFF,true);
+ if (CheckDPMI())
+ return false;
+
+ /* Standard DOS4GW, PMODE/W and Causeway */
+ if (InitPaging() == -1)
+ return false;
+ ClosePaging();
+ return true;
+}
+
+void * PMAPI InitDPMI(ulong baseAddr,int bankSize,int codeLen,void *bankFunc)
+/****************************************************************************
+*
+* Function: InitDOS4GW
+* Parameters: baseAddr - Base address of framebuffer bank window
+* bankSize - Physical size of banks in Kb (4 or 64)
+* codeLen - Length of 32 bit bank switch function
+* bankFunc - Pointer to protected mode bank function
+* Returns: Near pointer to virtual framebuffer, or NULL on failure.
+*
+* Description: Installs the virtual linear framebuffer handling for
+* DPMI environments. This requires the DVA.386 or VFLATD.386
+* virtual device drivers to be installed and functioning.
+*
+****************************************************************************/
+{
+ (void)baseAddr;
+ (void)bankSize;
+ (void)codeLen;
+ (void)bankFunc;
+ return NULL;
+}
+
+void * PMAPI InitDOS4GW(ulong baseAddr,int bankSize,int codeLen,void *bankFunc)
+/****************************************************************************
+*
+* Function: InitDOS4GW
+* Parameters: baseAddr - Base address of framebuffer bank window
+* bankSize - Physical size of banks in Kb (4 or 64)
+* codeLen - Length of 32 bit bank switch function
+* bankFunc - Pointer to protected mode bank function
+* Returns: Near pointer to virtual framebuffer, or NULL on failure.
+*
+* Description: Installs the virtual linear framebuffer handling for
+* the DOS4GW extender.
+*
+****************************************************************************/
+{
+ int i;
+
+ if (InitPaging() == -1)
+ return NULL; /* Cannot do hardware paging! */
+
+ /* Map 4MB of video memory into linear address space (read/write) */
+ if (bankSize == 64) {
+ for (i = 0; i < 64; i++) {
+ MapPhysical2Linear(baseAddr,VFLAT_START_ADDR+(i<<16),16,
+ PAGE_WRITE | PAGE_NOTPRESENT);
+ }
+ }
+ else {
+ for (i = 0; i < 1024; i++) {
+ MapPhysical2Linear(baseAddr,VFLAT_START_ADDR+(i<<12),1,
+ PAGE_WRITE | PAGE_NOTPRESENT);
+ }
+ }
+
+ /* Install our page fault handler and banks switch function */
+ InstallFaultHandler(baseAddr,bankSize);
+ InstallBankFunc(codeLen,bankFunc);
+ installed = true;
+ return (void*)VFLAT_START_ADDR;
+}
+
+void * PMAPI VF_init(ulong baseAddr,int bankSize,int codeLen,void *bankFunc)
+/****************************************************************************
+*
+* Function: VF_init
+* Parameters: baseAddr - Base address of framebuffer bank window
+* bankSize - Physical size of banks in Kb (4 or 64)
+* codeLen - Length of 32 bit bank switch function
+* bankFunc - Pointer to protected mode bank function
+* Returns: Near pointer to virtual framebuffer, or NULL on failure.
+*
+* Description: Installs the virtual linear framebuffer handling.
+*
+****************************************************************************/
+{
+ if (installed)
+ return (void*)VFLAT_START_ADDR;
+ if (codeLen > 100)
+ return NULL; /* Bank function is too large! */
+ if (!VF_zeroPtr)
+ VF_zeroPtr = PM_mapPhysicalAddr(0,0xFFFFFFFF,true);
+ if (CheckDPMI())
+ return InitDPMI(baseAddr,bankSize,codeLen,bankFunc);
+ return InitDOS4GW(baseAddr,bankSize,codeLen,bankFunc);
+}
+
+void PMAPI VF_exit(void)
+/****************************************************************************
+*
+* Function: VF_exit
+*
+* Description: Closes down the virtual framebuffer services and
+* restores the previous page fault handler.
+*
+****************************************************************************/
+{
+ if (installed) {
+ if (haveDPMI) {
+ /* DPMI support */
+ }
+ else {
+ /* Standard DOS4GW and PMODE/W support */
+ RemoveFaultHandler();
+ ClosePaging();
+ }
+ installed = false;
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+/* Support mapped out for other compilers. */
+/*-------------------------------------------------------------------------*/
+
+#else
+
+ibool PMAPI VF_available(void)
+{
+ return false;
+}
+
+void * PMAPI VF_init(ulong baseAddr,int bankSize,int codeLen,void *bankFunc)
+{
+ (void)baseAddr;
+ (void)bankSize;
+ (void)codeLen;
+ (void)bankFunc;
+ return NULL;
+}
+
+void PMAPI VF_exit(void)
+{
+}
+
+#endif
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/dos/ztimer.c
new file mode 100644
index 0000000000..960ed06cd7
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/ztimer.c
@@ -0,0 +1,111 @@
+/****************************************************************************
+*
+* 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: MSDOS
+*
+* Description: OS specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+
+/*---------------------------- Global variables ---------------------------*/
+
+uchar * _VARAPI _ZTimerBIOSPtr;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* External assembler functions */
+
+void _ASMAPI LZ_timerOn(void);
+ulong _ASMAPI LZ_timerLap(void);
+void _ASMAPI LZ_timerOff(void);
+ulong _ASMAPI LZ_timerCount(void);
+void _ASMAPI LZ_disable(void);
+void _ASMAPI LZ_enable(void);
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+void __ZTimerInit(void)
+{
+ _ZTimerBIOSPtr = PM_getBIOSPointer();
+}
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOn(tm) LZ_timerOn()
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerLap(tm) LZ_timerLap()
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOff(tm) LZ_timerOff()
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerCount(tm) LZ_timerCount()
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 54925
+
+/****************************************************************************
+REMARKS:
+Read the Long Period timer value from the BIOS timer tick.
+****************************************************************************/
+static ulong __ULZReadTime(void)
+{
+ ulong ticks;
+ LZ_disable(); /* Turn of interrupts */
+ ticks = PM_getLong(_ZTimerBIOSPtr+0x6C);
+ LZ_enable(); /* Turn on interrupts again */
+ return ticks;
+}
+
+/****************************************************************************
+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)
+{
+ if (finish < start)
+ finish += 1573040L; /* Number of ticks in 24 hours */
+ return finish - start;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/event.c b/board/MAI/bios_emulator/scitech/src/pm/event.c
new file mode 100644
index 0000000000..b284c68cfb
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/event.c
@@ -0,0 +1,1115 @@
+/****************************************************************************
+*
+* 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: Main implementation for the SciTech cross platform event
+* library. This module contains all the generic cross platform
+* code, and pulls in modules specific to each target OS
+* environment.
+*
+****************************************************************************/
+
+#include "event.h"
+#include "pmapi.h"
+#include <time.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "oshdr.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+#define EVENTQSIZE 100 /* Number of events in event queue */
+#define JOY_NUM_AXES 4 /* Number of joystick axes supported */
+
+static struct {
+ int mx,my; /* Current mouse position */
+ int head; /* Head of event queue */
+ int tail; /* Tail of event queue */
+ int freeHead; /* Head of free list */
+ int count; /* No. of items currently in queue */
+ event_t evtq[EVENTQSIZE]; /* The queue structure itself */
+ int oldMove; /* Previous movement event */
+ int oldKey; /* Previous key repeat event */
+ int oldJoyMove; /* Previous joystick movement event */
+ int joyMask; /* Mask of joystick axes present */
+ int joyMin[JOY_NUM_AXES];
+ int joyCenter[JOY_NUM_AXES];
+ int joyMax[JOY_NUM_AXES];
+ int joyPrev[JOY_NUM_AXES];
+ int joyButState;
+ ulong doubleClick;
+ ulong autoRepeat;
+ ulong autoDelay;
+ ulong autoTicks;
+ ulong doubleClickThresh;
+ ulong firstAuto;
+ int autoMouse_x;
+ int autoMouse_y;
+ event_t downMouse;
+ ulong keyModifiers; /* Current keyboard modifiers */
+ uchar keyTable[128]; /* Table of key up/down flags */
+ ibool allowLEDS; /* True if LEDS should change */
+ _EVT_userEventFilter userEventCallback;
+ _EVT_mouseMoveHandler mouseMove;
+ _EVT_heartBeatCallback heartBeat;
+ void *heartBeatParams;
+ codepage_t *codePage;
+ } EVT;
+
+/*---------------------------- Implementation -----------------------------*/
+
+#if defined(__REALDOS__) || defined(__SMX32__)
+/* {secret} */
+void EVTAPI _EVT_cCodeStart(void) {}
+#endif
+
+/* External assembler functions */
+
+int EVTAPI _EVT_readJoyAxis(int mask,int *axis);
+int EVTAPI _EVT_readJoyButtons(void);
+
+/* Forward declaration */
+
+ulong _EVT_getTicks(void);
+
+/****************************************************************************
+PARAMETERS:
+evt - Event to add to the 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.
+
+NOTE: Interrupts MUST be OFF while this routine is called to ensure we have
+ mutually exclusive access to our internal data structures for
+ interrupt driven systems (like under DOS).
+****************************************************************************/
+static void addEvent(
+ event_t *evt)
+{
+ int evtID;
+
+ /* Check for mouse double click events */
+ if (evt->what & EVT_MOUSEEVT) {
+ EVT.autoMouse_x = evt->where_x;
+ EVT.autoMouse_y = evt->where_y;
+ if ((evt->what & EVT_MOUSEDOWN) && !(evt->message & EVT_DBLCLICK)) {
+ /* Determine if the last mouse event was a double click event */
+ uint diff_x = ABS(evt->where_x - EVT.downMouse.where_x);
+ uint diff_y = ABS(evt->where_y - EVT.downMouse.where_y);
+ if ((evt->message == EVT.downMouse.message)
+ && ((evt->when - EVT.downMouse.when) <= EVT.doubleClick)
+ && (diff_x <= EVT.doubleClickThresh)
+ && (diff_y <= EVT.doubleClickThresh)) {
+ evt->message |= EVT_DBLCLICK;
+ EVT.downMouse = *evt;
+ EVT.downMouse.when = 0;
+ }
+ else
+ EVT.downMouse = *evt;
+ EVT.autoTicks = _EVT_getTicks();
+ }
+ else if (evt->what & EVT_MOUSEUP) {
+ EVT.downMouse.what = EVT_NULLEVT;
+ EVT.firstAuto = true;
+ }
+ }
+
+ /* Call user supplied callback to modify the event if desired */
+ if (EVT.userEventCallback) {
+ if (!EVT.userEventCallback(evt))
+ return;
+ }
+
+ /* Get spot to place the event from the free list */
+ evtID = EVT.freeHead;
+ EVT.freeHead = EVT.evtq[EVT.freeHead].next;
+
+ /* Add to the EVT.tail of the event queue */
+ evt->next = -1;
+ evt->prev = EVT.tail;
+ if (EVT.tail != -1)
+ EVT.evtq[EVT.tail].next = evtID;
+ else
+ EVT.head = evtID;
+ EVT.tail = evtID;
+ EVT.evtq[evtID] = *evt;
+ EVT.count++;
+}
+
+/****************************************************************************
+REMARKS:
+Internal function to initialise the event queue to the empty state.
+****************************************************************************/
+static void initEventQueue(void)
+{
+ int i;
+
+ /* Build free list, and initialize global data structures */
+ for (i = 0; i < EVENTQSIZE; i++)
+ EVT.evtq[i].next = i+1;
+ EVT.evtq[EVENTQSIZE-1].next = -1; /* Terminate list */
+ EVT.count = EVT.freeHead = 0;
+ EVT.head = EVT.tail = -1;
+ EVT.oldMove = -1;
+ EVT.oldKey = -1;
+ EVT.oldJoyMove = -1;
+ EVT.joyButState = 0;
+ EVT.mx = EVT.my = 0;
+ EVT.keyModifiers = 0;
+ EVT.allowLEDS = true;
+
+ /* Set default values for mouse double click and mouse auto events */
+ EVT.doubleClick = 440;
+ EVT.autoRepeat = 55;
+ EVT.autoDelay = 330;
+ EVT.autoTicks = 0;
+ EVT.doubleClickThresh = 5;
+ EVT.firstAuto = true;
+ EVT.autoMouse_x = EVT.autoMouse_y = 0;
+ memset(&EVT.downMouse,0,sizeof(EVT.downMouse));
+
+ /* Setup default pointers for event library */
+ EVT.userEventCallback = NULL;
+ EVT.codePage = &_CP_US_English;
+
+ /* Initialise the joystick module and do basic calibration (which assumes
+ * the joystick is centered.
+ */
+ EVT.joyMask = EVT_joyIsPresent();
+}
+
+#if defined(NEED_SCALE_JOY_AXIS) || !defined(USE_OS_JOYSTICK)
+/****************************************************************************
+REMARKS:
+This function scales a joystick axis value to normalised form.
+****************************************************************************/
+static int scaleJoyAxis(
+ int raw,
+ int axis)
+{
+ int scaled,range;
+
+ /* Make sure the joystick is calibrated properly */
+ if (EVT.joyCenter[axis] - EVT.joyMin[axis] < 5)
+ return raw;
+ if (EVT.joyMax[axis] - EVT.joyCenter[axis] < 5)
+ return raw;
+
+ /* Now scale the coordinates to -128 to 127 */
+ raw -= EVT.joyCenter[axis];
+ if (raw < 0)
+ range = EVT.joyCenter[axis]-EVT.joyMin[axis];
+ else
+ range = EVT.joyMax[axis]-EVT.joyCenter[axis];
+ scaled = (raw * 128) / range;
+ if (scaled < -128)
+ scaled = -128;
+ if (scaled > 127)
+ scaled = 127;
+ return scaled;
+}
+#endif
+
+#if defined(__SMX32__)
+#include "smx/event.c"
+#elif defined(__RTTARGET__)
+#include "rttarget/event.c"
+#elif defined(__REALDOS__)
+#include "dos/event.c"
+#elif defined(__WINDOWS32__)
+#include "win32/event.c"
+#elif defined(__OS2__)
+#if defined(__OS2_PM__)
+#include "os2pm/event.c"
+#else
+#include "os2/event.c"
+#endif
+#elif defined(__LINUX__)
+#if defined(__USE_X11__)
+#include "x11/event.c"
+#else
+#include "linux/event.c"
+#endif
+#elif defined(__QNX__)
+#if defined(__USE_PHOTON__)
+#include "photon/event.c"
+#elif defined(__USE_X11__)
+#include "x11/event.c"
+#else
+#include "qnx/event.c"
+#endif
+#elif defined(__BEOS__)
+#include "beos/event.c"
+#else
+#error Event library not ported to this platform yet!
+#endif
+
+/*------------------------ Public interface routines ----------------------*/
+
+/* If USE_OS_JOYSTICK is defined, the OS specific libraries will implement
+ * the joystick code rather than using the generic OS portable version.
+ */
+
+#ifndef USE_OS_JOYSTICK
+/****************************************************************************
+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)
+{
+ int mask,i;
+
+ 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;
+#ifdef __LINUX__
+ PM_init();
+#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 (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 click 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
+
+/****************************************************************************
+DESCRIPTION:
+Posts a user defined event to the event queue
+
+HEADER:
+event.h
+
+RETURNS:
+True if event was posted, false if event queue is full.
+
+PARAMETERS:
+what - Type code for message to post
+message - Event specific message to post
+modifiers - Event specific modifier flags to post
+
+REMARKS:
+This routine is used to post user defined events to the event queue.
+
+SEE ALSO:
+EVT_flush, EVT_getNext, EVT_peekNext, EVT_halt
+****************************************************************************/
+ibool EVTAPI EVT_post(
+ ulong which,
+ ulong what,
+ ulong message,
+ ulong modifiers)
+{
+ event_t evt;
+ uint ps;
+
+ if (EVT.count < EVENTQSIZE) {
+ /* Save information in event record */
+ ps = _EVT_disableInt();
+ evt.which = which;
+ evt.when = _EVT_getTicks();
+ evt.what = what;
+ evt.message = message;
+ evt.modifiers = modifiers;
+ addEvent(&evt); /* Add to EVT.tail of event queue */
+ _EVT_restoreInt(ps);
+ return true;
+ }
+ else
+ return false;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Flushes all events of a specified type from the event queue.
+
+PARAMETERS:
+mask - Mask specifying the types of events that should be removed
+
+HEADER:
+event.h
+
+REMARKS:
+Flushes (removes) all pending events of the specified type from the event
+queue. You may combine the masks for different event types with a simple
+logical OR.
+
+SEE ALSO:
+EVT_getNext, EVT_halt, EVT_peekNext
+****************************************************************************/
+void EVTAPI EVT_flush(
+ ulong mask)
+{
+ event_t evt;
+
+ do { /* Flush all events */
+ EVT_getNext(&evt,mask);
+ } while (evt.what != EVT_NULLEVT);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Halts until and event of the specified type is recieved.
+
+HEADER:
+event.h
+
+PARAMETERS:
+evt - Pointer to
+mask - Mask specifying the types of events that should be removed
+
+REMARKS:
+This functions halts exceution until an event of the specified type is
+recieved into the event queue. It does not flush the event queue of events
+before performing the busy loop. However this function does throw away
+any events other than the ones you have requested via the event mask, to
+avoid the event queue filling up with unwanted events (like EVT_KEYUP or
+EVT_MOUSEMOVE events).
+
+SEE ALSO:
+EVT_getNext, EVT_flush, EVT_peekNext
+****************************************************************************/
+void EVTAPI EVT_halt(
+ event_t *evt,
+ ulong mask)
+{
+ do { /* Wait for an event */
+ if (mask & (EVT_JOYEVT))
+ EVT_pollJoystick();
+ EVT_getNext(evt,EVT_EVERYEVT);
+ } while (!(evt->what & mask));
+}
+
+/****************************************************************************
+DESCRIPTION:
+Peeks at the next pending event in the event queue.
+
+HEADER:
+event.h
+
+RETURNS:
+True if an event is pending, false if not.
+
+PARAMETERS:
+evt - Pointer to structure to return the event info in
+mask - Mask specifying the types of events that should be removed
+
+REMARKS:
+Peeks at the next pending event of the specified type in the event queue. The
+mask parameter is used to specify the type of events to be peeked at, and
+can be any logical combination of any of the flags defined by the
+EVT_eventType enumeration.
+
+In contrast to EVT_getNext, the event is not removed from the event queue.
+You may combine the masks for different event types with a simple logical OR.
+
+SEE ALSO:
+EVT_flush, EVT_getNext, EVT_halt
+****************************************************************************/
+ibool EVTAPI EVT_peekNext(
+ event_t *evt,
+ ulong mask)
+{
+ int evtID;
+ uint ps;
+
+ if (EVT.heartBeat)
+ EVT.heartBeat(EVT.heartBeatParams);
+ _EVT_pumpMessages(); /* Pump all messages into queue */
+ EVT.mouseMove(EVT.mx,EVT.my); /* Move the mouse cursor */
+ evt->what = EVT_NULLEVT; /* Default to null event */
+ if (EVT.count) {
+ /* It is possible that an event be posted while we are trying
+ * to access the event queue. This would create problems since
+ * we may end up with invalid data for our event queue pointers. To
+ * alleviate this, all interrupts are suspended while we manipulate
+ * our pointers.
+ */
+ ps = _EVT_disableInt(); /* disable interrupts */
+ for (evtID = EVT.head; evtID != -1; evtID = EVT.evtq[evtID].next) {
+ if (EVT.evtq[evtID].what & mask)
+ break; /* Found an event */
+ }
+ if (evtID == -1) {
+ _EVT_restoreInt(ps);
+ return false; /* Event was not found */
+ }
+ *evt = EVT.evtq[evtID]; /* Return the event */
+ _EVT_restoreInt(ps);
+ if (evt->what & EVT_KEYEVT)
+ _EVT_maskKeyCode(evt);
+ }
+ return evt->what != EVT_NULLEVT;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Retrieves the next pending event from the event queue.
+
+PARAMETERS:
+evt - Pointer to structure to return the event info in
+mask - Mask specifying the types of events that should be removed
+
+HEADER:
+event.h
+
+RETURNS:
+True if an event was pending, false if not.
+
+REMARKS:
+Retrieves the next pending event from the event queue, and stores it in a
+event_t structure. The mask parameter is used to specify the type of events
+to be removed, and can be any logical combination of any of the flags defined
+by the EVT_eventType enumeration.
+
+The what field of the event contains the event code of the event that was
+extracted. All application specific events should begin with the EVT_USEREVT
+code and build from there. Since the event code is stored in an integer,
+there is a maximum of 32 different event codes that can be distinguished.
+You can store extra information about the event in the message field to
+distinguish between events of the same class (for instance the button used in
+a EVT_MOUSEDOWN event).
+
+If an event of the specified type was not in the event queue, the what field
+of the event will be set to NULLEVT, and the return value will return false.
+
+Note: You should /always/ use the EVT_EVERYEVT mask for extracting events
+ from your main event loop handler. Using a mask for only a specific
+ type of event for long periods of time will cause the event queue to
+ fill up with events of the type you are ignoring, eventually causing
+ the application to hang when the event queue becomes full.
+
+SEE ALSO:
+EVT_flush, EVT_halt, EVT_peekNext
+****************************************************************************/
+ibool EVTAPI EVT_getNext(
+ event_t *evt,
+ ulong mask)
+{
+ int evtID,next,prev;
+ uint ps;
+
+ if (EVT.heartBeat)
+ EVT.heartBeat(EVT.heartBeatParams);
+ _EVT_pumpMessages(); /* Pump all messages into queue */
+ EVT.mouseMove(EVT.mx,EVT.my); /* Move the mouse cursor */
+ evt->what = EVT_NULLEVT; /* Default to null event */
+ if (EVT.count) {
+ /* It is possible that an event be posted while we are trying
+ * to access the event queue. This would create problems since
+ * we may end up with invalid data for our event queue pointers. To
+ * alleviate this, all interrupts are suspended while we manipulate
+ * our pointers.
+ */
+ ps = _EVT_disableInt(); /* disable interrupts */
+ for (evtID = EVT.head; evtID != -1; evtID = EVT.evtq[evtID].next) {
+ if (EVT.evtq[evtID].what & mask)
+ break; /* Found an event */
+ }
+ if (evtID == -1) {
+ _EVT_restoreInt(ps);
+ return false; /* Event was not found */
+ }
+ next = EVT.evtq[evtID].next;
+ prev = EVT.evtq[evtID].prev;
+ if (prev != -1)
+ EVT.evtq[prev].next = next;
+ else
+ EVT.head = next;
+ if (next != -1)
+ EVT.evtq[next].prev = prev;
+ else
+ EVT.tail = prev;
+ *evt = EVT.evtq[evtID]; /* Return the event */
+ EVT.evtq[evtID].next = EVT.freeHead; /* and return to free list */
+ EVT.freeHead = evtID;
+ EVT.count--;
+ if (evt->what == EVT_MOUSEMOVE)
+ EVT.oldMove = -1;
+ if (evt->what == EVT_KEYREPEAT)
+ EVT.oldKey = -1;
+ if (evt->what == EVT_JOYMOVE)
+ EVT.oldJoyMove = -1;
+ _EVT_restoreInt(ps); /* enable interrupts */
+ if (evt->what & EVT_KEYEVT)
+ _EVT_maskKeyCode(evt);
+ }
+
+ /* If there is no event pending, check if we should generate an auto
+ * mouse down event if the mouse is still currently down.
+ */
+ if (evt->what == EVT_NULLEVT && EVT.autoRepeat && (mask & EVT_MOUSEAUTO) && (EVT.downMouse.what & EVT_MOUSEDOWN)) {
+ ulong ticks = _EVT_getTicks();
+ if ((ticks - EVT.autoTicks) >= (EVT.autoRepeat + (EVT.firstAuto ? EVT.autoDelay : 0))) {
+ evt->what = EVT_MOUSEAUTO;
+ evt->message = EVT.downMouse.message;
+ evt->modifiers = EVT.downMouse.modifiers;
+ evt->where_x = EVT.autoMouse_x;
+ evt->where_y = EVT.autoMouse_y;
+ evt->relative_x = 0;
+ evt->relative_y = 0;
+ EVT.autoTicks = evt->when = ticks;
+ EVT.firstAuto = false;
+ }
+ }
+ return evt->what != EVT_NULLEVT;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Installs a user supplied event filter callback for event handling.
+
+HEADER:
+event.h
+
+PARAMETERS:
+userEventFilter - Address of user supplied event filter callback
+
+REMARKS:
+This function allows the application programmer to install an event filter
+callback for event handling. Once you install your callback, the MGL
+event handling routines will call your callback with a pointer to the
+new event that will be placed into the event queue. Your callback can the
+modify the contents of the event before it is placed into the queue (for
+instance adding custom information or perhaps high precision timing
+information).
+
+If your callback returns FALSE, the event will be ignore and will not be
+posted to the event queue. You should always return true from your event
+callback unless you plan to use the events immediately that they are
+recieved.
+
+Note: Your event callback may be called in response to a hardware
+ interrupt and will be executing in the context of the hardware
+ interrupt handler under MSDOS (ie: keyboard interrupt or mouse
+ interrupt). For this reason the code pages for the callback that
+ you register must be locked in memory with the PM_lockCodePages
+ function. You must also lock down any data pages that your function
+ needs to reference as well.
+
+Note: You can also use this filter callback to process events at the
+ time they are activated by the user (ie: when the user hits the
+ key or moves the mouse), but make sure your code runs as fast as
+ possible as it will be executing inside the context of an interrupt
+ handler on some systems.
+
+SEE ALSO:
+EVT_getNext, EVT_peekNext
+****************************************************************************/
+void EVTAPI EVT_setUserEventFilter(
+ _EVT_userEventFilter filter)
+{
+ EVT.userEventCallback = filter;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Installs a user supplied event heartbeat callback function.
+
+HEADER:
+event.h
+
+PARAMETERS:
+callback - Address of user supplied event heartbeat callback
+params - Parameters to pass to the event heartbeat function
+
+REMARKS:
+This function allows the application programmer to install an event heatbeat
+function that gets called every time that EVT_getNext or EVT_peekNext
+is called. This is primarily useful for simulating text mode cursors inside
+event handling code when running in graphics modes as opposed to hardware
+text modes.
+
+SEE ALSO:
+EVT_getNext, EVT_peekNext, EVT_getHeartBeatCallback
+****************************************************************************/
+void EVTAPI EVT_setHeartBeatCallback(
+ _EVT_heartBeatCallback callback,
+ void *params)
+{
+ EVT.heartBeat = callback;
+ EVT.heartBeatParams = params;
+}
+
+
+/****************************************************************************
+DESCRIPTION:
+Returns the current user supplied event heartbeat callback function.
+
+HEADER:
+event.h
+
+PARAMETERS:
+callback - Place to store the address of user supplied event heartbeat callback
+params - Place to store the parameters to pass to the event heartbeat function
+
+REMARKS:
+This function retrieves the current event heatbeat function that gets called
+every time that EVT_getNext or EVT_peekNext is called.
+
+SEE ALSO:
+EVT_getNext, EVT_peekNext, EVT_setHeartBeatCallback
+****************************************************************************/
+void EVTAPI EVT_getHeartBeatCallback(
+ _EVT_heartBeatCallback *callback,
+ void **params)
+{
+ *callback = EVT.heartBeat;
+ *params = EVT.heartBeatParams;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Determines if a specified key is currently down.
+
+PARAMETERS:
+scanCode - Scan code to test
+
+RETURNS:
+True of the specified key is currently held down.
+
+HEADER:
+event.h
+
+REMARKS:
+This function determines if a specified key is currently down at the
+time that the call is made. You simply need to pass in the scan code of
+the key that you wish to test, and the MGL will tell you if it is currently
+down or not. The MGL does this by keeping track of the up and down state
+of all the keys.
+****************************************************************************/
+ibool EVTAPI EVT_isKeyDown(
+ uchar scanCode)
+{
+ return _EVT_isKeyDown(scanCode);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Set the mouse position for the event module
+
+PARAMETERS:
+x - X coordinate to move the mouse cursor position to
+y - Y coordinate to move the mouse cursor position to
+
+HEADER:
+event.h
+
+REMARKS:
+This function moves the mouse cursor position for the event module to the
+specified location.
+
+SEE ALSO:
+EVT_getMousePos
+****************************************************************************/
+void EVTAPI EVT_setMousePos(
+ int x,
+ int y)
+{
+ EVT.mx = x;
+ EVT.my = y;
+ _EVT_setMousePos(&EVT.mx,&EVT.my);
+ EVT.mouseMove(EVT.mx,EVT.my);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns the current mouse cursor location.
+
+HEADER:
+event.h
+
+PARAMETERS:
+x - Place to store value for mouse x coordinate (screen coordinates)
+y - Place to store value for mouse y coordinate (screen coordinates)
+
+REMARKS:
+Obtains the current mouse cursor position in screen coordinates. Normally the
+mouse cursor location is tracked using the mouse movement events that are
+posted to the event queue when the mouse moves, however this routine
+provides an alternative method of polling the mouse cursor location.
+
+SEE ALSO:
+EVT_setMousePos
+****************************************************************************/
+void EVTAPI EVT_getMousePos(
+ int *x,
+ int *y)
+{
+ *x = EVT.mx;
+ *y = EVT.my;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns the currently active code page for translation of keyboard characters.
+
+HEADER:
+event.h
+
+RETURNS:
+Pointer to the currently active code page translation table.
+
+REMARKS:
+This function is returns a pointer to the currently active code page
+translation table. See EVT_setCodePage for more information.
+
+SEE ALSO:
+EVT_setCodePage
+****************************************************************************/
+codepage_t * EVTAPI EVT_getCodePage(void)
+{
+ return EVT.codePage;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Sets the currently active code page for translation of keyboard characters.
+
+HEADER:
+event.h
+
+PARAMETERS:
+page - New code page to make active
+
+REMARKS:
+This function is used to set a new code page translation table that is used
+to translate virtual scan code values to ASCII characters for different
+keyboard configurations. The default is usually US English, although if
+possible the PM library will auto-detect the correct code page translation
+for the target OS if OS services are available to determine what type of
+keyboard is currently attached.
+
+SEE ALSO:
+EVT_getCodePage
+****************************************************************************/
+void EVTAPI EVT_setCodePage(
+ codepage_t *page)
+{
+ EVT.codePage = page;
+}
+
+/* The following contains fake C prototypes and documentation for the
+ * macro functions in the event.h header file. These exist soley so
+ * that DocJet will correctly pull in the documentation for these functions.
+ */
+#ifdef INCLUDE_DOC_FUNCTIONS
+
+/****************************************************************************
+DESCRIPTION:
+Macro to extract the ASCII code from a message.
+
+PARAMETERS:
+message - Message to extract ASCII code from
+
+RETURNS:
+ASCII code extracted from the message.
+
+HEADER:
+event.h
+
+REMARKS:
+Macro to extract the ASCII code from the message field of the event_t
+structure. You pass the message field to the macro as the parameter and
+the ASCII code is the result, for example:
+
+ event_t EVT.myEvent;
+ uchar code;
+ code = EVT_asciiCode(EVT.myEvent.message);
+
+SEE ALSO:
+EVT_scanCode, EVT_repeatCount
+****************************************************************************/
+uchar EVT_asciiCode(
+ ulong message);
+
+/****************************************************************************
+DESCRIPTION:
+Macro to extract the keyboard scan code from a message.
+
+HEADER:
+event.h
+
+PARAMETERS:
+message - Message to extract scan code from
+
+RETURNS:
+Keyboard scan code extracted from the message.
+
+REMARKS:
+Macro to extract the keyboard scan code from the message field of the event
+structure. You pass the message field to the macro as the parameter and
+the scan code is the result, for example:
+
+ event_t EVT.myEvent;
+ uchar code;
+ code = EVT_scanCode(EVT.myEvent.message);
+
+NOTE: Scan codes in the event library are not really hardware scan codes,
+ but rather virtual scan codes as generated by a low level keyboard
+ interface driver. All virtual scan code values are defined by the
+ EVT_scanCodesType enumeration, and will be identical across all
+ supports OS'es and platforms.
+
+SEE ALSO:
+EVT_asciiCode, EVT_repeatCount
+****************************************************************************/
+uchar EVT_scanCode(
+ ulong message);
+
+/****************************************************************************
+DESCRIPTION:
+Macro to extract the repeat count from a message.
+
+HEADER:
+event.h
+
+PARAMETERS:
+message - Message to extract repeat count from
+
+RETURNS:
+Repeat count extracted from the message.
+
+REMARKS:
+Macro to extract the repeat count from the message field of the event
+structure. The repeat count is the number of times that the key repeated
+before there was another keyboard event to be place in the queue, and
+allows the event handling code to avoid keyboard buffer overflow
+conditions when a single key is held down by the user. If you are processing
+a key repeat code, you will probably want to check this field to see how
+many key repeats you should process for this message.
+
+SEE ALSO:
+EVT_asciiCode, EVT_repeatCount
+****************************************************************************/
+short EVT_repeatCount(
+ ulong message);
+
+#endif /* DOC FUNCTIONS */
+
+#if defined(__REALDOS__) || defined(__SMX32__)
+/* {secret} */
+void EVTAPI _EVT_cCodeEnd(void) {}
+#endif
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/linux/cpuinfo.c
new file mode 100644
index 0000000000..e88d210954
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/cpuinfo.c
@@ -0,0 +1,68 @@
+/****************************************************************************
+*
+* Ultra Long Period Timer
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Linux
+*
+* Description: Linux specific code for the CPU detection module.
+*
+****************************************************************************/
+
+#include <ztimer.h>
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+TODO: We should implement this for Linux!
+****************************************************************************/
+#define SetMaxThreadPriority() 0
+
+/****************************************************************************
+REMARKS:
+TODO: We should implement this for Linux!
+****************************************************************************/
+#define RestoreThreadPriority(i)
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ freq->low = 1000000;
+ freq->high = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ struct timeval tv; \
+ gettimeofday(&tv,NULL); \
+ (t)->low = tv.tv_sec*1000000 + tv.tv_usec; \
+ (t)->high = 0; \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/event.c b/board/MAI/bios_emulator/scitech/src/pm/linux/event.c
new file mode 100644
index 0000000000..c2668ceb88
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/event.c
@@ -0,0 +1,1361 @@
+/****************************************************************************
+*
+* SciTech Multi-platform Graphics Library
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Linux
+*
+* Description: Linux fullscreen console implementation for the SciTech
+* cross platform event library.
+* Portions ripped straigth from the gpm source code for mouse
+* handling.
+*
+****************************************************************************/
+
+/*---------------------------- Global Variables ---------------------------*/
+
+extern int _PM_console_fd;
+static ushort keyUpMsg[256] = {0};
+static int _EVT_mouse_fd = 0;
+static int range_x, range_y;
+static int opt_baud = 1200, opt_sample = 100;
+#ifdef USE_OS_JOYSTICK
+static short *axis0 = NULL, *axis1 = NULL;
+static uchar *buts0 = NULL, *buts1 = NULL;
+static int joystick0_fd = 0, joystick1_fd = 0;
+static int js_version = 0;
+#endif
+
+/* This defines the supported mouse drivers */
+
+typedef enum {
+ EVT_noMouse = -1,
+ EVT_microsoft = 0,
+ EVT_ps2,
+ EVT_mousesystems,
+ EVT_gpm,
+ EVT_MMseries,
+ EVT_logitech,
+ EVT_busmouse,
+ EVT_mouseman,
+ EVT_intellimouse,
+ EVT_intellimouse_ps2,
+ } mouse_drivers_t;
+
+static mouse_drivers_t mouse_driver = EVT_noMouse;
+static char mouse_dev[20] = "/dev/mouse";
+
+typedef struct {
+ char *name;
+ int flags;
+ void (*init)(void);
+ uchar proto[4];
+ int packet_len;
+ int read;
+ } mouse_info;
+
+#define STD_FLG (CREAD | CLOCAL | HUPCL)
+
+static void _EVT_mouse_init(void);
+static void _EVT_logitech_init(void);
+static void _EVT_pnpmouse_init(void);
+
+mouse_info mouse_infos[] = {
+ {"Microsoft", CS7 | B1200 | STD_FLG, _EVT_mouse_init, {0x40, 0x40, 0x40, 0x00}, 3, 1},
+ {"PS2", STD_FLG, NULL, {0xc0, 0x00, 0x00, 0x00}, 3, 1},
+ {"MouseSystems", CS8 | CSTOPB | STD_FLG, _EVT_mouse_init, {0xf8, 0x80, 0x00, 0x00}, 5, 5},
+ {"GPM", CS8 | CSTOPB | STD_FLG, NULL, {0xf8, 0x80, 0x00, 0x00}, 5, 5},
+ {"MMSeries", CS8 | PARENB | PARODD | STD_FLG, _EVT_mouse_init, {0xe0, 0x80, 0x80, 0x00}, 3, 1},
+ {"Logitech", CS8 | CSTOPB | STD_FLG, _EVT_logitech_init, {0xe0, 0x80, 0x80, 0x00}, 3, 3},
+ {"BusMouse", STD_FLG, NULL, {0xf8, 0x80, 0x00, 0x00}, 3, 3},
+ {"MouseMan", CS7 | STD_FLG, _EVT_mouse_init, {0x40, 0x40, 0x40, 0x00}, 3, 1},
+ {"IntelliMouse", CS7 | STD_FLG, _EVT_pnpmouse_init, {0xc0, 0x40, 0xc0, 0x00}, 4, 1},
+ {"IMPS2", CS7 | STD_FLG, NULL, {0xc0, 0x40, 0xc0, 0x00}, 4, 1}, // ?
+ };
+
+#define NB_MICE (sizeof(mouse_infos)/sizeof(mouse_info))
+
+/* The name of the environment variables that are used to change the defaults above */
+
+#define ENV_MOUSEDRV "MGL_MOUSEDRV"
+#define ENV_MOUSEDEV "MGL_MOUSEDEV"
+#define ENV_MOUSESPD "MGL_MOUSESPD"
+#define ENV_JOYDEV0 "MGL_JOYDEV1"
+#define ENV_JOYDEV1 "MGL_JOYDEV2"
+
+/* Scancode mappings on Linux for special keys */
+
+typedef struct {
+ int scan;
+ int map;
+ } keymap;
+
+// TODO: Fix this and set it up so we can do a binary search!
+
+keymap keymaps[] = {
+ {96, KB_padEnter},
+ {74, KB_padMinus},
+ {78, KB_padPlus},
+ {55, KB_padTimes},
+ {98, KB_padDivide},
+ {71, KB_padHome},
+ {72, KB_padUp},
+ {73, KB_padPageUp},
+ {75, KB_padLeft},
+ {76, KB_padCenter},
+ {77, KB_padRight},
+ {79, KB_padEnd},
+ {80, KB_padDown},
+ {81, KB_padPageDown},
+ {82, KB_padInsert},
+ {83, KB_padDelete},
+ {105,KB_left},
+ {108,KB_down},
+ {106,KB_right},
+ {103,KB_up},
+ {110,KB_insert},
+ {102,KB_home},
+ {104,KB_pageUp},
+ {111,KB_delete},
+ {107,KB_end},
+ {109,KB_pageDown},
+ {125,KB_leftWindows},
+ {126,KB_rightWindows},
+ {127,KB_menu},
+ {100,KB_rightAlt},
+ {97,KB_rightCtrl},
+ };
+
+/* And the keypad with num lock turned on (changes the ASCII code only) */
+
+keymap keypad[] = {
+ {71, ASCII_7},
+ {72, ASCII_8},
+ {73, ASCII_9},
+ {75, ASCII_4},
+ {76, ASCII_5},
+ {77, ASCII_6},
+ {79, ASCII_1},
+ {80, ASCII_2},
+ {81, ASCII_3},
+ {82, ASCII_0},
+ {83, ASCII_period},
+ };
+
+#define NB_KEYMAPS (sizeof(keymaps)/sizeof(keymaps[0]))
+#define NB_KEYPAD (sizeof(keypad)/sizeof(keypad[0]))
+
+typedef struct {
+ int sample;
+ char code[2];
+ } sample_rate;
+
+sample_rate sampletab[]={
+ { 0,"O"},
+ { 15,"J"},
+ { 27,"K"},
+ { 42,"L"},
+ { 60,"R"},
+ { 85,"M"},
+ {125,"Q"},
+ {1E9,"N"},
+ };
+
+/* Number of keycodes to read at a time from the console */
+
+#define KBDREADBUFFERSIZE 32
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* These are not used under Linux */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flaps)
+
+/****************************************************************************
+PARAMETERS:
+scanCode - Scan code to test
+
+REMARKS:
+This macro determines if a specified key is currently down at the
+time that the call is made.
+****************************************************************************/
+#define _EVT_isKeyDown(scanCode) (keyUpMsg[scanCode] != 0)
+
+/****************************************************************************
+REMARKS:
+This function is used to return the number of ticks since system
+startup in milliseconds. This should be the same value that is placed into
+the time stamp fields of events, and is used to implement auto mouse down
+events.
+****************************************************************************/
+ulong _EVT_getTicks(void)
+{
+ static uint starttime = 0;
+ struct timeval t;
+
+ gettimeofday(&t, NULL);
+ if (starttime == 0)
+ starttime = t.tv_sec * 1000 + (t.tv_usec/1000);
+ return ((t.tv_sec * 1000 + (t.tv_usec/1000)) - starttime);
+}
+
+/****************************************************************************
+REMARKS:
+Small Unix function that checks for availability on a file using select()
+****************************************************************************/
+static ibool dataReady(
+ int fd)
+{
+ static struct timeval t = { 0L, 0L };
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ return select(fd+1, &fds, NULL, NULL, &t) > 0;
+}
+
+/****************************************************************************
+REMARKS:
+Reads mouse data according to the selected mouse driver.
+****************************************************************************/
+static ibool readMouseData(
+ int *buttons,
+ int *dx,
+ int *dy)
+{
+ static uchar data[32],prev = 0;
+ int cnt = 0,ret;
+ mouse_info *drv;
+
+ /* Read the first byte to check for the protocol */
+ drv = &mouse_infos[mouse_driver];
+ if (read(_EVT_mouse_fd, data, drv->read) != drv->read) {
+ perror("read");
+ return false;
+ }
+ if ((data[0] & drv->proto[0]) != drv->proto[1])
+ return false;
+
+ /* Load a whole protocol packet */
+ cnt += drv->read;
+ while (cnt < drv->packet_len) {
+ ret = read(_EVT_mouse_fd, data+cnt, drv->read);
+ if (ret == drv->read)
+ cnt += ret;
+ else {
+ perror("read");
+ return false;
+ }
+ }
+ if ((data[1] & drv->proto[2]) != drv->proto[3])
+ return false;
+
+ /* Now decode the protocol packet */
+ switch (mouse_driver) {
+ case EVT_microsoft:
+ if (data[0] == 0x40 && !(prev|data[1]|data[2]))
+ *buttons = 2; /* Third button on MS compatible mouse */
+ else
+ *buttons= ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4);
+ prev = *buttons;
+ *dx = (char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
+ *dy = (char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
+ break;
+ case EVT_ps2:
+ *buttons = !!(data[0]&1) * 4 + !!(data[0]&2) * 1 + !!(data[0]&4) * 2;
+ if (data[1] != 0)
+ *dx = (data[0] & 0x10) ? data[1]-256 : data[1];
+ else
+ *dx = 0;
+ if (data[2] != 0)
+ *dy = -((data[0] & 0x20) ? data[2]-256 : data[2]);
+ else
+ *dy = 0;
+ break;
+ case EVT_mousesystems: case EVT_gpm:
+ *buttons = (~data[0]) & 0x07;
+ *dx = (char)(data[1]) + (char)(data[3]);
+ *dy = -((char)(data[2]) + (char)(data[4]));
+ break;
+ case EVT_logitech:
+ *buttons= data[0] & 0x07;
+ *dx = (data[0] & 0x10) ? data[1] : - data[1];
+ *dy = (data[0] & 0x08) ? - data[2] : data[2];
+ break;
+ case EVT_busmouse:
+ *buttons= (~data[0]) & 0x07;
+ *dx = (char)data[1];
+ *dy = -(char)data[2];
+ break;
+ case EVT_MMseries:
+ *buttons = data[0] & 0x07;
+ *dx = (data[0] & 0x10) ? data[1] : - data[1];
+ *dy = (data[0] & 0x08) ? - data[2] : data[2];
+ break;
+ case EVT_intellimouse:
+ *buttons = ((data[0] & 0x20) >> 3) /* left */
+ | ((data[3] & 0x10) >> 3) /* middle */
+ | ((data[0] & 0x10) >> 4); /* right */
+ *dx = (char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
+ *dy = (char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
+ break;
+ case EVT_intellimouse_ps2:
+ *buttons = (data[0] & 0x04) >> 1 /* Middle */
+ | (data[0] & 0x02) >> 1 /* Right */
+ | (data[0] & 0x01) << 2; /* Left */
+ *dx = (data[0] & 0x10) ? data[1]-256 : data[1];
+ *dy = (data[0] & 0x20) ? -(data[2]-256) : -data[2];
+ break;
+ case EVT_mouseman: {
+ static int getextra;
+ static uchar prev=0;
+ uchar b;
+
+ /* The damned MouseMan has 3/4 bytes packets. The extra byte
+ * is only there if the middle button is active.
+ * I get the extra byte as a packet with magic numbers in it.
+ * and then switch to 4-byte mode.
+ */
+ if (data[1] == 0xAA && data[2] == 0x55) {
+ /* Got unexpected fourth byte */
+ if ((b = (*data>>4)) > 0x3)
+ return false; /* just a sanity check */
+ *dx = *dy = 0;
+ drv->packet_len=4;
+ getextra=0;
+ }
+ else {
+ /* Got 3/4, as expected */
+ /* Motion is independent of packetlen... */
+ *dx = (char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
+ *dy = (char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
+ prev = ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4);
+ if (drv->packet_len==4)
+ b = data[3]>>4;
+ }
+ if (drv->packet_len == 4) {
+ if (b == 0) {
+ drv->packet_len = 3;
+ getextra = 1;
+ }
+ else {
+ if (b & 0x2)
+ prev |= 2;
+ }
+ }
+ *buttons = prev;
+
+ /* This "chord-middle" behaviour was reported by David A. van Leeuwen */
+ if (((prev ^ *buttons) & 5) == 5)
+ *buttons = *buttons ? 2 : 0;
+ prev = *buttons;
+ break;
+ }
+ case EVT_noMouse:
+ return false;
+ break;
+ }
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Map a keypress via the key mapping table
+****************************************************************************/
+static int getKeyMapping(
+ keymap *tab,
+ int nb,
+ int key)
+{
+ int i;
+
+ for(i = 0; i < nb; i++) {
+ if (tab[i].scan == key)
+ return tab[i].map;
+ }
+ return key;
+}
+
+#ifdef USE_OS_JOYSTICK
+
+static char js0_axes = 0, js0_buttons = 0;
+static char js1_axes = 0, js1_buttons = 0;
+static char joystick0_dev[20] = "/dev/js0";
+static char joystick1_dev[20] = "/dev/js1";
+
+/****************************************************************************
+REMARKS:
+Create a joystick event from the joystick data
+****************************************************************************/
+static void makeJoyEvent(
+ event_t *evt)
+{
+ evt->message = 0;
+ if (buts0 && axis0) {
+ if (buts0[0]) evt->message |= EVT_JOY1_BUTTONA;
+ if (buts0[1]) evt->message |= EVT_JOY1_BUTTONB;
+ evt->where_x = axis0[0];
+ evt->where_y = axis0[1];
+ }
+ else
+ evt->where_x = evt->where_y = 0;
+ if (buts1 && axis1) {
+ if (buts1[0]) evt->message |= EVT_JOY2_BUTTONA;
+ if (buts1[1]) evt->message |= EVT_JOY2_BUTTONB;
+ evt->where_x = axis1[0];
+ evt->where_y = axis1[1];
+ }
+ else
+ evt->where_x = evt->where_y = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the joystick axis data
+****************************************************************************/
+int EVTAPI _EVT_readJoyAxis(
+ int jmask,
+ int *axis)
+{
+ int mask = 0;
+
+ if ((js_version & ~0xffff) == 0) {
+ /* Old 0.x driver */
+ struct JS_DATA_TYPE js;
+ if (joystick0_fd && read(joystick0_fd, &js, JS_RETURN) == JS_RETURN) {
+ if (jmask & EVT_JOY_AXIS_X1)
+ axis[0] = js.x;
+ if (jmask & EVT_JOY_AXIS_Y1)
+ axis[1] = js.y;
+ mask |= EVT_JOY_AXIS_X1|EVT_JOY_AXIS_Y1;
+ }
+ if (joystick1_fd && read(joystick1_fd, &js, JS_RETURN) == JS_RETURN) {
+ if (jmask & EVT_JOY_AXIS_X2)
+ axis[2] = js.x;
+ if (jmask & EVT_JOY_AXIS_Y2)
+ axis[3] = js.y;
+ mask |= EVT_JOY_AXIS_X2|EVT_JOY_AXIS_Y2;
+ }
+ }
+ else {
+ if (axis0) {
+ if (jmask & EVT_JOY_AXIS_X1)
+ axis[0] = axis0[0];
+ if (jmask & EVT_JOY_AXIS_Y1)
+ axis[1] = axis0[1];
+ mask |= EVT_JOY_AXIS_X1 | EVT_JOY_AXIS_Y1;
+ }
+ if (axis1) {
+ if (jmask & EVT_JOY_AXIS_X2)
+ axis[2] = axis1[0];
+ if (jmask & EVT_JOY_AXIS_Y2)
+ axis[3] = axis1[1];
+ mask |= EVT_JOY_AXIS_X2 | EVT_JOY_AXIS_Y2;
+ }
+ }
+ return mask;
+}
+
+/****************************************************************************
+REMARKS:
+Read the joystick button data
+****************************************************************************/
+int EVTAPI _EVT_readJoyButtons(void)
+{
+ int buts = 0;
+
+ if ((js_version & ~0xffff) == 0) {
+ /* Old 0.x driver */
+ struct JS_DATA_TYPE js;
+ if (joystick0_fd && read(joystick0_fd, &js, JS_RETURN) == JS_RETURN)
+ buts = js.buttons;
+ if (joystick1_fd && read(joystick1_fd, &js, JS_RETURN) == JS_RETURN)
+ buts |= js.buttons << 2;
+ }
+ else {
+ if (buts0)
+ buts |= EVT_JOY1_BUTTONA*buts0[0] + EVT_JOY1_BUTTONB*buts0[1];
+ if (buts1)
+ buts |= EVT_JOY2_BUTTONA*buts1[0] + EVT_JOY2_BUTTONB*buts1[1];
+ }
+ return buts;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns the mask indicating what joystick axes are attached.
+
+HEADER:
+event.h
+
+REMARKS:
+This function is used to detect the attached joysticks, and determine
+what axes are present and functioning. This function will re-detect any
+attached joysticks when it is called, so if the user forgot to attach
+the joystick when the application started, you can call this function to
+re-detect any newly attached joysticks.
+
+SEE ALSO:
+EVT_joySetLowerRight, EVT_joySetCenter, EVT_joyIsPresent
+****************************************************************************/
+int EVTAPI EVT_joyIsPresent(void)
+{
+ static int mask = 0;
+ int i;
+ char *tmp, name0[128], name1[128];
+ static ibool inited = false;
+
+ if (inited)
+ return mask;
+ memset(EVT.joyMin,0,sizeof(EVT.joyMin));
+ memset(EVT.joyCenter,0,sizeof(EVT.joyCenter));
+ memset(EVT.joyMax,0,sizeof(EVT.joyMax));
+ memset(EVT.joyPrev,0,sizeof(EVT.joyPrev));
+ EVT.joyButState = 0;
+ if ((tmp = getenv(ENV_JOYDEV0)) != NULL)
+ strcpy(joystick0_dev,tmp);
+ if ((tmp = getenv(ENV_JOYDEV1)) != NULL)
+ strcpy(joystick1_dev,tmp);
+ if ((joystick0_fd = open(joystick0_dev, O_RDONLY)) < 0)
+ joystick0_fd = 0;
+ if ((joystick1_fd = open(joystick1_dev, O_RDONLY)) < 0)
+ joystick1_fd = 0;
+ if (!joystick0_fd && !joystick1_fd) // No joysticks detected
+ return 0;
+ inited = true;
+ if (ioctl(joystick0_fd ? joystick0_fd : joystick1_fd, JSIOCGVERSION, &js_version) < 0)
+ return 0;
+
+ /* Initialise joystick 0 */
+ if (joystick0_fd) {
+ ioctl(joystick0_fd, JSIOCGNAME(sizeof(name0)), name0);
+ if (js_version & ~0xffff) {
+ struct js_event js;
+
+ ioctl(joystick0_fd, JSIOCGAXES, &js0_axes);
+ ioctl(joystick0_fd, JSIOCGBUTTONS, &js0_buttons);
+ axis0 = PM_calloc((int)js0_axes, sizeof(short));
+ buts0 = PM_malloc((int)js0_buttons);
+ /* Read the initial events */
+ while(dataReady(joystick0_fd)
+ && read(joystick0_fd, &js, sizeof(struct js_event)) == sizeof(struct js_event)
+ && (js.type & JS_EVENT_INIT)
+ ) {
+ if (js.type & JS_EVENT_BUTTON)
+ buts0[js.number] = js.value;
+ else if (js.type & JS_EVENT_AXIS)
+ axis0[js.number] = scaleJoyAxis(js.value,js.number);
+ }
+ }
+ else {
+ js0_axes = 2;
+ js0_buttons = 2;
+ axis0 = PM_calloc((int)js0_axes, sizeof(short));
+ buts0 = PM_malloc((int)js0_buttons);
+ }
+ }
+
+ /* Initialise joystick 1 */
+ if (joystick1_fd) {
+ ioctl(joystick1_fd, JSIOCGNAME(sizeof(name1)), name1);
+ if (js_version & ~0xffff) {
+ struct js_event js;
+
+ ioctl(joystick1_fd, JSIOCGAXES, &js1_axes);
+ ioctl(joystick1_fd, JSIOCGBUTTONS, &js1_buttons);
+ axis1 = PM_calloc((int)js1_axes, sizeof(short));
+ buts1 = PM_malloc((int)js1_buttons);
+ /* Read the initial events */
+ while(dataReady(joystick1_fd)
+ && read(joystick1_fd, &js, sizeof(struct js_event))==sizeof(struct js_event)
+ && (js.type & JS_EVENT_INIT)
+ ) {
+ if (js.type & JS_EVENT_BUTTON)
+ buts1[js.number] = js.value;
+ else if (js.type & JS_EVENT_AXIS)
+ axis1[js.number] = scaleJoyAxis(js.value,js.number<<2);
+ }
+ }
+ else {
+ js1_axes = 2;
+ js1_buttons = 2;
+ axis1 = PM_calloc((int)js1_axes, sizeof(short));
+ buts1 = PM_malloc((int)js1_buttons);
+ }
+ }
+
+#ifdef CHECKED
+ fprintf(stderr,"Using joystick driver version %d.%d.%d\n",
+ js_version >> 16, (js_version >> 8) & 0xff, js_version & 0xff);
+ if (joystick0_fd)
+ fprintf(stderr,"Joystick 1 (%s): %s\n", joystick0_dev, name0);
+ if (joystick1_fd)
+ fprintf(stderr,"Joystick 2 (%s): %s\n", joystick1_dev, name1);
+#endif
+ mask = _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyCenter);
+ if (mask) {
+ for (i = 0; i < JOY_NUM_AXES; i++)
+ EVT.joyMax[i] = EVT.joyCenter[i]*2;
+ }
+ return mask;
+}
+
+/****************************************************************************
+DESCRIPTION:
+Polls the joystick for position and button information.
+
+HEADER:
+event.h
+
+REMARKS:
+This routine is used to poll analogue joysticks for button and position
+information. It should be called once for each main loop of the user
+application, just before processing all pending events via EVT_getNext.
+All information polled from the joystick will be posted to the event
+queue for later retrieval.
+
+Note: Most analogue joysticks will provide readings that change even
+ though the joystick has not moved. Hence if you call this routine
+ you will likely get an EVT_JOYMOVE event every time through your
+ event loop.
+
+SEE ALSO:
+EVT_getNext, EVT_peekNext, EVT_joySetUpperLeft, EVT_joySetLowerRight,
+EVT_joySetCenter, EVT_joyIsPresent
+****************************************************************************/
+void EVTAPI EVT_pollJoystick(void)
+{
+ event_t evt;
+ int i,axis[JOY_NUM_AXES],newButState,mask,moved,ps;
+
+ if ((js_version & ~0xFFFF) == 0 && EVT.joyMask) {
+ /* Read joystick axes and post movement events if they have
+ * changed since the last time we polled. Until the events are
+ * actually flushed, we keep modifying the same joystick movement
+ * event, so you won't get multiple movement event
+ */
+ mask = _EVT_readJoyAxis(EVT.joyMask,axis);
+ newButState = _EVT_readJoyButtons();
+ moved = false;
+ for (i = 0; i < JOY_NUM_AXES; i++) {
+ if (mask & (EVT_JOY_AXIS_X1 << i))
+ axis[i] = scaleJoyAxis(axis[i],i);
+ else
+ axis[i] = EVT.joyPrev[i];
+ if (axis[i] != EVT.joyPrev[i])
+ moved = true;
+ }
+ if (moved) {
+ memcpy(EVT.joyPrev,axis,sizeof(EVT.joyPrev));
+ ps = _EVT_disableInt();
+ if (EVT.oldJoyMove != -1) {
+ /* Modify the existing joystick movement event */
+ EVT.evtq[EVT.oldJoyMove].message = newButState;
+ EVT.evtq[EVT.oldJoyMove].where_x = EVT.joyPrev[0];
+ EVT.evtq[EVT.oldJoyMove].where_y = EVT.joyPrev[1];
+ EVT.evtq[EVT.oldJoyMove].relative_x = EVT.joyPrev[2];
+ EVT.evtq[EVT.oldJoyMove].relative_y = EVT.joyPrev[3];
+ }
+ else if (EVT.count < EVENTQSIZE) {
+ /* Add a new joystick movement event */
+ EVT.oldJoyMove = EVT.freeHead;
+ memset(&evt,0,sizeof(evt));
+ evt.what = EVT_JOYMOVE;
+ evt.message = EVT.joyButState;
+ evt.where_x = EVT.joyPrev[0];
+ evt.where_y = EVT.joyPrev[1];
+ evt.relative_x = EVT.joyPrev[2];
+ evt.relative_y = EVT.joyPrev[3];
+ addEvent(&evt);
+ }
+ _EVT_restoreInt(ps);
+ }
+
+ /* Read the joystick buttons, and post events to reflect the change
+ * in state for the joystick buttons.
+ */
+ if (newButState != EVT.joyButState) {
+ if (EVT.count < EVENTQSIZE) {
+ /* Add a new joystick movement event */
+ ps = _EVT_disableInt();
+ memset(&evt,0,sizeof(evt));
+ evt.what = EVT_JOYCLICK;
+ evt.message = newButState;
+ EVT.evtq[EVT.oldJoyMove].where_x = EVT.joyPrev[0];
+ EVT.evtq[EVT.oldJoyMove].where_y = EVT.joyPrev[1];
+ EVT.evtq[EVT.oldJoyMove].relative_x = EVT.joyPrev[2];
+ EVT.evtq[EVT.oldJoyMove].relative_y = EVT.joyPrev[3];
+ addEvent(&evt);
+ _EVT_restoreInt(ps);
+ }
+ EVT.joyButState = newButState;
+ }
+ }
+}
+
+/****************************************************************************
+DESCRIPTION:
+Calibrates the joystick upper left position
+
+HEADER:
+event.h
+
+REMARKS:
+This function can be used to zero in on better joystick calibration factors,
+which may work better than the default simplistic calibration (which assumes
+the joystick is centered when the event library is initialised).
+To use this function, ask the user to hold the stick in the upper left
+position and then have them press a key or button. and then call this
+function. This function will then read the joystick and update the
+calibration factors.
+
+Usually, assuming that the stick was centered when the event library was
+initialized, you really only need to call EVT_joySetLowerRight since the
+upper left position is usually always 0,0 on most joysticks. However, the
+safest procedure is to call all three calibration functions.
+
+SEE ALSO:
+EVT_joySetUpperLeft, EVT_joySetLowerRight, EVT_joyIsPresent
+****************************************************************************/
+void EVTAPI EVT_joySetUpperLeft(void)
+{
+ _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyMin);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Calibrates the joystick lower right position
+
+HEADER:
+event.h
+
+REMARKS:
+This function can be used to zero in on better joystick calibration factors,
+which may work better than the default simplistic calibration (which assumes
+the joystick is centered when the event library is initialised).
+To use this function, ask the user to hold the stick in the lower right
+position and then have them press a key or button. and then call this
+function. This function will then read the joystick and update the
+calibration factors.
+
+Usually, assuming that the stick was centered when the event library was
+initialized, you really only need to call EVT_joySetLowerRight since the
+upper left position is usually always 0,0 on most joysticks. However, the
+safest procedure is to call all three calibration functions.
+
+SEE ALSO:
+EVT_joySetUpperLeft, EVT_joySetCenter, EVT_joyIsPresent
+****************************************************************************/
+void EVTAPI EVT_joySetLowerRight(void)
+{
+ _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyMax);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Calibrates the joystick center position
+
+HEADER:
+event.h
+
+REMARKS:
+This function can be used to zero in on better joystick calibration factors,
+which may work better than the default simplistic calibration (which assumes
+the joystick is centered when the event library is initialised).
+To use this function, ask the user to hold the stick in the center
+position and then have them press a key or button. and then call this
+function. This function will then read the joystick and update the
+calibration factors.
+
+Usually, assuming that the stick was centered when the event library was
+initialized, you really only need to call EVT_joySetLowerRight since the
+upper left position is usually always 0,0 on most joysticks. However, the
+safest procedure is to call all three calibration functions.
+
+SEE ALSO:
+EVT_joySetUpperLeft, EVT_joySetLowerRight, EVT_joySetCenter
+****************************************************************************/
+void EVTAPI EVT_joySetCenter(void)
+{
+ _EVT_readJoyAxis(EVT_JOY_AXIS_ALL,EVT.joyCenter);
+}
+#endif
+
+/****************************************************************************
+REMARKS:
+Pumps all messages in the message queue from Linux into our event queue.
+****************************************************************************/
+static void _EVT_pumpMessages(void)
+{
+ event_t evt;
+ int i,numkeys, c;
+ ibool release;
+ static struct kbentry ke;
+ static char buf[KBDREADBUFFERSIZE];
+ static ushort repeatKey[128] = {0};
+
+ /* Poll keyboard events */
+ while (dataReady(_PM_console_fd) && (numkeys = read(_PM_console_fd, buf, KBDREADBUFFERSIZE)) > 0) {
+ for (i = 0; i < numkeys; i++) {
+ c = buf[i];
+ release = c & 0x80;
+ c &= 0x7F;
+
+ // TODO: This is wrong! We need this to be the time stamp at
+ // ** interrupt ** time!! One solution would be to
+ // put the keyboard and mouse polling loops into
+ // a separate thread that can block on I/O to the
+ // necessay file descriptor.
+ evt.when = _EVT_getTicks();
+
+ if (release) {
+ /* Key released */
+ evt.what = EVT_KEYUP;
+ switch (c) {
+ case KB_leftShift:
+ _PM_modifiers &= ~EVT_LEFTSHIFT;
+ break;
+ case KB_rightShift:
+ _PM_modifiers &= ~EVT_RIGHTSHIFT;
+ break;
+ case 29:
+ _PM_modifiers &= ~(EVT_LEFTCTRL|EVT_CTRLSTATE);
+ break;
+ case 97: /* Control */
+ _PM_modifiers &= ~EVT_CTRLSTATE;
+ break;
+ case 56:
+ _PM_modifiers &= ~(EVT_LEFTALT|EVT_ALTSTATE);
+ break;
+ case 100:
+ _PM_modifiers &= ~EVT_ALTSTATE;
+ break;
+ default:
+ }
+ evt.modifiers = _PM_modifiers;
+ evt.message = keyUpMsg[c];
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ keyUpMsg[c] = 0;
+ repeatKey[c] = 0;
+ }
+ else {
+ /* Key pressed */
+ evt.what = EVT_KEYDOWN;
+ switch (c) {
+ case KB_leftShift:
+ _PM_modifiers |= EVT_LEFTSHIFT;
+ break;
+ case KB_rightShift:
+ _PM_modifiers |= EVT_RIGHTSHIFT;
+ break;
+ case 29:
+ _PM_modifiers |= EVT_LEFTCTRL|EVT_CTRLSTATE;
+ break;
+ case 97: /* Control */
+ _PM_modifiers |= EVT_CTRLSTATE;
+ break;
+ case 56:
+ _PM_modifiers |= EVT_LEFTALT|EVT_ALTSTATE;
+ break;
+ case 100:
+ _PM_modifiers |= EVT_ALTSTATE;
+ break;
+ case KB_capsLock: /* Caps Lock */
+ _PM_leds ^= LED_CAP;
+ ioctl(_PM_console_fd, KDSETLED, _PM_leds);
+ break;
+ case KB_numLock: /* Num Lock */
+ _PM_leds ^= LED_NUM;
+ ioctl(_PM_console_fd, KDSETLED, _PM_leds);
+ break;
+ case KB_scrollLock: /* Scroll Lock */
+ _PM_leds ^= LED_SCR;
+ ioctl(_PM_console_fd, KDSETLED, _PM_leds);
+ break;
+ default:
+ }
+ evt.modifiers = _PM_modifiers;
+ if (keyUpMsg[c]) {
+ evt.what = EVT_KEYREPEAT;
+ evt.message = keyUpMsg[c] | (repeatKey[c]++ << 16);
+ }
+ else {
+ int asc;
+
+ evt.message = getKeyMapping(keymaps, NB_KEYMAPS, c) << 8;
+ ke.kb_index = c;
+ ke.kb_table = 0;
+ if ((_PM_modifiers & EVT_SHIFTKEY) || (_PM_leds & LED_CAP))
+ ke.kb_table |= K_SHIFTTAB;
+ if (_PM_modifiers & (EVT_LEFTALT | EVT_ALTSTATE))
+ ke.kb_table |= K_ALTTAB;
+ if (ioctl(_PM_console_fd, KDGKBENT, (unsigned long)&ke)<0)
+ perror("ioctl(KDGKBENT)");
+ if ((_PM_leds & LED_NUM) && (getKeyMapping(keypad, NB_KEYPAD, c)!=c)) {
+ asc = getKeyMapping(keypad, NB_KEYPAD, c);
+ }
+ else {
+ switch (c) {
+ case 14:
+ asc = ASCII_backspace;
+ break;
+ case 15:
+ asc = ASCII_tab;
+ break;
+ case 28:
+ case 96:
+ asc = ASCII_enter;
+ break;
+ case 1:
+ asc = ASCII_esc;
+ default:
+ asc = ke.kb_value & 0xFF;
+ if (asc < 0x1B)
+ asc = 0;
+ break;
+ }
+ }
+ if ((_PM_modifiers & (EVT_CTRLSTATE|EVT_LEFTCTRL)) && isalpha(asc))
+ evt.message |= toupper(asc) - 'A' + 1;
+ else
+ evt.message |= asc;
+ keyUpMsg[c] = evt.message;
+ repeatKey[c]++;
+ }
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+ }
+ }
+
+ /* Poll mouse events */
+ if (_EVT_mouse_fd) {
+ int dx, dy, buts;
+ static int oldbuts;
+
+ while (dataReady(_EVT_mouse_fd)) {
+ if (readMouseData(&buts, &dx, &dy)) {
+ EVT.mx += dx;
+ EVT.my += dy;
+ if (EVT.mx < 0) EVT.mx = 0;
+ if (EVT.my < 0) EVT.my = 0;
+ if (EVT.mx > range_x) EVT.mx = range_x;
+ if (EVT.my > range_y) EVT.my = range_y;
+ evt.where_x = EVT.mx;
+ evt.where_y = EVT.my;
+ evt.relative_x = dx;
+ evt.relative_y = dy;
+
+ // TODO: This is wrong! We need this to be the time stamp at
+ // ** interrupt ** time!! One solution would be to
+ // put the keyboard and mouse polling loops into
+ // a separate thread that can block on I/O to the
+ // necessay file descriptor.
+ evt.when = _EVT_getTicks();
+ evt.modifiers = _PM_modifiers;
+ if (buts & 4)
+ evt.modifiers |= EVT_LEFTBUT;
+ if (buts & 1)
+ evt.modifiers |= EVT_RIGHTBUT;
+ if (buts & 2)
+ evt.modifiers |= EVT_MIDDLEBUT;
+
+ /* Left click events */
+ if ((buts&4) != (oldbuts&4)) {
+ if (buts&4)
+ evt.what = EVT_MOUSEDOWN;
+ else
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_LEFTBMASK;
+ EVT.oldMove = -1;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+ /* Right click events */
+ if ((buts&1) != (oldbuts&1)) {
+ if (buts&1)
+ evt.what = EVT_MOUSEDOWN;
+ else
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_RIGHTBMASK;
+ EVT.oldMove = -1;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+ /* Middle click events */
+ if ((buts&2) != (oldbuts&2)) {
+ if (buts&2)
+ evt.what = EVT_MOUSEDOWN;
+ else
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_MIDDLEBMASK;
+ EVT.oldMove = -1;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+ /* Mouse movement event */
+ if (dx || dy) {
+ evt.what = EVT_MOUSEMOVE;
+ evt.message = 0;
+ if (EVT.oldMove != -1) {
+ /* Modify existing movement event */
+ EVT.evtq[EVT.oldMove].where_x = evt.where_x;
+ EVT.evtq[EVT.oldMove].where_y = evt.where_y;
+ }
+ else {
+ /* Save id of this movement event */
+ EVT.oldMove = EVT.freeHead;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+ }
+ oldbuts = buts;
+ }
+ }
+ }
+
+#ifdef USE_OS_JOYSTICK
+ // Poll joystick events using the 1.x joystick driver API in the 2.2 kernels
+ if (js_version & ~0xffff) {
+ static struct js_event js;
+
+ /* Read joystick axis 0 */
+ evt.when = 0;
+ evt.modifiers = _PM_modifiers;
+ if (joystick0_fd && dataReady(joystick0_fd) &&
+ read(joystick0_fd, &js, sizeof(js)) == sizeof(js)) {
+ if (js.type & JS_EVENT_BUTTON) {
+ if (js.number < 2) { /* Only 2 buttons for now :( */
+ buts0[js.number] = js.value;
+ evt.what = EVT_JOYCLICK;
+ makeJoyEvent(&evt);
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+ }
+ else if (js.type & JS_EVENT_AXIS) {
+ axis0[js.number] = scaleJoyAxis(js.value,js.number);
+ evt.what = EVT_JOYMOVE;
+ if (EVT.oldJoyMove != -1) {
+ makeJoyEvent(&EVT.evtq[EVT.oldJoyMove]);
+ }
+ else if (EVT.count < EVENTQSIZE) {
+ EVT.oldJoyMove = EVT.freeHead;
+ makeJoyEvent(&evt);
+ addEvent(&evt);
+ }
+ }
+ }
+
+ /* Read joystick axis 1 */
+ if (joystick1_fd && dataReady(joystick1_fd) &&
+ read(joystick1_fd, &js, sizeof(js))==sizeof(js)) {
+ if (js.type & JS_EVENT_BUTTON) {
+ if (js.number < 2) { /* Only 2 buttons for now :( */
+ buts1[js.number] = js.value;
+ evt.what = EVT_JOYCLICK;
+ makeJoyEvent(&evt);
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+ }
+ else if (js.type & JS_EVENT_AXIS) {
+ axis1[js.number] = scaleJoyAxis(js.value,js.number<<2);
+ evt.what = EVT_JOYMOVE;
+ if (EVT.oldJoyMove != -1) {
+ makeJoyEvent(&EVT.evtq[EVT.oldJoyMove]);
+ }
+ else if (EVT.count < EVENTQSIZE) {
+ EVT.oldJoyMove = EVT.freeHead;
+ makeJoyEvent(&evt);
+ addEvent(&evt);
+ }
+ }
+ }
+ }
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+This macro/function is used to converts the scan codes reported by the
+keyboard to our event libraries normalised format. We only have one scan
+code for the 'A' key, and use shift _PM_modifiers to determine if it is a
+Ctrl-F1, Alt-F1 etc. The raw scan codes from the keyboard work this way,
+but the OS gives us 'cooked' scan codes, we have to translate them back
+to the raw format.
+****************************************************************************/
+#define _EVT_maskKeyCode(evt)
+
+/****************************************************************************
+REMARKS:
+Set the speed of the serial port
+****************************************************************************/
+static int setspeed(
+ int fd,
+ int old,
+ int new,
+ unsigned short flags)
+{
+ struct termios tty;
+ char *c;
+
+ tcgetattr(fd, &tty);
+ tty.c_iflag = IGNBRK | IGNPAR;
+ tty.c_oflag = 0;
+ tty.c_lflag = 0;
+ tty.c_line = 0;
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VMIN] = 1;
+ switch (old) {
+ case 9600: tty.c_cflag = flags | B9600; break;
+ case 4800: tty.c_cflag = flags | B4800; break;
+ case 2400: tty.c_cflag = flags | B2400; break;
+ case 1200:
+ default: tty.c_cflag = flags | B1200; break;
+ }
+ tcsetattr(fd, TCSAFLUSH, &tty);
+ switch (new) {
+ case 9600: c = "*q"; tty.c_cflag = flags | B9600; break;
+ case 4800: c = "*p"; tty.c_cflag = flags | B4800; break;
+ case 2400: c = "*o"; tty.c_cflag = flags | B2400; break;
+ case 1200:
+ default: c = "*n"; tty.c_cflag = flags | B1200; break;
+ }
+ write(fd, c, 2);
+ usleep(100000);
+ tcsetattr(fd, TCSAFLUSH, &tty);
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Generic mouse driver init code
+****************************************************************************/
+static void _EVT_mouse_init(void)
+{
+ int i;
+
+ /* Change from any available speed to the chosen one */
+ for (i = 9600; i >= 1200; i /= 2)
+ setspeed(_EVT_mouse_fd, i, opt_baud, mouse_infos[mouse_driver].flags);
+}
+
+/****************************************************************************
+REMARKS:
+Logitech mouse driver init code
+****************************************************************************/
+static void _EVT_logitech_init(void)
+{
+ int i;
+ struct stat buf;
+ int busmouse;
+
+ /* is this a serial- or a bus- mouse? */
+ if (fstat(_EVT_mouse_fd,&buf) == -1)
+ perror("fstat");
+ i = MAJOR(buf.st_rdev);
+ if (stat("/dev/ttyS0",&buf) == -1)
+ perror("stat");
+ busmouse=(i != MAJOR(buf.st_rdev));
+
+ /* Fix the howmany field, so that serial mice have 1, while busmice have 3 */
+ mouse_infos[mouse_driver].read = busmouse ? 3 : 1;
+
+ /* Change from any available speed to the chosen one */
+ for (i = 9600; i >= 1200; i /= 2)
+ setspeed(_EVT_mouse_fd, i, opt_baud, mouse_infos[mouse_driver].flags);
+
+ /* This stuff is peculiar of logitech mice, also for the serial ones */
+ write(_EVT_mouse_fd, "S", 1);
+ setspeed(_EVT_mouse_fd, opt_baud, opt_baud,CS8 |PARENB |PARODD |CREAD |CLOCAL |HUPCL);
+
+ /* Configure the sample rate */
+ for (i = 0; opt_sample <= sampletab[i].sample; i++)
+ ;
+ write(_EVT_mouse_fd,sampletab[i].code,1);
+}
+
+/****************************************************************************
+REMARKS:
+Microsoft Intellimouse init code
+****************************************************************************/
+static void _EVT_pnpmouse_init(void)
+{
+ struct termios tty;
+
+ tcgetattr(_EVT_mouse_fd, &tty);
+ tty.c_iflag = IGNBRK | IGNPAR;
+ tty.c_oflag = 0;
+ tty.c_lflag = 0;
+ tty.c_line = 0;
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VMIN] = 1;
+ tty.c_cflag = mouse_infos[mouse_driver].flags | B1200;
+ tcsetattr(_EVT_mouse_fd, TCSAFLUSH, &tty); /* set parameters */
+}
+
+/****************************************************************************
+PARAMETERS:
+mouseMove - Callback function to call wheneve the mouse needs to be moved
+
+REMARKS:
+Initiliase the event handling module. Here we install our mouse handling ISR
+to be called whenever any button's are pressed or released. We also build
+the free list of events in the event queue.
+
+We use handler number 2 of the mouse libraries interrupt handlers for our
+event handling routines.
+****************************************************************************/
+void EVTAPI EVT_init(
+ _EVT_mouseMoveHandler mouseMove)
+{
+ int i;
+ char *tmp;
+
+ /* Initialise the event queue */
+ EVT.mouseMove = mouseMove;
+ initEventQueue();
+ for (i = 0; i < 256; i++)
+ keyUpMsg[i] = 0;
+
+ /* Keyboard initialization */
+ if (_PM_console_fd == -1)
+ PM_fatalError("You must first call PM_openConsole to use the EVT functions!");
+ _PM_keyboard_rawmode();
+ fcntl(_PM_console_fd,F_SETFL,fcntl(_PM_console_fd,F_GETFL) | O_NONBLOCK);
+
+ /* Mouse initialization */
+ if ((tmp = getenv(ENV_MOUSEDRV)) != NULL) {
+ for (i = 0; i < NB_MICE; i++) {
+ if (!strcasecmp(tmp, mouse_infos[i].name)) {
+ mouse_driver = i;
+ break;
+ }
+ }
+ if (i == NB_MICE) {
+ fprintf(stderr,"Unknown mouse driver: %s\n", tmp);
+ mouse_driver = EVT_noMouse;
+ _EVT_mouse_fd = 0;
+ }
+ }
+ if (mouse_driver != EVT_noMouse) {
+ if (mouse_driver == EVT_gpm)
+ strcpy(mouse_dev,"/dev/gpmdata");
+ if ((tmp = getenv(ENV_MOUSEDEV)) != NULL)
+ strcpy(mouse_dev,tmp);
+#ifdef CHECKED
+ fprintf(stderr,"Using the %s MGL mouse driver on %s.\n", mouse_infos[mouse_driver].name, mouse_dev);
+#endif
+ if ((_EVT_mouse_fd = open(mouse_dev, O_RDWR)) < 0) {
+ perror("open");
+ fprintf(stderr, "Unable to open mouse device %s, dropping mouse support.\n", mouse_dev);
+ sleep(1);
+ mouse_driver = EVT_noMouse;
+ _EVT_mouse_fd = 0;
+ }
+ else {
+ char c;
+
+ /* Init and flush the mouse pending input queue */
+ if (mouse_infos[mouse_driver].init)
+ mouse_infos[mouse_driver].init();
+ while(dataReady(_EVT_mouse_fd) && read(_EVT_mouse_fd, &c, 1) == 1)
+ ;
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS
+Changes the range of coordinates returned by the mouse functions to the
+specified range of values. This is used when changing between graphics
+modes set the range of mouse coordinates for the new display mode.
+****************************************************************************/
+void EVTAPI EVT_setMouseRange(
+ int xRes,
+ int yRes)
+{
+ range_x = xRes;
+ range_y = yRes;
+}
+
+/****************************************************************************
+REMARKS
+Modifes the mouse coordinates as necessary if scaling to OS coordinates,
+and sets the OS mouse cursor position.
+****************************************************************************/
+#define _EVT_setMousePos(x,y)
+
+/****************************************************************************
+REMARKS:
+Initiailises the internal event handling modules. The EVT_suspend function
+can be called to suspend event handling (such as when shelling out to DOS),
+and this function can be used to resume it again later.
+****************************************************************************/
+void EVT_resume(void)
+{
+ // Do nothing for Linux
+}
+
+/****************************************************************************
+REMARKS
+Suspends all of our event handling operations. This is also used to
+de-install the event handling code.
+****************************************************************************/
+void EVT_suspend(void)
+{
+ // Do nothing for Linux
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+ /* Restore signal handlers */
+ _PM_restore_kb_mode();
+ if (_EVT_mouse_fd) {
+ close(_EVT_mouse_fd);
+ _EVT_mouse_fd = 0;
+ }
+#ifdef USE_OS_JOYSTICK
+ if (joystick0_fd) {
+ close(joystick0_fd);
+ free(axis0);
+ free(buts0);
+ joystick0_fd = 0;
+ }
+ if (joystick1_fd) {
+ close(joystick1_fd);
+ free(axis1);
+ free(buts1);
+ joystick1_fd = 0;
+ }
+#endif
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/event.svga b/board/MAI/bios_emulator/scitech/src/pm/linux/event.svga
new file mode 100644
index 0000000000..c0358a0f8a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/event.svga
@@ -0,0 +1,1058 @@
+/****************************************************************************
+*
+* The SuperVGA Kit - UniVBE Software Development Kit
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: IBM PC (MS DOS)
+*
+* Description: Routines to provide a Linux event queue, which automatically
+* handles keyboard and mouse events for the Linux compatability
+* libraries. Based on the event handling code in the MGL.
+*
+****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <termios.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <gpm.h>
+#include "pm.h"
+#include "vesavbe.h"
+#include "wdirect.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+#define EVENTQSIZE 100 /* Number of events in event queue */
+
+static int head = -1; /* Head of event queue */
+static int tail = -1; /* Tail of event queue */
+static int freeHead = -1; /* Head of free list */
+static int count = 0; /* No. of items currently in queue */
+static WD_event evtq[EVENTQSIZE]; /* The queue structure itself */
+static int oldMove = -1; /* Previous movement event */
+static int oldKey = -1; /* Previous key repeat event */
+static int mx,my; /* Current mouse position */
+static int xRes,yRes; /* Screen resolution coordinates */
+static void *stateBuf; /* Pointer to console state buffer */
+static int conn; /* GPM file descriptor for mouse handling */
+static int tty_fd; /* File descriptor for /dev/console */
+extern int tty_vc; /* Virtual console ID, from the PM/Pro library */
+static ibool key_down[128]; /* State of all keyboard keys */
+static struct termios old_conf; /* Saved terminal configuration */
+static int oldkbmode; /* and previous keyboard mode */
+struct vt_mode oldvtmode; /* Old virtual terminal mode */
+static int old_flags; /* Old flags for fcntl */
+static ulong key_modifiers; /* Keyboard modifiers */
+static int forbid_vt_release=0;/* Flag to forbid release of VT */
+static int forbid_vt_acquire=0;/* Flag to forbid cature of VT */
+static int oldmode; /* Old SVGA mode saved for VT switch*/
+static int initmode; /* Initial text mode */
+static ibool installed = false; /* True if we are installed */
+static void (_ASMAPI *moveCursor)(int x,int y) = NULL;
+static int (_ASMAPI *suspendAppCallback)(int flags) = NULL;
+
+#if 0
+/* Keyboard Translation table from scancodes to ASCII */
+
+static uchar keyTable[128] =
+"\0\0331234567890-=\010"
+"\011qwertyuiop[]\015"
+"\0asdfghjkl;'`\0\\"
+"zxcvbnm,./\0*\0 \0"
+"\0\0\0\0\0\0\0\0\0\0\0\0" /* Function keys */
+"789-456+1230.\0\0\0\0\0" /* Keypad keys */
+"\0\0\0\0\0\0\0\015\0/";
+
+static uchar keyTableShifted[128] =
+"\0\033!@#$%^&*()_+\010"
+"\011QWERTYUIOP{}\015"
+"\0ASDFGHJKL:\"~\0|"
+"ZXCVBNM<>?\0*\0 \0"
+"\0\0\0\0\0\0\0\0\0\0\0\0" /* Function keys */
+"789-456+1230.\0\0\0\0\0" /* Keypad keys */
+"\0\0\0\0\0\0\0\015\0/";
+#endif
+
+/* Macros to keep track of the CAPS and NUM lock states */
+
+#define EVT_CAPSSTATE 0x0100
+#define EVT_NUMSTATE 0x0200
+
+/* Helper macros for dealing with timers */
+
+#define TICKS_TO_USEC(t) ((t)*65536.0/1.193180)
+#define USEC_TO_TICKS(u) ((u)*1.193180/65536.0)
+
+/* Number of keycodes to read at a time from the console */
+
+#define KBDREADBUFFERSIZE 32
+
+/*---------------------------- Implementation -----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Returns the current time stamp in units of 18.2 ticks per second.
+****************************************************************************/
+static ulong getTimeStamp(void)
+{
+ return (ulong)(clock() / (CLOCKS_PER_SEC / 18.2));
+}
+
+/****************************************************************************
+PARAMETERS:
+evt - Event to place onto event queue
+
+REMARKS:
+Adds an event to the event queue by tacking it onto the tail of the event
+queue. This routine assumes that at least one spot is available on the
+freeList for the event to be inserted.
+****************************************************************************/
+static void addEvent(
+ WD_event *evt)
+{
+ int evtID;
+
+ /* Get spot to place the event from the free list */
+ evtID = freeHead;
+ freeHead = evtq[freeHead].next;
+
+ /* Add to the tail of the event queue */
+ evt->next = -1;
+ evt->prev = tail;
+ if (tail != -1)
+ evtq[tail].next = evtID;
+ else
+ head = evtID;
+ tail = evtID;
+ evtq[evtID] = *evt;
+ count++;
+}
+
+/****************************************************************************
+PARAMETERS:
+what - Event code
+message - Event message
+modifiers - keyboard modifiers
+x - Mouse X position at time of event
+y - Mouse Y position at time of event
+but_stat - Mouse button status at time of event
+
+REMARKS:
+Adds a new mouse event to the event queue. This routine is called from
+within the mouse interrupt subroutine, so it must be efficient.
+****************************************************************************/
+static void addMouseEvent(
+ uint what,
+ uint message,
+ int x,
+ int y,
+ uint but_stat)
+{
+ WD_event evt;
+
+ if (count < EVENTQSIZE) {
+ evt.what = what;
+ evt.when = getTimeStamp();
+ evt.message = message;
+ evt.modifiers = but_stat | key_modifiers;
+ evt.where_x = x;
+ evt.where_y = y;
+ fprintf(stderr, "(%d,%d), buttons %ld\n", x,y, evt.modifiers);
+ addEvent(&evt); /* Add to tail of event queue */
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+scancode - Raw keyboard scan code
+modifiers - Keyboard modifiers flags
+
+REMARKS:
+Converts the raw scan code into the appropriate ASCII code using the scan
+code and the keyboard modifier flags.
+****************************************************************************/
+static ulong getKeyMessage(
+ uint scancode,
+ ulong modifiers)
+{
+ ushort code = scancode << 8;
+ ushort ascii;
+ struct kbentry ke;
+
+ ke.kb_index = scancode;
+
+ /* Find the basic ASCII code for the scan code */
+ if (modifiers & EVT_CAPSSTATE) {
+ if (modifiers & EVT_SHIFTKEY)
+ ke.kb_table = K_NORMTAB;
+ // ascii = tolower(keyTableShifted[scancode]);
+ else
+ ke.kb_table = K_SHIFTTAB;
+ // ascii = toupper(keyTable[scancode]);
+ }
+ else {
+ if (modifiers & EVT_SHIFTKEY)
+ ke.kb_table = K_SHIFTTAB;
+ // ascii = keyTableShifted[scancode];
+ else
+ ke.kb_table = K_NORMTAB;
+ // ascii = keyTable[scancode];
+ }
+ if(modifiers & EVT_ALTSTATE)
+ ke.kb_table |= K_ALTTAB;
+
+ if (ioctl(tty_fd, KDGKBENT, (unsigned long)&ke)) {
+ fprintf(stderr, "KDGKBENT at index %d in table %d: ",
+ scancode, ke.kb_table);
+ return 0;
+ }
+ ascii = ke.kb_value;
+
+ /* Add ASCII code if key is not alt'ed or ctrl'ed */
+ if (!(modifiers & (EVT_ALTSTATE | EVT_CTRLSTATE)))
+ code |= ascii;
+
+ return code;
+}
+
+/****************************************************************************
+PARAMETERS:
+what - Event code
+scancode - Raw scancode of keyboard event to add
+
+REMARKS:
+Adds a new keyboard event to the event queue. We only take KEYUP and
+KEYDOWN event codes, however if a key is already down we convert the KEYDOWN
+to a KEYREPEAT.
+****************************************************************************/
+static void addKeyEvent(
+ uint what,
+ uint scancode)
+{
+ WD_event evt;
+
+ if (count < EVENTQSIZE) {
+ evt.what = what;
+ evt.when = getTimeStamp();
+ evt.message = getKeyMessage(scancode,key_modifiers) | 0x10000UL;
+ evt.where_x = evt.where_y = 0;
+ evt.modifiers = key_modifiers;
+ if (evt.what == EVT_KEYUP)
+ key_down[scancode] = false;
+ else if (evt.what == EVT_KEYDOWN) {
+ if (key_down[scancode]) {
+ if (oldKey != -1) {
+ evtq[oldKey].message += 0x10000UL;
+ }
+ else {
+ evt.what = EVT_KEYREPEAT;
+ oldKey = freeHead;
+ addEvent(&evt);
+ oldMove = -1;
+ }
+ return;
+ }
+ key_down[scancode] = true;
+ }
+
+ addEvent(&evt);
+ oldMove = -1;
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+sig - Signal being sent to this signal handler
+
+REMARKS:
+Signal handler for the timer. This routine takes care of periodically
+posting timer events to the event queue.
+****************************************************************************/
+void timerHandler(
+ int sig)
+{
+ WD_event evt;
+
+ if (sig == SIGALRM) {
+ if (count < EVENTQSIZE) {
+ evt.when = getTimeStamp();
+ evt.what = EVT_TIMERTICK;
+ evt.message = 0;
+ evt.where_x = evt.where_y = 0;
+ evt.modifiers = 0;
+ addEvent(&evt);
+ oldMove = -1;
+ oldKey = -1;
+ }
+ signal(SIGALRM, timerHandler);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Restore the terminal to normal operation on exit
+****************************************************************************/
+static void restore_term(void)
+{
+ RMREGS regs;
+
+ if (installed) {
+ /* Restore text mode and the state of the console */
+ regs.x.ax = 0x3;
+ PM_int86(0x10,&regs,&regs);
+ PM_restoreConsoleState(stateBuf,tty_fd);
+
+ /* Restore console to normal operation */
+ ioctl(tty_fd, VT_SETMODE, &oldvtmode);
+ ioctl(tty_fd, KDSKBMODE, oldkbmode);
+ tcsetattr(tty_fd, TCSAFLUSH, &old_conf);
+ fcntl(tty_fd,F_SETFL,old_flags &= ~O_NONBLOCK);
+ PM_closeConsole(tty_fd);
+
+ /* Close the mouse driver */
+ close(conn);
+
+ /* Flag that we are not no longer installed */
+ installed = false;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Signal handler to capture forced program termination conditions so that
+we can clean up properly.
+****************************************************************************/
+static void exitHandler(int sig)
+{
+ exit(-1);
+}
+
+/****************************************************************************
+REMARKS:
+Sleep until the virtual terminal is active
+****************************************************************************/
+void wait_vt_active(void)
+{
+ while (ioctl(tty_fd, VT_WAITACTIVE, tty_vc) < 0) {
+ if ((errno != EAGAIN) && (errno != EINTR)) {
+ perror("ioctl(VT_WAITACTIVE)");
+ exit(1);
+ }
+ usleep(150000);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Signal handler called when our virtual terminal has been released and we are
+losing the active focus.
+****************************************************************************/
+static void release_vt_signal(int n)
+{
+ forbid_vt_acquire = 1;
+ if (forbid_vt_release) {
+ forbid_vt_acquire = 0;
+ ioctl(tty_fd, VT_RELDISP, 0);
+ return;
+ }
+
+ // TODO: Call the user supplied suspendAppCallback and restore text
+ // mode (saving the existing mode so we can restore it).
+ //
+ // Also if the suspendAppCallback is NULL then we have to
+ // ignore the switch request!
+ if(suspendAppCallback){
+ oldmode = VBE_getVideoMode();
+ suspendAppCallback(true);
+ VBE_setVideoMode(initmode);
+ }
+
+ ioctl(tty_fd, VT_RELDISP, 1);
+ forbid_vt_acquire = 0;
+ wait_vt_active();
+}
+
+/****************************************************************************
+REMARKS:
+Signal handler called when our virtual terminal has been re-aquired and we
+are now regaiing the active focus.
+****************************************************************************/
+static void acquire_vt_signal(int n)
+{
+ forbid_vt_release = 1;
+ if (forbid_vt_acquire) {
+ forbid_vt_release = 0;
+ return;
+ }
+
+ // TODO: Restore the old display mode, call the user suspendAppCallback
+ // and and we will be back in graphics mode.
+
+ if(suspendAppCallback){
+ VBE_setVideoMode(oldmode);
+ suspendAppCallback(false);
+ }
+
+ ioctl(tty_fd, VT_RELDISP, VT_ACKACQ);
+ forbid_vt_release = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the action for a specific signal to call our signal handler.
+****************************************************************************/
+static void set_sigaction(int sig,void (*handler)(int))
+{
+ struct sigaction siga;
+
+ siga.sa_handler = handler;
+ siga.sa_flags = SA_RESTART;
+ memset(&(siga.sa_mask), 0, sizeof(sigset_t));
+ sigaction(sig, &siga, NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Function to take over control of VT switching so that we can capture
+virtual terminal release and aquire signals, allowing us to properly
+support VT switching while in graphics modes.
+****************************************************************************/
+static void take_vt_control(void)
+{
+ struct vt_mode vtmode;
+
+ ioctl(tty_fd, VT_GETMODE, &vtmode);
+ oldvtmode = vtmode;
+ vtmode.mode = VT_PROCESS;
+ vtmode.relsig = SIGUSR1;
+ vtmode.acqsig = SIGUSR2;
+ set_sigaction(SIGUSR1, release_vt_signal);
+ set_sigaction(SIGUSR2, acquire_vt_signal);
+ ioctl(tty_fd, VT_SETMODE, &oldvtmode);
+}
+
+/****************************************************************************
+REMARKS:
+Set the shift keyboard LED's based on the current keyboard modifiers flags.
+****************************************************************************/
+static void updateLEDStatus(void)
+{
+ int state = 0;
+ if (key_modifiers & EVT_CAPSSTATE)
+ state |= LED_CAP;
+ if (key_modifiers & EVT_NUMSTATE)
+ state |= LED_NUM;
+ ioctl(tty_fd,KDSETLED,state);
+}
+
+/****************************************************************************
+PARAMETERS:
+scancode - Raw scan code to handle
+
+REMARKS:
+Handles the shift key modifiers and keeps track of the shift key states
+so that we can return the correct ASCII codes for the keyboard.
+****************************************************************************/
+static void toggleModifiers(
+ int scancode)
+{
+ static int caps_down = 0,num_down = 0;
+
+ if (scancode & 0x80) {
+ /* Handle key-release function */
+ scancode &= 0x7F;
+ if (scancode == 0x2A || scancode == 0x36)
+ key_modifiers &= ~EVT_SHIFTKEY;
+ else if (scancode == 0x1D || scancode == 0x61)
+ key_modifiers &= ~EVT_CTRLSTATE;
+ else if (scancode == 0x38 || scancode == 0x64)
+ key_modifiers &= ~EVT_ALTSTATE;
+ else if (scancode == 0x3A)
+ caps_down = false;
+ else if (scancode == 0x45)
+ num_down = false;
+ }
+ else {
+ /* Handle key-down function */
+ scancode &= 0x7F;
+ if (scancode == 0x2A || scancode == 0x36)
+ key_modifiers |= EVT_SHIFTKEY;
+ else if (scancode == 0x1D || scancode == 0x61)
+ key_modifiers |= EVT_CTRLSTATE;
+ else if (scancode == 0x38 || scancode == 0x64)
+ key_modifiers |= EVT_ALTSTATE;
+ else if (scancode == 0x3A) {
+ if (!caps_down) {
+ key_modifiers ^= EVT_CAPSSTATE;
+ updateLEDStatus();
+ }
+ caps_down = true;
+ }
+ else if (scancode == 0x45) {
+ if (!num_down) {
+ key_modifiers ^= EVT_NUMSTATE;
+ updateLEDStatus();
+ }
+ num_down = true;
+ }
+ }
+}
+
+/***************************************************************************
+REMARKS:
+Returns the number of bits that have changed from 0 to 1
+(a negative value means the number of bits that have changed from 1 to 0)
+ **************************************************************************/
+static int compareBits(short a, short b)
+{
+ int ret = 0;
+ if( (a&1) != (b&1) ) ret += (b&1) ? 1 : -1;
+ if( (a&2) != (b&2) ) ret += (b&2) ? 1 : -1;
+ if( (a&4) != (b&4) ) ret += (b&4) ? 1 : -1;
+ return ret;
+}
+
+/***************************************************************************
+REMARKS:
+Turns off all keyboard state because we can't rely on them anymore as soon
+as we switch VT's
+***************************************************************************/
+static void keyboard_clearstate(void)
+{
+ key_modifiers = 0;
+ memset(key_down, 0, sizeof(key_down));
+}
+
+/****************************************************************************
+REMARKS:
+Pumps all events from the console event queue into the WinDirect event queue.
+****************************************************************************/
+static void pumpEvents(void)
+{
+ static uchar buf[KBDREADBUFFERSIZE];
+ static char data[5];
+ static int old_buts, old_mx, old_my;
+ static struct timeval t;
+ fd_set fds;
+ int numkeys,i;
+ int dx, dy, buts;
+
+ /* Read all pending keypresses from keyboard buffer and process */
+ while ((numkeys = read(tty_fd, buf, KBDREADBUFFERSIZE)) > 0) {
+ for (i = 0; i < numkeys; i++) {
+ toggleModifiers(buf[i]);
+ if (key_modifiers & EVT_ALTSTATE){
+ int fkey = 0;
+
+ // Do VT switching here for Alt+Fx keypresses
+ switch(buf[i] & 0x7F){
+ case 59 ... 68: /* F1 to F10 */
+ fkey = (buf[i] & 0x7F) - 58;
+ break;
+ case 87: /* F11 */
+ case 88: /* F12 */
+ fkey = (buf[i] & 0x7F) - 76;
+ break;
+ }
+ if(fkey){
+ struct vt_stat vts;
+ ioctl(tty_fd, VT_GETSTATE, &vts);
+
+ if(fkey != vts.v_active){
+ keyboard_clearstate();
+ ioctl(tty_fd, VT_ACTIVATE, fkey);
+ }
+ }
+ }
+
+ if (buf[i] & 0x80)
+ addKeyEvent(EVT_KEYUP,buf[i] & 0x7F);
+ else
+ addKeyEvent(EVT_KEYDOWN,buf[i] & 0x7F);
+ }
+
+ // TODO: If we want to handle VC switching we will need to do it
+ // in here so that we can switch away from the VC and then
+ // switch back to it later. Right now VC switching is disabled
+ // and in order to enable it we need to save/restore the state
+ // of the graphics screen (using the suspendAppCallback and
+ // saving/restoring the state of the current display mode).
+
+ }
+
+ /* Read all pending mouse events and process them */
+ if(conn > 0){
+ FD_ZERO(&fds);
+ FD_SET(conn, &fds);
+ t.tv_sec = t.tv_usec = 0L;
+ while (select(conn+1, &fds, NULL, NULL, &t) > 0) {
+ if(read(conn, data, 5) == 5){
+ buts = (~data[0]) & 0x07;
+ dx = (char)(data[1]) + (char)(data[3]);
+ dy = -((char)(data[2]) + (char)(data[4]));
+
+ mx += dx; my += dy;
+
+ if (dx || dy)
+ addMouseEvent(EVT_MOUSEMOVE, 0, mx, my, buts);
+
+ if (buts != old_buts){
+ int c = compareBits(buts,old_buts);
+ if(c>0)
+ addMouseEvent(EVT_MOUSEDOWN, 0, mx, my, buts);
+ else if(c<0)
+ addMouseEvent(EVT_MOUSEUP, 0, mx, my, buts);
+ }
+ old_mx = mx; old_my = my;
+ old_buts = buts;
+ FD_SET(conn, &fds);
+ t.tv_sec = t.tv_usec = 0L;
+ }
+ }
+ }
+}
+
+/*------------------------ Public interface routines ----------------------*/
+
+/****************************************************************************
+PARAMETERS:
+which - Which code for event to post
+what - Event code for event to post
+message - Event message
+modifiers - Shift key/mouse button modifiers
+
+RETURNS:
+True if the event was posted, false if queue is full.
+
+REMARKS:
+Posts an event to the event queue. This routine can be used to post any type
+of event into the queue.
+****************************************************************************/
+ibool _WDAPI WD_postEvent(
+ ulong which,
+ uint what,
+ ulong message,
+ ulong modifiers)
+{
+ WD_event evt;
+
+ if (count < EVENTQSIZE) {
+ /* Save information in event record */
+ evt.which = which;
+ evt.what = what;
+ evt.when = getTimeStamp();
+ evt.message = message;
+ evt.modifiers = modifiers;
+ addEvent(&evt); /* Add to tail of event queue */
+ return true;
+ }
+ else
+ return false;
+}
+
+/****************************************************************************
+PARAMETERS:
+mask - Event mask to use
+
+REMARKS:
+Flushes all the event specified in 'mask' from the event queue.
+****************************************************************************/
+void _WDAPI WD_flushEvent(
+ uint mask)
+{
+ WD_event evt;
+
+ do { /* Flush all events */
+ WD_getEvent(&evt,mask);
+ } while (evt.what != EVT_NULLEVT);
+}
+
+/****************************************************************************
+PARAMETERS:
+evt - Place to store event
+mask - Event mask to use
+
+REMARKS:
+Halts program execution until a specified event occurs. The event is
+returned. All pending events not in the specified mask will be ignored and
+removed from the queue.
+****************************************************************************/
+void _WDAPI WD_haltEvent(
+ WD_event *evt,
+ uint mask)
+{
+ do { /* Wait for an event */
+ WD_getEvent(evt,EVT_EVERYEVT);
+ } while (!(evt->what & mask));
+}
+
+/****************************************************************************
+PARAMETERS:
+evt - Place to store event
+mask - Event mask to use
+
+RETURNS:
+True if an event was pending.
+
+REMARKS:
+Retrieves the next pending event defined in 'mask' from the event queue.
+The event queue is adjusted to reflect the new state after the event has
+been removed.
+****************************************************************************/
+ibool _WDAPI WD_getEvent(
+ WD_event *evt,
+ uint mask)
+{
+ int evtID,next,prev;
+
+ pumpEvents();
+ if (moveCursor)
+ moveCursor(mx,my); /* Move the mouse cursor */
+ evt->what = EVT_NULLEVT; /* Default to null event */
+
+ if (count) {
+ for (evtID = head; evtID != -1; evtID = evtq[evtID].next) {
+ if (evtq[evtID].what & mask)
+ break; /* Found an event */
+ }
+ if (evtID == -1)
+ return false; /* Event was not found */
+ next = evtq[evtID].next;
+ prev = evtq[evtID].prev;
+ if (prev != -1)
+ evtq[prev].next = next;
+ else
+ head = next;
+ if (next != -1)
+ evtq[next].prev = prev;
+ else
+ tail = prev;
+ *evt = evtq[evtID]; /* Return the event */
+ evtq[evtID].next = freeHead; /* and return to free list */
+ freeHead = evtID;
+ count--;
+ if (evt->what == EVT_MOUSEMOVE)
+ oldMove = -1;
+ if (evt->what == EVT_KEYREPEAT)
+ oldKey = -1;
+ }
+ return evt->what != EVT_NULLEVT;
+}
+
+/****************************************************************************
+PARAMETERS:
+evt - Place to store event
+mask - Event mask to use
+
+RETURNS:
+True if an event is pending.
+
+REMARKS:
+Peeks at the next pending event defined in 'mask' in the event queue. The
+event is not removed from the event queue.
+****************************************************************************/
+ibool _WDAPI WD_peekEvent(
+ WD_event *evt,
+ uint mask)
+{
+ int evtID;
+
+ pumpEvents();
+ if (moveCursor)
+ moveCursor(mx,my); /* Move the mouse cursor */
+ evt->what = EVT_NULLEVT; /* Default to null event */
+
+ if (count) {
+ for (evtID = head; evtID != -1; evtID = evtq[evtID].next) {
+ if (evtq[evtID].what & mask)
+ break; /* Found an event */
+ }
+ if (evtID == -1)
+ return false; /* Event was not found */
+
+ *evt = evtq[evtID]; /* Return the event */
+ }
+ return evt->what != EVT_NULLEVT;
+}
+
+/****************************************************************************
+PARAMETERS:
+hwndMain - Handle to main window
+_xRes - X resolution of graphics mode to be used
+_yRes - Y resolulion of graphics mode to be used
+
+RETURNS:
+Handle to the fullscreen event window if (we return hwndMain on Linux)
+
+REMARKS:
+Initiliase the event handling module. Here we install our mouse handling
+ISR to be called whenever any button's are pressed or released. We also
+build the free list of events in the event queue.
+****************************************************************************/
+WD_HWND _WDAPI WD_startFullScreen(
+ WD_HWND hwndMain,
+ int _xRes,
+ int _yRes)
+{
+ int i;
+ struct termios conf;
+ if (!installed) {
+ Gpm_Connect gpm;
+
+ /* Build free list, and initialise global data structures */
+ for (i = 0; i < EVENTQSIZE; i++)
+ evtq[i].next = i+1;
+ evtq[EVENTQSIZE-1].next = -1; /* Terminate list */
+ count = freeHead = 0;
+ head = tail = -1;
+ oldMove = -1;
+ oldKey = -1;
+ xRes = _xRes;
+ yRes = _yRes;
+
+ /* Open the console device and initialise it for raw mode */
+ tty_fd = PM_openConsole();
+
+ /* Wait until virtual terminal is active and take over control */
+ wait_vt_active();
+ take_vt_control();
+
+ /* Initialise keyboard handling to raw mode */
+ if (ioctl(tty_fd, KDGKBMODE, &oldkbmode)) {
+ printf("WD_startFullScreen: cannot get keyboard mode.\n");
+ exit(-1);
+ }
+ old_flags = fcntl(tty_fd,F_GETFL);
+ fcntl(tty_fd,F_SETFL,old_flags |= O_NONBLOCK);
+ tcgetattr(tty_fd, &conf);
+ old_conf = conf;
+ conf.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH | ISIG);
+ conf.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
+ conf.c_iflag |= (IGNBRK | IGNPAR);
+ conf.c_cc[VMIN] = 1;
+ conf.c_cc[VTIME] = 0;
+ conf.c_cc[VSUSP] = 0;
+ tcsetattr(tty_fd, TCSAFLUSH, &conf);
+ ioctl(tty_fd, KDSKBMODE, K_MEDIUMRAW);
+
+ /* Clear the keyboard state information */
+ memset(key_down, 0, sizeof(key_down));
+ ioctl(tty_fd,KDSETLED,key_modifiers = 0);
+
+ /* Initialize the mouse connection
+ The user *MUST* run gpm with the option -R for this to work (or have a MouseSystems mouse)
+ */
+ if(Gpm_Open(&gpm,0) > 0){ /* GPM available */
+ if ((conn = open(GPM_NODE_FIFO,O_RDONLY|O_SYNC)) < 0)
+ fprintf(stderr,"WD_startFullScreen: Can't open mouse connection.\n");
+ }else{
+ fprintf(stderr,"Warning: when not using gpm -R, only MouseSystems mice are currently supported.\n");
+ if ((conn = open("/dev/mouse",O_RDONLY|O_SYNC)) < 0)
+ fprintf(stderr,"WD_startFullScreen: Can't open /dev/mouse.\n");
+ }
+ Gpm_Close();
+
+ /* TODO: Scale the mouse coordinates to the specific resolution */
+
+ /* Save the state of the console */
+ if ((stateBuf = malloc(PM_getConsoleStateSize())) == NULL) {
+ printf("Out of memory!\n");
+ exit(-1);
+ }
+ PM_saveConsoleState(stateBuf,tty_fd);
+ initmode = VBE_getVideoMode();
+
+ /* Initialize the signal handler for timer events */
+ signal(SIGALRM, timerHandler);
+
+ /* Capture termination signals so we can clean up properly */
+ signal(SIGTERM, exitHandler);
+ signal(SIGINT, exitHandler);
+ signal(SIGQUIT, exitHandler);
+ atexit(restore_term);
+
+ /* Signal that we are installed */
+ installed = true;
+ }
+ return hwndMain;
+}
+
+/****************************************************************************
+REMARKS:
+Lets the library know when fullscreen graphics mode has been initialized so
+that we can properly scale the mouse driver coordinates.
+****************************************************************************/
+void _WDAPI WD_inFullScreen(void)
+{
+ /* Nothing to do in here */
+}
+
+/****************************************************************************
+REMARKS:
+Suspends all of our event handling operations. This is also used to
+de-install the event handling code.
+****************************************************************************/
+void _WDAPI WD_restoreGDI(void)
+{
+ restore_term();
+}
+
+/****************************************************************************
+PARAMETERS:
+ticks - Number of ticks between timer tick messages
+
+RETURNS:
+Previous value for the timer tick event spacing.
+
+REMARKS:
+The event module will automatically generate periodic timer tick events for
+you, with 'ticks' between each event posting. If you set the value of
+'ticks' to 0, the timer tick events are turned off.
+****************************************************************************/
+int _WDAPI WD_setTimerTick(
+ int ticks)
+{
+ int old;
+ struct itimerval tim;
+ long ms = TICKS_TO_USEC(ticks);
+
+ getitimer(ITIMER_REAL, &tim);
+ old = USEC_TO_TICKS(tim.it_value.tv_sec*1000000.0 + tim.it_value.tv_usec);
+ tim.it_interval.tv_sec = ms / 1000000;
+ tim.it_interval.tv_usec = ms % 1000000;
+ setitimer(ITIMER_REAL, &tim, NULL);
+ return old;
+}
+
+/****************************************************************************
+PARAMETERS:
+saveState - Address of suspend app callback to register
+
+REMARKS:
+Registers a user application supplied suspend application callback so that
+we can properly handle virtual terminal switching.
+****************************************************************************/
+void _WDAPI WD_setSuspendAppCallback(
+ int (_ASMAPI *saveState)(int flags))
+{
+ suspendAppCallback = saveState;
+}
+
+/****************************************************************************
+PARAMETERS:
+x - New X coordinate to move the mouse cursor to
+y - New Y coordinate to move the mouse cursor to
+
+REMARKS:
+Moves to mouse cursor to the specified coordinate.
+****************************************************************************/
+void _WDAPI WD_setMousePos(
+ int x,
+ int y)
+{
+ mx = x;
+ my = y;
+}
+
+/****************************************************************************
+PARAMETERS:
+x - Place to store X coordinate of mouse cursor
+y - Place to store Y coordinate of mouse cursor
+
+REMARKS:
+Reads the current mouse cursor location int *screen* coordinates.
+****************************************************************************/
+void _WDAPI WD_getMousePos(
+ int *x,
+ int *y)
+{
+ *x = mx;
+ *y = my;
+}
+
+/****************************************************************************
+PARAMETERS:
+mcb - Address of mouse callback function
+
+REMARKS:
+Registers an application supplied mouse callback function that is called
+whenever the mouse cursor moves.
+****************************************************************************/
+void _WDAPI WD_setMouseCallback(
+ void (_ASMAPI *mcb)(int x,int y))
+{
+ moveCursor = mcb;
+}
+
+/****************************************************************************
+PARAMETERS:
+xRes - New X resolution of graphics mode
+yRes - New Y resolution of graphics mode
+
+REMARKS:
+This is called to inform the event handling code that the screen resolution
+has changed so that the mouse coordinates can be scaled appropriately.
+****************************************************************************/
+void _WDAPI WD_changeResolution(
+ int xRes,
+ int yRes)
+{
+ // Gpm_FitValues(xRes, yRes); // ??
+}
+
+/****************************************************************************
+PARAMETERS:
+scancode - Scan code to check if a key is down
+
+REMARKS:
+Determines if a particular key is down based on the scan code for the key.
+****************************************************************************/
+ibool _WDAPI WD_isKeyDown(
+ uchar scancode)
+{
+ return key_down[scancode];
+}
+
+/****************************************************************************
+REMARKS:
+Determines if the application needs to run in safe mode. Not necessary for
+anything but broken Windows 95 display drivers so we return false for
+Linux.
+****************************************************************************/
+int _WDAPI WD_isSafeMode(void)
+{
+ return false;
+}
+
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/linux/oshdr.h
new file mode 100644
index 0000000000..6023dff109
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/oshdr.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+*
+* SciTech Multi-platform Graphics Library
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Linux
+*
+* Description: Include all the OS specific header files.
+*
+****************************************************************************/
+
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/fs.h>
+#ifdef USE_OS_JOYSTICK
+#include <linux/joystick.h>
+#endif
+#include <termios.h>
+#include <signal.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/* Internal global variables */
+
+extern int _PM_console_fd,_PM_leds,_PM_modifiers;
+
+/* Internal function prototypes */
+
+void _PM_restore_kb_mode(void);
+void _PM_keyboard_rawmode(void);
+
+/* Linux needs the generic joystick scaling code */
+
+#define NEED_SCALE_JOY_AXIS
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/pm.c b/board/MAI/bios_emulator/scitech/src/pm/linux/pm.c
new file mode 100644
index 0000000000..1d52984a6a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/pm.c
@@ -0,0 +1,1810 @@
+;/****************************************************************************
+*
+* SciTech OS Portability Manager Library
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Portions copyright (C) Josh Vanderhoof
+*
+* Language: ANSI C
+* Environment: Linux
+*
+* Description: Implementation for the OS Portability Manager Library, which
+* contains functions to implement OS specific services in a
+* generic, cross platform API. Porting the OS Portability
+* Manager library is the first step to porting any SciTech
+* products to a new platform.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "drvlib/os/os.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/kd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/vt.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <syscall.h>
+#include <signal.h>
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#ifdef ENABLE_MTRR
+#include <asm/mtrr.h>
+#endif
+#include <asm/vm86.h>
+#ifdef __GLIBC__
+#include <sys/perm.h>
+#endif
+
+/*--------------------------- Global variables ----------------------------*/
+
+#define REAL_MEM_BASE ((void *)0x10000)
+#define REAL_MEM_SIZE 0x10000
+#define REAL_MEM_BLOCKS 0x100
+#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK)
+#define DEFAULT_STACK_SIZE 0x1000
+#define RETURN_TO_32_INT 255
+
+/* Quick and dirty fix for vm86() syscall from lrmi 0.6 */
+static int
+vm86(struct vm86_struct *vm)
+ {
+ int r;
+#ifdef __PIC__
+ asm volatile (
+ "pushl %%ebx\n\t"
+ "movl %2, %%ebx\n\t"
+ "int $0x80\n\t"
+ "popl %%ebx"
+ : "=a" (r)
+ : "0" (113), "r" (vm));
+#else
+ asm volatile (
+ "int $0x80"
+ : "=a" (r)
+ : "0" (113), "b" (vm));
+#endif
+ return r;
+ }
+
+
+static struct {
+ int ready;
+ unsigned short ret_seg, ret_off;
+ unsigned short stack_seg, stack_off;
+ struct vm86_struct vm;
+ } context = {0};
+
+struct mem_block {
+ unsigned int size : 20;
+ unsigned int free : 1;
+ };
+
+static struct {
+ int ready;
+ int count;
+ struct mem_block blocks[REAL_MEM_BLOCKS];
+ } mem_info = {0};
+
+int _PM_console_fd = -1;
+int _PM_leds = 0,_PM_modifiers = 0;
+static ibool inited = false;
+static int tty_vc = 0;
+static int console_count = 0;
+static int startup_vc;
+static int fd_mem = 0;
+static ibool in_raw_mode = false;
+#ifdef ENABLE_MTRR
+static int mtrr_fd;
+#endif
+static uint VESABuf_len = 1024; /* Length of the VESABuf buffer */
+static void *VESABuf_ptr = NULL; /* Near pointer to VESABuf */
+static uint VESABuf_rseg; /* Real mode segment of VESABuf */
+static uint VESABuf_roff; /* Real mode offset of VESABuf */
+#ifdef TRACE_IO
+static ulong traceAddr;
+#endif
+
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+#ifdef TRACE_IO
+extern void printk(char *msg,...);
+#endif
+
+static inline void port_out(int value, int port)
+{
+#ifdef TRACE_IO
+ printk("%04X:%04X: outb.%04X <- %02X\n", traceAddr >> 16, traceAddr & 0xFFFF, (ushort)port, (uchar)value);
+#endif
+ asm volatile ("outb %0,%1"
+ ::"a" ((unsigned char) value), "d"((unsigned short) port));
+}
+
+static inline void port_outw(int value, int port)
+{
+#ifdef TRACE_IO
+ printk("%04X:%04X: outw.%04X <- %04X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ushort)value);
+#endif
+ asm volatile ("outw %0,%1"
+ ::"a" ((unsigned short) value), "d"((unsigned short) port));
+}
+
+static inline void port_outl(int value, int port)
+{
+#ifdef TRACE_IO
+ printk("%04X:%04X: outl.%04X <- %08X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ulong)value);
+#endif
+ asm volatile ("outl %0,%1"
+ ::"a" ((unsigned long) value), "d"((unsigned short) port));
+}
+
+static inline unsigned int port_in(int port)
+{
+ unsigned char value;
+ asm volatile ("inb %1,%0"
+ :"=a" ((unsigned char)value)
+ :"d"((unsigned short) port));
+#ifdef TRACE_IO
+ printk("%04X:%04X: inb.%04X -> %02X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (uchar)value);
+#endif
+ return value;
+}
+
+static inline unsigned int port_inw(int port)
+{
+ unsigned short value;
+ asm volatile ("inw %1,%0"
+ :"=a" ((unsigned short)value)
+ :"d"((unsigned short) port));
+#ifdef TRACE_IO
+ printk("%04X:%04X: inw.%04X -> %04X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ushort)value);
+#endif
+ return value;
+}
+
+static inline unsigned int port_inl(int port)
+{
+ unsigned long value;
+ asm volatile ("inl %1,%0"
+ :"=a" ((unsigned long)value)
+ :"d"((unsigned short) port));
+#ifdef TRACE_IO
+ printk("%04X:%04X: inl.%04X -> %08X\n", traceAddr >> 16,traceAddr & 0xFFFF, (ushort)port, (ulong)value);
+#endif
+ return value;
+}
+
+static int real_mem_init(void)
+{
+ void *m;
+ int fd_zero;
+
+ if (mem_info.ready)
+ return 1;
+
+ if ((fd_zero = open("/dev/zero", O_RDONLY)) == -1)
+ PM_fatalError("You must have root privledges to run this program!");
+ if ((m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, fd_zero, 0)) == (void *)-1) {
+ close(fd_zero);
+ PM_fatalError("You must have root privledges to run this program!");
+ }
+ mem_info.ready = 1;
+ mem_info.count = 1;
+ mem_info.blocks[0].size = REAL_MEM_SIZE;
+ mem_info.blocks[0].free = 1;
+ return 1;
+}
+
+static void insert_block(int i)
+{
+ memmove(
+ mem_info.blocks + i + 1,
+ mem_info.blocks + i,
+ (mem_info.count - i) * sizeof(struct mem_block));
+ mem_info.count++;
+}
+
+static void delete_block(int i)
+{
+ mem_info.count--;
+
+ memmove(
+ mem_info.blocks + i,
+ mem_info.blocks + i + 1,
+ (mem_info.count - i) * sizeof(struct mem_block));
+}
+
+static inline void set_bit(unsigned int bit, void *array)
+{
+ unsigned char *a = array;
+ a[bit / 8] |= (1 << (bit % 8));
+}
+
+static inline unsigned int get_int_seg(int i)
+{
+ return *(unsigned short *)(i * 4 + 2);
+}
+
+static inline unsigned int get_int_off(int i)
+{
+ return *(unsigned short *)(i * 4);
+}
+
+static inline void pushw(unsigned short i)
+{
+ struct vm86_regs *r = &context.vm.regs;
+ r->esp -= 2;
+ *(unsigned short *)(((unsigned int)r->ss << 4) + r->esp) = i;
+}
+
+ibool PMAPI PM_haveBIOSAccess(void)
+{ return true; }
+
+void PMAPI PM_init(void)
+{
+ void *m;
+ uint r_seg,r_off;
+
+ if (inited)
+ return;
+
+ /* Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502)
+ * and the physical framebuffer and ROM images from (0xa0000 - 0x100000)
+ */
+ real_mem_init();
+ if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1) {
+ PM_fatalError("You must have root privileges to run this program!");
+ }
+ if ((m = mmap((void *)0, 0x502,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, fd_mem, 0)) == (void *)-1) {
+ PM_fatalError("You must have root privileges to run this program!");
+ }
+ if ((m = mmap((void *)0xA0000, 0xC0000 - 0xA0000,
+ PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED, fd_mem, 0xA0000)) == (void *)-1) {
+ PM_fatalError("You must have root privileges to run this program!");
+ }
+ if ((m = mmap((void *)0xC0000, 0xD0000 - 0xC0000,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, fd_mem, 0xC0000)) == (void *)-1) {
+ PM_fatalError("You must have root privileges to run this program!");
+ }
+ if ((m = mmap((void *)0xD0000, 0x100000 - 0xD0000,
+ PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED, fd_mem, 0xD0000)) == (void *)-1) {
+ PM_fatalError("You must have root privileges to run this program!");
+ }
+ inited = 1;
+
+ /* Allocate a stack */
+ m = PM_allocRealSeg(DEFAULT_STACK_SIZE,&r_seg,&r_off);
+ context.stack_seg = r_seg;
+ context.stack_off = r_off+DEFAULT_STACK_SIZE;
+
+ /* Allocate the return to 32 bit routine */
+ m = PM_allocRealSeg(2,&r_seg,&r_off);
+ context.ret_seg = r_seg;
+ context.ret_off = r_off;
+ ((uchar*)m)[0] = 0xCD; /* int opcode */
+ ((uchar*)m)[1] = RETURN_TO_32_INT;
+ memset(&context.vm, 0, sizeof(context.vm));
+
+ /* Enable kernel emulation of all ints except RETURN_TO_32_INT */
+ memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored));
+ set_bit(RETURN_TO_32_INT, &context.vm.int_revectored);
+ context.ready = 1;
+#ifdef ENABLE_MTRR
+ mtrr_fd = open("/dev/cpu/mtrr", O_RDWR, 0);
+ if (mtrr_fd < 0)
+ mtrr_fd = open("/proc/mtrr", O_RDWR, 0);
+#endif
+ /* Enable I/O permissions to directly access I/O ports. We break the
+ * allocation into two parts, one for the ports from 0-0x3FF and
+ * another for the remaining ports up to 0xFFFF. Standard Linux kernels
+ * only allow the first 0x400 ports to be enabled, so to enable all
+ * 65536 ports you need a patched kernel that will enable the full
+ * 8Kb I/O permissions bitmap.
+ */
+#ifndef TRACE_IO
+ ioperm(0x0,0x400,1);
+ ioperm(0x400,0x10000-0x400,1);
+#endif
+ iopl(3);
+}
+
+long PMAPI PM_getOSType(void)
+{ return _OS_LINUX; }
+
+int PMAPI PM_getModeType(void)
+{ return PM_386; }
+
+void PMAPI PM_backslash(char *s)
+{
+ uint pos = strlen(s);
+ if (s[pos-1] != '/') {
+ s[pos] = '/';
+ s[pos+1] = '\0';
+ }
+}
+
+void PMAPI PM_setFatalErrorCleanup(
+ void (PMAPIP cleanup)(void))
+{
+ fatalErrorCleanup = cleanup;
+}
+
+void PMAPI PM_fatalError(const char *msg)
+{
+ if (fatalErrorCleanup)
+ fatalErrorCleanup();
+ fprintf(stderr,"%s\n", msg);
+ fflush(stderr);
+ exit(1);
+}
+
+static void ExitVBEBuf(void)
+{
+ if (VESABuf_ptr)
+ PM_freeRealSeg(VESABuf_ptr);
+ VESABuf_ptr = 0;
+}
+
+void * PMAPI PM_getVESABuf(uint *len,uint *rseg,uint *roff)
+{
+ if (!VESABuf_ptr) {
+ /* Allocate a global buffer for communicating with the VESA VBE */
+ if ((VESABuf_ptr = PM_allocRealSeg(VESABuf_len, &VESABuf_rseg, &VESABuf_roff)) == NULL)
+ return NULL;
+ atexit(ExitVBEBuf);
+ }
+ *len = VESABuf_len;
+ *rseg = VESABuf_rseg;
+ *roff = VESABuf_roff;
+ return VESABuf_ptr;
+}
+
+/* New raw console based getch and kbhit functions */
+
+#define KB_CAPS LED_CAP /* 4 */
+#define KB_NUMLOCK LED_NUM /* 2 */
+#define KB_SCROLL LED_SCR /* 1 */
+#define KB_SHIFT 8
+#define KB_CONTROL 16
+#define KB_ALT 32
+
+/* Structure used to save the keyboard mode to disk. We save it to disk
+ * so that we can properly restore the mode later if the program crashed.
+ */
+
+typedef struct {
+ struct termios termios;
+ int kb_mode;
+ int leds;
+ int flags;
+ int startup_vc;
+ } keyboard_mode;
+
+/* Name of the file used to save keyboard mode information */
+
+#define KBMODE_DAT "kbmode.dat"
+
+/****************************************************************************
+REMARKS:
+Open the keyboard mode file on disk.
+****************************************************************************/
+static FILE *open_kb_mode(
+ char *mode,
+ char *path)
+{
+ if (!PM_findBPD("graphics.bpd",path))
+ return NULL;
+ PM_backslash(path);
+ strcat(path,KBMODE_DAT);
+ return fopen(path,mode);
+}
+
+/****************************************************************************
+REMARKS:
+Restore the keyboard to normal mode
+****************************************************************************/
+void _PM_restore_kb_mode(void)
+{
+ FILE *kbmode;
+ keyboard_mode mode;
+ char path[PM_MAX_PATH];
+
+ if (_PM_console_fd != -1 && (kbmode = open_kb_mode("rb",path)) != NULL) {
+ if (fread(&mode,1,sizeof(mode),kbmode) == sizeof(mode)) {
+ if (mode.startup_vc > 0)
+ ioctl(_PM_console_fd, VT_ACTIVATE, mode.startup_vc);
+ ioctl(_PM_console_fd, KDSKBMODE, mode.kb_mode);
+ ioctl(_PM_console_fd, KDSETLED, mode.leds);
+ tcsetattr(_PM_console_fd, TCSAFLUSH, &mode.termios);
+ fcntl(_PM_console_fd,F_SETFL,mode.flags);
+ }
+ fclose(kbmode);
+ unlink(path);
+ in_raw_mode = false;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _PM_abort(
+ int signo)
+{
+ char buf[80];
+
+ sprintf(buf,"Terminating on signal %d",signo);
+ _PM_restore_kb_mode();
+ PM_fatalError(buf);
+}
+
+/****************************************************************************
+REMARKS:
+Put the keyboard into raw mode
+****************************************************************************/
+void _PM_keyboard_rawmode(void)
+{
+ struct termios conf;
+ FILE *kbmode;
+ keyboard_mode mode;
+ char path[PM_MAX_PATH];
+ int i;
+ static int sig_list[] = {
+ SIGHUP,
+ SIGINT,
+ SIGQUIT,
+ SIGILL,
+ SIGTRAP,
+ SIGABRT,
+ SIGIOT,
+ SIGBUS,
+ SIGFPE,
+ SIGKILL,
+ SIGSEGV,
+ SIGTERM,
+ };
+
+ if ((kbmode = open_kb_mode("rb",path)) == NULL) {
+ if ((kbmode = open_kb_mode("wb",path)) == NULL)
+ PM_fatalError("Unable to open kbmode.dat file for writing!");
+ if (ioctl(_PM_console_fd, KDGKBMODE, &mode.kb_mode))
+ perror("KDGKBMODE");
+ ioctl(_PM_console_fd, KDGETLED, &mode.leds);
+ _PM_leds = mode.leds & 0xF;
+ _PM_modifiers = 0;
+ tcgetattr(_PM_console_fd, &mode.termios);
+ conf = mode.termios;
+ conf.c_lflag &= ~(ICANON | ECHO | ISIG);
+ conf.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
+ conf.c_iflag |= (IGNBRK | IGNPAR);
+ conf.c_cc[VMIN] = 1;
+ conf.c_cc[VTIME] = 0;
+ conf.c_cc[VSUSP] = 0;
+ tcsetattr(_PM_console_fd, TCSAFLUSH, &conf);
+ mode.flags = fcntl(_PM_console_fd,F_GETFL);
+ if (ioctl(_PM_console_fd, KDSKBMODE, K_MEDIUMRAW))
+ perror("KDSKBMODE");
+ atexit(_PM_restore_kb_mode);
+ for (i = 0; i < sizeof(sig_list)/sizeof(sig_list[0]); i++)
+ signal(sig_list[i], _PM_abort);
+ mode.startup_vc = startup_vc;
+ if (fwrite(&mode,1,sizeof(mode),kbmode) != sizeof(mode))
+ PM_fatalError("Error writing kbmode.dat!");
+ fclose(kbmode);
+ in_raw_mode = true;
+ }
+}
+
+int PMAPI PM_kbhit(void)
+{
+ fd_set s;
+ struct timeval tv = { 0, 0 };
+
+ if (console_count == 0)
+ PM_fatalError("You *must* open a console before using PM_kbhit!");
+ if (!in_raw_mode)
+ _PM_keyboard_rawmode();
+ FD_ZERO(&s);
+ FD_SET(_PM_console_fd, &s);
+ return select(_PM_console_fd+1, &s, NULL, NULL, &tv) > 0;
+}
+
+int PMAPI PM_getch(void)
+{
+ static uchar c;
+ int release;
+ static struct kbentry ke;
+
+ if (console_count == 0)
+ PM_fatalError("You *must* open a console before using PM_getch!");
+ if (!in_raw_mode)
+ _PM_keyboard_rawmode();
+ while (read(_PM_console_fd, &c, 1) > 0) {
+ release = c & 0x80;
+ c &= 0x7F;
+ if (release) {
+ switch(c){
+ case 42: case 54: // Shift
+ _PM_modifiers &= ~KB_SHIFT;
+ break;
+ case 29: case 97: // Control
+ _PM_modifiers &= ~KB_CONTROL;
+ break;
+ case 56: case 100: // Alt / AltGr
+ _PM_modifiers &= ~KB_ALT;
+ break;
+ }
+ continue;
+ }
+ switch (c) {
+ case 42: case 54: // Shift
+ _PM_modifiers |= KB_SHIFT;
+ break;
+ case 29: case 97: // Control
+ _PM_modifiers |= KB_CONTROL;
+ break;
+ case 56: case 100: // Alt / AltGr
+ _PM_modifiers |= KB_ALT;
+ break;
+ case 58: // Caps Lock
+ _PM_modifiers ^= KB_CAPS;
+ ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
+ break;
+ case 69: // Num Lock
+ _PM_modifiers ^= KB_NUMLOCK;
+ ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
+ break;
+ case 70: // Scroll Lock
+ _PM_modifiers ^= KB_SCROLL;
+ ioctl(_PM_console_fd, KDSETLED, _PM_modifiers & 7);
+ break;
+ case 28:
+ return 0x1C;
+ default:
+ ke.kb_index = c;
+ ke.kb_table = 0;
+ if ((_PM_modifiers & KB_SHIFT) || (_PM_modifiers & KB_CAPS))
+ ke.kb_table |= K_SHIFTTAB;
+ if (_PM_modifiers & KB_ALT)
+ ke.kb_table |= K_ALTTAB;
+ ioctl(_PM_console_fd, KDGKBENT, (ulong)&ke);
+ c = ke.kb_value & 0xFF;
+ return c;
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Sleep until the virtual terminal is active
+****************************************************************************/
+static void wait_vt_active(
+ int _PM_console_fd)
+{
+ while (ioctl(_PM_console_fd, VT_WAITACTIVE, tty_vc) < 0) {
+ if ((errno != EAGAIN) && (errno != EINTR)) {
+ perror("ioctl(VT_WAITACTIVE)");
+ exit(1);
+ }
+ usleep(150000);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Checks the owner of the specified virtual console.
+****************************************************************************/
+static int check_owner(
+ int vc)
+{
+ struct stat sbuf;
+ char fname[30];
+
+ sprintf(fname, "/dev/tty%d", vc);
+ if ((stat(fname, &sbuf) >= 0) && (getuid() == sbuf.st_uid))
+ return 1;
+ printf("You must be the owner of the current console to use this program.\n");
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Checks if the console is currently in graphics mode, and if so we forcibly
+restore it back to text mode again. This handles the case when a Nucleus or
+MGL program crashes and leaves the console in graphics mode. Running the
+textmode utility (or any other Nucleus/MGL program) via a telnet session
+into the machine will restore it back to normal.
+****************************************************************************/
+static void restore_text_console(
+ int console_id)
+{
+ if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0)
+ LOGWARN("ioctl(KDSETMODE) failed");
+ _PM_restore_kb_mode();
+}
+
+/****************************************************************************
+REMARKS:
+Opens up the console device for output by finding an appropriate virutal
+console that we can run on.
+****************************************************************************/
+PM_HWND PMAPI PM_openConsole(
+ PM_HWND hwndUser,
+ int device,
+ int xRes,
+ int yRes,
+ int bpp,
+ ibool fullScreen)
+{
+ struct vt_mode vtm;
+ struct vt_stat vts;
+ struct stat sbuf;
+ char fname[30];
+
+ /* Check if we have already opened the console */
+ if (console_count++)
+ return _PM_console_fd;
+
+ /* Now, it would be great if we could use /dev/tty and see what it is
+ * connected to. Alas, we cannot find out reliably what VC /dev/tty is
+ * bound to. Thus we parse stdin through stderr for a reliable VC.
+ */
+ startup_vc = 0;
+ for (_PM_console_fd = 0; _PM_console_fd < 3; _PM_console_fd++) {
+ if (fstat(_PM_console_fd, &sbuf) < 0)
+ continue;
+ if (ioctl(_PM_console_fd, VT_GETMODE, &vtm) < 0)
+ continue;
+ if ((sbuf.st_rdev & 0xFF00) != 0x400)
+ continue;
+ if (!(sbuf.st_rdev & 0xFF))
+ continue;
+ tty_vc = sbuf.st_rdev & 0xFF;
+ restore_text_console(_PM_console_fd);
+ return _PM_console_fd;
+ }
+ if ((_PM_console_fd = open("/dev/console", O_RDWR)) < 0) {
+ printf("open_dev_console: can't open /dev/console \n");
+ exit(1);
+ }
+ if (ioctl(_PM_console_fd, VT_OPENQRY, &tty_vc) < 0)
+ goto Error;
+ if (tty_vc <= 0)
+ goto Error;
+ sprintf(fname, "/dev/tty%d", tty_vc);
+ close(_PM_console_fd);
+
+ /* Change our control terminal */
+ setsid();
+
+ /* We must use RDWR to allow for output... */
+ if (((_PM_console_fd = open(fname, O_RDWR)) >= 0) &&
+ (ioctl(_PM_console_fd, VT_GETSTATE, &vts) >= 0)) {
+ if (!check_owner(vts.v_active))
+ goto Error;
+ restore_text_console(_PM_console_fd);
+
+ /* Success, redirect all stdios */
+ fflush(stdin);
+ fflush(stdout);
+ fflush(stderr);
+ close(0);
+ close(1);
+ close(2);
+ dup(_PM_console_fd);
+ dup(_PM_console_fd);
+ dup(_PM_console_fd);
+
+ /* clear screen and switch to it */
+ fwrite("\e[H\e[J", 6, 1, stderr);
+ fflush(stderr);
+ if (tty_vc != vts.v_active) {
+ startup_vc = vts.v_active;
+ ioctl(_PM_console_fd, VT_ACTIVATE, tty_vc);
+ wait_vt_active(_PM_console_fd);
+ }
+ }
+ return _PM_console_fd;
+
+Error:
+ if (_PM_console_fd > 2)
+ close(_PM_console_fd);
+ console_count = 0;
+ PM_fatalError(
+ "Not running in a graphics capable console,\n"
+ "and unable to find one.\n");
+ return -1;
+}
+
+#define FONT_C 0x10000 /* 64KB for font data */
+
+/****************************************************************************
+REMARKS:
+Returns the size of the console state buffer.
+****************************************************************************/
+int PMAPI PM_getConsoleStateSize(void)
+{
+ if (!inited)
+ PM_init();
+ return PM_getVGAStateSize() + FONT_C*2;
+}
+
+/****************************************************************************
+REMARKS:
+Save the state of the Linux console.
+****************************************************************************/
+void PMAPI PM_saveConsoleState(void *stateBuf,int console_id)
+{
+ uchar *regs = stateBuf;
+
+ /* Save the current console font */
+ if (ioctl(console_id,GIO_FONT,&regs[PM_getVGAStateSize()]) < 0)
+ perror("ioctl(GIO_FONT)");
+
+ /* Inform the Linux console that we are going into graphics mode */
+ if (ioctl(console_id, KDSETMODE, KD_GRAPHICS) < 0)
+ perror("ioctl(KDSETMODE)");
+
+ /* Save state of VGA registers */
+ PM_saveVGAState(stateBuf);
+}
+
+void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
+{
+ /* TODO: Implement support for allowing console switching! */
+}
+
+/****************************************************************************
+REMARKS:
+Restore the state of the Linux console.
+****************************************************************************/
+void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND console_id)
+{
+ const uchar *regs = stateBuf;
+
+ /* Restore the state of the VGA compatible registers */
+ PM_restoreVGAState(stateBuf);
+
+ /* Inform the Linux console that we are back from graphics modes */
+ if (ioctl(console_id, KDSETMODE, KD_TEXT) < 0)
+ LOGWARN("ioctl(KDSETMODE) failed");
+
+ /* Restore the old console font */
+ if (ioctl(console_id,PIO_FONT,&regs[PM_getVGAStateSize()]) < 0)
+ LOGWARN("ioctl(KDSETMODE) failed");
+
+ /* Coming back from graphics mode on Linux also restored the previous
+ * text mode console contents, so we need to clear the screen to get
+ * around this since the cursor does not get homed by our code.
+ */
+ fflush(stdout);
+ fflush(stderr);
+ printf("\033[H\033[J");
+ fflush(stdout);
+}
+
+/****************************************************************************
+REMARKS:
+Close the Linux console and put it back to normal.
+****************************************************************************/
+void PMAPI PM_closeConsole(PM_HWND _PM_console_fd)
+{
+ /* Restore console to normal operation */
+ if (--console_count == 0) {
+ /* Re-activate the original virtual console */
+ if (startup_vc > 0)
+ ioctl(_PM_console_fd, VT_ACTIVATE, startup_vc);
+
+ /* Close the console file descriptor */
+ if (_PM_console_fd > 2)
+ close(_PM_console_fd);
+ _PM_console_fd = -1;
+ }
+}
+
+void PM_setOSCursorLocation(int x,int y)
+{
+ /* Nothing to do in here */
+}
+
+/****************************************************************************
+REMARKS:
+Set the screen width and height for the Linux console.
+****************************************************************************/
+void PM_setOSScreenWidth(int width,int height)
+{
+ struct winsize ws;
+ struct vt_sizes vs;
+
+ // Resize the software terminal
+ ws.ws_col = width;
+ ws.ws_row = height;
+ ioctl(_PM_console_fd, TIOCSWINSZ, &ws);
+
+ // And the hardware
+ vs.v_rows = height;
+ vs.v_cols = width;
+ vs.v_scrollsize = 0;
+ ioctl(_PM_console_fd, VT_RESIZE, &vs);
+}
+
+ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler ih, int frequency)
+{
+ // TODO: Implement this for Linux
+ return false;
+}
+
+void PMAPI PM_setRealTimeClockFrequency(int frequency)
+{
+ // TODO: Implement this for Linux
+}
+
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ // TODO: Implement this for Linux
+}
+
+char * PMAPI PM_getCurrentPath(
+ char *path,
+ int maxLen)
+{
+ return getcwd(path,maxLen);
+}
+
+char PMAPI PM_getBootDrive(void)
+{ return '/'; }
+
+const char * PMAPI PM_getVBEAFPath(void)
+{ return PM_getNucleusConfigPath(); }
+
+const char * PMAPI PM_getNucleusPath(void)
+{
+ char *env = getenv("NUCLEUS_PATH");
+ return env ? env : "/usr/lib/nucleus";
+}
+
+const char * PMAPI PM_getNucleusConfigPath(void)
+{
+ static char path[256];
+ strcpy(path,PM_getNucleusPath());
+ PM_backslash(path);
+ strcat(path,"config");
+ return path;
+}
+
+const char * PMAPI PM_getUniqueID(void)
+{
+ static char buf[128];
+ gethostname(buf, 128);
+ return buf;
+}
+
+const char * PMAPI PM_getMachineName(void)
+{
+ static char buf[128];
+ gethostname(buf, 128);
+ return buf;
+}
+
+void * PMAPI PM_getBIOSPointer(void)
+{
+ static uchar *zeroPtr = NULL;
+ if (!zeroPtr)
+ zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
+ return (void*)(zeroPtr + 0x400);
+}
+
+void * PMAPI PM_getA0000Pointer(void)
+{
+ /* PM_init maps in the 0xA0000 framebuffer region 1:1 with our
+ * address mapping, so we can return the address here.
+ */
+ if (!inited)
+ PM_init();
+ return (void*)(0xA0000);
+}
+
+void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{
+ uchar *p;
+ ulong baseAddr,baseOfs;
+
+ if (!inited)
+ PM_init();
+ if (base >= 0xA0000 && base < 0x100000)
+ return (void*)base;
+ if (!fd_mem && (fd_mem = open("/dev/mem", O_RDWR)) == -1)
+ return NULL;
+
+ /* Round the physical address to a 4Kb boundary and the limit to a
+ * 4Kb-1 boundary before passing the values to mmap. If we round the
+ * physical address, then we also add an extra offset into the address
+ * that we return.
+ */
+ baseOfs = base & 4095;
+ baseAddr = base & ~4095;
+ limit = ((limit+baseOfs+1+4095) & ~4095)-1;
+ if ((p = mmap(0, limit+1,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd_mem, baseAddr)) == (void *)-1)
+ return NULL;
+ return (void*)(p+baseOfs);
+}
+
+void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
+{
+ if ((ulong)ptr >= 0x100000)
+ munmap(ptr,limit+1);
+}
+
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{
+ // TODO: This function should find the physical address of a linear
+ // address.
+ return 0xFFFFFFFFUL;
+}
+
+ibool PMAPI PM_getPhysicalAddrRange(void *p,ulong length,ulong *physAddress)
+{
+ // TODO: This function should find a range of physical addresses
+ // for a linear address.
+ return false;
+}
+
+void PMAPI PM_sleep(ulong milliseconds)
+{
+ // TODO: Put the process to sleep for milliseconds
+}
+
+int PMAPI PM_getCOMPort(int port)
+{
+ // TODO: Re-code this to determine real values using the Plug and Play
+ // manager for the OS.
+ switch (port) {
+ case 0: return 0x3F8;
+ case 1: return 0x2F8;
+ }
+ return 0;
+}
+
+int PMAPI PM_getLPTPort(int port)
+{
+ // TODO: Re-code this to determine real values using the Plug and Play
+ // manager for the OS.
+ switch (port) {
+ case 0: return 0x3BC;
+ case 1: return 0x378;
+ case 2: return 0x278;
+ }
+ return 0;
+}
+
+void * PMAPI PM_mallocShared(long size)
+{
+ return PM_malloc(size);
+}
+
+void PMAPI PM_freeShared(void *ptr)
+{
+ PM_free(ptr);
+}
+
+void * PMAPI PM_mapToProcess(void *base,ulong limit)
+{ return (void*)base; }
+
+void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
+{
+ /* PM_init maps in the 0xA0000-0x100000 region 1:1 with our
+ * address mapping, as well as all memory blocks in a 1:1 address
+ * mapping so we can simply return the physical address in here.
+ */
+ if (!inited)
+ PM_init();
+ return (void*)MK_PHYS(r_seg,r_off);
+}
+
+void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
+{
+ int i;
+ char *r = (char *)REAL_MEM_BASE;
+
+ if (!inited)
+ PM_init();
+ if (!mem_info.ready)
+ return NULL;
+ if (mem_info.count == REAL_MEM_BLOCKS)
+ return NULL;
+ size = (size + 15) & ~15;
+ for (i = 0; i < mem_info.count; i++) {
+ if (mem_info.blocks[i].free && size < mem_info.blocks[i].size) {
+ insert_block(i);
+ mem_info.blocks[i].size = size;
+ mem_info.blocks[i].free = 0;
+ mem_info.blocks[i + 1].size -= size;
+ *r_seg = (uint)(r) >> 4;
+ *r_off = (uint)(r) & 0xF;
+ return (void *)r;
+ }
+ r += mem_info.blocks[i].size;
+ }
+ return NULL;
+}
+
+void PMAPI PM_freeRealSeg(void *mem)
+{
+ int i;
+ char *r = (char *)REAL_MEM_BASE;
+
+ if (!mem_info.ready)
+ return;
+ i = 0;
+ while (mem != (void *)r) {
+ r += mem_info.blocks[i].size;
+ i++;
+ if (i == mem_info.count)
+ return;
+ }
+ mem_info.blocks[i].free = 1;
+ if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free) {
+ mem_info.blocks[i].size += mem_info.blocks[i + 1].size;
+ delete_block(i + 1);
+ }
+ if (i - 1 >= 0 && mem_info.blocks[i - 1].free) {
+ mem_info.blocks[i - 1].size += mem_info.blocks[i].size;
+ delete_block(i);
+ }
+}
+
+#define DIRECTION_FLAG (1 << 10)
+
+static void em_ins(int size)
+{
+ unsigned int edx, edi;
+
+ edx = context.vm.regs.edx & 0xffff;
+ edi = context.vm.regs.edi & 0xffff;
+ edi += (unsigned int)context.vm.regs.ds << 4;
+ if (context.vm.regs.eflags & DIRECTION_FLAG) {
+ if (size == 4)
+ asm volatile ("std; insl; cld"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ else if (size == 2)
+ asm volatile ("std; insw; cld"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ else
+ asm volatile ("std; insb; cld"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ }
+ else {
+ if (size == 4)
+ asm volatile ("cld; insl"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ else if (size == 2)
+ asm volatile ("cld; insw"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ else
+ asm volatile ("cld; insb"
+ : "=D" (edi) : "d" (edx), "0" (edi));
+ }
+ edi -= (unsigned int)context.vm.regs.ds << 4;
+ context.vm.regs.edi &= 0xffff0000;
+ context.vm.regs.edi |= edi & 0xffff;
+}
+
+static void em_rep_ins(int size)
+{
+ unsigned int ecx, edx, edi;
+
+ ecx = context.vm.regs.ecx & 0xffff;
+ edx = context.vm.regs.edx & 0xffff;
+ edi = context.vm.regs.edi & 0xffff;
+ edi += (unsigned int)context.vm.regs.ds << 4;
+ if (context.vm.regs.eflags & DIRECTION_FLAG) {
+ if (size == 4)
+ asm volatile ("std; rep; insl; cld"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ else if (size == 2)
+ asm volatile ("std; rep; insw; cld"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ else
+ asm volatile ("std; rep; insb; cld"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ }
+ else {
+ if (size == 4)
+ asm volatile ("cld; rep; insl"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ else if (size == 2)
+ asm volatile ("cld; rep; insw"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ else
+ asm volatile ("cld; rep; insb"
+ : "=D" (edi), "=c" (ecx)
+ : "d" (edx), "0" (edi), "1" (ecx));
+ }
+
+ edi -= (unsigned int)context.vm.regs.ds << 4;
+ context.vm.regs.edi &= 0xffff0000;
+ context.vm.regs.edi |= edi & 0xffff;
+ context.vm.regs.ecx &= 0xffff0000;
+ context.vm.regs.ecx |= ecx & 0xffff;
+}
+
+static void em_outs(int size)
+{
+ unsigned int edx, esi;
+
+ edx = context.vm.regs.edx & 0xffff;
+ esi = context.vm.regs.esi & 0xffff;
+ esi += (unsigned int)context.vm.regs.ds << 4;
+ if (context.vm.regs.eflags & DIRECTION_FLAG) {
+ if (size == 4)
+ asm volatile ("std; outsl; cld"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ else if (size == 2)
+ asm volatile ("std; outsw; cld"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ else
+ asm volatile ("std; outsb; cld"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ }
+ else {
+ if (size == 4)
+ asm volatile ("cld; outsl"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ else if (size == 2)
+ asm volatile ("cld; outsw"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ else
+ asm volatile ("cld; outsb"
+ : "=S" (esi) : "d" (edx), "0" (esi));
+ }
+
+ esi -= (unsigned int)context.vm.regs.ds << 4;
+ context.vm.regs.esi &= 0xffff0000;
+ context.vm.regs.esi |= esi & 0xffff;
+}
+
+static void em_rep_outs(int size)
+{
+ unsigned int ecx, edx, esi;
+
+ ecx = context.vm.regs.ecx & 0xffff;
+ edx = context.vm.regs.edx & 0xffff;
+ esi = context.vm.regs.esi & 0xffff;
+ esi += (unsigned int)context.vm.regs.ds << 4;
+ if (context.vm.regs.eflags & DIRECTION_FLAG) {
+ if (size == 4)
+ asm volatile ("std; rep; outsl; cld"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ else if (size == 2)
+ asm volatile ("std; rep; outsw; cld"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ else
+ asm volatile ("std; rep; outsb; cld"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ }
+ else {
+ if (size == 4)
+ asm volatile ("cld; rep; outsl"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ else if (size == 2)
+ asm volatile ("cld; rep; outsw"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ else
+ asm volatile ("cld; rep; outsb"
+ : "=S" (esi), "=c" (ecx)
+ : "d" (edx), "0" (esi), "1" (ecx));
+ }
+
+ esi -= (unsigned int)context.vm.regs.ds << 4;
+ context.vm.regs.esi &= 0xffff0000;
+ context.vm.regs.esi |= esi & 0xffff;
+ context.vm.regs.ecx &= 0xffff0000;
+ context.vm.regs.ecx |= ecx & 0xffff;
+}
+
+static int emulate(void)
+{
+ unsigned char *insn;
+ struct {
+ unsigned int size : 1;
+ unsigned int rep : 1;
+ } prefix = { 0, 0 };
+ int i = 0;
+
+ insn = (unsigned char *)((unsigned int)context.vm.regs.cs << 4);
+ insn += context.vm.regs.eip;
+
+ while (1) {
+#ifdef TRACE_IO
+ traceAddr = ((ulong)context.vm.regs.cs << 16) + context.vm.regs.eip + i;
+#endif
+ if (insn[i] == 0x66) {
+ prefix.size = 1 - prefix.size;
+ i++;
+ }
+ else if (insn[i] == 0xf3) {
+ prefix.rep = 1;
+ i++;
+ }
+ else if (insn[i] == 0xf0 || insn[i] == 0xf2
+ || insn[i] == 0x26 || insn[i] == 0x2e
+ || insn[i] == 0x36 || insn[i] == 0x3e
+ || insn[i] == 0x64 || insn[i] == 0x65
+ || insn[i] == 0x67) {
+ /* these prefixes are just ignored */
+ i++;
+ }
+ else if (insn[i] == 0x6c) {
+ if (prefix.rep)
+ em_rep_ins(1);
+ else
+ em_ins(1);
+ i++;
+ break;
+ }
+ else if (insn[i] == 0x6d) {
+ if (prefix.rep) {
+ if (prefix.size)
+ em_rep_ins(4);
+ else
+ em_rep_ins(2);
+ }
+ else {
+ if (prefix.size)
+ em_ins(4);
+ else
+ em_ins(2);
+ }
+ i++;
+ break;
+ }
+ else if (insn[i] == 0x6e) {
+ if (prefix.rep)
+ em_rep_outs(1);
+ else
+ em_outs(1);
+ i++;
+ break;
+ }
+ else if (insn[i] == 0x6f) {
+ if (prefix.rep) {
+ if (prefix.size)
+ em_rep_outs(4);
+ else
+ em_rep_outs(2);
+ }
+ else {
+ if (prefix.size)
+ em_outs(4);
+ else
+ em_outs(2);
+ }
+ i++;
+ break;
+ }
+ else if (insn[i] == 0xec) {
+ *((uchar*)&context.vm.regs.eax) = port_in(context.vm.regs.edx);
+ i++;
+ break;
+ }
+ else if (insn[i] == 0xed) {
+ if (prefix.size)
+ *((ulong*)&context.vm.regs.eax) = port_inl(context.vm.regs.edx);
+ else
+ *((ushort*)&context.vm.regs.eax) = port_inw(context.vm.regs.edx);
+ i++;
+ break;
+ }
+ else if (insn[i] == 0xee) {
+ port_out(context.vm.regs.eax,context.vm.regs.edx);
+ i++;
+ break;
+ }
+ else if (insn[i] == 0xef) {
+ if (prefix.size)
+ port_outl(context.vm.regs.eax,context.vm.regs.edx);
+ else
+ port_outw(context.vm.regs.eax,context.vm.regs.edx);
+ i++;
+ break;
+ }
+ else
+ return 0;
+ }
+
+ context.vm.regs.eip += i;
+ return 1;
+}
+
+static void debug_info(int vret)
+{
+ int i;
+ unsigned char *p;
+
+ fputs("vm86() failed\n", stderr);
+ fprintf(stderr, "return = 0x%x\n", vret);
+ fprintf(stderr, "eax = 0x%08lx\n", context.vm.regs.eax);
+ fprintf(stderr, "ebx = 0x%08lx\n", context.vm.regs.ebx);
+ fprintf(stderr, "ecx = 0x%08lx\n", context.vm.regs.ecx);
+ fprintf(stderr, "edx = 0x%08lx\n", context.vm.regs.edx);
+ fprintf(stderr, "esi = 0x%08lx\n", context.vm.regs.esi);
+ fprintf(stderr, "edi = 0x%08lx\n", context.vm.regs.edi);
+ fprintf(stderr, "ebp = 0x%08lx\n", context.vm.regs.ebp);
+ fprintf(stderr, "eip = 0x%08lx\n", context.vm.regs.eip);
+ fprintf(stderr, "cs = 0x%04x\n", context.vm.regs.cs);
+ fprintf(stderr, "esp = 0x%08lx\n", context.vm.regs.esp);
+ fprintf(stderr, "ss = 0x%04x\n", context.vm.regs.ss);
+ fprintf(stderr, "ds = 0x%04x\n", context.vm.regs.ds);
+ fprintf(stderr, "es = 0x%04x\n", context.vm.regs.es);
+ fprintf(stderr, "fs = 0x%04x\n", context.vm.regs.fs);
+ fprintf(stderr, "gs = 0x%04x\n", context.vm.regs.gs);
+ fprintf(stderr, "eflags = 0x%08lx\n", context.vm.regs.eflags);
+ fputs("cs:ip = [ ", stderr);
+ p = (unsigned char *)((context.vm.regs.cs << 4) + (context.vm.regs.eip & 0xffff));
+ for (i = 0; i < 16; ++i)
+ fprintf(stderr, "%02x ", (unsigned int)p[i]);
+ fputs("]\n", stderr);
+ fflush(stderr);
+}
+
+static int run_vm86(void)
+{
+ unsigned int vret;
+
+ for (;;) {
+ vret = vm86(&context.vm);
+ if (VM86_TYPE(vret) == VM86_INTx) {
+ unsigned int v = VM86_ARG(vret);
+ if (v == RETURN_TO_32_INT)
+ return 1;
+ pushw(context.vm.regs.eflags);
+ pushw(context.vm.regs.cs);
+ pushw(context.vm.regs.eip);
+ context.vm.regs.cs = get_int_seg(v);
+ context.vm.regs.eip = get_int_off(v);
+ context.vm.regs.eflags &= ~(VIF_MASK | TF_MASK);
+ continue;
+ }
+ if (VM86_TYPE(vret) != VM86_UNKNOWN)
+ break;
+ if (!emulate())
+ break;
+ }
+ debug_info(vret);
+ return 0;
+}
+
+#define IND(ereg) context.vm.regs.ereg = regs->ereg
+#define OUTD(ereg) regs->ereg = context.vm.regs.ereg
+
+void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ IND(eax); IND(ebx); IND(ecx); IND(edx); IND(esi); IND(edi);
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(intno);
+ context.vm.regs.eip = get_int_off(intno);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+ OUTD(eax); OUTD(ebx); OUTD(ecx); OUTD(edx); OUTD(esi); OUTD(edi);
+ regs->flags = context.vm.regs.eflags;
+}
+
+#define IN(ereg) context.vm.regs.ereg = in->e.ereg
+#define OUT(ereg) out->e.ereg = context.vm.regs.ereg
+
+int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(intno);
+ context.vm.regs.eip = get_int_off(intno);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ out->x.cflag = context.vm.regs.eflags & 1;
+ return out->x.ax;
+}
+
+int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
+ RMSREGS *sregs)
+{
+ if (!inited)
+ PM_init();
+ if (intno == 0x21) {
+ time_t today = time(NULL);
+ struct tm *t;
+ t = localtime(&today);
+ out->x.cx = t->tm_year + 1900;
+ out->h.dh = t->tm_mon + 1;
+ out->h.dl = t->tm_mday;
+ }
+ else {
+ unsigned int seg, off;
+ seg = get_int_seg(intno);
+ off = get_int_off(intno);
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = seg;
+ context.vm.regs.eip = off;
+ context.vm.regs.es = sregs->es;
+ context.vm.regs.ds = sregs->ds;
+ context.vm.regs.fs = sregs->fs;
+ context.vm.regs.gs = sregs->gs;
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ sregs->es = context.vm.regs.es;
+ sregs->ds = context.vm.regs.ds;
+ sregs->fs = context.vm.regs.fs;
+ sregs->gs = context.vm.regs.gs;
+ out->x.cflag = context.vm.regs.eflags & 1;
+ }
+ return out->e.eax;
+}
+
+#define OUTR(ereg) in->e.ereg = context.vm.regs.ereg
+
+void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
+ RMSREGS *sregs)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = seg;
+ context.vm.regs.eip = off;
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ context.vm.regs.es = sregs->es;
+ context.vm.regs.ds = sregs->ds;
+ context.vm.regs.fs = sregs->fs;
+ context.vm.regs.gs = sregs->gs;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+ OUTR(eax); OUTR(ebx); OUTR(ecx); OUTR(edx); OUTR(esi); OUTR(edi);
+ sregs->es = context.vm.regs.es;
+ sregs->ds = context.vm.regs.ds;
+ sregs->fs = context.vm.regs.fs;
+ sregs->gs = context.vm.regs.gs;
+ in->x.cflag = context.vm.regs.eflags & 1;
+}
+
+void PMAPI PM_availableMemory(ulong *physical,ulong *total)
+{
+ FILE *mem = fopen("/proc/meminfo","r");
+ char buf[1024];
+
+ fgets(buf,1024,mem);
+ fgets(buf,1024,mem);
+ sscanf(buf,"Mem: %*d %*d %ld", physical);
+ fgets(buf,1024,mem);
+ sscanf(buf,"Swap: %*d %*d %ld", total);
+ fclose(mem);
+ *total += *physical;
+}
+
+void * PMAPI PM_allocLockedMem(uint size,ulong *physAddr,ibool contiguous,ibool below16M)
+{
+ // TODO: Implement this for Linux
+ return NULL;
+}
+
+void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous)
+{
+ // TODO: Implement this for Linux
+}
+
+void * PMAPI PM_allocPage(
+ ibool locked)
+{
+ // TODO: Implement this for Linux
+ return NULL;
+}
+
+void PMAPI PM_freePage(
+ void *p)
+{
+ // TODO: Implement this for Linux
+}
+
+void PMAPI PM_setBankA(int bank)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ context.vm.regs.eax = 0x4F05;
+ context.vm.regs.ebx = 0x0000;
+ context.vm.regs.edx = bank;
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(0x10);
+ context.vm.regs.eip = get_int_off(0x10);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+}
+
+void PMAPI PM_setBankAB(int bank)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ context.vm.regs.eax = 0x4F05;
+ context.vm.regs.ebx = 0x0000;
+ context.vm.regs.edx = bank;
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(0x10);
+ context.vm.regs.eip = get_int_off(0x10);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+ context.vm.regs.eax = 0x4F05;
+ context.vm.regs.ebx = 0x0001;
+ context.vm.regs.edx = bank;
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(0x10);
+ context.vm.regs.eip = get_int_off(0x10);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+}
+
+void PMAPI PM_setCRTStart(int x,int y,int waitVRT)
+{
+ if (!inited)
+ PM_init();
+ memset(&context.vm.regs, 0, sizeof(context.vm.regs));
+ context.vm.regs.eax = 0x4F07;
+ context.vm.regs.ebx = waitVRT;
+ context.vm.regs.ecx = x;
+ context.vm.regs.edx = y;
+ context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
+ context.vm.regs.cs = get_int_seg(0x10);
+ context.vm.regs.eip = get_int_off(0x10);
+ context.vm.regs.ss = context.stack_seg;
+ context.vm.regs.esp = context.stack_off;
+ pushw(DEFAULT_VM86_FLAGS);
+ pushw(context.ret_seg);
+ pushw(context.ret_off);
+ run_vm86();
+}
+
+int PMAPI PM_enableWriteCombine(ulong base,ulong length,uint type)
+{
+#ifdef ENABLE_MTRR
+ struct mtrr_sentry sentry;
+
+ if (mtrr_fd < 0)
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+ sentry.base = base;
+ sentry.size = length;
+ sentry.type = type;
+ if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) == -1) {
+ // TODO: Need to decode MTRR error codes!!
+ return PM_MTRR_NOT_SUPPORTED;
+ }
+ return PM_MTRR_ERR_OK;
+#else
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+#endif
+}
+
+/****************************************************************************
+PARAMETERS:
+callback - Function to callback with write combine information
+
+REMARKS:
+Function to enumerate all write combine regions currently enabled for the
+processor.
+****************************************************************************/
+int PMAPI PM_enumWriteCombine(
+ PM_enumWriteCombine_t callback)
+{
+#ifdef ENABLE_MTRR
+ struct mtrr_gentry gentry;
+
+ if (mtrr_fd < 0)
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+
+ for (gentry.regnum = 0; ioctl (mtrr_fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
+ ++gentry.regnum) {
+ if (gentry.size > 0) {
+ // WARNING: This code assumes that the types in pmapi.h match the ones
+ // in the Linux kernel (mtrr.h)
+ callback(gentry.base, gentry.size, gentry.type);
+ }
+ }
+
+ return PM_MTRR_ERR_OK;
+#else
+ return PM_MTRR_ERR_NO_OS_SUPPORT;
+#endif
+}
+
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *copyOfBIOS,
+ ulong BIOSLen)
+{
+ char *bios_ptr = (char*)0xC0000;
+ char *old_bios;
+ ulong Current10, Current6D, *rvec = 0;
+ RMREGS regs;
+ RMSREGS sregs;
+
+ /* The BIOS is mapped to 0xC0000 with a private memory mapping enabled
+ * which means we have a copy on write scheme. Hence we simply copy
+ * the secondary BIOS image over the top of the old one.
+ */
+ if (!inited)
+ PM_init();
+ if ((old_bios = PM_malloc(BIOSLen)) == NULL)
+ return false;
+ if (BIOSPhysAddr != 0xC0000) {
+ memcpy(old_bios,bios_ptr,BIOSLen);
+ memcpy(bios_ptr,copyOfBIOS,BIOSLen);
+ }
+
+ /* The interrupt vectors should already be mmap()'ed from 0-0x400 in PM_init */
+ Current10 = rvec[0x10];
+ Current6D = rvec[0x6D];
+
+ /* POST the secondary BIOS */
+ rvec[0x10] = rvec[0x42]; /* Restore int 10h to STD-BIOS */
+ regs.x.ax = axVal;
+ PM_callRealMode(0xC000,0x0003,&regs,&sregs);
+
+ /* Restore interrupt vectors */
+ rvec[0x10] = Current10;
+ rvec[0x6D] = Current6D;
+
+ /* Restore original BIOS image */
+ if (BIOSPhysAddr != 0xC0000)
+ memcpy(bios_ptr,old_bios,BIOSLen);
+ PM_free(old_bios);
+ return true;
+}
+
+int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ p = p; len = len;
+ return 1;
+}
+
+int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ p = p; len = len;
+ return 1;
+}
+
+int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ p = p; len = len;
+ return 1;
+}
+
+int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ p = p; len = len;
+ return 1;
+}
+
+PM_MODULE PMAPI PM_loadLibrary(
+ const char *szDLLName)
+{
+ // TODO: Implement this to load shared libraries!
+ (void)szDLLName;
+ return NULL;
+}
+
+void * PMAPI PM_getProcAddress(
+ PM_MODULE hModule,
+ const char *szProcName)
+{
+ // TODO: Implement this!
+ (void)hModule;
+ (void)szProcName;
+ return NULL;
+}
+
+void PMAPI PM_freeLibrary(
+ PM_MODULE hModule)
+{
+ // TODO: Implement this!
+ (void)hModule;
+}
+
+int PMAPI PM_setIOPL(
+ int level)
+{
+ // TODO: Move the IOPL switching into this function!!
+ return level;
+}
+
+void PMAPI PM_flushTLB(void)
+{
+ // Do nothing on Linux.
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/linux/vflat.c
new file mode 100644
index 0000000000..579ef2c95c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/vflat.c
@@ -0,0 +1,49 @@
+/****************************************************************************
+*
+* SciTech OS Portability Manager Library
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Any
+*
+* Description: Dummy module; no virtual framebuffer for this OS
+*
+****************************************************************************/
+
+#include "pmapi.h"
+
+ibool PMAPI VF_available(void)
+{
+ return false;
+}
+
+void * PMAPI VF_init(ulong baseAddr,int bankSize,int codeLen,void *bankFunc)
+{
+ baseAddr = baseAddr;
+ bankSize = bankSize;
+ codeLen = codeLen;
+ bankFunc = bankFunc;
+ return NULL;
+}
+
+void PMAPI VF_exit(void)
+{
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/linux/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/linux/ztimer.c
new file mode 100644
index 0000000000..1b9bae28a6
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/linux/ztimer.c
@@ -0,0 +1,95 @@
+/****************************************************************************
+*
+* Ultra Long Period Timer
+*
+* ========================================================================
+*
+* The contents of this file are subject to the SciTech MGL Public
+* License Version 1.0 (the "License"); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.scitechsoft.com/mgl-license.txt
+*
+* Software distributed under the License is distributed on an
+* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+* The Initial Developer of the Original Code is SciTech Software, Inc.
+* All Rights Reserved.
+*
+* ========================================================================
+*
+* Language: ANSI C
+* Environment: Linux
+*
+* Description: Linux specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+#include <unistd.h>
+#include <sys/time.h>
+#include "pmapi.h"
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+void __ZTimerInit(void)
+{
+}
+
+/****************************************************************************
+REMARKS:
+Use the gettimeofday() function to get microsecond precision (probably less
+though)
+****************************************************************************/
+static inline ulong __ULZReadTime(void)
+{
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ return t.tv_sec*1000000 + t.tv_usec;
+}
+
+/****************************************************************************
+REMARKS:
+Start the Zen Timer counting.
+****************************************************************************/
+#define __LZTimerOn(tm) tm->start.low = __ULZReadTime()
+
+/****************************************************************************
+REMARKS:
+Compute the lap time since the timer was started.
+****************************************************************************/
+#define __LZTimerLap(tm) (__ULZReadTime() - tm->start.low)
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOff(tm) tm->end.low = __ULZReadTime()
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerCount(tm) (tm->end.low - tm->start.low)
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 1
+
+/****************************************************************************
+REMARKS:
+Compute the elapsed time from the BIOS timer tick. Note that we check to see
+whether a midnight boundary has passed, and if so adjust the finish time to
+account for this. We cannot detect if more that one midnight boundary has
+passed, so if this happens we will be generating erronous results.
+****************************************************************************/
+ulong __ULZElapsedTime(ulong start,ulong finish)
+{ return finish - start; }
diff --git a/board/MAI/bios_emulator/scitech/src/pm/makefile b/board/MAI/bios_emulator/scitech/src/pm/makefile
new file mode 100644
index 0000000000..265f0e36d0
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/makefile
@@ -0,0 +1,290 @@
+#############################################################################
+#
+# Copyright (C) 1996 SciTech Software.
+# All rights reserved.
+#
+# Descripton: Generic makefile for the PM library. Builds the library
+# file and all test programs.
+#
+#############################################################################
+
+.IMPORT .IGNORE : DEBUG_AGP_DRIVER TEST_HARNESS DEBUG_SDDPMI
+
+#----------------------------------------------------------------------------
+# Add DOS extender dependant flags to command line
+#----------------------------------------------------------------------------
+
+CFLAGS += $(DX_CFLAGS)
+ASFLAGS += $(DX_ASFLAGS)
+NO_PMLIB := 1
+
+#----------------------------------------------------------------------------
+# Include definitions specific for the target system
+#----------------------------------------------------------------------------
+
+.IF $(USE_VXD)
+
+# Building for Win32 VxD (minimal PM library implementation)
+
+LIBNAME = pm
+OBJECTS = pm$O vflat$O ztimer$O cpuinfo$O mtrr$O fileio$O pcilib$O \
+ agp$O malloc$O vgastate$O gavxd$O _pm$O _mtrr$O _cpuinfo$O \
+ _int64$O _pcihelp$O
+DEPEND_SRC := vxd;common;codepage;tests
+.SOURCE: vxd common codepage tests
+
+.ELIF $(USE_NTDRV)
+
+# Building for NT device drivers (minimal PM library implementation)
+
+LIBNAME = pm
+OBJECTS = pm$O vflat$O ztimer$O cpuinfo$O mtrr$O mem$O irq$O int86$O \
+ stdio$O stdlib$O pcilib$O agp$O malloc$O vgastate$O gantdrv$O \
+ _pm$O _mtrr$O _cpuinfo$O _int64$O _pcihelp$O _irq$O
+DEPEND_SRC := ntdrv;common;codepage;tests
+.SOURCE: ntdrv common codepage tests
+
+.ELIF $(USE_WIN32)
+
+# Building for Win32
+
+CFLAGS += -DUSE_OS_JOYSTICK
+LIBNAME = pm
+OBJECTS = pm$O vflat$O event$O ddraw$O ztimer$O cpuinfo$O pcilib$O \
+ agp$O malloc$O vgastate$O gawin32$O ntservc$O _joy$O _cpuinfo$O \
+ _int64$O _pcihelp$O
+DEPEND_SRC := win32;common;codepage;tests
+.SOURCE: win32 common codepage tests
+
+.ELIF $(USE_OS232)
+
+# Building for OS/2
+
+.IF $(USE_OS2GUI)
+LIBNAME = pm_pm
+.ELSE
+LIBNAME = pm
+.ENDIF
+OBJECTS = pm$O vflat$O event$O ztimer$O cpuinfo$O mtrr$O pcilib$O \
+ agp$O malloc$O vgastate$O gaos2$O _pmos2$O _joy$O _cpuinfo$O \
+ _int64$O _pcihelp$O dossctl$O
+DEPEND_SRC := os2;common;codepage;tests
+.SOURCE: os2 common codepage tests
+
+.ELIF $(USE_QNX)
+
+# Building for QNX
+
+USE_BIOS := 1
+.IF $(USE_PHOTON)
+LIBNAME = pm_ph
+.ELIF $(USE_X11)
+LIBNAME = pm_x11
+.ELSE
+LIBNAME = pm
+.ENDIF
+OBJECTS = pm$O vflat$O event$O ztimer$O cpuinfo$O mtrr$O pcilib$O \
+ agp$O malloc$O mtrrqnx$O unixio$O vgastate$O gaqnx$O _joy$O \
+ _mtrrqnx$O _cpuinfo$O _int64$O _pcihelp$O
+DEPEND_SRC := qnx;common;codepage;tests
+.SOURCE: qnx common codepage tests
+
+# Indicate that this program uses Nucleus device drivers (so needs I/O access)
+USE_NUCLEUS := 1
+
+.ELIF $(USE_LINUX)
+
+# Building for Linux
+
+CFLAGS += -DENABLE_MTRR -DUSE_OS_JOYSTICK
+.IF $(USE_X11)
+LIBNAME = pm_x11
+.ELSE
+LIBNAME = pm
+.ENDIF
+OBJECTS = pm$O vflat$O event$O ztimer$O cpuinfo$O pcilib$O \
+ agp$O malloc$O unixio$O vgastate$O galinux$O _cpuinfo$O \
+ _int64$O _pcihelp$O
+DEPEND_SRC := linux;common;codepage;tests;x11
+.SOURCE: linux common codepage tests x11
+
+# Building a shared library
+.IF $(SOFILE)
+LIB := ld
+LIBFLAGS := -r -o
+CFLAGS += -fPIC
+.ENDIF
+
+.ELIF $(USE_BEOS)
+
+# Building for BeOS GUI
+
+LIBNAME = pm
+OBJECTS = pm$O vflat$O event$O ztimer$O cpuinfo$O pcilib$O \
+ agp$O malloc$O vgastate$O gabeos$O _joy$O _cpuinfo$O \
+ _int64$O _pcihelp$O
+DEPEND_SRC := beos;common;codepage;tests
+.SOURCE: beos common codepage tests
+
+.ELIF $(USE_SMX32)
+
+# Building for SMX
+
+LIBNAME = pm
+OBJECTS = pm$O pmsmx$O vflat$O event$O ztimer$O cpuinfo$O mtrr$O pcilib$O \
+ agp$O malloc$O vgastate$O gasmx$O _pm$O _pmsmx$O _mtrr$O _event$O \
+ _joy$O _cpuinfo$O _int64$O _pcihelp$O _lztimer$O
+DEPEND_SRC := smx;common;codepage;tests
+.SOURCE: smx common codepage tests
+
+.ELIF $(USE_RTTARGET)
+
+# Building for RTTarget-32
+
+LIBNAME = pm
+OBJECTS = pm$O vflat$O event$O ztimer$O cpuinfo$O mtrr$O pcilib$O \
+ agp$O malloc$O vgastate$O gartt$O _mtrr$O _joy$O _cpuinfo$O \
+ _int64$O _pcihelp$O
+DEPEND_SRC := rttarget;common;codepage;tests
+.SOURCE: rttarget common codepage tests
+
+.ELSE
+
+# Building for MSDOS
+
+LIBNAME = pm
+OBJECTS = pm$O pmdos$O vflat$O event$O ztimer$O cpuinfo$O mtrr$O \
+ agp$O malloc$O pcilib$O vgastate$O gados$O \
+ _pm$O _pmdos$O _mtrr$O _vflat$O _event$O _joy$O _pcihelp$O \
+ _cpuinfo$O _int64$O _lztimer$O _dma$O
+DEPEND_SRC := dos;common;codepage;tests
+.SOURCE: dos common codepage tests
+
+.ENDIF
+
+# Object modules for keyboard code pages
+
+OBJECTS += us_eng$O
+
+# Common object modules
+
+OBJECTS += common$O
+.IF $(CHECKED)
+OBJECTS += debug$O
+.ENDIF
+
+# Nucleus loader library object modules. Note that when compiling a test harness
+# library we need to exclude the Nucleus loader library.
+
+.IF $(TEST_HARNESS)
+CFLAGS += -DTEST_HARNESS -DPMLIB
+LIBNAME = pm_test
+.ELSE
+OBJECTS += galib$O _ga_imp$O
+.ENDIF
+
+.IF $(DEBUG_SDDPMI)
+CFLAGS += -DDEBUG_SDDPMI
+.ENDIF
+
+# AGP library object modules
+
+.IF $(DEBUG_AGP_DRIVER)
+CFLAGS += -DDEBUG_AGP_DRIVER
+OBJECTS += agplib$O
+.ELSE
+OBJECTS += agplib$O peloader$O libcimp$O _gatimer$O
+.ENDIF
+
+#----------------------------------------------------------------------------
+# Name of library and generic object files required to build it
+#----------------------------------------------------------------------------
+
+.IF $(STKCALL)
+LIBFILE = s$(LP)$(LIBNAME)$L
+.ELSE
+LIBFILE = $(LP)$(LIBNAME)$L
+.ENDIF
+LIBCLEAN = *.lib *.a
+
+#----------------------------------------------------------------------------
+# Change destination for library file depending the extender being used. This
+# is only necessary for DOS extender since the file go into a subdirectory
+# in the normal library directory, one for each supported extender. Other
+# OS'es put the file into the regular library directory, since there is
+# only one per OS in this case.
+#----------------------------------------------------------------------------
+
+MK_PMODE = 1
+
+.IF $(TEST_HARNESS)
+LIB_DEST := $(LIB_BASE)
+.ELIF $(USE_TNT)
+LIB_DEST := $(LIB_BASE)\tnt
+.ELIF $(USE_DOS4GW)
+LIB_DEST := $(LIB_BASE)\dos4gw
+.ELIF $(USE_X32)
+LIB_DEST := $(LIB_BASE)\x32
+.ELIF $(USE_DPMI16)
+LIB_DEST := $(LIB_BASE)\dpmi16
+.ELIF $(USE_DPMI32)
+LIB_DEST := $(LIB_BASE)\dpmi32
+.ELIF $(USE_DOSX)
+LIB_DEST := $(LIB_BASE)\dosx
+.END
+
+#----------------------------------------------------------------------------
+# Names of all executable files built
+#----------------------------------------------------------------------------
+
+.IF $(USE_REALDOS)
+EXEFILES = memtest$E biosptr$E video$E isvesa$E callreal$E \
+ mouse$E tick$E key$E key15$E brk$E altbrk$E \
+ critical$E altcrit$E vftest$E rtc$E getch$E \
+ cpu$E timerc$E timercpp$E showpci$E uswc$E block$E
+.ELSE
+EXEFILES = memtest$E video$E isvesa$E callreal$E vftest$E getch$E \
+ cpu$E timerc$E timercpp$E showpci$E uswc$E block$E \
+ save$E restore$E
+.ENDIF
+
+all: $(EXEFILES)
+
+$(EXEFILES): $(LIBFILE)
+
+memtest$E: memtest$O
+biosptr$E: biosptr$O
+video$E: video$O
+isvesa$E: isvesa$O
+mouse$E: mouse$O
+tick$E: tick$O
+key$E: key$O
+key15$E: key15$O
+brk$E: brk$O
+altbrk$E: altbrk$O
+critical$E: critical$O
+altcrit$E: altcrit$O
+callreal$E: callreal$O
+vftest$E: vftest$O
+rtc$E: rtc$O
+getch$E: getch$O
+cpu$E: cpu$O
+timerc$E: timerc$O
+timercpp$E: timercpp$O
+showpci$E: showpci$O
+uswc$E: uswc$O
+block$E: block$O
+save$E: save$O
+restore$E: restore$O
+test$E: test$O _test$O
+
+#----------------------------------------------------------------------------
+# Define the list of object files to create dependency information for
+#----------------------------------------------------------------------------
+
+DEPEND_OBJ := $(OBJECTS) memtest$O biosptr$O video$O isvesa$O mouse$O \
+ tick$O key$O key$O brk$O altbrk$O critical$O altcrit$O \
+ callreal$O vftest$O getch$O timercpp$O
+
+.INCLUDE: "$(SCITECH)/makedefs/common.mk"
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/_irq.asm b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/_irq.asm
new file mode 100644
index 0000000000..11824a0afc
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/_irq.asm
@@ -0,0 +1,288 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: 32-bit Windows NT device driver
+;*
+;* Description: Low level assembly support for the PM library specific to
+;* Windows NT device drivers.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _irq ; Set up memory model
+
+begdataseg _irq
+
+ cextern _PM_rtcHandler,CPTR
+ cextern _PM_prevRTC,FCPTR
+
+RtcInside dw 0 ; Are we still handling current interrupt
+sidtBuf df 0 ; Buffer for sidt instruction
+
+enddataseg _irq
+
+begcodeseg _irq ; Start of code segment
+
+cpublic _PM_irqCodeStart
+
+; Macro to delay briefly to ensure that enough time has elapsed between
+; successive I/O accesses so that the device being accessed can respond
+; to both accesses even on a very fast PC.
+
+ifdef USE_NASM
+%macro DELAY 0
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+%endmacro
+%macro IODELAYN 1
+%rep %1
+ DELAY
+%endrep
+%endmacro
+else
+macro DELAY
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+endm
+macro IODELAYN N
+ rept N
+ DELAY
+ endm
+endm
+endif
+
+;----------------------------------------------------------------------------
+; PM_rtcISR - Real time clock interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the timer interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. Make sure your C code executes as
+; quickly as possible, since a timer overrun will simply hang the
+; system.
+;----------------------------------------------------------------------------
+cprocfar _PM_rtcISR
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+; If we enable interrupts and call into any C based interrupt handling code,
+; we need to setup a bunch of important information for the NT kernel. The
+; code below takes care of this housekeeping for us (see Undocumented NT for
+; details). If we don't do this housekeeping and interrupts are enabled,
+; the kernel will become very unstable and crash within 10 seconds or so.
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ pushad
+ pushfd
+ push fs
+
+ mov ebx,00000030h
+ mov fs,bx
+ sub esp,50h
+ mov ebp,esp
+
+; Setup the exception frame to NULL
+
+ mov ebx,[DWORD cs:0FFDFF000h]
+ mov [DWORD ds:0FFDFF000h], 0FFFFFFFFh
+ mov [DWORD ebp],ebx
+
+; Save away the existing KSS ebp
+
+ mov esi,[DWORD cs:0FFDFF124h]
+ mov ebx,[DWORD esi+00000128h]
+ mov [DWORD ebp+4h],ebx
+ mov [DWORD esi+00000128h],ebp
+
+; Save away the kernel time and the thread mode (kernel/user)
+
+ mov edi,[DWORD esi+00000137h]
+ mov [DWORD ebp+8h],edi
+
+; Set the thread mode (kernel/user) based on the code selector
+
+ mov ebx,[DWORD ebp+7Ch]
+ and ebx,01
+ mov [BYTE esi+00000137h],bl
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+; End of special interrupt Prolog code
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+; Clear priority interrupt controller and re-enable interrupts so we
+; dont lock things up for long.
+
+ mov al,20h
+ out 0A0h,al
+ out 020h,al
+
+; Clear real-time clock timeout
+
+ in al,70h ; Read CMOS index register
+ push eax ; and save for later
+ IODELAYN 3
+ mov al,0Ch
+ out 70h,al
+ IODELAYN 5
+ in al,71h
+
+; Call the C interrupt handler function
+
+ cmp [BYTE RtcInside],1 ; Check for mutual exclusion
+ je @@Exit
+ mov [BYTE RtcInside],1
+ sti ; Enable interrupts
+ cld ; Clear direction flag for C code
+ call [CPTR _PM_rtcHandler]
+ cli ; Disable interrupts on exit!
+ mov [BYTE RtcInside],0
+
+@@Exit: pop eax
+ out 70h,al ; Restore CMOS index register
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+; Start of special epilog code to restore stuff on exit from handler
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+; Restore the KSS ebp
+
+ mov esi,[DWORD cs:0FFDFF124h]
+ mov ebx,[DWORD ebp+4]
+ mov [DWORD esi+00000128h],ebx
+
+; Restore the exception frame
+
+ mov ebx,[DWORD ebp]
+ mov [DWORD fs:00000000],ebx
+
+; Restore the thread mode
+
+ mov ebx,[DWORD ebp+8h]
+ mov esi,[DWORD fs:00000124h]
+ mov [BYTE esi+00000137h],bl
+ add esp, 50h
+ pop fs
+ popfd
+ popad
+
+; Return from interrupt
+
+ iret
+
+cprocend
+
+cpublic _PM_irqCodeEnd
+
+;----------------------------------------------------------------------------
+; void _PM_getISR(int irq,PMFARPTR *handler);
+;----------------------------------------------------------------------------
+; Function to return the specific IRQ handler direct from the IDT.
+;----------------------------------------------------------------------------
+cprocstart _PM_getISR
+
+ ARG idtEntry:UINT, handler:DPTR
+
+ enter_c 0
+ mov ecx,[handler] ; Get address of handler to fill in
+ sidt [sidtBuf] ; Get IDTR register into sidtBuf
+ mov eax,[DWORD sidtBuf+2] ; Get address of IDT into EAX
+ mov ebx,[idtEntry]
+ lea eax,[eax+ebx*8] ; Get entry in the IDT
+ movzx edx,[WORD eax+6] ; Get high order 16-bits
+ shl edx,16 ; Move into top 16-bits of address
+ mov dx,[WORD eax] ; Get low order 16-bits
+ mov [DWORD ecx],edx ; Store linear address of handler
+ mov dx,[WORD eax+2] ; Get selector value
+ mov [WORD ecx+4],dx ; Store selector value
+ leave_c
+ ret
+
+cprocend _PM_getISR
+
+;----------------------------------------------------------------------------
+; void _PM_setISR(int irq,void *handler);
+;----------------------------------------------------------------------------
+; Function to set the specific IRQ handler direct in the IDT.
+;----------------------------------------------------------------------------
+cprocstart _PM_setISR
+
+ ARG irq:UINT, handler:CPTR
+
+ enter_c 0
+ mov ecx,[handler] ; Get address of new handler
+ mov dx,cs ; Get selector for new handler
+ sidt [sidtBuf] ; Get IDTR register into sidtBuf
+ mov eax,[DWORD sidtBuf+2] ; Get address of IDT into EAX
+ mov ebx,[idtEntry]
+ lea eax,[eax+ebx*8] ; Get entry in the IDT
+ cli
+ mov [WORD eax+2],dx ; Store code segment selector
+ mov [WORD eax],cx ; Store low order bits of handler
+ shr ecx,16
+ mov [WORD eax+6],cx ; Store high order bits of handler
+ sti
+ leave_c
+ ret
+
+cprocend _PM_setISR
+
+;----------------------------------------------------------------------------
+; void _PM_restoreISR(int irq,PMFARPTR *handler);
+;----------------------------------------------------------------------------
+; Function to set the specific IRQ handler direct in the IDT.
+;----------------------------------------------------------------------------
+cprocstart _PM_restoreISR
+
+ ARG irq:UINT, handler:CPTR
+
+ enter_c 0
+ mov ecx,[handler]
+ mov dx,[WORD ecx+4] ; Get selector for old handler
+ mov ecx,[DWORD ecx] ; Get address of old handler
+ sidt [sidtBuf] ; Get IDTR register into sidtBuf
+ mov eax,[DWORD sidtBuf+2] ; Get address of IDT into EAX
+ mov ebx,[idtEntry]
+ lea eax,[eax+ebx*8] ; Get entry in the IDT
+ cli
+ mov [WORD eax+2],dx ; Store code segment selector
+ mov [WORD eax],cx ; Store low order bits of handler
+ shr ecx,16
+ mov [WORD eax+6],cx ; Store high order bits of handler
+ sti
+ leave_c
+ ret
+
+cprocend _PM_restoreISR
+
+endcodeseg _irq
+
+ END ; End of module
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/_pm.asm b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/_pm.asm
new file mode 100644
index 0000000000..6cb276d25e
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/_pm.asm
@@ -0,0 +1,281 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: 32-bit Windows NT device driver
+;*
+;* Description: Low level assembly support for the PM library specific to
+;* Windows NT device drivers.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pm ; Set up memory model
+
+P586
+
+begdataseg
+
+; Watcom C++ externals required to link when compiling floating point
+; C code. They are not actually used in the code because we compile with
+; inline floating point instructions, however the compiler still generates
+; the references in the object modules.
+
+__8087 dd 0
+ PUBLIC __8087
+__imthread:
+__fltused:
+_fltused_ dd 0
+ PUBLIC __imthread
+ PUBLIC _fltused_
+ PUBLIC __fltused
+
+enddataseg
+
+begcodeseg _pm ; Start of code segment
+
+;----------------------------------------------------------------------------
+; void PM_segread(PMSREGS *sregs)
+;----------------------------------------------------------------------------
+; Read the current value of all segment registers
+;----------------------------------------------------------------------------
+cprocstart PM_segread
+
+ ARG sregs:DPTR
+
+ enter_c
+
+ mov ax,es
+ _les _si,[sregs]
+ mov [_ES _si],ax
+ mov [_ES _si+2],cs
+ mov [_ES _si+4],ss
+ mov [_ES _si+6],ds
+ mov [_ES _si+8],fs
+ mov [_ES _si+10],gs
+
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_int386x(int intno, PMREGS *in, PMREGS *out,PMSREGS *sregs)
+;----------------------------------------------------------------------------
+; Issues a software interrupt in protected mode. This routine has been
+; written to allow user programs to load CS and DS with different values
+; other than the default.
+;----------------------------------------------------------------------------
+cprocstart PM_int386x
+
+; Not used for NT device drivers
+
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setBankA(int bank)
+;----------------------------------------------------------------------------
+cprocstart PM_setBankA
+
+; Not used for NT device drivers
+
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setBankAB(int bank)
+;----------------------------------------------------------------------------
+cprocstart PM_setBankAB
+
+; Not used for NT device drivers
+
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setCRTStart(int x,int y,int waitVRT)
+;----------------------------------------------------------------------------
+cprocstart PM_setCRTStart
+
+; Not used for NT device drivers
+
+ ret
+
+cprocend
+
+; Macro to delay briefly to ensure that enough time has elapsed between
+; successive I/O accesses so that the device being accessed can respond
+; to both accesses even on a very fast PC.
+
+ifdef USE_NASM
+%macro DELAY 0
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+%endmacro
+%macro IODELAYN 1
+%rep %1
+ DELAY
+%endrep
+%endmacro
+else
+macro DELAY
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+endm
+macro IODELAYN N
+ rept N
+ DELAY
+ endm
+endm
+endif
+
+;----------------------------------------------------------------------------
+; uchar _PM_readCMOS(int index)
+;----------------------------------------------------------------------------
+; Read the value of a specific CMOS register. We do this with both
+; normal interrupts and NMI disabled.
+;----------------------------------------------------------------------------
+cprocstart _PM_readCMOS
+
+ ARG index:UINT
+
+ push _bp
+ mov _bp,_sp
+ pushfd
+ mov al,[BYTE index]
+ or al,80h ; Add disable NMI flag
+ cli
+ out 70h,al
+ IODELAYN 5
+ in al,71h
+ mov ah,al
+ xor al,al
+ IODELAYN 5
+ out 70h,al ; Re-enable NMI
+ mov al,ah ; Return value in AL
+ popfd
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_writeCMOS(int index,uchar value)
+;----------------------------------------------------------------------------
+; Read the value of a specific CMOS register. We do this with both
+; normal interrupts and NMI disabled.
+;----------------------------------------------------------------------------
+cprocstart _PM_writeCMOS
+
+ ARG index:UINT, value:UCHAR
+
+ push _bp
+ mov _bp,_sp
+ pushfd
+ mov al,[BYTE index]
+ or al,80h ; Add disable NMI flag
+ cli
+ out 70h,al
+ IODELAYN 5
+ mov al,[value]
+ out 71h,al
+ xor al,al
+ IODELAYN 5
+ out 70h,al ; Re-enable NMI
+ popfd
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; double _ftol(double f)
+;----------------------------------------------------------------------------
+; Calls to __ftol are generated by the Borland C++ compiler for code
+; that needs to convert a floating point type to an integral type.
+;
+; Input: floating point number on the top of the '87.
+;
+; Output: a (signed or unsigned) long in EAX
+; All other registers preserved.
+;-----------------------------------------------------------------------
+cprocstart _ftol
+
+ LOCAL temp1:WORD, temp2:QWORD = LocalSize
+
+ push ebp
+ mov ebp,esp
+ sub esp,LocalSize
+
+ fstcw [temp1] ; save the control word
+ fwait
+ mov al,[BYTE temp1+1]
+ or [BYTE temp1+1],0Ch ; set rounding control to chop
+ fldcw [temp1]
+ fistp [temp2] ; convert to 64-bit integer
+ mov [BYTE temp1+1],al
+ fldcw [temp1] ; restore the control word
+ mov eax,[DWORD temp2] ; return LS 32 bits
+ mov edx,[DWORD temp2+4] ; MS 32 bits
+
+ mov esp,ebp
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; _PM_getPDB - Return the Page Table Directory Base address
+;----------------------------------------------------------------------------
+cprocstart _PM_getPDB
+
+ mov eax,cr3
+ and eax,0FFFFF000h
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; Flush the Translation Lookaside buffer
+;----------------------------------------------------------------------------
+cprocstart PM_flushTLB
+
+ wbinvd ; Flush the CPU cache
+ mov eax,cr3
+ mov cr3,eax ; Flush the TLB
+ ret
+
+cprocend
+
+endcodeseg _pm
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/cpuinfo.c
new file mode 100644
index 0000000000..e72a856019
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/cpuinfo.c
@@ -0,0 +1,65 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows VxD
+*
+* Description: VxD specific code for the CPU detection module.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Do nothing for VxD's
+****************************************************************************/
+#define SetMaxThreadPriority() 0
+
+/****************************************************************************
+REMARKS:
+Do nothing for VxD's
+****************************************************************************/
+#define RestoreThreadPriority(i) (void)(i)
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ KeQueryPerformanceCounter((LARGE_INTEGER*)freq);
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ LARGE_INTEGER lt = KeQueryPerformanceCounter(NULL); \
+ (t)->low = lt.LowPart; \
+ (t)->high = lt.HighPart; \
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/int86.c b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/int86.c
new file mode 100644
index 0000000000..f93d9c22e7
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/int86.c
@@ -0,0 +1,252 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows NT device drivers.
+*
+* Description: Implementation for the real mode software interrupt
+* handling functions.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "drvlib/os/os.h"
+#include "sdd/sddhelp.h"
+#include "mtrr.h"
+#include "oshdr.h"
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+We do have limited BIOS access under Windows NT device drivers.
+****************************************************************************/
+ibool PMAPI PM_haveBIOSAccess(void)
+{
+ // Return false unless we have full buffer passing!
+ return false;
+}
+
+/****************************************************************************
+PARAMETERS:
+len - Place to store the length of the buffer
+rseg - Place to store the real mode segment of the buffer
+roff - Place to store the real mode offset of the buffer
+
+REMARKS:
+This function returns the address and length of the global VESA transfer
+buffer that is used for communicating with the VESA BIOS functions from
+Win16 and Win32 programs under Windows.
+****************************************************************************/
+void * PMAPI PM_getVESABuf(
+ uint *len,
+ uint *rseg,
+ uint *roff)
+{
+ // No buffers supported under Windows NT (Windows XP has them however if
+ // we ever decide to support this!)
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Issue a protected mode software interrupt.
+****************************************************************************/
+int PMAPI PM_int386(
+ int intno,
+ PMREGS *in,
+ PMREGS *out)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+ return PM_int386x(intno,in,out,&sregs);
+}
+
+/****************************************************************************
+REMARKS:
+Map a real mode pointer to a protected mode pointer.
+****************************************************************************/
+void * PMAPI PM_mapRealPointer(
+ uint r_seg,
+ uint r_off)
+{
+ // Not used for Windows NT drivers!
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of real mode memory
+****************************************************************************/
+void * PMAPI PM_allocRealSeg(
+ uint size,
+ uint *r_seg,
+ uint *r_off)
+{
+ // Not supported in NT drivers
+ (void)size;
+ (void)r_seg;
+ (void)r_off;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of real mode memory.
+****************************************************************************/
+void PMAPI PM_freeRealSeg(
+ void *mem)
+{
+ // Not supported in NT drivers
+ (void)mem;
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt (parameters in DPMI compatible structure)
+****************************************************************************/
+void PMAPI DPMI_int86(
+ int intno,
+ DPMI_regs *regs)
+{
+ // Not used in NT drivers
+}
+
+/****************************************************************************
+REMARKS:
+Call a V86 real mode function with the specified register values
+loaded before the call. The call returns with a far ret.
+****************************************************************************/
+void PMAPI PM_callRealMode(
+ uint seg,
+ uint off,
+ RMREGS *regs,
+ RMSREGS *sregs)
+{
+ // TODO!!
+#if 0
+ CLIENT_STRUCT saveRegs;
+
+ /* Bail if we do not have BIOS access (ie: the VxD was dynamically
+ * loaded, and not statically loaded.
+ */
+ if (!_PM_haveBIOS)
+ return;
+
+ TRACE("SDDHELP: Entering PM_callRealMode()\n");
+ Begin_Nest_V86_Exec();
+ LoadV86Registers(&saveRegs,regs,sregs);
+ Simulate_Far_Call(seg, off);
+ Resume_Exec();
+ ReadV86Registers(&saveRegs,regs,sregs);
+ End_Nest_Exec();
+ TRACE("SDDHELP: Exiting PM_callRealMode()\n");
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Issue a V86 real mode interrupt with the specified register values
+loaded before the interrupt.
+****************************************************************************/
+int PMAPI PM_int86(
+ int intno,
+ RMREGS *in,
+ RMREGS *out)
+{
+ // TODO!!
+#if 0
+ RMSREGS sregs = {0};
+ CLIENT_STRUCT saveRegs;
+ ushort oldDisable;
+
+ /* Disable pass-up to our VxD handler so we directly call BIOS */
+ TRACE("SDDHELP: Entering PM_int86()\n");
+ if (disableTSRFlag) {
+ oldDisable = *disableTSRFlag;
+ *disableTSRFlag = 0;
+ }
+ Begin_Nest_V86_Exec();
+ LoadV86Registers(&saveRegs,in,&sregs);
+ Exec_Int(intno);
+ ReadV86Registers(&saveRegs,out,&sregs);
+ End_Nest_Exec();
+
+ /* Re-enable pass-up to our VxD handler if previously enabled */
+ if (disableTSRFlag)
+ *disableTSRFlag = oldDisable;
+
+ TRACE("SDDHELP: Exiting PM_int86()\n");
+#else
+ *out = *in;
+#endif
+ return out->x.ax;
+}
+
+/****************************************************************************
+REMARKS:
+Issue a V86 real mode interrupt with the specified register values
+loaded before the interrupt.
+****************************************************************************/
+int PMAPI PM_int86x(
+ int intno,
+ RMREGS *in,
+ RMREGS *out,
+ RMSREGS *sregs)
+{
+ // TODO!!
+#if 0
+ CLIENT_STRUCT saveRegs;
+ ushort oldDisable;
+
+ /* Bail if we do not have BIOS access (ie: the VxD was dynamically
+ * loaded, and not statically loaded.
+ */
+ if (!_PM_haveBIOS) {
+ *out = *in;
+ return out->x.ax;
+ }
+
+ /* Disable pass-up to our VxD handler so we directly call BIOS */
+ TRACE("SDDHELP: Entering PM_int86x()\n");
+ if (disableTSRFlag) {
+ oldDisable = *disableTSRFlag;
+ *disableTSRFlag = 0;
+ }
+ Begin_Nest_V86_Exec();
+ LoadV86Registers(&saveRegs,in,sregs);
+ Exec_Int(intno);
+ ReadV86Registers(&saveRegs,out,sregs);
+ End_Nest_Exec();
+
+ /* Re-enable pass-up to our VxD handler if previously enabled */
+ if (disableTSRFlag)
+ *disableTSRFlag = oldDisable;
+
+ TRACE("SDDHELP: Exiting PM_int86x()\n");
+#else
+ *out = *in;
+#endif
+ return out->x.ax;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/irq.c b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/irq.c
new file mode 100644
index 0000000000..bc6b4274df
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/irq.c
@@ -0,0 +1,143 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows NT device drivers.
+*
+* Description: Implementation for the NT driver IRQ management functions
+* for the PM library.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "pmint.h"
+#include "drvlib/os/os.h"
+#include "sdd/sddhelp.h"
+#include "mtrr.h"
+#include "oshdr.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+static int globalDataStart;
+static uchar _PM_oldCMOSRegA;
+static uchar _PM_oldCMOSRegB;
+static uchar _PM_oldRTCPIC2;
+static ulong RTC_idtEntry;
+PM_intHandler _PM_rtcHandler = NULL;
+PMFARPTR _VARAPI _PM_prevRTC = PMNULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* Functions to read and write CMOS registers */
+
+uchar _ASMAPI _PM_readCMOS(int index);
+void _ASMAPI _PM_writeCMOS(int index,uchar value);
+void _ASMAPI _PM_rtcISR(void);
+void _ASMAPI _PM_getISR(int irq,PMFARPTR *handler);
+void _ASMAPI _PM_setISR(int irq,void *handler);
+void _ASMAPI _PM_restoreISR(int irq,PMFARPTR *handler);
+void _ASMAPI _PM_irqCodeStart(void);
+void _ASMAPI _PM_irqCodeEnd(void);
+
+/****************************************************************************
+REMARKS:
+Set the real time clock frequency (for stereo modes).
+****************************************************************************/
+void PMAPI PM_setRealTimeClockFrequency(
+ int frequency)
+{
+ static short convert[] = {
+ 8192,
+ 4096,
+ 2048,
+ 1024,
+ 512,
+ 256,
+ 128,
+ 64,
+ 32,
+ 16,
+ 8,
+ 4,
+ 2,
+ -1,
+ };
+ int i;
+
+ /* First clear any pending RTC timeout if not cleared */
+ _PM_readCMOS(0x0C);
+ if (frequency == 0) {
+ /* Disable RTC timout */
+ _PM_writeCMOS(0x0A,(uchar)_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,(uchar)(_PM_oldCMOSRegB & 0x0F));
+ }
+ else {
+ /* Convert frequency value to RTC clock indexes */
+ for (i = 0; convert[i] != -1; i++) {
+ if (convert[i] == frequency)
+ break;
+ }
+
+ /* Set RTC timout value and enable timeout */
+ _PM_writeCMOS(0x0A,(uchar)(0x20 | (i+3)));
+ _PM_writeCMOS(0x0B,(uchar)((_PM_oldCMOSRegB & 0x0F) | 0x40));
+ }
+}
+
+ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
+{
+ static ibool locked = false;
+
+ /* Save the old CMOS real time clock values */
+ _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
+ _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
+
+ /* Install the interrupt handler */
+ RTC_idtEntry = 0x38;
+ _PM_getISR(RTC_idtEntry, &_PM_prevRTC);
+ _PM_rtcHandler = th;
+ _PM_setISR(RTC_idtEntry, _PM_rtcISR);
+
+ /* Program the real time clock default frequency */
+ PM_setRealTimeClockFrequency(frequency);
+
+ /* Unmask IRQ8 in the PIC2 */
+ _PM_oldRTCPIC2 = PM_inpb(0xA1);
+ PM_outpb(0xA1,(uchar)(_PM_oldRTCPIC2 & 0xFE));
+ return true;
+}
+
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ if (_PM_rtcHandler) {
+ /* Restore CMOS registers and mask RTC clock */
+ _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
+ PM_outpb(0xA1,(uchar)((PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE)));
+
+ /* Restore the interrupt vector */
+ _PM_restoreISR(RTC_idtEntry, &_PM_prevRTC);
+ _PM_rtcHandler = NULL;
+ }
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/mem.c b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/mem.c
new file mode 100644
index 0000000000..b30d2be860
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/mem.c
@@ -0,0 +1,519 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows NT device drivers.
+*
+* Description: Implementation for the NT driver memory management functions
+* for the PM library.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "drvlib/os/os.h"
+#include "sdd/sddhelp.h"
+#include "mtrr.h"
+#include "oshdr.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+#define MAX_MEMORY_SHARED 100
+#define MAX_MEMORY_MAPPINGS 100
+#define MAX_MEMORY_LOCKED 100
+
+typedef struct {
+ void *linear;
+ ulong length;
+ PMDL pMdl;
+ } memshared;
+
+typedef struct {
+ void *linear;
+ void *mmIoMapped;
+ ulong length;
+ PMDL pMdl;
+ } memlocked;
+
+typedef struct {
+ ulong physical;
+ ulong linear;
+ ulong length;
+ ibool isCached;
+ } mmapping;
+
+static int numMappings = 0;
+static memshared shared[MAX_MEMORY_MAPPINGS] = {0};
+static mmapping maps[MAX_MEMORY_MAPPINGS];
+static memlocked locked[MAX_MEMORY_LOCKED];
+
+/*----------------------------- Implementation ----------------------------*/
+
+ulong PMAPI _PM_getPDB(void);
+
+// Page table entry flags
+
+#define PAGE_FLAGS_PRESENT 0x00000001
+#define PAGE_FLAGS_WRITEABLE 0x00000002
+#define PAGE_FLAGS_USER 0x00000004
+#define PAGE_FLAGS_WRITE_THROUGH 0x00000008
+#define PAGE_FLAGS_CACHE_DISABLE 0x00000010
+#define PAGE_FLAGS_ACCESSED 0x00000020
+#define PAGE_FLAGS_DIRTY 0x00000040
+#define PAGE_FLAGS_4MB 0x00000080
+
+/****************************************************************************
+PARAMETERS:
+base - Physical base address of the memory to maps in
+limit - Limit of physical memory to region to maps in
+
+RETURNS:
+Linear address of the newly mapped memory.
+
+REMARKS:
+Maps a physical memory range to a linear memory range.
+****************************************************************************/
+static ulong _PM_mapPhysicalToLinear(
+ ulong base,
+ ulong limit,
+ ibool isCached)
+{
+ ulong length = limit+1;
+ PHYSICAL_ADDRESS paIoBase = {0};
+
+ // NT loves large Ints
+ paIoBase = RtlConvertUlongToLargeInteger( base );
+
+ // Map IO space into Kernel
+ if (isCached)
+ return (ULONG)MmMapIoSpace(paIoBase, length, MmCached );
+ else
+ return (ULONG)MmMapIoSpace(paIoBase, length, MmNonCached );
+}
+
+/****************************************************************************
+REMARKS:
+Adjust the page table caching bits directly. Requires ring 0 access and
+only works with DOS4GW and compatible extenders (CauseWay also works since
+it has direct support for the ring 0 instructions we need from ring 3). Will
+not work in a DOS box, but we call into the ring 0 helper VxD so we should
+never get here in a DOS box anyway (assuming the VxD is present). If we
+do get here and we are in windows, this code will be skipped.
+****************************************************************************/
+static void _PM_adjustPageTables(
+ ulong linear,
+ ulong limit,
+ ibool isGlobal,
+ ibool isCached)
+{
+ int startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
+ ulong pageTable,*pPDB,*pPageTable;
+ ulong mask = 0xFFFFFFFF;
+ ulong bits = 0x00000000;
+
+ /* Enable user level access for page table entry */
+ if (isGlobal) {
+ mask &= ~PAGE_FLAGS_USER;
+ bits |= PAGE_FLAGS_USER;
+ }
+
+ /* Disable PCD bit if page table entry should be uncached */
+ if (!isCached) {
+ mask &= ~(PAGE_FLAGS_CACHE_DISABLE | PAGE_FLAGS_WRITE_THROUGH);
+ bits |= (PAGE_FLAGS_CACHE_DISABLE | PAGE_FLAGS_WRITE_THROUGH);
+ }
+
+ pPDB = (ulong*)_PM_mapPhysicalToLinear(_PM_getPDB(),0xFFF,true);
+ if (pPDB) {
+ startPDB = (linear >> 22) & 0x3FF;
+ startPage = (linear >> 12) & 0x3FF;
+ endPDB = ((linear+limit) >> 22) & 0x3FF;
+ endPage = ((linear+limit) >> 12) & 0x3FF;
+ for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
+ // Set the bits in the page directory entry - required as per
+ // Pentium 4 manual. This also takes care of the 4MB page entries
+ pPDB[iPDB] = (pPDB[iPDB] & mask) | bits;
+ if (!(pPDB[iPDB] & PAGE_FLAGS_4MB)) {
+ // If we are dealing with 4KB pages then we need to iterate
+ // through each of the page table entries
+ pageTable = pPDB[iPDB] & ~0xFFF;
+ pPageTable = (ulong*)_PM_mapPhysicalToLinear(pageTable,0xFFF,true);
+ start = (iPDB == startPDB) ? startPage : 0;
+ end = (iPDB == endPDB) ? endPage : 0x3FF;
+ for (iPage = start; iPage <= end; iPage++) {
+ pPageTable[iPage] = (pPageTable[iPage] & mask) | bits;
+ }
+ MmUnmapIoSpace(pPageTable,0xFFF);
+ }
+ }
+ MmUnmapIoSpace(pPDB,0xFFF);
+ PM_flushTLB();
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of shared memory. For NT we allocate shared memory
+as locked, global memory that is accessible from any memory context
+(including interrupt time context), which allows us to load our important
+data structure and code such that we can access it directly from a ring
+0 interrupt context.
+****************************************************************************/
+void * PMAPI PM_mallocShared(
+ long size)
+{
+ int i;
+
+ // First find a free slot in our shared memory table
+ for (i = 0; i < MAX_MEMORY_SHARED; i++) {
+ if (shared[i].linear == 0)
+ break;
+ }
+ if (i == MAX_MEMORY_SHARED)
+ return NULL;
+
+ // Allocate the paged pool
+ shared[i].linear = ExAllocatePool(PagedPool, size);
+
+ // Create a list to manage this allocation
+ shared[i].pMdl = IoAllocateMdl(shared[i].linear,size,FALSE,FALSE,(PIRP) NULL);
+
+ // Lock this allocation in memory
+ MmProbeAndLockPages(shared[i].pMdl,KernelMode,IoModifyAccess);
+
+ // Modify bits to grant user access
+ _PM_adjustPageTables((ulong)shared[i].linear, size, true, true);
+ return (void*)shared[i].linear;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of shared memory
+****************************************************************************/
+void PMAPI PM_freeShared(
+ void *p)
+{
+ int i;
+
+ // Find a shared memory block in our table and free it
+ for (i = 0; i < MAX_MEMORY_SHARED; i++) {
+ if (shared[i].linear == p) {
+ // Unlock what we locked
+ MmUnlockPages(shared[i].pMdl);
+
+ // Free our MDL
+ IoFreeMdl(shared[i].pMdl);
+
+ // Free our mem
+ ExFreePool(shared[i].linear);
+
+ // Flag that is entry is available
+ shared[i].linear = 0;
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Map a physical address to a linear address in the callers process.
+****************************************************************************/
+void * PMAPI PM_mapPhysicalAddr(
+ ulong base,
+ ulong limit,
+ ibool isCached)
+{
+ ulong linear,length = limit+1;
+ int i;
+
+ // Search table of existing mappings to see if we have already mapped
+ // a region of memory that will serve this purpose.
+ for (i = 0; i < numMappings; i++) {
+ if (maps[i].physical == base && maps[i].length == length && maps[i].isCached == isCached) {
+ _PM_adjustPageTables((ulong)maps[i].linear, maps[i].length, true, isCached);
+ return (void*)maps[i].linear;
+ }
+ }
+ if (numMappings == MAX_MEMORY_MAPPINGS)
+ return NULL;
+
+ // We did not find any previously mapped memory region, so maps it in.
+ if ((linear = _PM_mapPhysicalToLinear(base,limit,isCached)) == 0xFFFFFFFF)
+ return NULL;
+ maps[numMappings].physical = base;
+ maps[numMappings].length = length;
+ maps[numMappings].linear = linear;
+ maps[numMappings].isCached = isCached;
+ numMappings++;
+
+ // Grant user access to this I/O space
+ _PM_adjustPageTables((ulong)linear, length, true, isCached);
+ return (void*)linear;
+}
+
+/****************************************************************************
+REMARKS:
+Free a physical address mapping allocated by PM_mapPhysicalAddr.
+****************************************************************************/
+void PMAPI PM_freePhysicalAddr(
+ void *ptr,
+ ulong limit)
+{
+ // We don't free the memory mappings in here because we cache all
+ // the memory mappings we create in the system for later use.
+}
+
+/****************************************************************************
+REMARKS:
+Called when the device driver unloads to free all the page table mappings!
+****************************************************************************/
+void PMAPI _PM_freeMemoryMappings(void)
+{
+ int i;
+
+ for (i = 0; i < numMappings; i++)
+ MmUnmapIoSpace((void *)maps[i].linear,maps[i].length);
+}
+
+/****************************************************************************
+REMARKS:
+Find the physical address of a linear memory address in current process.
+****************************************************************************/
+ulong PMAPI PM_getPhysicalAddr(
+ void *p)
+{
+ PHYSICAL_ADDRESS paOurAddress;
+
+ paOurAddress = MmGetPhysicalAddress(p);
+ return paOurAddress.LowPart;
+}
+
+/****************************************************************************
+REMARKS:
+Find the physical address of a linear memory address in current process.
+****************************************************************************/
+ibool PMAPI PM_getPhysicalAddrRange(
+ void *p,
+ ulong length,
+ ulong *physAddress)
+{
+ int i;
+ ulong linear = (ulong)p & ~0xFFF;
+
+ for (i = (length + 0xFFF) >> 12; i > 0; i--) {
+ if ((*physAddress++ = PM_getPhysicalAddr((void*)linear)) == 0xFFFFFFFF)
+ return false;
+ linear += 4096;
+ }
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Allocates a block of locked physical memory.
+****************************************************************************/
+void * PMAPI PM_allocLockedMem(
+ uint size,
+ ulong *physAddr,
+ ibool contiguous,
+ ibool below16M)
+{
+ int i;
+ PHYSICAL_ADDRESS paOurAddress;
+
+ // First find a free slot in our shared memory table
+ for (i = 0; i < MAX_MEMORY_LOCKED; i++) {
+ if (locked[i].linear == 0)
+ break;
+ }
+ if (i == MAX_MEMORY_LOCKED)
+ return NULL;
+
+ // HighestAcceptableAddress - Specifies the highest valid physical address
+ // the driver can use. For example, if a device can only reference physical
+ // memory in the lower 16MB, this value would be set to 0x00000000FFFFFF.
+ paOurAddress.HighPart = 0;
+ if (below16M)
+ paOurAddress.LowPart = 0x00FFFFFF;
+ else
+ paOurAddress.LowPart = 0xFFFFFFFF;
+
+ if (contiguous) {
+ // Allocate from the non-paged pool (unfortunately 4MB pages)
+ locked[i].linear = MmAllocateContiguousMemory(size, paOurAddress);
+ if (!locked[i].linear)
+ return NULL;
+
+ // Flag no MDL
+ locked[i].pMdl = NULL;
+
+ // Map the physical address for the memory so we can manage
+ // the page tables in 4KB chunks mapped into user space.
+
+ // TODO: Map this with the physical address to the linear addresss
+ locked[i].mmIoMapped = locked[i].linear;
+
+ // Modify bits to grant user access, flag not cached
+ _PM_adjustPageTables((ulong)locked[i].mmIoMapped, size, true, false);
+ return (void*)locked[i].mmIoMapped;
+ }
+ else {
+ // Allocate from the paged pool
+ locked[i].linear = ExAllocatePool(PagedPool, size);
+ if (!locked[i].linear)
+ return NULL;
+
+ // Create a list to manage this allocation
+ locked[i].pMdl = IoAllocateMdl(locked[i].linear,size,FALSE,FALSE,(PIRP) NULL);
+
+ // Lock this allocation in memory
+ MmProbeAndLockPages(locked[i].pMdl,KernelMode,IoModifyAccess);
+
+ // Modify bits to grant user access, flag not cached
+ _PM_adjustPageTables((ulong)locked[i].linear, size, true, false);
+ return (void*)locked[i].linear;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Frees a block of locked physical memory.
+****************************************************************************/
+void PMAPI PM_freeLockedMem(
+ void *p,
+ uint size,
+ ibool contiguous)
+{
+ int i;
+
+ /* Find a locked memory block in our table and free it */
+ for (i = 0; i < MAX_MEMORY_LOCKED; i++) {
+ if (locked[i].linear == p) {
+ // An Mdl indicates that we used the paged pool, and locked it,
+ // so now we have to unlock, free the MDL, and free paged
+ if (locked[i].pMdl) {
+ // Unlock what we locked and free the Mdl
+ MmUnlockPages(locked[i].pMdl);
+ IoFreeMdl(locked[i].pMdl);
+ ExFreePool(locked[i].linear);
+ }
+ else {
+ // TODO: Free the mmIoMap mapping for the memory!
+
+ // Free non-paged pool
+ MmFreeContiguousMemory(locked[i].linear);
+ }
+
+ // Flag that is entry is available
+ locked[i].linear = 0;
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Allocates a page aligned and page sized block of memory
+****************************************************************************/
+void * PMAPI PM_allocPage(
+ ibool locked)
+{
+ // Allocate the memory from the non-paged pool if we want the memory
+ // to be locked.
+ return ExAllocatePool(
+ locked ? NonPagedPoolCacheAligned : PagedPoolCacheAligned,
+ PAGE_SIZE);
+}
+
+/****************************************************************************
+REMARKS:
+Free a page aligned and page sized block of memory
+****************************************************************************/
+void PMAPI PM_freePage(
+ void *p)
+{
+ if (p) ExFreePool(p);
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockDataPages(
+ void *p,
+ uint len,
+ PM_lockHandle *lh)
+{
+ MDL *pMdl;
+
+ // Create a list to manage this allocation
+ if ((pMdl = IoAllocateMdl(p,len,FALSE,FALSE,(PIRP)NULL)) == NULL)
+ return false;
+
+ // Lock this allocation in memory
+ MmProbeAndLockPages(pMdl,KernelMode,IoModifyAccess);
+ *((PMDL*)(&lh->h)) = pMdl;
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockDataPages(
+ void *p,
+ uint len,
+ PM_lockHandle *lh)
+{
+ if (p && lh) {
+ // Unlock what we locked
+ MDL *pMdl = *((PMDL*)(&lh->h));
+ MmUnlockPages(pMdl);
+ IoFreeMdl(pMdl);
+ }
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockCodePages(
+ void (*p)(),
+ uint len,
+ PM_lockHandle *lh)
+{
+ return PM_lockDataPages((void*)p,len,lh);
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockCodePages(
+ void (*p)(),
+ uint len,
+ PM_lockHandle *lh)
+{
+ return PM_unlockDataPages((void*)p,len,lh);
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/oshdr.h
new file mode 100644
index 0000000000..3f747bb9ce
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/oshdr.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows NT drivers
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
+
+#ifndef __NTDRV_OSHDR_H
+#define __NTDRV_OSHDR_H
+
+/*--------------------------- Macros and Typedefs -------------------------*/
+
+/*---------------------------- Global variables ---------------------------*/
+
+/*--------------------------- Function Prototypes -------------------------*/
+
+/* Internal unicode string handling functions */
+
+UNICODE_STRING * _PM_CStringToUnicodeString(const char *cstr);
+void _PM_FreeUnicodeString(UNICODE_STRING *uniStr);
+
+#endif // __NTDRV_OSHDR_H
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/pm.c b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/pm.c
new file mode 100644
index 0000000000..d4bbe228b7
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/pm.c
@@ -0,0 +1,934 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows NT device drivers.
+*
+* 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 "sdd/sddhelp.h"
+#include "mtrr.h"
+#include "oshdr.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+char _PM_cntPath[PM_MAX_PATH] = "";
+char _PM_nucleusPath[PM_MAX_PATH] = "";
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+static char *szNTWindowsKey = "\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion";
+static char *szNTSystemRoot = "SystemRoot";
+static char *szMachineNameKey = "\\REGISTRY\\Machine\\System\\CurrentControlSet\\control\\ComputerName\\ComputerName";
+static char *szMachineNameKeyNT = "\\REGISTRY\\Machine\\System\\CurrentControlSet\\control\\ComputerName\\ActiveComputerName";
+static char *szMachineName = "ComputerName";
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the PM library.
+****************************************************************************/
+void PMAPI PM_init(void)
+{
+ /* Initialiase the MTRR module */
+ MTRR_init();
+}
+
+/****************************************************************************
+REMARKS:
+Return the operating system type identifier.
+****************************************************************************/
+long PMAPI PM_getOSType(void)
+{
+ return _OS_WINNTDRV;
+}
+
+/****************************************************************************
+REMARKS:
+Return the runtime type identifier.
+****************************************************************************/
+int PMAPI PM_getModeType(void)
+{
+ return PM_386;
+}
+
+/****************************************************************************
+REMARKS:
+Add a file directory separator to the end of the filename.
+****************************************************************************/
+void PMAPI PM_backslash(char *s)
+{
+ uint pos = strlen(s);
+ if (s[pos-1] != '\\') {
+ s[pos] = '\\';
+ s[pos+1] = '\0';
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Add a user defined PM_fatalError cleanup function.
+****************************************************************************/
+void PMAPI PM_setFatalErrorCleanup(
+ void (PMAPIP cleanup)(void))
+{
+ fatalErrorCleanup = cleanup;
+}
+
+/****************************************************************************
+REMARKS:
+Handle fatal errors internally in the driver.
+****************************************************************************/
+void PMAPI PM_fatalError(
+ const char *msg)
+{
+ ULONG BugCheckCode = 0;
+ ULONG MoreBugCheckData[4] = {0};
+ char *p;
+ ULONG len;
+
+ if (fatalErrorCleanup)
+ fatalErrorCleanup();
+
+#ifdef DBG // Send output to debugger, just return so as not to force a reboot
+#pragma message("INFO: building for debug, PM_fatalError() re-routed")
+ DBGMSG2("SDDHELP> PM_fatalError(): ERROR: %s\n", msg);
+ return ;
+#endif
+ // KeBugCheckEx brings down the system in a controlled
+ // manner when the caller discovers an unrecoverable
+ // inconsistency that would corrupt the system if
+ // the caller continued to run.
+ //
+ // hack - dump the first 20 chars in hex using the variables
+ // provided - Each ULONG is equal to four characters...
+ for(len = 0; len < 20; len++)
+ if (msg[len] == (char)0)
+ break;
+
+ // This looks bad but it's quick and reliable...
+ p = (char *)&BugCheckCode;
+ if(len > 0) p[3] = msg[0];
+ if(len > 1) p[2] = msg[1];
+ if(len > 2) p[1] = msg[2];
+ if(len > 3) p[0] = msg[3];
+
+ p = (char *)&MoreBugCheckData[0];
+ if(len > 4) p[3] = msg[4];
+ if(len > 5) p[2] = msg[5];
+ if(len > 6) p[1] = msg[6];
+ if(len > 7) p[0] = msg[7];
+
+ p = (char *)&MoreBugCheckData[1];
+ if(len > 8) p[3] = msg[8];
+ if(len > 9) p[2] = msg[9];
+ if(len > 10) p[1] = msg[10];
+ if(len > 11) p[0] = msg[11];
+
+ p = (char *)&MoreBugCheckData[2];
+ if(len > 12) p[3] = msg[12];
+ if(len > 13) p[2] = msg[13];
+ if(len > 14) p[1] = msg[14];
+ if(len > 15) p[0] = msg[15];
+
+ p = (char *)&MoreBugCheckData[3];
+ if(len > 16) p[3] = msg[16];
+ if(len > 17) p[2] = msg[17];
+ if(len > 18) p[1] = msg[18];
+ if(len > 19) p[0] = msg[19];
+
+ // Halt the system!
+ KeBugCheckEx(BugCheckCode, MoreBugCheckData[0], MoreBugCheckData[1], MoreBugCheckData[2], MoreBugCheckData[3]);
+}
+
+/****************************************************************************
+REMARKS:
+Return the current operating system path or working directory.
+****************************************************************************/
+char * PMAPI PM_getCurrentPath(
+ char *path,
+ int maxLen)
+{
+ strncpy(path,_PM_cntPath,maxLen);
+ path[maxLen-1] = 0;
+ return path;
+}
+
+/****************************************************************************
+PARAMETERS:
+szKey - Key to query (can contain version number formatting)
+szValue - Value to get information for
+value - Place to store the registry key data read
+size - Size of the string buffer to read into
+
+RETURNS:
+true if the key was found, false if not.
+****************************************************************************/
+static ibool REG_queryString(
+ char *szKey,
+ const char *szValue,
+ char *value,
+ DWORD size)
+{
+ ibool status;
+ NTSTATUS rval;
+ ULONG length;
+ HANDLE Handle;
+ OBJECT_ATTRIBUTES keyAttributes;
+ UNICODE_STRING *uniKey = NULL;
+ UNICODE_STRING *uniValue = NULL;
+ PKEY_VALUE_FULL_INFORMATION fullInfo = NULL;
+ STRING stringdata;
+ UNICODE_STRING unidata;
+
+ // Convert strings to UniCode
+ status = false;
+ if ((uniKey = _PM_CStringToUnicodeString(szKey)) == NULL)
+ goto Exit;
+ if ((uniValue = _PM_CStringToUnicodeString(szValue)) == NULL)
+ goto Exit;
+
+ // Open the key
+ InitializeObjectAttributes( &keyAttributes,
+ uniKey,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+ rval = ZwOpenKey( &Handle,
+ KEY_ALL_ACCESS,
+ &keyAttributes );
+ if (!NT_SUCCESS(rval))
+ goto Exit;
+
+ // Query the value
+ length = sizeof (KEY_VALUE_FULL_INFORMATION)
+ + size * sizeof(WCHAR);
+ if ((fullInfo = ExAllocatePool (PagedPool, length)) == NULL)
+ goto Exit;
+ RtlZeroMemory(fullInfo, length);
+ rval = ZwQueryValueKey (Handle,
+ uniValue,
+ KeyValueFullInformation,
+ fullInfo,
+ length,
+ &length);
+ if (NT_SUCCESS (rval)) {
+ // Create the UniCode string so we can convert it
+ unidata.Buffer = (PWCHAR)(((PCHAR)fullInfo) + fullInfo->DataOffset);
+ unidata.Length = (USHORT)fullInfo->DataLength;
+ unidata.MaximumLength = (USHORT)fullInfo->DataLength + sizeof(WCHAR);
+
+ // Convert unicode univalue to ansi string.
+ rval = RtlUnicodeStringToAnsiString(&stringdata, &unidata, TRUE);
+ if (NT_SUCCESS(rval)) {
+ strcpy(value,stringdata.Buffer);
+ status = true;
+ }
+ }
+
+Exit:
+ if (fullInfo) ExFreePool(fullInfo);
+ if (uniKey) _PM_FreeUnicodeString(uniKey);
+ if (uniValue) _PM_FreeUnicodeString(uniValue);
+ return status;
+}
+
+/****************************************************************************
+REMARKS:
+Return the drive letter for the boot drive.
+****************************************************************************/
+char PMAPI PM_getBootDrive(void)
+{
+ char path[256];
+ if (REG_queryString(szNTWindowsKey,szNTSystemRoot,path,sizeof(path)))
+ return 'c';
+ return path[0];
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the VBE/AF driver files.
+****************************************************************************/
+const char * PMAPI PM_getVBEAFPath(void)
+{
+ return "c:\\";
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the Nucleus driver files.
+****************************************************************************/
+const char * PMAPI PM_getNucleusPath(void)
+{
+ static char path[256];
+
+ if (strlen(_PM_nucleusPath) > 0) {
+ strcpy(path,_PM_nucleusPath);
+ PM_backslash(path);
+ return path;
+ }
+ if (!REG_queryString(szNTWindowsKey,szNTSystemRoot,path,sizeof(path)))
+ strcpy(path,"c:\\winnt");
+ PM_backslash(path);
+ strcat(path,"system32\\nucleus");
+ return path;
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the Nucleus configuration files.
+****************************************************************************/
+const char * PMAPI PM_getNucleusConfigPath(void)
+{
+ static char path[256];
+ strcpy(path,PM_getNucleusPath());
+ PM_backslash(path);
+ strcat(path,"config");
+ return path;
+}
+
+/****************************************************************************
+REMARKS:
+Return a unique identifier for the machine if possible.
+****************************************************************************/
+const char * PMAPI PM_getUniqueID(void)
+{
+ return PM_getMachineName();
+}
+
+/****************************************************************************
+REMARKS:
+Get the name of the machine on the network.
+****************************************************************************/
+const char * PMAPI PM_getMachineName(void)
+{
+ static char name[256];
+
+ if (REG_queryString(szMachineNameKey,szMachineName,name,sizeof(name)))
+ return name;
+ if (REG_queryString(szMachineNameKeyNT,szMachineName,name,sizeof(name)))
+ return name;
+ return "Unknown";
+}
+
+/****************************************************************************
+REMARKS:
+Check if a key has been pressed.
+****************************************************************************/
+int PMAPI PM_kbhit(void)
+{
+ // Not used in NT drivers
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Wait for and return the next keypress.
+****************************************************************************/
+int PMAPI PM_getch(void)
+{
+ // Not used in NT drivers
+ return 0xD;
+}
+
+/****************************************************************************
+REMARKS:
+Open a console for output to the screen, creating the main event handling
+window if necessary.
+****************************************************************************/
+PM_HWND PMAPI PM_openConsole(
+ PM_HWND hwndUser,
+ int device,
+ int xRes,
+ int yRes,
+ int bpp,
+ ibool fullScreen)
+{
+ // Not used in NT drivers
+ (void)hwndUser;
+ (void)device;
+ (void)xRes;
+ (void)yRes;
+ (void)bpp;
+ (void)fullScreen;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Find the size of the console state buffer.
+****************************************************************************/
+int PMAPI PM_getConsoleStateSize(void)
+{
+ // Not used in NT drivers
+ return 1;
+}
+
+/****************************************************************************
+REMARKS:
+Save the state of the console.
+****************************************************************************/
+void PMAPI PM_saveConsoleState(
+ void *stateBuf,
+ PM_HWND hwndConsole)
+{
+ // Not used in NT drivers
+ (void)stateBuf;
+ (void)hwndConsole;
+}
+
+/****************************************************************************
+REMARKS:
+Set the suspend application callback for the fullscreen console.
+****************************************************************************/
+void PMAPI PM_setSuspendAppCallback(
+ PM_saveState_cb saveState)
+{
+ // Not used in NT drivers
+ (void)saveState;
+}
+
+/****************************************************************************
+REMARKS:
+Restore the console state.
+****************************************************************************/
+void PMAPI PM_restoreConsoleState(
+ const void *stateBuf,
+ PM_HWND hwndConsole)
+{
+ // Not used in NT drivers
+ (void)stateBuf;
+ (void)hwndConsole;
+}
+
+/****************************************************************************
+REMARKS:
+Close the fullscreen console.
+****************************************************************************/
+void PMAPI PM_closeConsole(
+ PM_HWND hwndConsole)
+{
+ // Not used in NT drivers
+ (void)hwndConsole;
+}
+
+/****************************************************************************
+REMARKS:
+Set the location of the OS console cursor.
+****************************************************************************/
+void PMAPI PM_setOSCursorLocation(
+ int x,
+ int y)
+{
+ /* Nothing to do for Windows */
+ (void)x;
+ (void)y;
+}
+
+/****************************************************************************
+REMARKS:
+Set the width of the OS console.
+****************************************************************************/
+void PMAPI PM_setOSScreenWidth(
+ int width,
+ int height)
+{
+ /* Nothing to do for Windows */
+ (void)width;
+ (void)height;
+}
+
+/****************************************************************************
+REMARKS:
+Maps a shared memory block into process address space. Does nothing since
+the memory blocks are already globally mapped into all processes.
+****************************************************************************/
+void * PMAPI PM_mapToProcess(
+ void *base,
+ ulong limit)
+{
+ // Not used anymore
+ (void)base;
+ (void)limit;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Execute the POST on the secondary BIOS for a controller.
+****************************************************************************/
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *mappedBIOS,
+ ulong BIOSLen)
+{
+ // This may not be possible in NT and should be done by the OS anyway
+ (void)axVal;
+ (void)BIOSPhysAddr;
+ (void)mappedBIOS;
+ (void)BIOSLen;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Return a pointer to the real mode BIOS data area.
+****************************************************************************/
+void * PMAPI PM_getBIOSPointer(void)
+{
+ // Note that on NT this probably does not do what we expect!
+ return PM_mapPhysicalAddr(0x400, 0x1000, true);
+}
+
+/****************************************************************************
+REMARKS:
+Return a pointer to 0xA0000 physical VGA graphics framebuffer.
+****************************************************************************/
+void * PMAPI PM_getA0000Pointer(void)
+{
+ return PM_mapPhysicalAddr(0xA0000,0xFFFF,false);
+}
+
+/****************************************************************************
+REMARKS:
+Sleep for the specified number of milliseconds.
+****************************************************************************/
+void PMAPI PM_sleep(
+ ulong milliseconds)
+{
+ // We never use this in NT drivers
+ (void)milliseconds;
+}
+
+/****************************************************************************
+REMARKS:
+Return the base I/O port for the specified COM port.
+****************************************************************************/
+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;
+ case 2: return 0x3E8;
+ case 3: return 0x2E8;
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Return the base I/O port for the specified LPT port.
+****************************************************************************/
+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;
+}
+
+/****************************************************************************
+REMARKS:
+Returns available memory. Not possible under Windows.
+****************************************************************************/
+void PMAPI PM_availableMemory(
+ ulong *physical,
+ ulong *total)
+{
+ *physical = *total = 0;
+}
+
+/****************************************************************************
+REMARKS:
+OS specific shared libraries not supported inside a VxD
+****************************************************************************/
+PM_MODULE PMAPI PM_loadLibrary(
+ const char *szDLLName)
+{
+ // Not used in NT drivers
+ (void)szDLLName;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+OS specific shared libraries not supported inside a VxD
+****************************************************************************/
+void * PMAPI PM_getProcAddress(
+ PM_MODULE hModule,
+ const char *szProcName)
+{
+ // Not used in NT drivers
+ (void)hModule;
+ (void)szProcName;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+OS specific shared libraries not supported inside a VxD
+****************************************************************************/
+void PMAPI PM_freeLibrary(
+ PM_MODULE hModule)
+{
+ // Not used in NT drivers
+ (void)hModule;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+void *PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ // TODO: This function should start a directory enumeration search
+ // given the filename (with wildcards). The data should be
+ // converted and returned in the findData standard form.
+ (void)filename;
+ (void)findData;
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ void *handle,
+ PM_findData *findData)
+{
+ // TODO: This function should find the next file in directory enumeration
+ // search given the search criteria defined in the call to
+ // PM_findFirstFile. The data should be converted and returned
+ // in the findData standard form.
+ (void)handle;
+ (void)findData;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ void *handle)
+{
+ // TODO: This function should close the find process. This may do
+ // nothing for some OS'es.
+ (void)handle;
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ // Not supported in NT drivers
+ (void)drive;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ // Not supported in NT drivers
+ (void)drive;
+ (void)dir;
+ (void)len;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+RETURNS:
+Error code describing the result.
+
+REMARKS:
+Function to enable write combining for the specified region of memory.
+****************************************************************************/
+int PMAPI PM_enableWriteCombine(
+ ulong base,
+ ulong size,
+ uint type)
+{
+ return MTRR_enableWriteCombine(base,size,type);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+ NTSTATUS status;
+ ACCESS_MASK DesiredAccess = GENERIC_READ | GENERIC_WRITE;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG ShareAccess = FILE_SHARE_READ;
+ ULONG CreateDisposition = FILE_OPEN;
+ HANDLE FileHandle = NULL;
+ UNICODE_STRING *uniFile = NULL;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_BASIC_INFORMATION FileBasic;
+ char kernelFilename[PM_MAX_PATH+5];
+ ULONG FileAttributes = 0;
+
+ // Convert file attribute flags
+ if (attrib & PM_FILE_READONLY)
+ FileAttributes |= FILE_ATTRIBUTE_READONLY;
+ if (attrib & PM_FILE_ARCHIVE)
+ FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
+ if (attrib & PM_FILE_HIDDEN)
+ FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+ if (attrib & PM_FILE_SYSTEM)
+ FileAttributes |= FILE_ATTRIBUTE_SYSTEM;
+
+ // Add prefix for addressing the file system. "\??\" is short for "\DosDevices\"
+ strcpy(kernelFilename, "\\??\\");
+ strcat(kernelFilename, filename);
+
+ // Convert filename string to ansi string
+ if ((uniFile = _PM_CStringToUnicodeString(kernelFilename)) == NULL)
+ goto Exit;
+
+ // Must open a file to query it's attributes
+ InitializeObjectAttributes (&ObjectAttributes,
+ uniFile,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+ status = ZwCreateFile( &FileHandle,
+ DesiredAccess | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL, //AllocationSize OPTIONAL,
+ FILE_ATTRIBUTE_NORMAL,
+ ShareAccess,
+ CreateDisposition,
+ FILE_RANDOM_ACCESS, //CreateOptions,
+ NULL, //EaBuffer OPTIONAL,
+ 0 //EaLength (required if EaBuffer)
+ );
+ if (!NT_SUCCESS (status))
+ goto Exit;
+
+ // Query timestamps
+ status = ZwQueryInformationFile(FileHandle,
+ &IoStatusBlock,
+ &FileBasic,
+ sizeof(FILE_BASIC_INFORMATION),
+ FileBasicInformation
+ );
+ if (!NT_SUCCESS (status))
+ goto Exit;
+
+ // Change the four bits we change
+ FileBasic.FileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_ARCHIVE
+ | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+ FileBasic.FileAttributes |= FileAttributes;
+
+ // Set timestamps
+ ZwSetInformationFile( FileHandle,
+ &IoStatusBlock,
+ &FileBasic,
+ sizeof(FILE_BASIC_INFORMATION),
+ FileBasicInformation
+ );
+
+Exit:
+ if (FileHandle) ZwClose(FileHandle);
+ if (uniFile) _PM_FreeUnicodeString(uniFile);
+ return;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file attributes for a specific file.
+****************************************************************************/
+uint PMAPI PM_getFileAttr(
+ const char *filename)
+{
+ NTSTATUS status;
+ ACCESS_MASK DesiredAccess = GENERIC_READ | GENERIC_WRITE;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG ShareAccess = FILE_SHARE_READ;
+ ULONG CreateDisposition = FILE_OPEN;
+ HANDLE FileHandle = NULL;
+ UNICODE_STRING *uniFile = NULL;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_BASIC_INFORMATION FileBasic;
+ char kernelFilename[PM_MAX_PATH+5];
+ ULONG FileAttributes = 0;
+ uint retval = 0;
+
+ // Add prefix for addressing the file system. "\??\" is short for "\DosDevices\"
+ strcpy(kernelFilename, "\\??\\");
+ strcat(kernelFilename, filename);
+
+ // Convert filename string to ansi string
+ if ((uniFile = _PM_CStringToUnicodeString(kernelFilename)) == NULL)
+ goto Exit;
+
+ // Must open a file to query it's attributes
+ InitializeObjectAttributes (&ObjectAttributes,
+ uniFile,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+ status = ZwCreateFile( &FileHandle,
+ DesiredAccess | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL, //AllocationSize OPTIONAL,
+ FILE_ATTRIBUTE_NORMAL,
+ ShareAccess,
+ CreateDisposition,
+ FILE_RANDOM_ACCESS, //CreateOptions,
+ NULL, //EaBuffer OPTIONAL,
+ 0 //EaLength (required if EaBuffer)
+ );
+ if (!NT_SUCCESS (status))
+ goto Exit;
+
+ // Query timestamps
+ status = ZwQueryInformationFile(FileHandle,
+ &IoStatusBlock,
+ &FileBasic,
+ sizeof(FILE_BASIC_INFORMATION),
+ FileBasicInformation
+ );
+ if (!NT_SUCCESS (status))
+ goto Exit;
+
+ // Translate the file attributes
+ if (FileBasic.FileAttributes & FILE_ATTRIBUTE_READONLY)
+ retval |= PM_FILE_READONLY;
+ if (FileBasic.FileAttributes & FILE_ATTRIBUTE_ARCHIVE)
+ retval |= PM_FILE_ARCHIVE;
+ if (FileBasic.FileAttributes & FILE_ATTRIBUTE_HIDDEN)
+ retval |= PM_FILE_HIDDEN;
+ if (FileBasic.FileAttributes & FILE_ATTRIBUTE_SYSTEM)
+ retval |= PM_FILE_SYSTEM;
+
+Exit:
+ if (FileHandle) ZwClose(FileHandle);
+ if (uniFile) _PM_FreeUnicodeString(uniFile);
+ return retval;
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+ // Not supported in NT drivers
+ (void)filename;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+ // Not supported in NT drivers
+ (void)filename;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_getFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // Not supported in NT drivers
+ (void)filename;
+ (void)gmTime;
+ (void)time;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_setFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // Not supported in NT drivers
+ (void)filename;
+ (void)gmTime;
+ (void)time;
+ return false;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/stdio.c b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/stdio.c
new file mode 100644
index 0000000000..856215206f
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/stdio.c
@@ -0,0 +1,331 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows NT driver
+*
+* Description: C library compatible I/O functions for use within a Windows
+* NT driver.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "oshdr.h"
+
+/*------------------------ Main Code Implementation -----------------------*/
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C fopen function.
+****************************************************************************/
+FILE * fopen(
+ const char *filename,
+ const char *mode)
+{
+ ACCESS_MASK DesiredAccess; // for ZwCreateFile...
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG ShareAccess;
+ ULONG CreateDisposition;
+ NTSTATUS status;
+ HANDLE FileHandle;
+ UNICODE_STRING *uniFile = NULL;
+ PWCHAR bufFile = NULL;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_STANDARD_INFORMATION FileInformation;
+ FILE_POSITION_INFORMATION FilePosition;
+ char kernelFilename[PM_MAX_PATH+5];
+ FILE *f;
+
+ // Add prefix for addressing the file system. "\??\" is short for "\DosDevices\"
+ strcpy(kernelFilename, "\\??\\");
+ strcat(kernelFilename, filename);
+ if ((f = PM_malloc(sizeof(FILE))) == NULL)
+ goto Error;
+ f->offset = 0;
+ f->text = (mode[1] == 't' || mode[2] == 't');
+ f->writemode = (mode[0] == 'w') || (mode[0] == 'a');
+ if (mode[0] == 'r') {
+ // omode = OPEN_ACCESS_READONLY | OPEN_SHARE_COMPATIBLE;
+ // action = ACTION_IFEXISTS_OPEN | ACTION_IFNOTEXISTS_FAIL;
+ DesiredAccess = GENERIC_READ;
+ ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ CreateDisposition = FILE_OPEN;
+ }
+ else if (mode[0] == 'w') {
+ // omode = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_COMPATIBLE;
+ // action = ACTION_IFEXISTS_TRUNCATE | ACTION_IFNOTEXISTS_CREATE;
+ DesiredAccess = GENERIC_WRITE;
+ ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ CreateDisposition = FILE_SUPERSEDE;
+ }
+ else {
+ // omode = OPEN_ACCESS_READWRITE | OPEN_SHARE_COMPATIBLE;
+ // action = ACTION_IFEXISTS_OPEN | ACTION_IFNOTEXISTS_CREATE;
+ DesiredAccess = GENERIC_READ | GENERIC_WRITE;
+ ShareAccess = FILE_SHARE_READ;
+ CreateDisposition = FILE_OPEN_IF;
+ }
+
+ // Convert filename string to ansi string and then to UniCode string
+ if ((uniFile = _PM_CStringToUnicodeString(kernelFilename)) == NULL)
+ return NULL;
+
+ // Create the file
+ InitializeObjectAttributes (&ObjectAttributes,
+ uniFile,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ status = ZwCreateFile( &FileHandle,
+ DesiredAccess | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL, // AllocationSize OPTIONAL,
+ FILE_ATTRIBUTE_NORMAL,
+ ShareAccess,
+ CreateDisposition,
+ FILE_RANDOM_ACCESS, // CreateOptions,
+ NULL, // EaBuffer OPTIONAL,
+ 0 // EaLength (required if EaBuffer)
+ );
+ if (!NT_SUCCESS (status))
+ goto Error;
+ f->handle = (int)FileHandle;
+
+ // Determine size of the file
+ status = ZwQueryInformationFile( FileHandle,
+ &IoStatusBlock,
+ &FileInformation,
+ sizeof(FILE_STANDARD_INFORMATION),
+ FileStandardInformation
+ );
+ if (!NT_SUCCESS (status))
+ goto Error;
+ f->filesize = FileInformation.EndOfFile.LowPart;
+
+ // Move to the end of the file if we are appending
+ if (mode[0] == 'a') {
+ FilePosition.CurrentByteOffset.HighPart = 0;
+ FilePosition.CurrentByteOffset.LowPart = f->filesize;
+ status = ZwSetInformationFile( FileHandle,
+ &IoStatusBlock,
+ &FilePosition,
+ sizeof(FILE_POSITION_INFORMATION),
+ FilePositionInformation
+ );
+ if (!NT_SUCCESS (status))
+ goto Error;
+ }
+ return f;
+
+Error:
+ if (f) PM_free(f);
+ if (uniFile) _PM_FreeUnicodeString(uniFile);
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C fread function.
+****************************************************************************/
+size_t fread(
+ void *ptr,
+ size_t size,
+ size_t n,
+ FILE *f)
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ LARGE_INTEGER ByteOffset;
+
+ // Read any extra bytes from the file
+ ByteOffset.HighPart = 0;
+ ByteOffset.LowPart = f->offset;
+ status = ZwReadFile( (HANDLE)f->handle,
+ NULL, //IN HANDLE Event OPTIONAL,
+ NULL, // IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ NULL, // IN PVOID ApcContext OPTIONAL,
+ &IoStatusBlock,
+ ptr, // OUT PVOID Buffer,
+ size * n, //IN ULONG Length,
+ &ByteOffset, //OPTIONAL,
+ NULL //IN PULONG Key OPTIONAL
+ );
+ if (!NT_SUCCESS (status))
+ return 0;
+ f->offset += IoStatusBlock.Information;
+ return IoStatusBlock.Information / size;
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C fwrite function.
+****************************************************************************/
+size_t fwrite(
+ const void *ptr,
+ size_t size,
+ size_t n,
+ FILE *f)
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ LARGE_INTEGER ByteOffset;
+
+ if (!f->writemode)
+ return 0;
+ ByteOffset.HighPart = 0;
+ ByteOffset.LowPart = f->offset;
+ status = ZwWriteFile( (HANDLE)f->handle,
+ NULL, //IN HANDLE Event OPTIONAL,
+ NULL, // IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ NULL, // IN PVOID ApcContext OPTIONAL,
+ &IoStatusBlock,
+ (void*)ptr, // OUT PVOID Buffer,
+ size * n, //IN ULONG Length,
+ &ByteOffset, //OPTIONAL,
+ NULL //IN PULONG Key OPTIONAL
+ );
+ if (!NT_SUCCESS (status))
+ return 0;
+ f->offset += IoStatusBlock.Information;
+ if (f->offset > f->filesize)
+ f->filesize = f->offset;
+ return IoStatusBlock.Information / size;
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C fflush function.
+****************************************************************************/
+int fflush(
+ FILE *f)
+{
+ // Nothing to do here as we are not doing buffered I/O
+ (void)f;
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C fseek function.
+****************************************************************************/
+int fseek(
+ FILE *f,
+ long int offset,
+ int whence)
+{
+ NTSTATUS status;
+ FILE_POSITION_INFORMATION FilePosition;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ if (whence == 0)
+ f->offset = offset;
+ else if (whence == 1)
+ f->offset += offset;
+ else if (whence == 2)
+ f->offset = f->filesize + offset;
+ FilePosition.CurrentByteOffset.HighPart = 0;
+ FilePosition.CurrentByteOffset.LowPart = f->offset;
+ status = ZwSetInformationFile( (HANDLE)f->handle,
+ &IoStatusBlock,
+ &FilePosition,
+ sizeof(FILE_POSITION_INFORMATION),
+ FilePositionInformation
+ );
+ if (!NT_SUCCESS (status))
+ return -1;
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C ftell function.
+****************************************************************************/
+long ftell(
+ FILE *f)
+{
+ return f->offset;
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C feof function.
+****************************************************************************/
+int feof(
+ FILE *f)
+{
+ return (f->offset == f->filesize);
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C fgets function.
+****************************************************************************/
+char *fgets(
+ char *s,
+ int n,
+ FILE *f)
+{
+ int len;
+ char *cs;
+
+ // Read the entire buffer into memory (our functions are unbuffered!)
+ if ((len = fread(s,1,n,f)) == 0)
+ return NULL;
+
+ // Search for '\n' or end of string
+ if (n > len)
+ n = len;
+ cs = s;
+ while (--n > 0) {
+ if (*cs == '\n')
+ break;
+ cs++;
+ }
+ *cs = '\0';
+ return s;
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C fputs function.
+****************************************************************************/
+int fputs(
+ const char *s,
+ FILE *f)
+{
+ return fwrite(s,1,strlen(s),f);
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C fclose function.
+****************************************************************************/
+int fclose(
+ FILE *f)
+{
+ ZwClose((HANDLE)f->handle);
+ PM_free(f);
+ return 0;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/stdlib.c b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/stdlib.c
new file mode 100644
index 0000000000..d7705130b7
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/stdlib.c
@@ -0,0 +1,140 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows NT driver
+*
+* Description: C library compatible stdlib.h functions for use within a
+* Windows NT driver.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "oshdr.h"
+
+/*------------------------ Main Code Implementation -----------------------*/
+
+/****************************************************************************
+REMARKS:
+PM_malloc override function for Nucleus drivers loaded in NT drivers's.
+****************************************************************************/
+void * malloc(
+ size_t size)
+{
+ return PM_mallocShared(size);
+}
+
+/****************************************************************************
+REMARKS:
+calloc library function for Nucleus drivers loaded in NT drivers's.
+****************************************************************************/
+void * calloc(
+ size_t nelem,
+ size_t size)
+{
+ void *p = PM_mallocShared(nelem * size);
+ if (p)
+ memset(p,0,nelem * size);
+ return p;
+}
+
+/****************************************************************************
+REMARKS:
+PM_realloc override function for Nucleus drivers loaded in VxD's.
+****************************************************************************/
+void * realloc(
+ void *ptr,
+ size_t size)
+{
+ void *p = PM_mallocShared(size);
+ if (p) {
+ memcpy(p,ptr,size);
+ PM_freeShared(ptr);
+ }
+ return p;
+}
+
+/****************************************************************************
+REMARKS:
+PM_free override function for Nucleus drivers loaded in VxD's.
+****************************************************************************/
+void free(
+ void *p)
+{
+ PM_freeShared(p);
+}
+
+/****************************************************************************
+PARAMETERS:
+cstr - C style ANSI string to convert
+
+RETURNS:
+Pointer to the UniCode string structure or NULL on failure to allocate memory
+
+REMARKS:
+Converts a C style string to a UniCode string structure that can be passed
+directly to NT kernel functions.
+****************************************************************************/
+UNICODE_STRING *_PM_CStringToUnicodeString(
+ const char *cstr)
+{
+ int length;
+ ANSI_STRING ansiStr;
+ UNICODE_STRING *uniStr;
+
+ // Allocate memory for the string structure
+ if ((uniStr = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING))) == NULL)
+ return NULL;
+
+ // Allocate memory for the wide string itself
+ length = (strlen(cstr) * sizeof(WCHAR)) + sizeof(WCHAR);
+ if ((uniStr->Buffer = ExAllocatePool(NonPagedPool, length)) == NULL) {
+ ExFreePool(uniStr);
+ return NULL;
+ }
+ RtlZeroMemory(uniStr->Buffer, length);
+ uniStr->Length = 0;
+ uniStr->MaximumLength = (USHORT)length;
+
+ // Convert filename string to ansi string and then to UniCode string
+ RtlInitAnsiString(&ansiStr, cstr);
+ RtlAnsiStringToUnicodeString(uniStr, &ansiStr, FALSE);
+ return uniStr;
+}
+
+/****************************************************************************
+PARAMETERS:
+uniStr - UniCode string structure to free
+
+REMARKS:
+Frees a string allocated by the above _PM_CStringToUnicodeString function.
+****************************************************************************/
+void _PM_FreeUnicodeString(
+ UNICODE_STRING *uniStr)
+{
+ if (uniStr) {
+ ExFreePool(uniStr->Buffer);
+ ExFreePool(uniStr);
+ }
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/vflat.c
new file mode 100644
index 0000000000..901ce1cf03
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/vflat.c
@@ -0,0 +1,45 @@
+/****************************************************************************
+*
+* 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)
+{
+ return NULL;
+}
+
+void PMAPI VF_exit(void)
+{
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/ztimer.c
new file mode 100644
index 0000000000..ef27294107
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/ztimer.c
@@ -0,0 +1,124 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows VxD
+*
+* Description: OS specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+/*---------------------------- Global variables ---------------------------*/
+
+static CPU_largeInteger countFreq;
+static ulong start,finish;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+static void __ZTimerInit(void)
+{
+ KeQueryPerformanceCounter((LARGE_INTEGER*)&countFreq);
+}
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+static void __LZTimerOn(
+ LZTimerObject *tm)
+{
+ LARGE_INTEGER lt = KeQueryPerformanceCounter(NULL);
+ tm->start.low = lt.LowPart;
+ tm->start.high = lt.HighPart;
+}
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+static ulong __LZTimerLap(
+ LZTimerObject *tm)
+{
+ LARGE_INTEGER tmLap = KeQueryPerformanceCounter(NULL);
+ CPU_largeInteger tmCount;
+
+ _CPU_diffTime64(&tm->start,(CPU_largeInteger*)&tmLap,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,countFreq.low);
+}
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+static void __LZTimerOff(
+ LZTimerObject *tm)
+{
+ LARGE_INTEGER lt = KeQueryPerformanceCounter(NULL);
+ tm->end.low = lt.LowPart;
+ tm->end.high = lt.HighPart;
+}
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+static ulong __LZTimerCount(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger tmCount;
+
+ _CPU_diffTime64(&tm->start,&tm->end,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,countFreq.low);
+}
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 1
+
+/****************************************************************************
+REMARKS:
+Read the Long Period timer value from the BIOS timer tick.
+****************************************************************************/
+static ulong __ULZReadTime(void)
+{
+ LARGE_INTEGER count;
+ KeQuerySystemTime(&count);
+ return (ulong)(*((_int64*)&count) / 10);
+}
+
+/****************************************************************************
+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; }
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/os2/_pmos2.asm b/board/MAI/bios_emulator/scitech/src/pm/os2/_pmos2.asm
new file mode 100644
index 0000000000..761f0f42e1
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/os2/_pmos2.asm
@@ -0,0 +1,180 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: OS/2 32 bit protected mode
+;*
+;* Description: Low level assembly support for the PM library specific
+;* to OS/2
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pmos2 ; Set up memory model
+
+begdataseg _pmos2
+
+ cglobal _PM_ioentry
+ cglobal _PM_gdt
+_PM_ioentry dd 0 ; Offset to call gate
+_PM_gdt dw 0 ; Selector to call gate
+
+enddataseg _pmos2
+
+begcodeseg _pmos2 ; Start of code segment
+
+;----------------------------------------------------------------------------
+; int PM_setIOPL(int iopl)
+;----------------------------------------------------------------------------
+; Change the IOPL level for the 32-bit task. Returns the previous level
+; so it can be restored for the task correctly.
+;----------------------------------------------------------------------------
+cprocstart PM_setIOPL
+
+ ARG iopl:UINT
+
+ enter_c
+ pushfd ; Save the old EFLAGS for later
+ mov ecx,[iopl] ; ECX := IOPL level
+ xor ebx,ebx ; Change IOPL level function code (0)
+ifdef USE_NASM
+ call far dword [_PM_ioentry]
+else
+ call [FWORD _PM_ioentry]
+endif
+ pop eax
+ and eax,0011000000000000b
+ shr eax,12
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_setGDTSelLimit(ushort selector, ulong limit);
+;----------------------------------------------------------------------------
+; Change the GDT selector limit to given value. Used to change selector
+; limits to address the entire system address space.
+;----------------------------------------------------------------------------
+cprocstart _PM_setGDTSelLimit
+
+ ARG selector:USHORT, limit:UINT
+
+ enter_c
+ sub esp,20 ; Make room for selector data on stack
+ mov ecx,esp ; ECX := selector data structure
+ mov bx,[selector] ; Fill out the data structure
+ and bx,0FFF8h ; Kick out the LDT/GDT and DPL bits
+ mov [WORD ecx],bx
+ mov ebx,[limit]
+ mov [DWORD ecx+4],ebx
+ mov ebx,5 ; Set GDT selector limit function code
+ifdef USE_NASM
+ call far dword [_PM_ioentry]
+else
+ call [FWORD _PM_ioentry]
+endif
+ add esp,20
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uchar _MTRR_getCx86(uchar reg);
+;----------------------------------------------------------------------------
+; Read a Cyrix CPU indexed register
+;----------------------------------------------------------------------------
+cprocstart _MTRR_getCx86
+
+ ARG reg:UCHAR
+
+ enter_c
+ mov al,[reg]
+ out 22h,al
+ in al,23h
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uchar _MTRR_setCx86(uchar reg,uchar val);
+;----------------------------------------------------------------------------
+; Write a Cyrix CPU indexed register
+;----------------------------------------------------------------------------
+cprocstart _MTRR_setCx86
+
+ ARG reg:UCHAR, val:UCHAR
+
+ enter_c
+ mov al,[reg]
+ out 22h,al
+ mov al,[val]
+ out 23h,al
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _MTRR_disableInt(void);
+;----------------------------------------------------------------------------
+; Return processor interrupt status and disable interrupts.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_disableInt
+
+; Do nothing!
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _MTRR_restoreInt(ulong ps);
+;----------------------------------------------------------------------------
+; Restore processor interrupt status.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_restoreInt
+
+; Do nothing!
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void DebugInt(void)
+;----------------------------------------------------------------------------
+cprocstart DebugInt
+
+ int 3
+ ret
+
+cprocend
+
+endcodeseg _pmos2
+
+ END ; End of module
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/os2/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/os2/cpuinfo.c
new file mode 100644
index 0000000000..7de400d067
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/os2/cpuinfo.c
@@ -0,0 +1,66 @@
+/****************************************************************************
+*
+* 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: OS/2
+*
+* Description: OS/2 specific code for the CPU detection module.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+TODO: This should be implemented for OS/2!
+****************************************************************************/
+#define SetMaxThreadPriority() 0
+
+/****************************************************************************
+REMARKS:
+TODO: This should be implemented for OS/2!
+****************************************************************************/
+#define RestoreThreadPriority(i)
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ freq->low = 100000;
+ freq->high = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ ULONG count; \
+ DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &count, sizeof(ULONG) ); \
+ (t)->low = count * 100; \
+ (t)->high = 0; \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/os2/event.c b/board/MAI/bios_emulator/scitech/src/pm/os2/event.c
new file mode 100644
index 0000000000..706e84d6f3
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/os2/event.c
@@ -0,0 +1,566 @@
+/****************************************************************************
+*
+* 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: IBM PC (OS/2)
+*
+* Description: OS/2 implementation for the SciTech cross platform
+* event library.
+*
+****************************************************************************/
+
+/*---------------------------- Global Variables ---------------------------*/
+
+/* Define generous keyboard monitor circular buffer size to minimize
+ * the danger of losing keystrokes
+ */
+#define KEYBUFSIZE (EVENTQSIZE + 10)
+
+static int oldMouseState; /* Old mouse state */
+static ulong oldKeyMessage; /* Old keyboard state */
+static ushort keyUpMsg[256] = {0}; /* Table of key up messages */
+static int rangeX,rangeY; /* Range of mouse coordinates */
+HMOU _EVT_hMouse; /* Handle to the mouse driver */
+HMONITOR _EVT_hKbdMon; /* Handle to the keyboard driver */
+TID kbdMonTID = 0; /* Keyboard monitor thread ID */
+HEV hevStart; /* Start event semaphore handle */
+BOOL bMonRunning; /* Flag set if monitor thread OK */
+HMTX hmtxKeyBuf; /* Mutex protecting key buffer */
+KEYPACKET keyMonPkts[KEYBUFSIZE]; /* Array of monitor key packets */
+int kpHead = 0; /* Key packet buffer head */
+int kpTail = 0; /* Key packet buffer tail */
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* These are not used under OS/2 */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flags)
+
+/****************************************************************************
+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)
+{
+ ULONG count;
+ DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &count, sizeof(ULONG) );
+ return count;
+}
+
+/****************************************************************************
+REMARKS:
+Converts a mickey movement value to a pixel adjustment value.
+****************************************************************************/
+static int MickeyToPixel(
+ int mickey)
+{
+ // TODO: We can add some code in here to handle 'acceleration' for
+ // the mouse cursor. For now just use the mickeys.
+ return mickey;
+}
+
+/* Some useful defines any typedefs used in the keyboard handling */
+#define KEY_RELEASE 0x40
+
+/****************************************************************************
+REMARKS:
+Pumps all messages in the message queue from OS/2 into our event queue.
+****************************************************************************/
+static void _EVT_pumpMessages(void)
+{
+ KBDINFO keyInfo; /* Must not cross a 64K boundary */
+ KBDKEYINFO key; /* Must not cross a 64K boundary */
+ MOUQUEINFO mqueue; /* Must not cross a 64K boundary */
+ MOUEVENTINFO mouse; /* Must not cross a 64K boundary */
+ ushort mWait; /* Must not cross a 64K boundary */
+ KEYPACKET kp; /* Must not cross a 64K boundary */
+ event_t evt;
+ int scan;
+ ibool noInput = TRUE; /* Flag to determine if any input was available */
+
+ /* First of all, check if we should do any session switch work */
+ __PM_checkConsoleSwitch();
+
+ /* Pump all keyboard messages from our circular buffer */
+ for (;;) {
+ /* Check that the monitor thread is still running */
+ if (!bMonRunning)
+ PM_fatalError("Keyboard monitor thread died!");
+
+ /* Protect keypacket buffer with mutex */
+ DosRequestMutexSem(hmtxKeyBuf, SEM_INDEFINITE_WAIT);
+ if (kpHead == kpTail) {
+ DosReleaseMutexSem(hmtxKeyBuf);
+ break;
+ }
+
+ noInput = FALSE;
+
+ /* Read packet from circular buffer and remove it */
+ memcpy(&kp, &keyMonPkts[kpTail], sizeof(KEYPACKET));
+ if (++kpTail == KEYBUFSIZE)
+ kpTail = 0;
+ DosReleaseMutexSem(hmtxKeyBuf);
+
+ /* Compensate for the 0xE0 character */
+ if (kp.XlatedScan && kp.XlatedChar == 0xE0)
+ kp.XlatedChar = 0;
+
+ /* Determine type of keyboard event */
+ memset(&evt,0,sizeof(evt));
+ if (kp.KbdDDFlagWord & KEY_RELEASE)
+ evt.what = EVT_KEYUP;
+ else
+ evt.what = EVT_KEYDOWN;
+
+ /* Convert keyboard codes */
+ scan = kp.MonFlagWord >> 8;
+ if (evt.what == EVT_KEYUP) {
+ /* Get message for keyup code from table of cached down values */
+ evt.message = keyUpMsg[scan];
+ keyUpMsg[scan] = 0;
+ oldKeyMessage = -1;
+ }
+ else {
+ evt.message = ((ulong)scan << 8) | kp.XlatedChar;
+ if (evt.message == keyUpMsg[scan]) {
+ evt.what = EVT_KEYREPEAT;
+ evt.message |= 0x10000;
+ }
+ oldKeyMessage = evt.message & 0x0FFFF;
+ keyUpMsg[scan] = (ushort)evt.message;
+ }
+
+ /* Convert shift state modifiers */
+ if (kp.u.ShiftState & 0x0001)
+ evt.modifiers |= EVT_RIGHTSHIFT;
+ if (kp.u.ShiftState & 0x0002)
+ evt.modifiers |= EVT_LEFTSHIFT;
+ if (kp.u.ShiftState & 0x0100)
+ evt.modifiers |= EVT_LEFTCTRL;
+ if (kp.u.ShiftState & 0x0200)
+ evt.modifiers |= EVT_LEFTALT;
+ if (kp.u.ShiftState & 0x0400)
+ evt.modifiers |= EVT_RIGHTCTRL;
+ if (kp.u.ShiftState & 0x0800)
+ evt.modifiers |= EVT_RIGHTALT;
+ EVT.oldMove = -1;
+
+ /* Add time stamp and add the event to the queue */
+ evt.when = key.time;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+ /* Don't just flush because that terminally confuses the monitor */
+ do {
+ KbdCharIn(&key, IO_NOWAIT, 0);
+ } while (key.fbStatus & KBDTRF_FINAL_CHAR_IN);
+
+ /* Pump all mouse messages */
+ KbdGetStatus(&keyInfo,0);
+ /* Check return code - mouse may not be operational!! */
+ if (MouGetNumQueEl(&mqueue,_EVT_hMouse) == NO_ERROR) {
+ while (mqueue.cEvents) {
+ while (mqueue.cEvents--) {
+ memset(&evt,0,sizeof(evt));
+ mWait = MOU_NOWAIT;
+ MouReadEventQue(&mouse,&mWait,_EVT_hMouse);
+
+ /* Update the mouse position. We get the mouse coordinates
+ * in mickeys so we have to translate these into pixels and
+ * move our mouse position. If we don't do this, OS/2 gives
+ * us the coordinates in character positions since it still
+ * thinks we are in text mode!
+ */
+ EVT.mx += MickeyToPixel(mouse.col);
+ EVT.my += MickeyToPixel(mouse.row);
+ if (EVT.mx < 0) EVT.mx = 0;
+ if (EVT.my < 0) EVT.my = 0;
+ if (EVT.mx > rangeX) EVT.mx = rangeX;
+ if (EVT.my > rangeY) EVT.my = rangeY;
+ evt.where_x = EVT.mx;
+ evt.where_y = EVT.my;
+ evt.relative_x = mouse.col;
+ evt.relative_y = mouse.row;
+ evt.when = key.time;
+ if (mouse.fs & (MOUSE_BN1_DOWN | MOUSE_MOTION_WITH_BN1_DOWN))
+ evt.modifiers |= EVT_LEFTBUT;
+ if (mouse.fs & (MOUSE_BN2_DOWN | MOUSE_MOTION_WITH_BN2_DOWN))
+ evt.modifiers |= EVT_RIGHTBUT;
+ if (mouse.fs & (MOUSE_BN3_DOWN | MOUSE_MOTION_WITH_BN3_DOWN))
+ evt.modifiers |= EVT_MIDDLEBUT;
+ if (keyInfo.fsState & 0x0001)
+ evt.modifiers |= EVT_RIGHTSHIFT;
+ if (keyInfo.fsState & 0x0002)
+ evt.modifiers |= EVT_LEFTSHIFT;
+ if (keyInfo.fsState & 0x0100)
+ evt.modifiers |= EVT_LEFTCTRL;
+ if (keyInfo.fsState & 0x0200)
+ evt.modifiers |= EVT_LEFTALT;
+ if (keyInfo.fsState & 0x0400)
+ evt.modifiers |= EVT_RIGHTCTRL;
+ if (keyInfo.fsState & 0x0800)
+ evt.modifiers |= EVT_RIGHTALT;
+
+ /* Check for left mouse click events */
+ /* 0x06 == (MOUSE_BN1_DOWN | MOUSE_MOTION_WITH_BN1_DOWN) */
+ if (((mouse.fs & 0x0006) && !(oldMouseState & 0x0006))
+ || (!(mouse.fs & 0x0006) && (oldMouseState & 0x0006))) {
+ if (mouse.fs & 0x0006)
+ evt.what = EVT_MOUSEDOWN;
+ else
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_LEFTBMASK;
+ EVT.oldMove = -1;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+ /* Check for right mouse click events */
+ /* 0x0018 == (MOUSE_BN2_DOWN | MOUSE_MOTION_WITH_BN2_DOWN) */
+ if (((mouse.fs & 0x0018) && !(oldMouseState & 0x0018))
+ || (!(mouse.fs & 0x0018) && (oldMouseState & 0x0018))) {
+ if (mouse.fs & 0x0018)
+ evt.what = EVT_MOUSEDOWN;
+ else
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_RIGHTBMASK;
+ EVT.oldMove = -1;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+ /* Check for middle mouse click events */
+ /* 0x0060 == (MOUSE_BN3_DOWN | MOUSE_MOTION_WITH_BN3_DOWN) */
+ if (((mouse.fs & 0x0060) && !(oldMouseState & 0x0060))
+ || (!(mouse.fs & 0x0060) && (oldMouseState & 0x0060))) {
+ if (mouse.fs & 0x0060)
+ evt.what = EVT_MOUSEDOWN;
+ else
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_MIDDLEBMASK;
+ EVT.oldMove = -1;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+ /* Check for mouse movement event */
+ if (mouse.fs & 0x002B) {
+ evt.what = EVT_MOUSEMOVE;
+ if (EVT.oldMove != -1) {
+ EVT.evtq[EVT.oldMove].where_x = evt.where_x;/* Modify existing one */
+ EVT.evtq[EVT.oldMove].where_y = evt.where_y;
+ }
+ else {
+ EVT.oldMove = EVT.freeHead; /* Save id of this move event */
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+ }
+
+ /* Save current mouse state */
+ oldMouseState = mouse.fs;
+ }
+ MouGetNumQueEl(&mqueue,_EVT_hMouse);
+ }
+ noInput = FALSE;
+ }
+
+ /* If there was no input available, give up the current timeslice
+ * Note: DosSleep(0) will effectively do nothing if no other thread is ready. Hence
+ * DosSleep(0) will still use 100% CPU _but_ should not interfere with other programs.
+ */
+ if (noInput)
+ DosSleep(0);
+}
+
+/****************************************************************************
+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 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:
+Keyboard monitor thread. Needed to catch both keyup and keydown events.
+****************************************************************************/
+static void _kbdMonThread(
+ void *params)
+{
+ APIRET rc;
+ KEYPACKET kp;
+ USHORT count = sizeof(KEYPACKET);
+ MONBUF monInbuf;
+ MONBUF monOutbuf;
+ int kpNew;
+
+ /* Raise thread priority for higher responsiveness */
+ DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
+ monInbuf.cb = sizeof(monInbuf) - sizeof(monInbuf.cb);
+ monOutbuf.cb = sizeof(monOutbuf) - sizeof(monOutbuf.cb);
+ bMonRunning = FALSE;
+
+ /* Register the buffers to be used for monitoring for current session */
+ if (DosMonReg(_EVT_hKbdMon, &monInbuf, (ULONG*)&monOutbuf,MONITOR_END, -1)) {
+ DosPostEventSem(hevStart); /* unblock the main thread */
+ return;
+ }
+
+ /* Unblock the main thread and tell it we're OK*/
+ bMonRunning = TRUE;
+ DosPostEventSem(hevStart);
+ while (bMonRunning) { /* Start an endless loop */
+ /* Read data from keyboard driver */
+ rc = DosMonRead((PBYTE)&monInbuf, IO_WAIT, (PBYTE)&kp, (PUSHORT)&count);
+ if (rc) {
+#ifdef CHECKED
+ if (bMonRunning)
+ printf("Error in DosMonRead, rc = %ld\n", rc);
+#endif
+ bMonRunning = FALSE;
+ return;
+ }
+
+ /* Pass FLUSH packets immediately */
+ if (kp.MonFlagWord & 4) {
+#ifdef CHECKED
+ printf("Flush packet!\n");
+#endif
+ DosMonWrite((PBYTE)&monOutbuf, (PBYTE)&kp, count);
+ continue;
+ }
+
+ //TODO: to be removed
+ /* Skip extended scancodes & some others */
+ if (((kp.MonFlagWord >> 8) == 0xE0) || ((kp.KbdDDFlagWord & 0x0F) == 0x0F)) {
+ DosMonWrite((PBYTE)&monOutbuf, (PBYTE)&kp, count);
+ continue;
+ }
+
+// printf("RawScan = %X, XlatedScan = %X, fbStatus = %X, KbdDDFlags = %X\n",
+// kp.MonFlagWord >> 8, kp.XlatedScan, kp.u.ShiftState, kp.KbdDDFlagWord);
+
+ /* Protect access to buffer with mutex semaphore */
+ rc = DosRequestMutexSem(hmtxKeyBuf, 1000);
+ if (rc) {
+#ifdef CHECKED
+ printf("Can't get access to mutex, rc = %ld\n", rc);
+#endif
+ bMonRunning = FALSE;
+ return;
+ }
+
+ /* Store packet in circular buffer, drop it if it's full */
+ kpNew = kpHead + 1;
+ if (kpNew == KEYBUFSIZE)
+ kpNew = 0;
+ if (kpNew != kpTail) {
+ memcpy(&keyMonPkts[kpHead], &kp, sizeof(KEYPACKET));
+ // TODO: fix this!
+ /* Convert break to make code */
+ keyMonPkts[kpHead].MonFlagWord &= 0x7FFF;
+ kpHead = kpNew;
+ }
+ DosReleaseMutexSem(hmtxKeyBuf);
+
+ /* Finally write the packet */
+ rc = DosMonWrite((PBYTE)&monOutbuf, (PBYTE)&kp, count);
+ if (rc) {
+#ifdef CHECKED
+ if (bMonRunning)
+ printf("Error in DosMonWrite, rc = %ld\n", rc);
+#endif
+ bMonRunning = FALSE;
+ return;
+ }
+ }
+ (void)params;
+}
+
+/****************************************************************************
+REMARKS:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort(
+ int signal)
+{
+ EVT_exit();
+ PM_fatalError("Unhandled exception!");
+}
+
+/****************************************************************************
+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)
+{
+ ushort stat;
+
+ /* Initialise the event queue */
+ PM_init();
+ EVT.mouseMove = mouseMove;
+ initEventQueue();
+ oldMouseState = 0;
+ oldKeyMessage = 0;
+ memset(keyUpMsg,0,sizeof(keyUpMsg));
+
+ /* Open the mouse driver, and set it up to report events in mickeys */
+ MouOpen(NULL,&_EVT_hMouse);
+ stat = 0x7F;
+ MouSetEventMask(&stat,_EVT_hMouse);
+ stat = (MOU_NODRAW | MOU_MICKEYS) << 8;
+ MouSetDevStatus(&stat,_EVT_hMouse);
+
+ /* Open the keyboard monitor */
+ if (DosMonOpen((PSZ)"KBD$", &_EVT_hKbdMon))
+ PM_fatalError("Unable to open keyboard monitor!");
+
+ /* Create event semaphore, the monitor will post it when it's initalized */
+ if (DosCreateEventSem(NULL, &hevStart, 0, FALSE))
+ PM_fatalError("Unable to create event semaphore!");
+
+ /* Create mutex semaphore protecting the keypacket buffer */
+ if (DosCreateMutexSem(NULL, &hmtxKeyBuf, 0, FALSE))
+ PM_fatalError("Unable to create mutex semaphore!");
+
+ /* Start keyboard monitor thread, use 32K stack */
+ kbdMonTID = _beginthread(_kbdMonThread, NULL, 0x8000, NULL);
+
+ /* Now block until the monitor thread is up and running */
+ /* Give the thread one second */
+ DosWaitEventSem(hevStart, 1000);
+ if (!bMonRunning) { /* Check the thread is OK */
+ DosMonClose(_EVT_hKbdMon);
+ PM_fatalError("Keyboard monitor thread didn't initialize!");
+ }
+
+ /* Catch program termination signals so we can clean up properly */
+ signal(SIGABRT, _EVT_abort);
+ signal(SIGFPE, _EVT_abort);
+ signal(SIGINT, _EVT_abort);
+}
+
+/****************************************************************************
+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)
+{
+ rangeX = xRes;
+ rangeY = 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 OS/2
+}
+
+/****************************************************************************
+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 OS/2
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+ APIRET rc;
+
+ /* Restore signal handlers */
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+
+ /* Close the mouse driver */
+ MouClose(_EVT_hMouse);
+
+ /* Stop the keyboard monitor thread and close the monitor */
+ bMonRunning = FALSE;
+ rc = DosKillThread(kbdMonTID);
+#ifdef CHECKED
+ if (rc)
+ printf("DosKillThread failed, rc = %ld\n", rc);
+#endif
+ rc = DosMonClose(_EVT_hKbdMon);
+#ifdef CHECKED
+ if (rc) {
+ printf("DosMonClose failed, rc = %ld\n", rc);
+ }
+#endif
+ DosCloseEventSem(hevStart);
+ DosCloseMutexSem(hmtxKeyBuf);
+ KbdFlushBuffer(0);
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/os2/mon.h b/board/MAI/bios_emulator/scitech/src/pm/os2/mon.h
new file mode 100644
index 0000000000..52f12f0d2d
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/os2/mon.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+*
+* 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: 32-bit OS/2
+*
+* Description: Include file to include all OS/2 keyboard monitor stuff.
+*
+****************************************************************************/
+
+/* Monitors stuff */
+
+#define MONITOR_DEFAULT 0x0000
+#define MONITOR_BEGIN 1
+#define MONITOR_END 2
+
+typedef SHANDLE HMONITOR;
+typedef HMONITOR *PHMONITOR;
+
+typedef struct _KEYPACKET {
+ USHORT MonFlagWord;
+ UCHAR XlatedChar;
+ UCHAR XlatedScan;
+ UCHAR DBCSStatus;
+ UCHAR DBCSShift;
+
+ union
+ {
+ USHORT ShiftState;
+ USHORT LayerIndex;
+ } u;
+
+ ULONG Milliseconds;
+ USHORT KbdDDFlagWord;
+} KEYPACKET;
+
+typedef struct _MLNPACKET {
+ USHORT MonFlagWord;
+ USHORT IOCTL;
+ USHORT CPId;
+ USHORT CPIndex;
+ ULONG Reserved;
+ USHORT KbdDDFlagWord;
+} MLNPACKET;
+
+// DBCSStatus
+
+#define SF_SHIFTS 1 // If set to 1, shift status returned without a character
+#define SF_NOTCHAR 2 // 0 - Scan code is a character
+ // 1 - Scan code is not a character;
+ // instead it is an extended key code from the keyboard.
+#define SF_IMMEDIATE 32 // If set to 1, immediate conversion requested
+#define SF_TYPEMASK 192 // Has the following values:
+ // 00 - Undefined
+ // 01 - Final character; interim character flag is turned off
+ // 10 - Interim character
+ // 11 - Final character; interim character flag is turned on.
+// MonFlagWord
+
+#define MF_OPEN 1 // open
+#define MF_CLOSE 2 // close
+#define MF_FLUSH 4 // is flush packet
+
+// KbdDDFlagWord
+
+#define KF_NOTSQPACKET 1024 // Don't put this packet in SQ buffer
+#define KF_ACCENTEDKEY 512 // Key was translated using previous accent.
+#define KF_MULTIMAKE 256 // Key was repeated make of a toggle key.
+#define KF_SECONDARYKEY 128 // Previous scan code was the E0 prefix code.
+#define KF_KEYBREAK 64 // This is the break of the key.
+#define KF_KEYTYPEMASK 63 // Isolates the Key Type field of DDFlags.
+#define KF_UNDEFKEY 63 // Key packet is undefined
+#define KF_SYSREQKEY 23 // This key packet is the SysReq key (4990)
+#define KF_PRINTFLUSHKEY 22 // This packet is Ct-Alt-PrtScr
+#define KF_PSPRINTECHOKEY 21 // This packet is Ctl-P
+#define KF_PRINTECHOKEY 20 // This packet is Ctl-PrtScr
+#define KF_PRTSCRKEY 19 // This packet is PrtScr
+#define KF_PSBREAKKEY 18 // This packet is Ctl-C
+#define KF_BREAKKEY 17 // This packet is Ctl-Break
+#define KF_ACCENTKEY 16 // This packet is an accent key
+#define KF_XRORPNOT 13 // This packet is a Read or Peek Notification Pct.
+#define KF_MLNOTIFICATION 14 // packet is a Multi-Layer NLS packet
+#define KF_HOTKEYPACKET 12 // This packet is the hot key.
+#define KF_BADKEYCOMBO 11 // Accent/char combo undefined, beep only.
+#define KF_WAKEUPKEY 10 // This packet is one following PAUSEKEY
+#define KF_PSPAUSEKEY 9 // This packet is Ctl-S
+#define KF_PAUSEKEY 8 // This packet is Ctl-Numlock or PAUSE
+#define KF_SHIFTMASK 7 // Key is a shift Key
+#define KF_DUMPKEY 6 // This packet is Ctl-Numlock-NumLock
+#define KF_REBOOTKEY 5 // This packet is Ctl-Alt-Del
+#define KF_RESENDCODE 4 // This packet is resend code from controller
+#define KF_OVERRUNCODE 3 // This packet is overrun code from controller
+#define KF_SECPREFIXCODE 2 // This packet is E0/E1 scan code
+#define KF_ACKCODE 1 // This packet is ack code from keyboard
+
+
+typedef struct _MONBUF {
+ USHORT cb;
+ KEYPACKET Buffer;
+ BYTE Reserved[20];
+} MONBUF;
+
+#define RS_SYSREG 32768 // Bit 15 SysReq key down
+#define RS_CAPSLOCK 16384 // Bit 14 Caps Lock key down
+#define RS_NUMLOCK 8192 // Bit 13 NumLock key down
+#define RS_SCROLLLOCK 4096 // Bit 12 Scroll Lock key down
+#define RS_RALT 2048 // Bit 11 Right Alt key down
+#define RS_RCONTROL 1024 // Bit 10 Right Ctrl key down
+#define RS_LALT 512 // Bit 9 Left Alt key down
+#define RS_LCONTROL 256 // Bit 8 Left Ctrl key down
+#define RS_INSERT 128 // Bit 7 Insert on
+#define RS_CAPS 64 // Bit 6 Caps Lock on
+#define RS_NUM 32 // Bit 5 NumLock on
+#define RS_SCROLL 16 // Bit 4 Scroll Lock on
+#define RS_ALT 8 // Bit 3 Either Alt key down
+#define RS_CONTROL 4 // Bit 2 Either Ctrl key down
+#define RS_LSHIFT 2 // Bit 1 Left Shift key down
+#define RS_RSHIFT 1 // Bit 0 Right Shift key down
+
+
+#define CS_RCONTROL 91 // Right Control
+#define CS_LSHIFT 42 // Left Shift
+#define CS_RSHIFT 54 // Right Shift
+#define CS_LALT 56 // Left Alt
+#define CS_RALT 94 // Right Alt
+
+
+/* DosMon* prototypes */
+#ifdef __EMX__
+ #define APIRET16 USHORT
+ #define APIENTRY16
+#else
+ #define DosMonOpen DOS16MONOPEN
+ #define DosMonClose DOS16MONCLOSE
+ #define DosMonReg DOS16MONREG
+ #define DosMonRead DOS16MONREAD
+ #define DosMonWrite DOS16MONWRITE
+ #define DosGetInfoSeg DOS16GETINFOSEG
+#endif
+
+APIRET16 APIENTRY16 DosMonOpen (PSZ pszDevName, PHMONITOR phmon);
+APIRET16 APIENTRY16 DosMonClose (HMONITOR hmon);
+APIRET16 APIENTRY16 DosMonReg (HMONITOR hmon, MONBUF *pbInBuf, /*MONBUF*/ULONG *pbOutBuf, USHORT fPosition, USHORT usIndex);
+APIRET16 APIENTRY16 DosMonRead (PBYTE pbInBuf, USHORT fWait, PBYTE pbDataBuf, PUSHORT pcbData);
+APIRET16 APIENTRY16 DosMonWrite (PBYTE pbOutBuf, PBYTE pbDataBuf, USHORT cbData);
diff --git a/board/MAI/bios_emulator/scitech/src/pm/os2/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/os2/oshdr.h
new file mode 100644
index 0000000000..ae1f97a06c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/os2/oshdr.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+*
+* 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: 32-bit OS/2
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
+
+#define INCL_DOSPROFILE
+#define INCL_DOSERRORS
+#define INCL_DOS
+#define INCL_SUB
+#define INCL_VIO
+#define INCL_KBD
+#include <os2.h>
+#include <process.h>
+#include "os2/mon.h"
+
+void __PM_checkConsoleSwitch(void);
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/os2/pm.c b/board/MAI/bios_emulator/scitech/src/pm/os2/pm.c
new file mode 100644
index 0000000000..5025102806
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/os2/pm.c
@@ -0,0 +1,2008 @@
+/****************************************************************************
+*
+* 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: 32-bit OS/2
+*
+* 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 "pm_help.h"
+#include "mtrr.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <process.h>
+#ifndef __EMX__
+#include <direct.h>
+#endif
+#define INCL_DOSERRORS
+#define INCL_DOS
+#define INCL_SUB
+#define INCL_VIO
+#define INCL_KBD
+#include <os2.h>
+
+/* Semaphore for communication with our background daemon */
+#define SHAREDSEM ((PSZ)"\\SEM32\\SDD\\DAEMON")
+#define DAEMON_NAME "SDDDAEMN.EXE"
+
+/*--------------------------- Global variables ----------------------------*/
+
+/* Public structures used to communicate with VIDEOPMI for implementing
+ * the ability to call the real mode BIOS functions.
+ */
+
+typedef struct _VIDEOMODEINFO {
+ ULONG miModeId;
+ USHORT usType;
+ USHORT usInt10ModeSet;
+ USHORT usXResolution;
+ USHORT usYResolution;
+ ULONG ulBufferAddress;
+ ULONG ulApertureSize;
+ BYTE bBitsPerPixel;
+ BYTE bBitPlanes;
+ BYTE bXCharSize;
+ BYTE bYCharSize;
+ USHORT usBytesPerScanLine;
+ USHORT usTextRows;
+ ULONG ulPageLength;
+ ULONG ulSaveSize;
+ BYTE bVrtRefresh;
+ BYTE bHrtRefresh;
+ BYTE bVrtPolPos;
+ BYTE bHrtPolPos;
+ CHAR bRedMaskSize;
+ CHAR bRedFieldPosition;
+ CHAR bGreenMaskSize;
+ CHAR bGreenFieldPosition;
+ CHAR bBlueMaskSize;
+ CHAR bBlueFieldPosition;
+ CHAR bRsvdMaskSize;
+ CHAR bRsvdFieldPosition;
+ ULONG ulColors;
+ ULONG ulReserved[3];
+ } VIDEOMODEINFO, FAR *PVIDEOMODEINFO;
+
+typedef struct _ADAPTERINFO {
+ ULONG ulAdapterID;
+ CHAR szOEMString[128];
+ CHAR szDACString[128];
+ CHAR szRevision[128];
+ ULONG ulTotalMemory;
+ ULONG ulMMIOBaseAddress;
+ ULONG ulPIOBaseAddress;
+ BYTE bBusType;
+ BYTE bEndian;
+ USHORT usDeviceBusID;
+ USHORT usVendorBusID;
+ USHORT SlotID;
+ } ADAPTERINFO, FAR *PADAPTERINFO;
+
+typedef struct _VIDEO_ADAPTER {
+ void *hvideo;
+ ADAPTERINFO Adapter;
+ VIDEOMODEINFO ModeInfo;
+ } VIDEO_ADAPTER, FAR *PVIDEO_ADAPTER;
+
+/* PMIREQUEST_SOFTWAREINT structures from OS/2 DDK */
+
+typedef struct {
+ ULONG ulFlags; // VDM initialization type
+#define VDM_POSTLOAD 0x1 // adapter just loaded, used internally for initialization
+#define VDM_INITIALIZE 0x2 // force initialization of a permanently open VDM, even if previously initialized
+#define VDM_TERMINATE_POSTINITIALIZE 0x6 //start VDM with initialization, but close it afterwards (includes VDM_INITIALIZE)
+#define VDM_QUERY_CAPABILITY 0x10 // query the current int 10 capability
+#define VDM_FULL_VDM_CREATED 0x20 // a full VDM is created
+#define VDM_MINI_VDM_CREATED 0x40 // a mini VDM is created
+#define VDM_MINI_VDM_SUPPORTED 0x80 // mini VDM support is available
+ PCHAR szName; // VDM initialization program
+ PCHAR szArgs; // VDM initialization arguments
+ }INITVDM;
+
+typedef struct {
+ BYTE bBufferType;
+#define BUFFER_NONE 0
+#define INPUT_BUFFER 1
+#define OUTPUT_BUFFER 2
+ BYTE bReserved;
+ BYTE bSelCRF;
+ BYTE bOffCRF;
+ PVOID pAddress;
+ ULONG ulSize;
+ } BUFFER, *PBUFFER;
+
+typedef struct vcrf_s {
+ ULONG reg_eax;
+ ULONG reg_ebx;
+ ULONG reg_ecx;
+ ULONG reg_edx;
+ ULONG reg_ebp;
+ ULONG reg_esi;
+ ULONG reg_edi;
+ ULONG reg_ds;
+ ULONG reg_es;
+ ULONG reg_fs;
+ ULONG reg_gs;
+ ULONG reg_cs;
+ ULONG reg_eip;
+ ULONG reg_eflag;
+ ULONG reg_ss;
+ ULONG reg_esp;
+ } VCRF;
+
+typedef struct {
+ ULONG ulBIOSIntNo;
+ VCRF aCRF;
+ BUFFER pB[2];
+ } INTCRF;
+
+#define PMIREQUEST_LOADPMIFILE 21
+#define PMIREQUEST_IDENTIFYADAPTER 22
+#define PMIREQUEST_SOFTWAREINT 23
+
+#ifdef PTR_DECL_IN_FRONT
+#define EXPENTRYP * EXPENTRY
+#else
+#define EXPENTRYP EXPENTRY *
+#endif
+
+/* Entry point to VIDEOPMI32Request. This may be overridden by external
+ * code that has already loaded VIDEOPMI to avoid loading it twice.
+ */
+
+APIRET (EXPENTRYP PM_VIDEOPMI32Request)(PVIDEO_ADAPTER, ULONG, PVOID, PVOID) = NULL;
+static ibool haveInt10 = -1; /* True if we have Int 10 support */
+static ibool useVPMI = true; /* False if VIDEOPMI unavailable */
+static VIDEO_ADAPTER Adapter; /* Video adapter for VIDEOPMI */
+static uchar RMBuf[1024]; /* Fake real mode transfer buffer */
+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 */
+static uchar * lowMem = NULL;
+static ibool isSessionSwitching = false;
+static ulong parmsIn[4]; /* Must not cross 64Kb boundary! */
+static ulong parmsOut[4]; /* Must not cross 64Kb boundary! */
+extern ushort _PM_gdt;
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+/* DosSysCtl prototype. It is not declared in the headers but it is in the
+ * standard import libraries (DOSCALLS.876). Funny.
+ */
+APIRET APIENTRY DosSysCtl(ULONG ulFunction, PVOID pvData);
+
+/* This is the stack size for the threads that track the session switch event */
+#define SESSION_SWITCH_STACK_SIZE 32768
+
+typedef struct {
+ VIOMODEINFO vmi;
+ USHORT CursorX;
+ USHORT CursorY;
+ UCHAR FrameBuffer[1];
+ } CONSOLE_SAVE;
+
+typedef struct _SESWITCHREC {
+ /* The following variable is volatile because of PM_SUSPEND_APP */
+ volatile int Flags; /* -1 or PM_DEACTIVATE or PM_REACTIVATE */
+ PM_saveState_cb Callback; /* Save/restore context callback */
+ HMTX Mutex; /* Exclusive access mutex */
+ HEV Event; /* Posted after callback is called */
+ } SESWITCHREC;
+
+// Page sized block cache
+
+#define PAGES_PER_BLOCK 32
+#define PAGE_BLOCK_SIZE (PAGES_PER_BLOCK * PM_PAGE_SIZE + (PM_PAGE_SIZE-1) + sizeof(pageblock))
+#define FREELIST_NEXT(p) (*(void**)(p))
+typedef struct pageblock {
+ struct pageblock *next;
+ struct pageblock *prev;
+ void *freeListStart;
+ void *freeList;
+ void *freeListEnd;
+ int freeCount;
+ PM_lockHandle lockHandle;
+ } pageblock;
+
+static pageblock *pageBlocks = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+func - Helper device driver function to call
+
+RETURNS:
+First return value from the device driver in parmsOut[0]
+
+REMARKS:
+Function to open our helper device driver, call it and close the file
+handle. Note that we have to open the device driver for every call because
+of two problems:
+
+ 1. We cannot open a single file handle in a DLL that is shared amongst
+ programs, since every process must have it's own open file handle.
+
+ 2. For some reason there appears to be a limit of about 12 open file
+ handles on a device driver in the system. Hence when we open more
+ than about 12 file handles things start to go very strange.
+
+Hence we simply open the file handle every time that we need to call the
+device driver to work around these problems.
+****************************************************************************/
+static ulong CallSDDHelp(
+ int func)
+{
+ static ulong inLen; /* Must not cross 64Kb boundary! */
+ static ulong outLen; /* Must not cross 64Kb boundary! */
+ HFILE hSDDHelp;
+ ULONG rc;
+ ulong result;
+
+ if ((rc = DosOpen(PMHELP_NAME,&hSDDHelp,&result,0,0,
+ FILE_OPEN, OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE,
+ NULL)) != 0) {
+ if (rc == 4) { /* Did we run out of file handles? */
+ ULONG ulNewFHs;
+ LONG lAddFHs = 5;
+
+ if (DosSetRelMaxFH(&lAddFHs, &ulNewFHs) != 0)
+ PM_fatalError("Failed to raise the file handles limit!");
+ else {
+ if ((rc = DosOpen(PMHELP_NAME,&hSDDHelp,&result,0,0,
+ FILE_OPEN, OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE,
+ NULL)) != 0) {
+ PM_fatalError("Unable to open SDDHELP$ helper device driver! (#2)");
+ }
+ }
+ }
+ else
+ PM_fatalError("Unable to open SDDHELP$ helper device driver!");
+ }
+ if (DosDevIOCtl(hSDDHelp,PMHELP_IOCTL,func,
+ &parmsIn, inLen = sizeof(parmsIn), &inLen,
+ &parmsOut, outLen = sizeof(parmsOut), &outLen) != 0)
+ PM_fatalError("Failure calling SDDHELP$ helper device driver!");
+ DosClose(hSDDHelp);
+ return parmsOut[0];
+}
+
+/****************************************************************************
+REMARKS:
+Determine if we're running on a DBCS system.
+****************************************************************************/
+ibool __IsDBCSSystem(void)
+{
+ CHAR achDBCSInfo[12];
+ COUNTRYCODE ccStruct = {0, 0};
+
+ memset(achDBCSInfo, 0, 12);
+
+ /* Get the DBCS vector - if it's not empty, we're on DBCS */
+ DosQueryDBCSEnv(sizeof(achDBCSInfo), &ccStruct, achDBCSInfo);
+ if (achDBCSInfo[0] != 0)
+ return true;
+ else
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Determine if PMSHELL is running - if it isn't, we can't use certain calls
+****************************************************************************/
+ibool __isShellLoaded(void)
+{
+ PVOID ptr;
+
+ if (DosGetNamedSharedMem(&ptr, (PSZ)"\\SHAREMEM\\PMGLOBAL.MEM", PAG_READ) == NO_ERROR) {
+ DosFreeMem(ptr);
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Initialise the PM library and connect to our helper device driver. If we
+cannot connect to our helper device driver, we bail out with an error
+message.
+****************************************************************************/
+void PMAPI PM_init(void)
+{
+ if (!lowMem) {
+ /* Obtain the 32->16 callgate from the device driver to enable IOPL */
+ if ((_PM_gdt = CallSDDHelp(PMHELP_GETGDT32)) == 0)
+ PM_fatalError("Unable to obtain call gate selector!");
+
+ PM_setIOPL(3);
+
+ /* Map the first Mb of physical memory into lowMem */
+ if ((lowMem = PM_mapPhysicalAddr(0,0xFFFFF,true)) == NULL)
+ PM_fatalError("Unable to map first Mb physical memory!");
+
+ /* Initialise the MTRR interface functions */
+ MTRR_init();
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Initialise the PM library for BIOS access via VIDEOPMI. This should work
+with any GRADD driver, including SDD/2.
+****************************************************************************/
+static ibool InitInt10(void)
+{
+ HMODULE hModGENPMI,hModSDDPMI,hModVideoPMI;
+ CHAR buf[80],path[_MAX_PATH];
+ HEV hevDaemon = NULLHANDLE;
+ RESULTCODES resCodes;
+
+ if (haveInt10 == -1) {
+ /* Connect to VIDEOPMI and get entry point. Note that we only
+ * do this if GENPMI or SDDPMI are already loaded, since we need
+ * a GRADD based driver for this to work.
+ */
+ PM_init();
+ haveInt10 = false;
+ if (DosQueryModuleHandle((PSZ)"GENPMI.DLL",&hModGENPMI) != 0)
+ hModGENPMI = NULLHANDLE;
+ if (DosQueryModuleHandle((PSZ)"SDDPMI.DLL",&hModSDDPMI) != 0)
+ hModSDDPMI = NULLHANDLE;
+ if (hModGENPMI || hModSDDPMI) {
+ if (DosLoadModule((PSZ)buf,sizeof(buf),(PSZ)"VIDEOPMI.DLL",&hModVideoPMI) == 0) {
+ if (DosQueryProcAddr(hModVideoPMI,0,(PSZ)"VIDEOPMI32Request",(void*)&PM_VIDEOPMI32Request) != 0)
+ PM_fatalError("Unable to get VIDEOPMI32Request entry point!");
+ strcpy(path,"X:\\OS2\\SVGADATA.PMI");
+ path[0] = PM_getBootDrive();
+ if (PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_LOADPMIFILE,path,NULL) != 0) {
+ DosFreeModule(hModVideoPMI);
+ PM_VIDEOPMI32Request = NULL;
+ haveInt10 = false;
+ }
+ else {
+ /* Attempt to initialise the full VDM in the system. This will only
+ * work if VPRPMI.SYS is loaded, but it provides support for passing
+ * values in ES/DS/ESI/EDI between the BIOS which does not work with
+ * kernel VDM's in fixpacks earlier than FP15. FP15 and later and
+ * the new Warp 4.51 and Warp Server convenience packs should work
+ * fine with the kernel mini-VDM.
+ *
+ * Also the full VDM is the only solution for really old kernels
+ * (but GRADD won't run on them so this is superfluous ;-).
+ */
+ INITVDM InitVDM = {VDM_INITIALIZE,NULL,NULL};
+ PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,&InitVDM,NULL);
+ haveInt10 = true;
+ }
+ }
+ }
+ else {
+ /* A GRADD driver isn't loaded, hence we can't use VIDEOPMI. But we will try
+ * to access the mini-VDM directly, first verifying that the support is
+ * available in the kernel (it should be for kernels that support GRADD).
+ * This may be needed in a command line boot or if non-GRADD driver is
+ * used (Matrox or classic VGA).
+ * Note: because of problems with mini-VDM support in the kernel, we have to
+ * spawn a daemon process that will do the actual mini-VDM access for us.
+ */
+ /* Try to open shared semaphore to see if our daemon is already up */
+ if (DosOpenEventSem(SHAREDSEM, &hevDaemon) == NO_ERROR) {
+ if (DosWaitEventSem(hevDaemon, 1) == NO_ERROR) {
+ /* If semaphore is posted, all is well */
+ useVPMI = false;
+ haveInt10 = true;
+ }
+ }
+ else {
+ /* Create shared event semaphore */
+ if (DosCreateEventSem(SHAREDSEM, &hevDaemon, DC_SEM_SHARED, FALSE) == NO_ERROR) {
+ PM_findBPD(DAEMON_NAME, path);
+ strcat(path, DAEMON_NAME);
+ if (DosExecPgm(buf, sizeof(buf), EXEC_BACKGROUND, (PSZ)DAEMON_NAME,
+ NULL, &resCodes, (PSZ)path) == NO_ERROR) {
+ /* The daemon was successfully spawned, now give it a sec to come up */
+ if (DosWaitEventSem(hevDaemon, 2000) == NO_ERROR) {
+ /* It's up! */
+ useVPMI = false;
+ haveInt10 = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return haveInt10;
+}
+
+/****************************************************************************
+REMARKS:
+We "probably" have BIOS access under OS/2 but we have to verify/initialize it
+first.
+****************************************************************************/
+ibool PMAPI PM_haveBIOSAccess(void)
+{
+ return InitInt10();
+}
+
+/****************************************************************************
+REMARKS:
+Return the operating system type identifier.
+****************************************************************************/
+long PMAPI PM_getOSType(void)
+{
+ return _OS_OS2;
+}
+
+/****************************************************************************
+REMARKS:
+Return the runtime type identifier.
+****************************************************************************/
+int PMAPI PM_getModeType(void)
+{
+ return PM_386;
+}
+
+/****************************************************************************
+REMARKS:
+Add a file directory separator to the end of the filename.
+****************************************************************************/
+void PMAPI PM_backslash(
+ char *s)
+{
+ uint pos = strlen(s);
+ if (s[pos-1] != '\\') {
+ s[pos] = '\\';
+ s[pos+1] = '\0';
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Add a user defined PM_fatalError cleanup function.
+****************************************************************************/
+void PMAPI PM_setFatalErrorCleanup(
+ void (PMAPIP cleanup)(void))
+{
+ fatalErrorCleanup = cleanup;
+}
+
+/****************************************************************************
+REMARKS:
+Report a fatal error condition and halt the program.
+****************************************************************************/
+void PMAPI PM_fatalError(
+ const char *msg)
+{
+ /* Be prepare to be called recursively (failed to fail situation :-) */
+ static int fatalErrorCount = 0;
+ if (fatalErrorCount++ == 0) {
+ if (fatalErrorCleanup)
+ fatalErrorCleanup();
+ }
+ fprintf(stderr,"%s\n", msg);
+ exit(1);
+}
+
+/****************************************************************************
+REMARKS:
+Allocate the real mode VESA transfer buffer for communicating with the BIOS.
+****************************************************************************/
+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;
+ }
+ *len = VESABuf_len;
+ *rseg = VESABuf_rseg;
+ *roff = VESABuf_roff;
+ return VESABuf_ptr;
+}
+
+/****************************************************************************
+REMARKS:
+Check if a key has been pressed.
+****************************************************************************/
+int PMAPI PM_kbhit(void)
+{
+ KBDKEYINFO key; /* Must not cross a 64K boundary */
+
+ KbdPeek(&key, 0);
+ return (key.fbStatus & KBDTRF_FINAL_CHAR_IN);
+}
+
+/****************************************************************************
+REMARKS:
+Wait for and return the next keypress.
+****************************************************************************/
+int PMAPI PM_getch(void)
+{
+ KBDKEYINFO key; /* Must not cross a 64K boundary */
+
+ KbdCharIn(&key,IO_WAIT,0);
+ return key.chChar;
+}
+
+/****************************************************************************
+REMARKS:
+Open a fullscreen console for output to the screen. This requires that
+the application be a fullscreen VIO program.
+****************************************************************************/
+PM_HWND PMAPI PM_openConsole(
+ PM_HWND hwndUser,
+ int device,
+ int xRes,
+ int yRes,
+ int bpp,
+ ibool fullScreen)
+{
+ (void)hwndUser;
+ (void)device;
+ (void)xRes;
+ (void)yRes;
+ (void)bpp;
+ (void)fullScreen;
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Find the size of the console state buffer.
+****************************************************************************/
+int PMAPI PM_getConsoleStateSize(void)
+{
+ VIOMODEINFO vmi;
+ vmi.cb = sizeof (VIOMODEINFO);
+ VioGetMode (&vmi, (HVIO)0);
+ return sizeof (CONSOLE_SAVE) - 1 + vmi.col * vmi.row * 2;
+}
+
+/****************************************************************************
+REMARKS:
+Save the state of the console.
+****************************************************************************/
+void PMAPI PM_saveConsoleState(
+ void *stateBuf,
+ PM_HWND hwndConsole)
+{
+ USHORT fblen;
+ CONSOLE_SAVE *cs = (CONSOLE_SAVE*)stateBuf;
+ VIOMODEINFO vmi;
+
+ /* The reason for the VIOMODEINFO juggling is 16-bit code. Because the user
+ * allocates the state buffer, cd->vmi might be crossing the 64K boundary and
+ * the 16-bit API would fail. If we create another copy on stack, the compiler
+ * should ensure that the 64K boundary will not be crossed (it adjusts the stack
+ * if it should cross).
+ */
+ vmi.cb = sizeof(VIOMODEINFO);
+ VioGetMode(&vmi,(HVIO)0);
+ memcpy(&cs->vmi, &vmi, sizeof(VIOMODEINFO));
+ VioGetCurPos(&cs->CursorY, &cs->CursorX, (HVIO)0);
+ fblen = cs->vmi.col * cs->vmi.row * 2;
+ VioReadCellStr((PCH)cs->FrameBuffer, &fblen, 0, 0, (HVIO)0);
+}
+
+/* Global variable to communicate between threads */
+static SESWITCHREC SesSwitchRec = { -1 };
+
+/****************************************************************************
+REMARKS:
+Called by external routines at least once per frame to check whenever a
+session save/restore should be performed. Since we receive such notifications
+asyncronously, we can't perform all required operations at that time.
+****************************************************************************/
+void __PM_checkConsoleSwitch(void)
+{
+ int Flags, Mode;
+ PM_saveState_cb Callback;
+
+ /* Quick optimized path for most common case */
+ if (SesSwitchRec.Flags == -1)
+ return;
+
+again:
+ if (DosRequestMutexSem(SesSwitchRec.Mutex, 100))
+ return;
+ Flags = SesSwitchRec.Flags;
+ Callback = SesSwitchRec.Callback;
+ SesSwitchRec.Flags = -1;
+ DosReleaseMutexSem(SesSwitchRec.Mutex);
+
+ isSessionSwitching = true; /* Prevent VIO calls */
+ Mode = Callback(Flags);
+ isSessionSwitching = false;
+ DosPostEventSem(SesSwitchRec.Event);
+ if (Flags == PM_DEACTIVATE && Mode == PM_SUSPEND_APP)
+ /* Suspend application until we switch back to our application */
+ for (;;) {
+ DosSleep (500);
+ /* SesSwitchRec.Flags is volatile so optimizer
+ * won't load it into a register
+ */
+ if (SesSwitchRec.Flags != -1)
+ goto again;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Waits until main thread processes the session switch event.
+****************************************************************************/
+static void _PM_SessionSwitchEvent(
+ PM_saveState_cb saveState,
+ int flags)
+{
+ ULONG Count;
+
+ if (DosRequestMutexSem(SesSwitchRec.Mutex, 10000))
+ return;
+
+ /* We're going to wait on that semaphore */
+ DosResetEventSem(SesSwitchRec.Event, &Count);
+ SesSwitchRec.Callback = saveState;
+ SesSwitchRec.Flags = flags;
+ DosReleaseMutexSem(SesSwitchRec.Mutex);
+
+ /* Now wait until all required operations are complete */
+ DosWaitEventSem (SesSwitchRec.Event, 10000);
+}
+
+/****************************************************************************
+REMARKS:
+This is the thread responsible for tracking switches back to our
+fullscreen session.
+****************************************************************************/
+static void _PM_ConsoleSwitch(
+ PM_saveState_cb saveState)
+{
+ USHORT NotifyType;
+
+ for (;;) {
+ if (VioModeWait(VMWR_POPUP, &NotifyType, 0) != 0)
+ break;
+ _PM_SessionSwitchEvent(saveState, PM_REACTIVATE);
+ }
+ VioModeUndo(UNDOI_RELEASEOWNER, UNDOK_ERRORCODE, (HVIO)0);
+}
+
+/****************************************************************************
+REMARKS:
+This is the thread responsible for tracking screen popups (usually fatal
+error handler uses them).
+****************************************************************************/
+static void _PM_ConsolePopup(
+ PM_saveState_cb saveState)
+{
+ USHORT NotifyType;
+ for (;;) {
+ if (VioSavRedrawWait(VSRWI_SAVEANDREDRAW, &NotifyType, 0) != 0)
+ break;
+ if (NotifyType == VSRWN_SAVE)
+ _PM_SessionSwitchEvent(saveState, PM_DEACTIVATE);
+ else if (NotifyType == VSRWN_REDRAW)
+ _PM_SessionSwitchEvent(saveState, PM_REACTIVATE);
+ }
+ VioSavRedrawUndo(UNDOI_RELEASEOWNER, UNDOK_ERRORCODE, (HVIO)0);
+}
+
+/****************************************************************************
+REMARKS:
+Set the suspend application callback for the fullscreen console.
+****************************************************************************/
+void PMAPI PM_setSuspendAppCallback(
+ PM_saveState_cb saveState)
+{
+ // If PM isn't loaded, this stuff will cause crashes!
+ if (__isShellLoaded()) {
+ if (saveState) {
+ /* Create the threads responsible for tracking console switches */
+ SesSwitchRec.Flags = -1;
+ DosCreateMutexSem(NULL, &SesSwitchRec.Mutex, 0, FALSE);
+ DosCreateEventSem(NULL, &SesSwitchRec.Event, 0, FALSE);
+ _beginthread ((void(*)(void*))_PM_ConsoleSwitch,NULL,SESSION_SWITCH_STACK_SIZE, (void*)saveState);
+ _beginthread ((void(*)(void*))_PM_ConsolePopup,NULL,SESSION_SWITCH_STACK_SIZE, (void*)saveState);
+ }
+ else {
+ /* Kill the threads responsible for tracking console switches */
+ VioModeUndo(UNDOI_RELEASEOWNER, UNDOK_TERMINATE, (HVIO)0);
+ VioSavRedrawUndo(UNDOI_RELEASEOWNER, UNDOK_TERMINATE, (HVIO)0);
+ DosCloseEventSem(SesSwitchRec.Event);
+ DosCloseMutexSem(SesSwitchRec.Mutex);
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Restore the console state.
+****************************************************************************/
+void PMAPI PM_restoreConsoleState(
+ const void *stateBuf,
+ PM_HWND hwndConsole)
+{
+ CONSOLE_SAVE *cs = (CONSOLE_SAVE *)stateBuf;
+ VIOMODEINFO vmi;
+
+ if (!cs)
+ return;
+
+ memcpy(&vmi, &cs->vmi, sizeof (VIOMODEINFO));
+ VioSetMode(&vmi, (HVIO)0);
+ VioSetCurPos(cs->CursorY, cs->CursorX, (HVIO)0);
+ VioWrtCellStr((PCH)cs->FrameBuffer, cs->vmi.col * cs->vmi.row * 2,0, 0, (HVIO)0);
+}
+
+/****************************************************************************
+REMARKS:
+Close the fullscreen console.
+****************************************************************************/
+void PMAPI PM_closeConsole(
+ PM_HWND hwndConsole)
+{
+ /* Kill the threads responsible for tracking console switches */
+ PM_setSuspendAppCallback(NULL);
+ (void)hwndConsole;
+}
+
+/****************************************************************************
+REMARKS:
+Set the location of the OS console cursor.
+****************************************************************************/
+void PM_setOSCursorLocation(
+ int x,
+ int y)
+{
+ /* If session switch is in progress, calling into VIO causes deadlocks! */
+ /* Also this call to VIO screws up our console library on DBCS boxes... */
+ if (!isSessionSwitching && !__IsDBCSSystem())
+ VioSetCurPos(y,x,0);
+}
+
+/****************************************************************************
+REMARKS:
+Set the width of the OS console.
+****************************************************************************/
+void PM_setOSScreenWidth(
+ int width,
+ int height)
+{
+ /* Nothing to do in here */
+ (void)width;
+ (void)height;
+}
+
+/****************************************************************************
+REMARKS:
+Set the real time clock handler (used for software stereo modes).
+****************************************************************************/
+ibool PMAPI PM_setRealTimeClockHandler(
+ PM_intHandler ih,
+ int frequency)
+{
+ // TODO: Implement this!
+ (void)ih;
+ (void)frequency;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Set the real time clock frequency (for stereo modes).
+****************************************************************************/
+void PMAPI PM_setRealTimeClockFrequency(
+ int frequency)
+{
+ // TODO: Implement this!
+ (void)frequency;
+}
+
+/****************************************************************************
+REMARKS:
+Restore the original real time clock handler.
+****************************************************************************/
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ // TODO: Implement this!
+}
+
+/****************************************************************************
+REMARKS:
+Return the current operating system path or working directory.
+****************************************************************************/
+char * PMAPI PM_getCurrentPath(
+ char *path,
+ int maxLen)
+{
+ return getcwd(path,maxLen);
+}
+
+/****************************************************************************
+REMARKS:
+Return the drive letter for the boot drive.
+****************************************************************************/
+char PMAPI PM_getBootDrive(void)
+{
+ ulong boot = 3;
+ DosQuerySysInfo(QSV_BOOT_DRIVE,QSV_BOOT_DRIVE,&boot,sizeof(boot));
+ return (char)('a' + boot - 1);
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the VBE/AF driver files.
+****************************************************************************/
+const char * PMAPI PM_getVBEAFPath(void)
+{
+ static char path[CCHMAXPATH];
+ strcpy(path,"x:\\");
+ path[0] = PM_getBootDrive();
+ return path;
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the Nucleus driver files.
+****************************************************************************/
+const char * PMAPI PM_getNucleusPath(void)
+{
+ static char path[CCHMAXPATH];
+ if (getenv("NUCLEUS_PATH") != NULL)
+ return getenv("NUCLEUS_PATH");
+ strcpy(path,"x:\\os2\\drivers");
+ path[0] = PM_getBootDrive();
+ PM_backslash(path);
+ strcat(path,"nucleus");
+ return path;
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the Nucleus configuration files.
+****************************************************************************/
+const char * PMAPI PM_getNucleusConfigPath(void)
+{
+ static char path[CCHMAXPATH];
+ strcpy(path,PM_getNucleusPath());
+ PM_backslash(path);
+ strcat(path,"config");
+ return path;
+}
+
+/****************************************************************************
+REMARKS:
+Return a unique identifier for the machine if possible.
+****************************************************************************/
+const char * PMAPI PM_getUniqueID(void)
+{
+ return PM_getMachineName();
+}
+
+/****************************************************************************
+REMARKS:
+Get the name of the machine on the network.
+****************************************************************************/
+const char * PMAPI PM_getMachineName(void)
+{
+ static char name[40],*env;
+
+ if ((env = getenv("HOSTNAME")) != NULL) {
+ strncpy(name,env,sizeof(name));
+ name[sizeof(name)-1] = 0;
+ return name;
+ }
+ return "OS2";
+}
+
+/****************************************************************************
+REMARKS:
+Return a pointer to the real mode BIOS data area.
+****************************************************************************/
+void * PMAPI PM_getBIOSPointer(void)
+{
+ PM_init();
+ return lowMem + 0x400;
+}
+
+/****************************************************************************
+REMARKS:
+Return a pointer to 0xA0000 physical VGA graphics framebuffer.
+****************************************************************************/
+void * PMAPI PM_getA0000Pointer(void)
+{
+ PM_init();
+ return lowMem + 0xA0000;
+}
+
+/****************************************************************************
+REMARKS:
+Map a physical address to a linear address in the callers process.
+****************************************************************************/
+void * PMAPI PM_mapPhysicalAddr(
+ ulong base,
+ ulong limit,
+ ibool isCached)
+{
+ ulong baseAddr,baseOfs,linear;
+
+ /* 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;
+ parmsIn[0] = baseAddr;
+ parmsIn[1] = limit;
+ parmsIn[2] = isCached;
+ if ((linear = CallSDDHelp(PMHELP_MAPPHYS)) == 0)
+ return NULL;
+ return (void*)(linear + baseOfs);
+}
+
+/****************************************************************************
+REMARKS:
+Free a physical address mapping allocated by PM_mapPhysicalAddr.
+****************************************************************************/
+void PMAPI PM_freePhysicalAddr(
+ void *ptr,
+ ulong limit)
+{
+ parmsIn[0] = (ulong)ptr;
+ parmsIn[1] = limit;
+ CallSDDHelp(PMHELP_FREEPHYS);
+}
+
+/****************************************************************************
+REMARKS:
+Find the physical address of a linear memory address in current process.
+****************************************************************************/
+ulong PMAPI PM_getPhysicalAddr(
+ void *p)
+{
+ parmsIn[0] = (ulong)p;
+ return CallSDDHelp(PMHELP_GETPHYSICALADDR);
+}
+
+/****************************************************************************
+REMARKS:
+Find the physical address of a linear memory address in current process.
+****************************************************************************/
+ibool PMAPI PM_getPhysicalAddrRange(
+ void *p,
+ ulong length,
+ ulong *physAddress)
+{
+ parmsIn[0] = (ulong)p;
+ parmsIn[1] = (ulong)length;
+ parmsIn[2] = (ulong)physAddress;
+ return CallSDDHelp(PMHELP_GETPHYSICALADDRRANGE);
+}
+
+/****************************************************************************
+REMARKS:
+Sleep for the specified number of milliseconds.
+****************************************************************************/
+void PMAPI PM_sleep(
+ ulong milliseconds)
+{
+ DosSleep(milliseconds);
+}
+
+/****************************************************************************
+REMARKS:
+Return the base I/O port for the specified COM port.
+****************************************************************************/
+int PMAPI PM_getCOMPort(
+ int port)
+{
+ switch (port) {
+ case 0: return 0x3F8;
+ case 1: return 0x2F8;
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Return the base I/O port for the specified LPT port.
+****************************************************************************/
+int PMAPI PM_getLPTPort(
+ int port)
+{
+ switch (port) {
+ case 0: return 0x3BC;
+ case 1: return 0x378;
+ case 2: return 0x278;
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of shared memory. For Win9x we allocate shared memory
+as locked, global memory that is accessible from any memory context
+(including interrupt time context), which allows us to load our important
+data structure and code such that we can access it directly from a ring
+0 interrupt context.
+****************************************************************************/
+void * PMAPI PM_mallocShared(
+ long size)
+{
+ parmsIn[0] = size;
+ return (void*)CallSDDHelp(PMHELP_MALLOCSHARED);
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of shared memory.
+****************************************************************************/
+void PMAPI PM_freeShared(
+ void *ptr)
+{
+ parmsIn[0] = (ulong)ptr;
+ CallSDDHelp(PMHELP_FREESHARED);
+}
+
+/****************************************************************************
+REMARKS:
+Map a linear memory address to the calling process address space. The
+address will have been allocated in another process using the
+PM_mapPhysicalAddr function.
+****************************************************************************/
+void * PMAPI PM_mapToProcess(
+ void *base,
+ ulong limit)
+{
+ ulong baseAddr,baseOfs;
+
+ /* 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 = (ulong)base & 4095;
+ baseAddr = (ulong)base & ~4095;
+ limit = ((limit+baseOfs+1+4095) & ~4095)-1;
+ parmsIn[0] = (ulong)baseAddr;
+ parmsIn[1] = limit;
+ return (void*)(CallSDDHelp(PMHELP_MAPTOPROCESS)+baseOfs);
+}
+
+/****************************************************************************
+REMARKS:
+Map a real mode pointer to a protected mode pointer.
+****************************************************************************/
+void * PMAPI PM_mapRealPointer(
+ uint r_seg,
+ uint r_off)
+{
+ if (r_seg == 0xFFFF)
+ return &RMBuf[r_off];
+ return lowMem + MK_PHYS(r_seg,r_off);
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of real mode memory
+****************************************************************************/
+void * PMAPI PM_allocRealSeg(
+ uint size,
+ uint *r_seg,
+ uint *r_off)
+{
+ if (size > sizeof(RMBuf))
+ return NULL;
+ *r_seg = 0xFFFF;
+ *r_off = 0x0000;
+ return &RMBuf;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of real mode memory.
+****************************************************************************/
+void PMAPI PM_freeRealSeg(
+ void *mem)
+{
+ /* Nothing to do in here */
+ (void)mem;
+}
+
+#define INDPMI(reg) rmregs.aCRF.reg_##reg = regs->reg
+#define OUTDPMI(reg) regs->reg = rmregs.aCRF.reg_##reg
+
+#define REG_OFFSET(field) (((ULONG)&(((VCRF*)0)->field)) / sizeof(ULONG))
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt (parameters in DPMI compatible structure)
+****************************************************************************/
+void PMAPI DPMI_int86(
+ int intno,
+ DPMI_regs *regs)
+{
+ INTCRF rmregs;
+ ulong eax = 0;
+
+ if (!InitInt10())
+ return;
+ memset(&rmregs, 0, sizeof(rmregs));
+ rmregs.ulBIOSIntNo = intno;
+ INDPMI(eax); INDPMI(ebx); INDPMI(ecx); INDPMI(edx); INDPMI(esi); INDPMI(edi);
+ rmregs.aCRF.reg_ds = regs->ds;
+ rmregs.aCRF.reg_es = regs->es;
+ if (intno == 0x10) {
+ eax = rmregs.aCRF.reg_eax;
+ switch (eax & 0xFFFF) {
+ case 0x4F00:
+ /* We have to hack the way this function works, due to
+ * some bugs in the IBM mini-VDM BIOS support. Specifically
+ * we need to make the input buffer and output buffer the
+ * 'same' buffer, and that ES:SI points to the output
+ * buffer (ignored by the BIOS). The data will end up
+ * being returned in the input buffer, except for the
+ * first four bytes ('VESA') that will not be returned.
+ */
+ rmregs.pB[0].bBufferType = INPUT_BUFFER;
+ rmregs.pB[0].bSelCRF = REG_OFFSET(reg_es);
+ rmregs.pB[0].bOffCRF = REG_OFFSET(reg_edi);
+ rmregs.pB[0].pAddress = RMBuf;
+ rmregs.pB[0].ulSize = 4;
+ rmregs.pB[1].bBufferType = OUTPUT_BUFFER;
+ rmregs.pB[1].bSelCRF = REG_OFFSET(reg_es);
+ rmregs.pB[1].bOffCRF = REG_OFFSET(reg_esi);
+ rmregs.pB[1].pAddress = ((PBYTE)RMBuf)+4;
+ rmregs.pB[1].ulSize = 512-4;
+ break;
+ case 0x4F01:
+ rmregs.pB[0].bBufferType = OUTPUT_BUFFER;
+ rmregs.pB[0].bSelCRF = REG_OFFSET(reg_es);
+ rmregs.pB[0].bOffCRF = REG_OFFSET(reg_edi);
+ rmregs.pB[0].pAddress = RMBuf;
+ rmregs.pB[0].ulSize = 256;
+ break;
+ case 0x4F02:
+ rmregs.pB[0].bBufferType = INPUT_BUFFER;
+ rmregs.pB[0].bSelCRF = REG_OFFSET(reg_es);
+ rmregs.pB[0].bOffCRF = REG_OFFSET(reg_edi);
+ rmregs.pB[0].pAddress = RMBuf;
+ rmregs.pB[0].ulSize = 256;
+ break;
+ case 0x4F09:
+ rmregs.pB[0].bBufferType = INPUT_BUFFER;
+ rmregs.pB[0].bSelCRF = REG_OFFSET(reg_es);
+ rmregs.pB[0].bOffCRF = REG_OFFSET(reg_edi);
+ rmregs.pB[0].pAddress = RMBuf;
+ rmregs.pB[0].ulSize = 1024;
+ break;
+ case 0x4F0A:
+ /* Due to bugs in the mini-VDM in OS/2, the 0x4F0A protected
+ * mode interface functions will not work (we never get any
+ * selectors returned), so we fail this function here. The
+ * rest of the VBE/Core driver will work properly if this
+ * function is failed, because the VBE 2.0 and 3.0 specs
+ * allow for this.
+ */
+ regs->eax = 0x014F;
+ return;
+ }
+ }
+ if (useVPMI)
+ PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,NULL,&rmregs);
+ else {
+ DosSysCtl(6, &rmregs);
+ }
+
+ OUTDPMI(eax); OUTDPMI(ebx); OUTDPMI(ecx); OUTDPMI(edx); OUTDPMI(esi); OUTDPMI(edi);
+ if (((regs->eax & 0xFFFF) == 0x004F) && ((eax & 0xFFFF) == 0x4F00)) {
+ /* Hack to fix up the missing 'VESA' string for mini-VDM */
+ memcpy(RMBuf,"VESA",4);
+ }
+ regs->ds = rmregs.aCRF.reg_ds;
+ regs->es = rmregs.aCRF.reg_es;
+ regs->flags = rmregs.aCRF.reg_eflag;
+}
+
+#define IN(reg) rmregs.reg = in->e.reg
+#define OUT(reg) out->e.reg = rmregs.reg
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt.
+****************************************************************************/
+int PMAPI PM_int86(
+ int intno,
+ RMREGS *in,
+ RMREGS *out)
+{
+ DPMI_regs rmregs;
+
+ memset(&rmregs, 0, sizeof(rmregs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ DPMI_int86(intno,&rmregs);
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ out->x.cflag = rmregs.flags & 0x1;
+ return out->x.ax;
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt.
+****************************************************************************/
+int PMAPI PM_int86x(
+ int intno,
+ RMREGS *in,
+ RMREGS *out,
+ RMSREGS *sregs)
+{
+ DPMI_regs rmregs;
+
+ memset(&rmregs, 0, sizeof(rmregs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ rmregs.es = sregs->es;
+ rmregs.ds = sregs->ds;
+ DPMI_int86(intno,&rmregs);
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ sregs->es = rmregs.es;
+ sregs->cs = rmregs.cs;
+ sregs->ss = rmregs.ss;
+ sregs->ds = rmregs.ds;
+ out->x.cflag = rmregs.flags & 0x1;
+ return out->x.ax;
+}
+
+/****************************************************************************
+REMARKS:
+Call a real mode far function.
+****************************************************************************/
+void PMAPI PM_callRealMode(
+ uint seg,
+ uint off,
+ RMREGS *in,
+ RMSREGS *sregs)
+{
+ PM_fatalError("PM_callRealMode not supported on OS/2!");
+}
+
+/****************************************************************************
+REMARKS:
+Return the amount of available memory.
+****************************************************************************/
+void PMAPI PM_availableMemory(
+ ulong *physical,
+ ulong *total)
+{
+ /* Unable to get reliable values from OS/2 for this */
+ *physical = *total = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of locked, physical memory for DMA operations.
+****************************************************************************/
+void * PMAPI PM_allocLockedMem(
+ uint size,
+ ulong *physAddr,
+ ibool contiguous,
+ ibool below16M)
+{
+ parmsIn[0] = size;
+ parmsIn[1] = contiguous;
+ parmsIn[2] = below16M;
+ CallSDDHelp(PMHELP_ALLOCLOCKED);
+ *physAddr = parmsOut[1];
+ return (void*)parmsOut[0];
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of locked physical memory.
+****************************************************************************/
+void PMAPI PM_freeLockedMem(
+ void *p,
+ uint size,
+ ibool contiguous)
+{
+ parmsIn[0] = (ulong)p;
+ CallSDDHelp(PMHELP_FREELOCKED);
+}
+
+/****************************************************************************
+REMARKS:
+Allocates a new block of pages for the page block manager.
+****************************************************************************/
+static pageblock *PM_addNewPageBlock(void)
+{
+ int i;
+ pageblock *newBlock;
+ char *p,*next;
+
+ /* Allocate memory for the new page block, and add to head of list */
+ if (DosAllocSharedMem((void**)&newBlock,NULL,PAGE_BLOCK_SIZE,OBJ_GETTABLE | PAG_READ | PAG_WRITE | PAG_COMMIT))
+ return NULL;
+ if (!PM_lockDataPages(newBlock,PAGE_BLOCK_SIZE,&newBlock->lockHandle))
+ return NULL;
+ newBlock->prev = NULL;
+ newBlock->next = pageBlocks;
+ if (pageBlocks)
+ pageBlocks->prev = newBlock;
+ pageBlocks = newBlock;
+
+ /* Initialise the page aligned free list for the page block */
+ newBlock->freeCount = PAGES_PER_BLOCK;
+ newBlock->freeList = p = (char*)(((ulong)(newBlock + 1) + (PM_PAGE_SIZE-1)) & ~(PM_PAGE_SIZE-1));
+ newBlock->freeListStart = newBlock->freeList;
+ newBlock->freeListEnd = p + (PAGES_PER_BLOCK-1) * PM_PAGE_SIZE;
+ for (i = 0; i < PAGES_PER_BLOCK; i++,p = next)
+ FREELIST_NEXT(p) = next = p + PM_PAGE_SIZE;
+ FREELIST_NEXT(p - PM_PAGE_SIZE) = NULL;
+ return newBlock;
+}
+
+/****************************************************************************
+REMARKS:
+Allocates a page aligned and page sized block of memory
+****************************************************************************/
+void * PMAPI PM_allocPage(
+ ibool locked)
+{
+ pageblock *block;
+ void *p;
+
+ /* Scan the block list looking for any free blocks. Allocate a new
+ * page block if no free blocks are found.
+ */
+ for (block = pageBlocks; block != NULL; block = block->next) {
+ if (block->freeCount)
+ break;
+ }
+ if (block == NULL && (block = PM_addNewPageBlock()) == NULL)
+ return NULL;
+ block->freeCount--;
+ p = block->freeList;
+ block->freeList = FREELIST_NEXT(p);
+ (void)locked;
+ return p;
+}
+
+/****************************************************************************
+REMARKS:
+Free a page aligned and page sized block of memory
+****************************************************************************/
+void PMAPI PM_freePage(
+ void *p)
+{
+ pageblock *block;
+
+ /* First find the page block that this page belongs to */
+ for (block = pageBlocks; block != NULL; block = block->next) {
+ if (p >= block->freeListStart && p <= block->freeListEnd)
+ break;
+ }
+ CHECK(block != NULL);
+
+ /* Now free the block by adding it to the free list */
+ FREELIST_NEXT(p) = block->freeList;
+ block->freeList = p;
+ if (++block->freeCount == PAGES_PER_BLOCK) {
+ /* If all pages in the page block are now free, free the entire
+ * page block itself.
+ */
+ if (block == pageBlocks) {
+ /* Delete from head */
+ pageBlocks = block->next;
+ if (block->next)
+ block->next->prev = NULL;
+ }
+ else {
+ /* Delete from middle of list */
+ CHECK(block->prev != NULL);
+ block->prev->next = block->next;
+ if (block->next)
+ block->next->prev = block->prev;
+ }
+
+ /* Unlock the memory and free it */
+ PM_unlockDataPages(block,PAGE_BLOCK_SIZE,&block->lockHandle);
+ DosFreeMem(block);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Map in all the shared memory blocks for managing the memory pages above.
+****************************************************************************/
+void PMAPI PM_mapSharedPages(void)
+{
+ pageblock *block;
+
+ /* Map all the page blocks above into the shared memory for process */
+ for (block = pageBlocks; block != NULL; block = block->next) {
+ DosGetSharedMem(block, PAG_READ | PAG_WRITE);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockDataPages(
+ void *p,
+ uint len,
+ PM_lockHandle *lockHandle)
+{
+ parmsIn[0] = (ulong)p;
+ parmsIn[1] = len;
+ CallSDDHelp(PMHELP_LOCKPAGES);
+ lockHandle->h[0] = parmsOut[1];
+ lockHandle->h[1] = parmsOut[2];
+ lockHandle->h[2] = parmsOut[3];
+ return parmsOut[0];
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockDataPages(
+ void *p,
+ uint len,
+ PM_lockHandle *lockHandle)
+{
+ parmsIn[0] = lockHandle->h[0];
+ parmsIn[1] = lockHandle->h[1];
+ parmsIn[2] = lockHandle->h[2];
+ return CallSDDHelp(PMHELP_UNLOCKPAGES);
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockCodePages(
+ void (*p)(),
+ uint len,
+ PM_lockHandle *lockHandle)
+{
+ parmsIn[0] = (ulong)p;
+ parmsIn[1] = len;
+ CallSDDHelp(PMHELP_LOCKPAGES);
+ lockHandle->h[0] = parmsOut[1];
+ lockHandle->h[1] = parmsOut[2];
+ lockHandle->h[2] = parmsOut[3];
+ return parmsOut[0];
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockCodePages(
+ void (*p)(),
+ uint len,
+ PM_lockHandle *lockHandle)
+{
+ parmsIn[0] = lockHandle->h[0];
+ parmsIn[1] = lockHandle->h[1];
+ parmsIn[2] = lockHandle->h[2];
+ return CallSDDHelp(PMHELP_UNLOCKPAGES);
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display banks.
+****************************************************************************/
+void PMAPI PM_setBankA(
+ int bank)
+{
+ INTCRF rmregs;
+
+ if (!InitInt10())
+ return;
+ memset(&rmregs, 0, sizeof(rmregs));
+ rmregs.ulBIOSIntNo = 0x10;
+ rmregs.aCRF.reg_eax = 0x4F05;
+ rmregs.aCRF.reg_ebx = 0x0000;
+ rmregs.aCRF.reg_edx = bank;
+ PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,&rmregs,NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display banks.
+****************************************************************************/
+void PMAPI PM_setBankAB(
+ int bank)
+{
+ INTCRF rmregs;
+
+ if (!InitInt10())
+ return;
+ memset(&rmregs, 0, sizeof(rmregs));
+ rmregs.ulBIOSIntNo = 0x10;
+ rmregs.aCRF.reg_eax = 0x4F05;
+ rmregs.aCRF.reg_ebx = 0x0000;
+ rmregs.aCRF.reg_edx = bank;
+ PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,&rmregs,NULL);
+ rmregs.ulBIOSIntNo = 0x10;
+ rmregs.aCRF.reg_eax = 0x4F05;
+ rmregs.aCRF.reg_ebx = 0x0001;
+ rmregs.aCRF.reg_edx = bank;
+ PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,&rmregs,NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display start address.
+****************************************************************************/
+void PMAPI PM_setCRTStart(
+ int x,
+ int y,
+ int waitVRT)
+{
+ INTCRF rmregs;
+
+ if (!InitInt10())
+ return;
+ memset(&rmregs, 0, sizeof(rmregs));
+ rmregs.ulBIOSIntNo = 0x10;
+ rmregs.aCRF.reg_eax = 0x4F07;
+ rmregs.aCRF.reg_ebx = waitVRT;
+ rmregs.aCRF.reg_ecx = x;
+ rmregs.aCRF.reg_edx = y;
+ PM_VIDEOPMI32Request(&Adapter,PMIREQUEST_SOFTWAREINT,&rmregs,NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Execute the POST on the secondary BIOS for a controller.
+****************************************************************************/
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *mappedBIOS,
+ ulong BIOSLen)
+{
+ (void)axVal;
+ (void)BIOSPhysAddr;
+ (void)mappedBIOS;
+ (void)BIOSLen;
+ return false;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+RETURNS:
+Error code describing the result.
+
+REMARKS:
+Function to enable write combining for the specified region of memory.
+****************************************************************************/
+int PMAPI PM_enableWriteCombine(
+ ulong base,
+ ulong size,
+ uint type)
+{
+ return MTRR_enableWriteCombine(base,size,type);
+}
+
+// TODO: Move the MTRR helper stuff into the call gate, or better yet
+// entirely into the ring 0 helper driver!!
+
+/* MTRR helper functions. To make it easier to implement the MTRR support
+ * under OS/2, we simply put our ring 0 helper functions into the
+ * helper device driver rather than the entire MTRR module. This makes
+ * it easier to maintain the MTRR support since we don't need to deal
+ * with 16-bit ring 0 code in the MTRR library.
+ */
+
+/****************************************************************************
+REMARKS:
+Flush the translation lookaside buffer.
+****************************************************************************/
+void PMAPI PM_flushTLB(void)
+{
+ CallSDDHelp(PMHELP_FLUSHTLB);
+}
+
+/****************************************************************************
+REMARKS:
+Return true if ring 0 (or if we can call the helpers functions at ring 0)
+****************************************************************************/
+ibool _ASMAPI _MTRR_isRing0(void)
+{
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Read and return the value of the CR4 register
+****************************************************************************/
+ulong _ASMAPI _MTRR_saveCR4(void)
+{
+ return CallSDDHelp(PMHELP_SAVECR4);
+}
+
+/****************************************************************************
+REMARKS:
+Restore the value of the CR4 register
+****************************************************************************/
+void _ASMAPI _MTRR_restoreCR4(ulong cr4Val)
+{
+ parmsIn[0] = cr4Val;
+ CallSDDHelp(PMHELP_RESTORECR4);
+}
+
+/****************************************************************************
+REMARKS:
+Read a machine status register for the CPU.
+****************************************************************************/
+void _ASMAPI _MTRR_readMSR(
+ ulong reg,
+ ulong *eax,
+ ulong *edx)
+{
+ parmsIn[0] = reg;
+ CallSDDHelp(PMHELP_READMSR);
+ *eax = parmsOut[0];
+ *edx = parmsOut[1];
+}
+
+/****************************************************************************
+REMARKS:
+Write a machine status register for the CPU.
+****************************************************************************/
+void _ASMAPI _MTRR_writeMSR(
+ ulong reg,
+ ulong eax,
+ ulong edx)
+{
+ parmsIn[0] = reg;
+ parmsIn[1] = eax;
+ parmsIn[2] = edx;
+ CallSDDHelp(PMHELP_WRITEMSR);
+}
+
+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;
+}
+
+/****************************************************************************
+REMARKS:
+Internal function to convert the find data to the generic interface.
+****************************************************************************/
+static void convertFindData(
+ PM_findData *findData,
+ FILEFINDBUF3 *blk)
+{
+ ulong dwSize = findData->dwSize;
+
+ memset(findData,0,findData->dwSize);
+ findData->dwSize = dwSize;
+ if (blk->attrFile & FILE_READONLY)
+ findData->attrib |= PM_FILE_READONLY;
+ if (blk->attrFile & FILE_DIRECTORY)
+ findData->attrib |= PM_FILE_DIRECTORY;
+ if (blk->attrFile & FILE_ARCHIVED)
+ findData->attrib |= PM_FILE_ARCHIVE;
+ if (blk->attrFile & FILE_HIDDEN)
+ findData->attrib |= PM_FILE_HIDDEN;
+ if (blk->attrFile & FILE_SYSTEM)
+ findData->attrib |= PM_FILE_SYSTEM;
+ findData->sizeLo = blk->cbFile;
+ findData->sizeHi = 0;
+ strncpy(findData->name,blk->achName,PM_MAX_PATH);
+ findData->name[PM_MAX_PATH-1] = 0;
+}
+
+#define FIND_MASK (FILE_ARCHIVED | FILE_DIRECTORY | FILE_SYSTEM | FILE_HIDDEN | FILE_READONLY)
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+void *PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ FILEFINDBUF3 blk;
+ HDIR hdir = HDIR_CREATE;
+ ulong count = 1;
+
+ if (DosFindFirst((PSZ)filename,&hdir,FIND_MASK,&blk,sizeof(blk),&count,FIL_STANDARD) == NO_ERROR) {
+ convertFindData(findData,&blk);
+ return (void*)hdir;
+ }
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ void *handle,
+ PM_findData *findData)
+{
+ FILEFINDBUF3 blk;
+ ulong count = 1;
+
+ if (DosFindNext((HDIR)handle,&blk,sizeof(blk),&count) == NO_ERROR) {
+ convertFindData(findData,&blk);
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ void *handle)
+{
+ DosFindClose((HDIR)handle);
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 0 - Current drive
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ ulong cntDisk,cntDriveMap;
+ ibool valid;
+
+ DosQueryCurrentDisk(&cntDisk,&cntDriveMap);
+ valid = (DosSetDefaultDisk(drive) == NO_ERROR);
+ DosSetDefaultDisk(cntDisk);
+ return valid;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ ulong length = len;
+
+ DosQueryCurrentDir(drive, (PSZ)dir, &length);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+ FILESTATUS3 s;
+
+ if (DosQueryPathInfo((PSZ)filename,FIL_STANDARD,(PVOID)&s,sizeof(s)))
+ return;
+ s.attrFile = 0;
+ if (attrib & PM_FILE_READONLY)
+ s.attrFile |= FILE_READONLY;
+ if (attrib & PM_FILE_ARCHIVE)
+ s.attrFile |= FILE_ARCHIVED;
+ if (attrib & PM_FILE_HIDDEN)
+ s.attrFile |= FILE_HIDDEN;
+ if (attrib & PM_FILE_SYSTEM)
+ s.attrFile |= FILE_SYSTEM;
+ DosSetPathInfo((PSZ)filename,FIL_STANDARD,(PVOID)&s,sizeof(s),0L);
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file attributes for a specific file.
+****************************************************************************/
+uint PMAPI PM_getFileAttr(
+ const char *filename)
+{
+ FILESTATUS3 fs3;
+ uint retval = 0;
+
+ if (DosQueryPathInfo((PSZ)filename, FIL_STANDARD, &fs3, sizeof(FILESTATUS3)))
+ return 0;
+ if (fs3.attrFile & FILE_READONLY)
+ retval |= PM_FILE_READONLY;
+ if (fs3.attrFile & FILE_ARCHIVED)
+ retval |= PM_FILE_ARCHIVE;
+ if (fs3.attrFile & FILE_HIDDEN)
+ retval |= PM_FILE_HIDDEN;
+ if (fs3.attrFile & FILE_SYSTEM)
+ retval |= PM_FILE_SYSTEM;
+ return retval;
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+ return DosCreateDir((PSZ)filename,NULL) == NO_ERROR;
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+ return DosDeleteDir((PSZ)filename) == NO_ERROR;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_getFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ FILESTATUS3 fs3;
+ struct tm tc;
+ struct tm *ret;
+ time_t tt;
+
+ if (DosQueryPathInfo((PSZ)filename, FIL_STANDARD, &fs3, sizeof(FILESTATUS3)))
+ return false;
+ if (gmTime) {
+ tc.tm_year = fs3.fdateLastWrite.year + 80;
+ tc.tm_mon = fs3.fdateLastWrite.month - 1;
+ tc.tm_mday = fs3.fdateLastWrite.day;
+ tc.tm_hour = fs3.ftimeLastWrite.hours;
+ tc.tm_min = fs3.ftimeLastWrite.minutes;
+ tc.tm_sec = fs3.ftimeLastWrite.twosecs * 2;
+ if((tt = mktime(&tc)) == -1)
+ return false;
+ if(!(ret = gmtime(&tt)))
+ return false;
+ time->sec = ret->tm_sec;
+ time->day = ret->tm_mday;
+ time->mon = ret->tm_mon + 1;
+ time->year = ret->tm_year - 80;
+ time->min = ret->tm_min;
+ time->hour = ret->tm_hour;
+ }
+ else {
+ time->sec = fs3.ftimeLastWrite.twosecs * 2;
+ time->day = fs3.fdateLastWrite.day;
+ time->mon = fs3.fdateLastWrite.month;
+ time->year = fs3.fdateLastWrite.year;
+ time->min = fs3.ftimeLastWrite.minutes;
+ time->hour = fs3.ftimeLastWrite.hours;
+ }
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_setFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ FILESTATUS3 fs3;
+ struct tm tc;
+ struct tm *ret;
+ time_t tt;
+
+ if (DosQueryPathInfo((PSZ)filename,FIL_STANDARD,(PVOID)&fs3,sizeof(fs3)))
+ return false;
+ if (gmTime) {
+ tc.tm_year = time->year + 80;
+ tc.tm_mon = time->mon - 1;
+ tc.tm_mday = time->day;
+ tc.tm_hour = time->hour;
+ tc.tm_min = time->min;
+ tc.tm_sec = time->sec;
+ if((tt = mktime(&tc)) == -1)
+ return false;
+ ret = localtime(&tt);
+ fs3.ftimeLastWrite.twosecs = ret->tm_sec / 2;
+ fs3.fdateLastWrite.day = ret->tm_mday;
+ fs3.fdateLastWrite.month = ret->tm_mon + 1;
+ fs3.fdateLastWrite.year = ret->tm_year - 80;
+ fs3.ftimeLastWrite.minutes = ret->tm_min;
+ fs3.ftimeLastWrite.hours = ret->tm_hour;
+ }
+ else {
+ fs3.ftimeLastWrite.twosecs = time->sec / 2;
+ fs3.fdateLastWrite.day = time->day;
+ fs3.fdateLastWrite.month = time->mon;
+ fs3.fdateLastWrite.year = time->year;
+ fs3.ftimeLastWrite.minutes = time->min;
+ fs3.ftimeLastWrite.hours = time->hour;
+ }
+ memcpy(&fs3.fdateLastAccess, &fs3.fdateLastWrite, sizeof(FDATE));
+ memcpy(&fs3.fdateCreation, &fs3.fdateLastWrite, sizeof(FDATE));
+ memcpy(&fs3.ftimeLastAccess, &fs3.ftimeLastWrite, sizeof(FTIME));
+ memcpy(&fs3.ftimeCreation, &fs3.ftimeLastWrite, sizeof(FTIME));
+ DosSetPathInfo((PSZ)filename,FIL_STANDARD,(PVOID)&fs3,sizeof(FILESTATUS3),0L);
+ return true;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/os2/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/os2/vflat.c
new file mode 100644
index 0000000000..579ef2c95c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/os2/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/os2/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/os2/ztimer.c
new file mode 100644
index 0000000000..30ffe4340b
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/os2/ztimer.c
@@ -0,0 +1,110 @@
+/****************************************************************************
+*
+* 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: OS/2
+*
+* Description: OS specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+/*---------------------------- Global variables ---------------------------*/
+
+static ulong frequency;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+void __ZTimerInit(void)
+{
+ DosTmrQueryFreq(&frequency);
+}
+
+/****************************************************************************
+REMARKS:
+Start the Zen Timer counting.
+****************************************************************************/
+#define __LZTimerOn(tm) DosTmrQueryTime((QWORD*)&tm->start)
+
+/****************************************************************************
+REMARKS:
+Compute the lap time since the timer was started.
+****************************************************************************/
+static ulong __LZTimerLap(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger tmLap,tmCount;
+
+ DosTmrQueryTime((QWORD*)&tmLap);
+ _CPU_diffTime64(&tm->start,&tmLap,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,frequency);
+}
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOff(tm) DosTmrQueryTime((QWORD*)&tm->end)
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+static ulong __LZTimerCount(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger tmCount;
+
+ _CPU_diffTime64(&tm->start,&tm->end,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,frequency);
+}
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 1000
+
+/****************************************************************************
+REMARKS:
+Read the Long Period timer value from the BIOS timer tick.
+****************************************************************************/
+static ulong __ULZReadTime(void)
+{
+ ULONG count;
+ DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &count, sizeof(ULONG) );
+ return count;
+}
+
+/****************************************************************************
+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; }
diff --git a/board/MAI/bios_emulator/scitech/src/pm/os2pm/event.c b/board/MAI/bios_emulator/scitech/src/pm/os2pm/event.c
new file mode 100644
index 0000000000..97c2caa82f
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/os2pm/event.c
@@ -0,0 +1,170 @@
+/****************************************************************************
+*
+* 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: IBM PC (OS/2)
+*
+* Description: OS/2 implementation for the SciTech cross platform
+* event library.
+*
+****************************************************************************/
+
+/*---------------------------- Global Variables ---------------------------*/
+
+static int oldMouseState; /* Old mouse state */
+static ulong oldKeyMessage; /* Old keyboard state */
+static ushort keyUpMsg[256] = {0};/* Table of key up messages */
+static int rangeX,rangeY; /* Range of mouse coordinates */
+HMOU _EVT_hMouse; /* Handle to the mouse driver */
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* These are not used under OS/2 */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flags)
+
+/****************************************************************************
+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:
+Pumps all messages in the message queue from OS/2 into our event queue.
+****************************************************************************/
+static void _EVT_pumpMessages(void)
+{
+ // TODO: Implement this for OS/2 Presentation Manager apps!
+}
+
+/****************************************************************************
+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 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:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort()
+{
+ EVT_exit();
+ PM_fatalError("Unhandled exception!");
+}
+
+/****************************************************************************
+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)
+{
+ /* Initialise the event queue */
+ EVT.mouseMove = mouseMove;
+ initEventQueue();
+ oldMouseState = 0;
+ oldKeyMessage = 0;
+ memset(keyUpMsg,0,sizeof(keyUpMsg));
+
+ // TODO: OS/2 PM specific initialisation code!
+
+ /* Catch program termination signals so we can clean up properly */
+ signal(SIGABRT, _EVT_abort);
+ signal(SIGFPE, _EVT_abort);
+ signal(SIGINT, _EVT_abort);
+}
+
+/****************************************************************************
+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)
+{
+ rangeX = xRes;
+ rangeY = yRes;
+}
+
+/****************************************************************************
+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 OS/2
+}
+
+/****************************************************************************
+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 OS/2
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+ /* Restore signal handlers */
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+
+ // TODO: OS/2 PM specific exit code
+}
+
+/****************************************************************************
+REMARKS
+Modifes the mouse coordinates as necessary if scaling to OS coordinates,
+and sets the OS mouse cursor position.
+****************************************************************************/
+#define _EVT_setMousePos(x,y)
diff --git a/board/MAI/bios_emulator/scitech/src/pm/os2pm/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/os2pm/oshdr.h
new file mode 100644
index 0000000000..0b69f8222c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/os2pm/oshdr.h
@@ -0,0 +1,36 @@
+/****************************************************************************
+*
+* 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: 32-bit OS/2
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
+
+#define INCL_DOSERRORS
+#define INCL_DOS
+#define INCL_SUB
+#define INCL_VIO
+#define INCL_KBD
+#include <os2.h>
diff --git a/board/MAI/bios_emulator/scitech/src/pm/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/oshdr.h
new file mode 100644
index 0000000000..404e5c93c5
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/oshdr.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+*
+* 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: Header file to pull in OS specific headers for the target
+* OS environment.
+*
+****************************************************************************/
+
+#if defined(__SMX32__)
+#include "smx/oshdr.h"
+#elif defined(__RTTARGET__)
+#include "rttarget/oshdr.h"
+#elif defined(__REALDOS__)
+#include "dos/oshdr.h"
+#elif defined(__WIN32_VXD__)
+#include "vxd/oshdr.h"
+#elif defined(__NT_DRIVER__)
+#include "ntdrv/oshdr.h"
+#elif defined(__WINDOWS32__)
+#include "win32/oshdr.h"
+#elif defined(__OS2_VDD__)
+#include "vxd/oshdr.h"
+#elif defined(__OS2__)
+#if defined(__OS2_PM__)
+#include "os2pm/oshdr.h"
+#else
+#include "os2/oshdr.h"
+#endif
+#elif defined(__LINUX__)
+#if defined(__USE_X11__)
+#include "x11/oshdr.h"
+#else
+#include "linux/oshdr.h"
+#endif
+#elif defined(__QNX__)
+#if defined(__USE_PHOTON__)
+#include "photon/oshdr.h"
+#elif defined(__USE_X11__)
+#include "x11/oshdr.h"
+#else
+#include "qnx/oshdr.h"
+#endif
+#elif defined(__BEOS__)
+#include "beos/oshdr.h"
+#else
+#error PM library not ported to this platform yet!
+#endif
diff --git a/board/MAI/bios_emulator/scitech/src/pm/photon/event.c b/board/MAI/bios_emulator/scitech/src/pm/photon/event.c
new file mode 100644
index 0000000000..738dfea379
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/photon/event.c
@@ -0,0 +1,268 @@
+/****************************************************************************
+*
+* 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: QNX Photon GUI
+*
+* Description: QNX fullscreen console implementation for the SciTech
+* cross platform event library.
+*
+****************************************************************************/
+
+/*--------------------------- Global variables ----------------------------*/
+
+static ushort keyUpMsg[256] = {0};/* Table of key up messages */
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* These are not used under Linux */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flags)
+
+/****************************************************************************
+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.
+****************************************************************************/
+static ibool _EVT_isKeyDown(
+ uchar scancode)
+{
+ return (KeyState[(scancode & 0xf8) >> 3] & (1 << (scancode & 0x7)) ?
+ true : false);
+}
+
+/****************************************************************************
+REMARKS:
+Retrieves all events from the mouse/keyboard event queue and stuffs them
+into the MGL event queue for further processing.
+****************************************************************************/
+static void _EVT_pumpMessages(void)
+{
+ int pid;
+ uint msg, but_stat, message;
+ uchar evt[sizeof (PhEvent_t) + 1024];
+ PhEvent_t *event = (void *)evt;
+ PhKeyEvent_t *key;
+ PhPointerEvent_t *mouse;
+ static int extended;
+ event_t _evt;
+
+ while (count < EVENTQSIZE) {
+ uint mods = 0, keyp = 0;
+
+ pid = Creceive(0, &msg, sizeof (msg));
+
+ if (pid == -1)
+ return;
+
+ if (PhEventRead(pid, event, sizeof (evt)) == Ph_EVENT_MSG) {
+ memset(&evt, 0, sizeof (evt));
+ if (event->type == Ph_EV_KEY) {
+ key = PhGetData(event);
+
+ if (key->key_flags & KEY_SCAN_VALID) {
+ keyp = key->key_scan;
+ if (key->key_flags & KEY_DOWN)
+ KeyState[(keyp & 0xf800) >> 11]
+ |= 1 << ((keyp & 0x700) >> 8);
+ else
+ KeyState[(keyp & 0xf800) >> 11]
+ &= ~(1 << ((keyp & 0x700) >> 8));
+ }
+ if ((key->key_flags & KEY_SYM_VALID) || extended)
+ keyp |= key->key_sym;
+
+ /* No way to tell left from right... */
+ if (key->key_mods & KEYMOD_SHIFT)
+ mods = (EVT_LEFTSHIFT | EVT_RIGHTSHIFT);
+ if (key->key_mods & KEYMOD_CTRL)
+ mods |= (EVT_CTRLSTATE | EVT_LEFTCTRL);
+ if (key->key_mods & KEYMOD_ALT)
+ mods |= (EVT_ALTSTATE | EVT_LEFTALT);
+
+ _evt.when = evt->timestamp;
+ if (key->key_flags & KEY_REPEAT) {
+ _evt.what = EVT_KEYREPEAT;
+ _evt.message = 0x10000;
+ }
+ else if (key->key_flags & KEY_DOWN)
+ _evt.what = EVT_KEYDOWN;
+ else
+ _evt.what = EVT_KEYUP;
+ _evt.modifiers = mods;
+ _evt.message |= keyp;
+
+ addEvent(&_evt);
+
+ switch(key->key_scan & 0xff00) {
+ case 0xe000:
+ extended = 1;
+ break;
+ case 0xe001:
+ extended = 2;
+ break;
+ default:
+ if (extended)
+ extended--;
+ }
+ }
+ else if (event->type & Ph_EV_PTR_ALL) {
+ but_stat = message = 0;
+ mouse = PhGetData(event);
+
+ if (mouse->button_state & Ph_BUTTON_3)
+ but_stat = EVT_LEFTBUT;
+ if (mouse->buttons & Ph_BUTTON_3)
+ message = EVT_LEFTBMASK;
+
+ if (mouse->button_state & Ph_BUTTON_1)
+ but_stat |= EVT_RIGHTBUT;
+ if (mouse->buttons & Ph_BUTTON_1)
+ message |= EVT_RIGHTBMASK;
+
+ _evt.when = evt->timestamp;
+ if (event->type & Ph_EV_PTR_MOTION) {
+ _evt.what = EVT_MOUSEMOVE;
+ _evt.where_x = mouse->pos.x;
+ _evt.where_y = mouse->pos.y;
+ _evt.modifiers = but_stat;
+ addEvent(&_evt);
+ }
+ if (event->type & Ph_EV_BUT_PRESS)
+ _evt.what = EVT_MOUSEDOWN;
+ else
+ _evt.what = EVT_MOUSEUP;
+ _evt.where_x = mouse->pos.x;
+ _evt.where_y = mouse->pos.y;
+ _evt.modifiers = but_stat;
+ _evt.message = message;
+ addEvent(&_evt);
+ }
+ }
+ else
+ return;
+ }
+}
+
+/****************************************************************************
+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 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:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort(
+ int signo)
+{
+ char buf[80];
+
+ EVT_exit();
+ sprintf(buf,"Terminating on signal %d",signo);
+ PM_fatalError(buf);
+}
+
+/****************************************************************************
+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;
+
+ /* Initialise the event queue */
+ _mouseMove = mouseMove;
+ initEventQueue();
+ memset((void *)KeyState, 0, sizeof (KeyState));
+
+ /* Catch program termination signals so we can clean up properly */
+ signal(SIGABRT, _EVT_abort);
+ signal(SIGFPE, _EVT_abort);
+ signal(SIGINT, _EVT_abort);
+}
+
+/****************************************************************************
+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)
+{
+ // TODO: Need to call Input to change the coordinates that it returns
+ // for mouse events!!
+}
+
+/****************************************************************************
+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 Photon
+}
+
+/****************************************************************************
+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 Photon
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+ /* Restore signal handlers */
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/photon/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/photon/oshdr.h
new file mode 100644
index 0000000000..3c72563de2
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/photon/oshdr.h
@@ -0,0 +1,38 @@
+/****************************************************************************
+*
+* 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: QNX Photon GUI
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
+
+#include <sys/mouse.h>
+#include <sys/keyboard.h>
+#include <sys/fd.h>
+#include <sys/stat.h>
+#include <conio.h>
+#include <process.h>
+#include <sys/kernel.h>
+#include <Ph.h>
diff --git a/board/MAI/bios_emulator/scitech/src/pm/pm.vpw b/board/MAI/bios_emulator/scitech/src/pm/pm.vpw
new file mode 100644
index 0000000000..26e68a7a3a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/pm.vpw
@@ -0,0 +1,43 @@
+[Dependencies]
+[CurrentProject]
+curproj=pmlinux.vpj
+[ProjectFiles]
+pmcommon.vpj
+pmdos.vpj
+pmlinux.vpj
+pmqnx.vpj
+pmvxd.vpj
+pmwin32.vpj
+z_samples.vpj
+..\a-global includes.vpj
+[TreeExpansion]
+"..\a-global includes.vpj" 0
+pmcommon.vpj 0
+pmdos.vpj 0
+pmlinux.vpj 0
+pmqnx.vpj 0
+pmvxd.vpj 0
+pmwin32.vpj 0
+z_samples.vpj 1 1
+[State]
+SCREEN: 1280 1024 0 0 960 746 0 0 M 0 0 0 0 977 631
+CWD: C:\scitech\src\pm
+FILEHIST: 9
+C:\scitech\makedefs\gcc_win32.mk
+C:\scitech\bin\gcc2-w32.bat
+C:\scitech\bin\gcc2-c32.bat
+C:\scitech\bin\gcc2-linux.bat
+C:\scitech\makedefs\gcc_linux.mk
+C:\scitech\src\pm\linux\event.c
+C:\scitech\src\pm\linux\oshdr.h
+C:\scitech\src\pm\event.c
+C:\scitech\src\pm\pmlinux.vpj
+[ProjectDates]
+pmcommon.vpj=20010517164335290
+pmdos.vpj=20010517164335290
+pmlinux.vpj=20010620175829812
+pmqnx.vpj=20010517164335290
+pmvxd.vpj=20010517164335306
+pmwin32.vpj=20010517164335306
+z_samples.vpj=20010517164335306
+..\a-global includes.vpj=20010517164334978
diff --git a/board/MAI/bios_emulator/scitech/src/pm/pmcommon.vpj b/board/MAI/bios_emulator/scitech/src/pm/pmcommon.vpj
new file mode 100644
index 0000000000..48b872d981
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/pmcommon.vpj
@@ -0,0 +1,45 @@
+[COMPILER]
+version=5.0b
+MACRO=\n
+activeconfig=,wc10-d32
+FILTERNAME=Source Files\nInclude Files\nAssembler Files\nOther Files\n
+FILTERPATTERN=*.c;*.cpp;*.cxx;*.prg;*.pas;*.dpr;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc\n*.h\n*.asm\n*.*\n
+FILTERASSOCIATEFILETYPES=0 0 0 0
+FILTERAPPCOMMAND=\n\n\n\n
+vcsproject=SCC:Perforce SCM://depot
+vcslocalpath=SCC:Perforce SCM:c:\
+compile=concur|capture|hide|:Compile:&Compile,
+make=concur|capture|hide|clear|saveall|:Build:&Build,
+rebuild=concur|capture|hide|clear|saveall|:Rebuild:&Rebuild,
+debug=concur|capture|hide|savenone|:Debug:&Debug,
+execute=hide|savenone|:Execute:E&xecute,
+user1=hide|:User 1:User 1,
+user2=hide|:User 2:User 2,
+workingdir=.
+includedirs=%(SCITECH)\include;%(PRIVATE)\include
+reffile=
+[FILES]
+common.c
+cpuinfo.c
+debug.c
+event.c
+makefile
+oshdr.h
+ztimer.c
+..\common\agplib.c
+codepage\us_eng.c
+common\_cpuinfo.asm
+common\_dma.asm
+common\_int64.asm
+common\_joy.asm
+common\_mtrr.asm
+common\_pcilib.asm
+common\agp.c
+common\keyboard.c
+common\malloc.c
+common\mtrr.c
+common\pcilib.c
+common\unixio.c
+common\vgastate.c
+[ASSOCIATION]
+[CONFIGURATIONS]
diff --git a/board/MAI/bios_emulator/scitech/src/pm/pmdos.vpj b/board/MAI/bios_emulator/scitech/src/pm/pmdos.vpj
new file mode 100644
index 0000000000..1157513b30
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/pmdos.vpj
@@ -0,0 +1,41 @@
+[SciTech]
+compiler=wc10-
+targetos=d32
+[COMPILER]
+version=5.0b
+MACRO=enable_current_compiler\n
+activeconfig=,TEST_HARNESS=1
+FILTERNAME=Source Files\nInclude Files\nAssembler Files\n
+FILTERPATTERN=*.c;*.cpp;*.cxx;*.prg;*.pas;*.dpr;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc\n*.h\n*.asm\n
+FILTERASSOCIATEFILETYPES=0 0 0
+FILTERAPPCOMMAND=\n\n\n
+vcsproject=SCC:Perforce SCM://depot
+vcslocalpath=SCC:Perforce SCM:c:\
+compile=concur|capture|clear|:Compile:&Compile,dmake %n.obj -u %b
+make=concur|capture|clear|saveall|:Build:&Build,dmake install %b
+rebuild=concur|capture|clear|saveall|:Rebuild:&Rebuild,dmake cleanexe & dmake install -u %b
+debug=concur|capture|hide|savenone|:Debug:&Debug,
+execute=hide|savenone|nochangedir|:Execute:E&xecute,
+user1=hide|:User 1:User 1,
+user2=hide|:User 2:User 2,
+usertool_clean_directory=concur|capture|hide|savenone|nochangedir|:Clean Directory:C&lean Directory,dmake cleanexe
+workingdir=.
+includedirs=%(SCITECH)\include;%(PRIVATE)\include
+reffile=
+[FILES]
+dos\_event.asm
+dos\_lztimer.asm
+dos\_pm.asm
+dos\_pmdos.asm
+dos\_vflat.asm
+dos\cpuinfo.c
+dos\event.c
+dos\oshdr.h
+dos\pm.c
+dos\pmdos.c
+dos\vflat.c
+dos\ztimer.c
+[ASSOCIATION]
+[CONFIGURATIONS]
+config=,NORMAL_BUILD=1
+config=,TEST_HARNESS=1
diff --git a/board/MAI/bios_emulator/scitech/src/pm/pmlinux.vpj b/board/MAI/bios_emulator/scitech/src/pm/pmlinux.vpj
new file mode 100644
index 0000000000..0bfbf8446a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/pmlinux.vpj
@@ -0,0 +1,35 @@
+[SciTech]
+compiler=gcc2-
+targetos=linux
+[COMPILER]
+version=5.0b
+MACRO=enable_current_compiler\n
+FILTERNAME=Source Files\nInclude Files\nAssembler Files\n
+FILTERPATTERN=*.c;*.cpp;*.cxx;*.prg;*.pas;*.dpr;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc\n*.h\n*.asm\n
+FILTERASSOCIATEFILETYPES=0 0 0
+FILTERAPPCOMMAND=\n\n\n
+vcsproject=SCC:Perforce SCM://depot
+vcslocalpath=SCC:Perforce SCM:c:\
+activeconfig=,install BUILD_DLL=1
+compile=concur|capture|clear|:Compile:&Compile,dmake %n.o -u
+make=concur|capture|clear|saveall|:Build:&Build,dmake %b
+rebuild=concur|capture|clear|saveall|:Rebuild:&Rebuild,dmake cleanexe & dmake -u %b
+debug=concur|capture|hide|savenone|:Debug:&Debug,
+execute=hide|savenone|nochangedir|:Execute:E&xecute,
+user1=hide|:User 1:User 1,
+user2=hide|:User 2:User 2,
+usertool_clean_directory=concur|capture|hide|savenone|nochangedir|:Clean Directory:C&lean Directory,dmake cleanexe
+workingdir=.
+includedirs=%(SCITECH)\include;%(PRIVATE)\include
+reffile=
+[FILES]
+linux\cpuinfo.c
+linux\event.c
+linux\oshdr.h
+linux\pm.c
+linux\vflat.c
+linux\ztimer.c
+[ASSOCIATION]
+[CONFIGURATIONS]
+config=,install BUILD_DLL=1
+config=,install
diff --git a/board/MAI/bios_emulator/scitech/src/pm/pmntdrv.vpj b/board/MAI/bios_emulator/scitech/src/pm/pmntdrv.vpj
new file mode 100644
index 0000000000..3ec35a76e4
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/pmntdrv.vpj
@@ -0,0 +1,39 @@
+[SciTech]
+compiler=vc60-
+targetos=drvw2k
+[COMPILER]
+version=5.0b
+MACRO=enable_current_compiler\n
+activeconfig=,wc10-d32
+FILTERNAME=Source Files\nInclude Files\nAssembler Files\n
+FILTERPATTERN=*.c;*.cpp;*.cxx;*.prg;*.pas;*.dpr;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc\n*.h\n*.asm\n
+FILTERASSOCIATEFILETYPES=0 0 0
+FILTERAPPCOMMAND=\n\n\n
+vcsproject=SCC:Perforce SCM://depot
+vcslocalpath=SCC:Perforce SCM:c:\
+compile=concur|capture|:Compile:&Compile,dmake %n.obj
+make=concur|capture|clear|saveall|:Build:&Build,dmake install
+rebuild=concur|capture|clear|saveall|:Rebuild:&Rebuild,dmake cleanexe & dmake install -u
+debug=concur|capture|hide|savenone|:Debug:&Debug,
+execute=hide|savenone|nochangedir|:Execute:E&xecute,
+user1=hide|:User 1:User 1,
+user2=hide|:User 2:User 2,
+usertool_clean_directory=concur|capture|hide|savenone|:Clean Directory:&Clean Directory,dmake cleanexe
+workingdir=.
+includedirs=%(SCITECH)\include;%(PRIVATE)\include
+reffile=
+[FILES]
+..\..\include\ntdriver.h
+ntdrv\_pm.asm
+ntdrv\cpuinfo.c
+ntdrv\int86.c
+ntdrv\irq.c
+ntdrv\mem.c
+ntdrv\oshdr.h
+ntdrv\pm.c
+ntdrv\stdio.c
+ntdrv\stdlib.c
+ntdrv\vflat.c
+ntdrv\ztimer.c
+[ASSOCIATION]
+[CONFIGURATIONS]
diff --git a/board/MAI/bios_emulator/scitech/src/pm/pmqnx.vpj b/board/MAI/bios_emulator/scitech/src/pm/pmqnx.vpj
new file mode 100644
index 0000000000..d54170252c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/pmqnx.vpj
@@ -0,0 +1,35 @@
+[SciTech]
+compiler=wc10-
+targetos=qnx
+[COMPILER]
+version=5.0b
+MACRO=enable_current_compiler\n
+activeconfig=,wc10-d32
+FILTERNAME=Source Files\nInclude Files\nAssembler Files\n
+FILTERPATTERN=*.c;*.cpp;*.cxx;*.prg;*.pas;*.dpr;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc\n*.h\n*.asm\n
+FILTERASSOCIATEFILETYPES=0 0 0
+FILTERAPPCOMMAND=\n\n\n
+vcsproject=SCC:Perforce SCM://depot
+vcslocalpath=SCC:Perforce SCM:c:\
+compile=concur|capture|clear|:Compile:&Compile,dmake %n.obj
+make=concur|capture|clear|saveall|:Build:&Build,dmake install
+rebuild=concur|capture|clear|saveall|:Rebuild:&Rebuild,dmake cleanexe & dmake install -u
+debug=concur|capture|hide|savenone|:Debug:&Debug,
+execute=hide|savenone|nochangedir|:Execute:E&xecute,
+user1=hide|:User 1:User 1,
+user2=hide|:User 2:User 2,
+usertool_clean_directory=concur|capture|hide|savenone|nochangedir|:Clean Directory:C&lean Directory,dmake cleanexe
+workingdir=.
+includedirs=%(SCITECH)\include;%(PRIVATE)\include
+reffile=
+[FILES]
+qnx\_mtrrqnx.asm
+qnx\cpuinfo.c
+qnx\event.c
+qnx\mtrrqnx.c
+qnx\oshdr.h
+qnx\pm.c
+qnx\vflat.c
+qnx\ztimer.c
+[ASSOCIATION]
+[CONFIGURATIONS]
diff --git a/board/MAI/bios_emulator/scitech/src/pm/pmvxd.vpj b/board/MAI/bios_emulator/scitech/src/pm/pmvxd.vpj
new file mode 100644
index 0000000000..1fcf911769
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/pmvxd.vpj
@@ -0,0 +1,34 @@
+[SciTech]
+compiler=bc50-
+targetos=vxd
+[COMPILER]
+version=5.0b
+MACRO=enable_current_compiler\n
+activeconfig=,wc10-d32
+FILTERNAME=Source Files\nInclude Files\nAssembler Files\n
+FILTERPATTERN=*.c;*.cpp;*.cxx;*.prg;*.pas;*.dpr;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc\n*.h\n*.asm\n
+FILTERASSOCIATEFILETYPES=0 0 0
+FILTERAPPCOMMAND=\n\n\n
+vcsproject=SCC:Perforce SCM://depot
+vcslocalpath=SCC:Perforce SCM:c:\
+compile=concur|capture|nochangedir|:Compile:&Compile,dmake %n.obj
+make=concur|capture|clear|saveall|nochangedir|:Build:&Build,dmake install
+rebuild=concur|capture|clear|saveall|nochangedir|:Rebuild:&Rebuild,dmake cleanexe & dmake install -u
+debug=concur|capture|hide|savenone|nochangedir|:Debug:&Debug,
+execute=hide|savenone|nochangedir|:Execute:E&xecute,
+user1=hide|:User 1:User 1,
+user2=hide|:User 2:User 2,
+usertool_clean_directory=concur|capture|hide|savenone|nochangedir|:Clean Directory:&Clean Directory,dmake cleanexe
+workingdir=.
+includedirs=%(SCITECH)\include;%(PRIVATE)\include
+reffile=
+[FILES]
+vxd\_pm.asm
+vxd\cpuinfo.c
+vxd\fileio.c
+vxd\oshdr.h
+vxd\pm.c
+vxd\vflat.c
+vxd\ztimer.c
+[ASSOCIATION]
+[CONFIGURATIONS]
diff --git a/board/MAI/bios_emulator/scitech/src/pm/pmwin32.vpj b/board/MAI/bios_emulator/scitech/src/pm/pmwin32.vpj
new file mode 100644
index 0000000000..ace682208c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/pmwin32.vpj
@@ -0,0 +1,35 @@
+[SciTech]
+compiler=vc60-
+targetos=c32
+[COMPILER]
+version=5.0b
+MACRO=enable_current_compiler\n
+activeconfig=,wc10-d32
+FILTERNAME=Source Files\nInclude Files\nAssembler Files\n
+FILTERPATTERN=*.c;*.cpp;*.cxx;*.prg;*.pas;*.dpr;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc\n*.h\n*.asm\n
+FILTERASSOCIATEFILETYPES=0 0 0
+FILTERAPPCOMMAND=\n\n\n
+vcsproject=SCC:Perforce SCM://depot
+vcslocalpath=SCC:Perforce SCM:c:\
+compile=concur|capture|:Compile:&Compile,dmake %n.obj
+make=concur|capture|clear|saveall|:Build:&Build,dmake install
+rebuild=concur|capture|clear|saveall|:Rebuild:&Rebuild,dmake cleanexe & dmake install -u
+debug=concur|capture|hide|savenone|:Debug:&Debug,
+execute=hide|savenone|nochangedir|:Execute:E&xecute,
+user1=hide|:User 1:User 1,
+user2=hide|:User 2:User 2,
+usertool_clean_directory=concur|capture|savenone|:Clean Directory:&Clean Directory,dmake cleanexe
+workingdir=.
+includedirs=%(SCITECH)\include;%(PRIVATE)\include
+reffile=
+[FILES]
+win32\_pmwin32.asm
+win32\cpuinfo.c
+win32\ddraw.c
+win32\event.c
+win32\oshdr.h
+win32\pm.c
+win32\vflat.c
+win32\ztimer.c
+[ASSOCIATION]
+[CONFIGURATIONS]
diff --git a/board/MAI/bios_emulator/scitech/src/pm/qnx/_mtrrqnx.asm b/board/MAI/bios_emulator/scitech/src/pm/qnx/_mtrrqnx.asm
new file mode 100644
index 0000000000..5a3fe105ec
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/qnx/_mtrrqnx.asm
@@ -0,0 +1,226 @@
+;****************************************************************************
+;*
+;* 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: NASM
+;* Environment: QNX
+;*
+;* Description: Assembler support routines for the Memory Type Range Register
+;* (MTRR) module for QNX.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _mtrrqnx ; Set up memory model
+
+begdataseg _mtrrqnx ; Start of code segment
+
+ifdef USE_NASM
+%define R0_FLUSH_TLB 0
+%define R0_SAVE_CR4 1
+%define R0_RESTORE_CR4 2
+%define R0_READ_MSR 3
+%define R0_WRITE_MSR 4
+else
+R0_FLUSH_TLB EQU 0
+R0_SAVE_CR4 EQU 1
+R0_RESTORE_CR4 EQU 2
+R0_READ_MSR EQU 3
+R0_WRITE_MSR EQU 4
+endif
+
+cpublic _PM_R0
+_PM_R0_service dd 0
+_PM_R0_reg dd 0
+_PM_R0_eax dd 0
+_PM_R0_edx dd 0
+
+enddataseg _mtrrqnx ; Start of code segment
+
+begcodeseg _mtrrqnx ; Start of code segment
+
+P586
+
+;----------------------------------------------------------------------------
+; ulong _MTRR_disableInt(void);
+;----------------------------------------------------------------------------
+; Return processor interrupt status and disable interrupts.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_disableInt
+
+ pushfd ; Put flag word on stack
+; cli ; Disable interrupts!
+ pop eax ; deposit flag word in return register
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _MTRR_restoreInt(ulong ps);
+;----------------------------------------------------------------------------
+; Restore processor interrupt status.
+;----------------------------------------------------------------------------
+cprocstart _MTRR_restoreInt
+
+ ARG ps:ULONG
+
+ push ebp
+ mov ebp,esp ; Set up stack frame
+ push [ULONG ps]
+ popfd ; Restore processor status (and interrupts)
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uchar _MTRR_getCx86(uchar reg);
+;----------------------------------------------------------------------------
+; Read a Cyrix CPU indexed register
+;----------------------------------------------------------------------------
+cprocstart _MTRR_getCx86
+
+ ARG reg:UCHAR
+
+ enter_c
+ mov al,[reg]
+ out 22h,al
+ in al,23h
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; uchar _MTRR_setCx86(uchar reg,uchar val);
+;----------------------------------------------------------------------------
+; Write a Cyrix CPU indexed register
+;----------------------------------------------------------------------------
+cprocstart _MTRR_setCx86
+
+ ARG reg:UCHAR, val:UCHAR
+
+ enter_c
+ mov al,[reg]
+ out 22h,al
+ mov al,[val]
+ out 23h,al
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; ulong _PM_ring0_isr(void);
+;----------------------------------------------------------------------------
+; Ring 0 clock interrupt handler that we use to execute the MTRR support
+; code.
+;----------------------------------------------------------------------------
+cprocnear _PM_ring0_isr
+
+;--------------------------------------------------------
+; void PM_flushTLB(void);
+;--------------------------------------------------------
+ pushad
+ cmp [DWORD _PM_R0_service],R0_FLUSH_TLB
+ jne @@1
+ wbinvd ; Flush the CPU cache
+ mov eax,cr3
+ mov cr3,eax ; Flush the TLB
+ jmp @@Exit
+
+;--------------------------------------------------------
+; ulong _MTRR_saveCR4(void);
+;--------------------------------------------------------
+@@1: cmp [DWORD _PM_R0_service],R0_SAVE_CR4
+ jne @@2
+
+; Save value of CR4 and clear Page Global Enable (bit 7)
+
+ mov ebx,cr4
+ mov eax,ebx
+ and al,7Fh
+ mov cr4,eax
+
+; Disable and flush caches
+
+ mov eax,cr0
+ or eax,40000000h
+ wbinvd
+ mov cr0,eax
+ wbinvd
+
+; Return value from CR4
+
+ mov [_PM_R0_reg],ebx
+ jmp @@Exit
+
+;--------------------------------------------------------
+; void _MTRR_restoreCR4(ulong cr4Val)
+;--------------------------------------------------------
+@@2: cmp [DWORD _PM_R0_service],R0_RESTORE_CR4
+ jne @@3
+
+ mov eax,cr0
+ and eax,0BFFFFFFFh
+ mov cr0,eax
+ mov eax,[_PM_R0_reg]
+ mov cr4,eax
+ jmp @@Exit
+
+;--------------------------------------------------------
+; void _MTRR_readMSR(int reg, ulong FAR *eax, ulong FAR *edx);
+;--------------------------------------------------------
+@@3: cmp [DWORD _PM_R0_service],R0_READ_MSR
+ jne @@4
+
+ mov ecx,[_PM_R0_reg]
+ rdmsr
+ mov [_PM_R0_eax],eax
+ mov [_PM_R0_edx],edx
+ jmp @@Exit
+
+;--------------------------------------------------------
+; void _MTRR_writeMSR(int reg, ulong eax, ulong edx);
+;--------------------------------------------------------
+@@4: cmp [DWORD _PM_R0_service],R0_WRITE_MSR
+ jne @@Exit
+
+ mov ecx,[_PM_R0_reg]
+ mov eax,[_PM_R0_eax]
+ mov edx,[_PM_R0_edx]
+ wrmsr
+ jmp @@Exit
+
+@@Exit: mov [DWORD _PM_R0_service],-1
+ popad
+ mov eax,0
+ retf
+
+cprocend
+
+endcodeseg _mtrrqnx
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/qnx/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/qnx/cpuinfo.c
new file mode 100644
index 0000000000..a8782542b2
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/qnx/cpuinfo.c
@@ -0,0 +1,64 @@
+/****************************************************************************
+*
+* 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: QNX
+*
+* Description: QNX specific code for the CPU detection module.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+TODO: We should implement this for QNX!
+****************************************************************************/
+#define SetMaxThreadPriority() 0
+
+/****************************************************************************
+REMARKS:
+TODO: We should implement this for QNX!
+****************************************************************************/
+#define RestoreThreadPriority(i)
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ freq->low = CLOCKS_PER_SEC * 1000;
+ freq->high = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ (t)->low = clock() * 1000; \
+ (t)->high = 0; \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/qnx/event.c b/board/MAI/bios_emulator/scitech/src/pm/qnx/event.c
new file mode 100644
index 0000000000..e16f8a5392
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/qnx/event.c
@@ -0,0 +1,602 @@
+/****************************************************************************
+*
+* 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: QNX
+*
+* Description: QNX fullscreen console implementation for the SciTech
+* cross platform event library.
+*
+****************************************************************************/
+
+#include <errno.h>
+#include <unistd.h>
+
+/*--------------------------- Global variables ----------------------------*/
+
+#ifndef __QNXNTO__
+static struct _mouse_ctrl *_PM_mouse_ctl;
+static int _PM_keyboard_fd = -1;
+//static int _PM_modifiers, _PM_leds;
+#else
+static int kbd_fd = -1, mouse_fd = -1;
+#endif
+static int kill_pid = 0;
+static ushort keyUpMsg[256] = {0};/* Table of key up messages */
+static int rangeX,rangeY; /* Range of mouse coordinates */
+
+#define TIME_TO_MSEC(__t) ((__t).tv_nsec / 1000000 + (__t).tv_sec * 1000)
+
+#define LED_NUM 1
+#define LED_CAP 2
+#define LED_SCR 4
+
+/* Scancode mappings on QNX 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]))
+
+/*---------------------------- Implementation -----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Include generic raw scancode keyboard module.
+****************************************************************************/
+#include "common/keyboard.c"
+
+/* These are not used under QNX */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flags)
+
+/****************************************************************************
+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)
+{
+ struct timespec t;
+ clock_gettime(CLOCK_REALTIME,&t);
+ return (t.tv_nsec / 1000000 + t.tv_sec * 1000);
+}
+
+/****************************************************************************
+REMARKS:
+Converts a mickey movement value to a pixel adjustment value.
+****************************************************************************/
+static int MickeyToPixel(
+ int mickey)
+{
+ // TODO: We can add some code in here to handle 'acceleration' for
+ // the mouse cursor. For now just use the mickeys.
+ return mickey;
+}
+
+#ifdef __QNXNTO__
+/****************************************************************************
+REMARKS:
+Retrieves all events from the mouse/keyboard event queue and stuffs them
+into the MGL event queue for further processing.
+****************************************************************************/
+static void _EVT_pumpMessages(void)
+{
+ int rc1, rc2;
+ struct _keyboard_packet key;
+ struct _mouse_packet ms;
+ static long old_buttons = 0;
+ uint message = 0, but_stat = 0, mods = 0;
+ event_t evt;
+
+ while (EVT.count < EVENTQSIZE) {
+ rc1 = read(kbd_fd, (void *)&key, sizeof(key));
+ if (rc1 == -1) {
+ if (errno == EAGAIN)
+ rc1 = 0;
+ else {
+ perror("getEvents");
+ PM_fatalError("Keyboard error");
+ }
+ }
+ if (rc1 > 0) {
+ memset(&evt, 0, sizeof(evt));
+ if (key.data.modifiers & KEYMOD_SHIFT)
+ mods |= EVT_LEFTSHIFT;
+ if (key.data.modifiers & KEYMOD_CTRL)
+ mods |= EVT_CTRLSTATE;
+ if (key.data.modifiers & KEYMOD_ALT)
+ mods |= EVT_ALTSTATE;
+
+ /* Now store the keyboard event data */
+ evt.when = TIME_TO_MSEC(key.time);
+ if (key.data.flags & KEY_SCAN_VALID)
+ evt.message |= (key.data.key_scan & 0x7F) << 8;
+ if ((key.data.flags & KEY_SYM_VALID) &&
+ (((key.data.key_sym & 0xff00) == 0xf000 &&
+ (key.data.key_sym & 0xff) < 0x20) ||
+ key.data.key_sym < 0x80))
+ evt.message |= (key.data.key_sym & 0xFF);
+ evt.modifiers = mods;
+ if (key.data.flags & KEY_DOWN) {
+ evt.what = EVT_KEYDOWN;
+ keyUpMsg[evt.message >> 8] = (ushort)evt.message;
+ }
+ else if (key.data.flags & KEY_REPEAT) {
+ evt.message |= 0x10000;
+ evt.what = EVT_KEYREPEAT;
+ }
+ else {
+ evt.what = EVT_KEYUP;
+ evt.message = keyUpMsg[evt.message >> 8];
+ if (evt.message == 0)
+ continue;
+ keyUpMsg[evt.message >> 8] = 0;
+ }
+
+ /* Now add the new event to the event queue */
+ addEvent(&evt);
+ }
+ rc2 = read(mouse_fd, (void *)&ms, sizeof (ms));
+ if (rc2 == -1) {
+ if (errno == EAGAIN)
+ rc2 = 0;
+ else {
+ perror("getEvents");
+ PM_fatalError("Mouse error");
+ }
+ }
+ if (rc2 > 0) {
+ memset(&evt, 0, sizeof(evt));
+ ms.hdr.buttons &=
+ (_POINTER_BUTTON_LEFT | _POINTER_BUTTON_RIGHT);
+ if (ms.hdr.buttons & _POINTER_BUTTON_LEFT)
+ but_stat = EVT_LEFTBUT;
+ if ((ms.hdr.buttons & _POINTER_BUTTON_LEFT) !=
+ (old_buttons & _POINTER_BUTTON_LEFT))
+ message = EVT_LEFTBMASK;
+ if (ms.hdr.buttons & _POINTER_BUTTON_RIGHT)
+ but_stat |= EVT_RIGHTBUT;
+ if ((ms.hdr.buttons & _POINTER_BUTTON_RIGHT) !=
+ (old_buttons & _POINTER_BUTTON_RIGHT))
+ message |= EVT_RIGHTBMASK;
+ if (ms.dx || ms.dy) {
+ ms.dy = -ms.dy;
+ EVT.mx += MickeyToPixel(ms.dx);
+ EVT.my += MickeyToPixel(ms.dy);
+ if (EVT.mx < 0) EVT.mx = 0;
+ if (EVT.my < 0) EVT.my = 0;
+ if (EVT.mx > rangeX) EVT.mx = rangeX;
+ if (EVT.my > rangeY) EVT.my = rangeY;
+ evt.what = EVT_MOUSEMOVE;
+ evt.when = TIME_TO_MSEC(ms.hdr.time);
+ evt.where_x = EVT.mx;
+ evt.where_y = EVT.my;
+ evt.relative_x = ms.dx;
+ evt.relative_y = ms.dy;
+ evt.modifiers = but_stat;
+ addEvent(&evt);
+ }
+ evt.what = ms.hdr.buttons < old_buttons ?
+ EVT_MOUSEUP : EVT_MOUSEDOWN;
+ evt.when = TIME_TO_MSEC(ms.hdr.time);
+ evt.where_x = EVT.mx;
+ evt.where_y = EVT.my;
+ evt.relative_x = ms.dx;
+ evt.relative_y = ms.dy;
+ evt.modifiers = but_stat;
+ evt.message = message;
+ if (ms.hdr.buttons != old_buttons) {
+ addEvent(&evt);
+ old_buttons = ms.hdr.buttons;
+ }
+ }
+ if (rc1 + rc2 == 0)
+ break;
+ }
+}
+#else
+/****************************************************************************
+REMARKS:
+Retrieves all events from the mouse/keyboard event queue and stuffs them
+into the MGL event queue for further processing.
+****************************************************************************/
+static void _EVT_pumpMessages(void)
+{
+ struct mouse_event ev;
+ int rc;
+ static long old_buttons = 0;
+ uint message = 0, but_stat = 0;
+ event_t evt;
+ char buf[32];
+ int numkeys, i;
+
+ /* Poll keyboard events */
+ while ((numkeys = read(_PM_keyboard_fd, buf, sizeof buf)) > 0) {
+ for (i = 0; i < numkeys; i++) {
+ processRawScanCode(buf[i]);
+ }
+ }
+
+ if (_PM_mouse_ctl == NULL)
+ return;
+
+ /* Gobble pending mouse events */
+ while (EVT.count < EVENTQSIZE) {
+ rc = mouse_read(_PM_mouse_ctl, &ev, 1, 0, NULL);
+ if (rc == -1) {
+ perror("getEvents");
+ PM_fatalError("Mouse error (Input terminated?)");
+ }
+ if (rc == 0)
+ break;
+
+ message = 0, but_stat = 0;
+ memset(&evt, 0, sizeof(evt));
+
+ ev.buttons &= (_MOUSE_LEFT | _MOUSE_RIGHT);
+ if (ev.buttons & _MOUSE_LEFT)
+ but_stat = EVT_LEFTBUT;
+ if ((ev.buttons & _MOUSE_LEFT) != (old_buttons & _MOUSE_LEFT))
+ message = EVT_LEFTBMASK;
+ if (ev.buttons & _MOUSE_RIGHT)
+ but_stat |= EVT_RIGHTBUT;
+ if ((ev.buttons & _MOUSE_RIGHT) != (old_buttons & _MOUSE_RIGHT))
+ message |= EVT_RIGHTBMASK;
+ if (ev.dx || ev.dy) {
+ ev.dy = -ev.dy;
+ EVT.mx += MickeyToPixel(ev.dx);
+ EVT.my += MickeyToPixel(ev.dy);
+ if (EVT.mx < 0) EVT.mx = 0;
+ if (EVT.my < 0) EVT.my = 0;
+ if (EVT.mx > rangeX) EVT.mx = rangeX;
+ if (EVT.my > rangeY) EVT.my = rangeY;
+ evt.what = EVT_MOUSEMOVE;
+ evt.when = ev.timestamp*100;
+ evt.where_x = EVT.mx;
+ evt.where_y = EVT.my;
+ evt.relative_x = ev.dx;
+ evt.relative_y = ev.dy;
+ evt.modifiers = but_stat;
+ addEvent(&evt);
+ }
+ evt.what = ev.buttons < old_buttons ? EVT_MOUSEUP : EVT_MOUSEDOWN;
+ evt.when = ev.timestamp*100;
+ evt.where_x = EVT.mx;
+ evt.where_y = EVT.my;
+ evt.relative_x = ev.dx;
+ evt.relative_y = ev.dy;
+ evt.modifiers = but_stat;
+ evt.message = message;
+ if (ev.buttons != old_buttons) {
+ addEvent(&evt);
+ old_buttons = ev.buttons;
+ }
+ }
+}
+#endif /* __QNXNTO__ */
+
+/****************************************************************************
+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 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:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort(
+ int signo)
+{
+ char buf[80];
+
+ EVT_exit();
+ sprintf(buf,"Terminating on signal %d",signo);
+ PM_fatalError(buf);
+}
+
+/****************************************************************************
+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;
+ struct stat st;
+ char *iarg[16];
+#ifdef __QNXNTO__
+ char buf[128];
+ FILE *p;
+ int argno,len;
+#endif
+
+#ifdef __QNXNTO__
+ ThreadCtl(_NTO_TCTL_IO, 0); /* So joystick code won't blow up */
+#endif
+
+ /* Initialise the event queue */
+ EVT.mouseMove = mouseMove;
+ initEventQueue();
+ memset(keyUpMsg,0,sizeof(keyUpMsg));
+
+#ifdef __QNXNTO__
+ /*
+ * User may already have input running with the right parameters.
+ * Thus they could start input at boot time, using the output of
+ * inputtrap, passing the the -r flag to make it run as a resource
+ * manager.
+ */
+ if ((mouse_fd = open("/dev/mouse0", O_RDONLY | O_NONBLOCK)) < 0) {
+ /* Run inputtrap to get the args for input */
+ if ((p = popen("inputtrap", "r")) == NULL)
+ PM_fatalError("Error running 'inputtrap'");
+ fgets(buf, sizeof(buf), p);
+ pclose(p);
+
+ /* Build the argument list */
+ len = strlen(buf);
+ iarg[0] = buf;
+ for (i = 0, argno = 0; i < len && argno < 15;) {
+ if (argno == 1) {
+ /*
+ * Add flags to input's arg list.
+ * '-r' means run as resource
+ * manager, providing the /dev/mouse
+ * and /dev/keyboard interfaces.
+ * '-P' supresses the /dev/photon
+ * mechanism.
+ */
+ iarg[argno++] = "-Pr";
+ continue;
+ }
+ while (buf[i] == ' ')
+ i++;
+ if (buf[i] == '\0' || buf[i] == '\n')
+ break;
+ iarg[argno++] = &buf[i];
+ while (buf[i] != ' '
+ && buf[i] != '\0' && buf[i] != '\n')
+ i++;
+ buf[i++] = '\0';
+ }
+ iarg[argno] = NULL;
+
+ if ((kill_pid = spawnvp(P_NOWAITO, iarg[0], iarg)) == -1) {
+ perror("spawning input resmgr");
+ PM_fatalError("Could not start input resmgr");
+ }
+ for (i = 0; i < 10; i++) {
+ if (stat("/dev/mouse0", &st) == 0)
+ break;
+ sleep(1);
+ }
+ if ((mouse_fd = open("/dev/mouse0", O_RDONLY|O_NONBLOCK)) < 0) {
+ perror("/dev/mouse0");
+ PM_fatalError("Could not open /dev/mouse0");
+ }
+ }
+ if ((kbd_fd = open("/dev/keyboard0", O_RDONLY|O_NONBLOCK)) < 0) {
+ perror("/dev/keyboard0");
+ PM_fatalError("Could not open /dev/keyboard0");
+ }
+#else
+ /* Connect to Input/Mouse for event handling */
+ if (_PM_mouse_ctl == NULL) {
+ _PM_mouse_ctl = mouse_open(0, "/dev/mouse", 0);
+
+ /* "Mouse" is not running; attempt to start it */
+ if (_PM_mouse_ctl == NULL) {
+ iarg[0] = "mousetrap";
+ iarg[1] = "start";
+ iarg[2] = NULL;
+ if ((kill_pid = spawnvp(P_NOWAITO, iarg[0], (void*)iarg)) == -1)
+ perror("spawn (mousetrap)");
+ else {
+ for (i = 0; i < 10; i++) {
+ if (stat("/dev/mouse", &st) == 0)
+ break;
+ sleep(1);
+ }
+ _PM_mouse_ctl = mouse_open(0, "/dev/mouse", 0);
+ }
+ }
+ }
+ if (_PM_keyboard_fd == -1)
+ _PM_keyboard_fd = open("/dev/kbd", O_RDONLY|O_NONBLOCK);
+#endif
+
+ /* Catch program termination signals so we can clean up properly */
+ signal(SIGABRT, _EVT_abort);
+ signal(SIGFPE, _EVT_abort);
+ signal(SIGINT, _EVT_abort);
+}
+
+/****************************************************************************
+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)
+{
+ rangeX = xRes;
+ rangeY = 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 QNX
+}
+
+/****************************************************************************
+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 QNX
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+#ifdef __QNXNTO__
+ char c;
+ int flags;
+
+ if (kbd_fd != -1) {
+ close(kbd_fd);
+ kbd_fd = -1;
+ }
+ if (mouse_fd != -1) {
+ close(mouse_fd);
+ mouse_fd = -1;
+ }
+#endif
+
+ /* Restore signal handlers */
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+
+#ifndef __QNXNTO__
+ /* Kill the Input/Mouse driver if we have spawned it */
+ if (_PM_mouse_ctl != NULL) {
+ struct _fd_entry fde;
+ uint pid = 0;
+
+ /* Find out the pid of the mouse driver */
+ if (kill_pid > 0) {
+ if (qnx_fd_query(0,
+ 0, _PM_mouse_ctl->fd, &fde) != -1)
+ pid = fde.pid;
+ }
+ mouse_close(_PM_mouse_ctl);
+ _PM_mouse_ctl = NULL;
+
+ if (pid > 0) {
+ /* For some reasons the PID's are different under QNX4,
+ * so we use the old mechanism to kill the mouse server.
+ */
+ kill(pid, SIGTERM);
+ kill_pid = 0;
+ }
+ }
+#endif
+ if (kill_pid > 0) {
+ kill(kill_pid, SIGTERM);
+ kill_pid = 0;
+ }
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/qnx/mtrrqnx.c b/board/MAI/bios_emulator/scitech/src/pm/qnx/mtrrqnx.c
new file mode 100644
index 0000000000..de749e3834
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/qnx/mtrrqnx.c
@@ -0,0 +1,182 @@
+/****************************************************************************
+*
+* 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: QNX
+*
+* Description: MTRR helper functions module. To make it easier to implement
+* the MTRR support under QNX, we simply put our ring 0 helper
+* functions into stubs that run them at ring 0 using whatever
+* mechanism is available.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include <stdio.h>
+#include <sys/mman.h>
+#include <time.h>
+#ifdef __QNXNTO__
+#include <sys/neutrino.h>
+#include <sys/syspage.h>
+#else
+#include <i86.h>
+#include <sys/irqinfo.h>
+#endif
+
+/*--------------------------- Global variables ----------------------------*/
+
+#define R0_FLUSH_TLB 0
+#define R0_SAVE_CR4 1
+#define R0_RESTORE_CR4 2
+#define R0_READ_MSR 3
+#define R0_WRITE_MSR 4
+
+typedef struct {
+ int service;
+ int reg;
+ ulong eax;
+ ulong edx;
+ } R0_data;
+
+extern volatile R0_data _PM_R0;
+
+/*----------------------------- Implementation ----------------------------*/
+
+#ifdef __QNXNTO__
+const struct sigevent * _ASMAPI _PM_ring0_isr(void *arg, int id);
+#else
+pid_t far _ASMAPI _PM_ring0_isr();
+#endif
+
+/****************************************************************************
+REMARKS:
+Return true if ring 0 (or if we can call the helpers functions at ring 0)
+****************************************************************************/
+ibool _ASMAPI _MTRR_isRing0(void)
+{
+#ifdef __QNXNTO__
+ return false; // Not implemented yet!
+#else
+ return true;
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Function to execute a service at ring 0. This is done using the clock
+interrupt handler since the code we attach to it will always run at ring 0.
+****************************************************************************/
+static void CallRing0(void)
+{
+#ifdef __QNXNTO__
+ uint clock_intno = SYSPAGE_ENTRY(qtime)->intr;
+#else
+ uint clock_intno = 0; /* clock irq */
+#endif
+ int intrid;
+
+#ifdef __QNXNTO__
+ mlock((void*)&_PM_R0, sizeof(_PM_R0));
+ ThreadCtl(_NTO_TCTL_IO, 0);
+#endif
+#ifdef __QNXNTO__
+ if ((intrid = InterruptAttach(_NTO_INTR_CLASS_EXTERNAL | clock_intno,
+ _PM_ring0_isr, (void*)&_PM_R0, sizeof(_PM_R0), _NTO_INTR_FLAGS_END)) == -1) {
+#else
+ if ((intrid = qnx_hint_attach(clock_intno, _PM_ring0_isr, FP_SEG(&_PM_R0))) == -1) {
+#endif
+ perror("Attach");
+ exit(-1);
+ }
+ while (_PM_R0.service != -1)
+ ;
+#ifdef __QNXNTO__
+ InterruptDetachId(intrid);
+#else
+ qnx_hint_detach(intrid);
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Flush the translation lookaside buffer.
+****************************************************************************/
+void PMAPI PM_flushTLB(void)
+{
+ _PM_R0.service = R0_FLUSH_TLB;
+ CallRing0();
+}
+
+/****************************************************************************
+REMARKS:
+Read and return the value of the CR4 register
+****************************************************************************/
+ulong _ASMAPI _MTRR_saveCR4(void)
+{
+ _PM_R0.service = R0_SAVE_CR4;
+ CallRing0();
+ return _PM_R0.reg;
+}
+
+/****************************************************************************
+REMARKS:
+Restore the value of the CR4 register
+****************************************************************************/
+void _ASMAPI _MTRR_restoreCR4(ulong cr4Val)
+{
+ _PM_R0.service = R0_RESTORE_CR4;
+ _PM_R0.reg = cr4Val;
+ CallRing0();
+}
+
+/****************************************************************************
+REMARKS:
+Read a machine status register for the CPU.
+****************************************************************************/
+void _ASMAPI _MTRR_readMSR(
+ int reg,
+ ulong *eax,
+ ulong *edx)
+{
+ _PM_R0.service = R0_READ_MSR;
+ _PM_R0.reg = reg;
+ CallRing0();
+ *eax = _PM_R0.eax;
+ *edx = _PM_R0.edx;
+}
+
+/****************************************************************************
+REMARKS:
+Write a machine status register for the CPU.
+****************************************************************************/
+void _ASMAPI _MTRR_writeMSR(
+ int reg,
+ ulong eax,
+ ulong edx)
+{
+ _PM_R0.service = R0_WRITE_MSR;
+ _PM_R0.reg = reg;
+ _PM_R0.eax = eax;
+ _PM_R0.edx = edx;
+ CallRing0();
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/qnx/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/qnx/oshdr.h
new file mode 100644
index 0000000000..0961193049
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/qnx/oshdr.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+*
+* 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: QNX
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <process.h>
+#include <time.h>
+#ifndef __QNXNTO__
+#include <sys/mouse.h>
+#include <sys/keyboard.h>
+#include <sys/fd.h>
+#include <conio.h>
+#else
+#include <sys/dcmd_input.h>
+
+/* Things 'borrowed' from photon/keycodes.h */
+
+/*
+ * Keyboard modifiers
+ */
+#define KEYMODBIT_SHIFT 0
+#define KEYMODBIT_CTRL 1
+#define KEYMODBIT_ALT 2
+#define KEYMODBIT_ALTGR 3
+#define KEYMODBIT_SHL3 4
+#define KEYMODBIT_MOD6 5
+#define KEYMODBIT_MOD7 6
+#define KEYMODBIT_MOD8 7
+
+#define KEYMODBIT_SHIFT_LOCK 8
+#define KEYMODBIT_CTRL_LOCK 9
+#define KEYMODBIT_ALT_LOCK 10
+#define KEYMODBIT_ALTGR_LOCK 11
+#define KEYMODBIT_SHL3_LOCK 12
+#define KEYMODBIT_MOD6_LOCK 13
+#define KEYMODBIT_MOD7_LOCK 14
+#define KEYMODBIT_MOD8_LOCK 15
+
+#define KEYMODBIT_CAPS_LOCK 16
+#define KEYMODBIT_NUM_LOCK 17
+#define KEYMODBIT_SCROLL_LOCK 18
+
+#define KEYMOD_SHIFT (1 << KEYMODBIT_SHIFT)
+#define KEYMOD_CTRL (1 << KEYMODBIT_CTRL)
+#define KEYMOD_ALT (1 << KEYMODBIT_ALT)
+#define KEYMOD_ALTGR (1 << KEYMODBIT_ALTGR)
+#define KEYMOD_SHL3 (1 << KEYMODBIT_SHL3)
+#define KEYMOD_MOD6 (1 << KEYMODBIT_MOD6)
+#define KEYMOD_MOD7 (1 << KEYMODBIT_MOD7)
+#define KEYMOD_MOD8 (1 << KEYMODBIT_MOD8)
+
+#define KEYMOD_SHIFT_LOCK (1 << KEYMODBIT_SHIFT_LOCK)
+#define KEYMOD_CTRL_LOCK (1 << KEYMODBIT_CTRL_LOCK)
+#define KEYMOD_ALT_LOCK (1 << KEYMODBIT_ALT_LOCK)
+#define KEYMOD_ALTGR_LOCK (1 << KEYMODBIT_ALTGR_LOCK)
+#define KEYMOD_SHL3_LOCK (1 << KEYMODBIT_SHL3_LOCK)
+#define KEYMOD_MOD6_LOCK (1 << KEYMODBIT_MOD6_LOCK)
+#define KEYMOD_MOD7_LOCK (1 << KEYMODBIT_MOD7_LOCK)
+#define KEYMOD_MOD8_LOCK (1 << KEYMODBIT_MOD8_LOCK)
+
+#define KEYMOD_CAPS_LOCK (1 << KEYMODBIT_CAPS_LOCK)
+#define KEYMOD_NUM_LOCK (1 << KEYMODBIT_NUM_LOCK)
+#define KEYMOD_SCROLL_LOCK (1 << KEYMODBIT_SCROLL_LOCK)
+
+/*
+ * Keyboard flags
+ */
+#define KEY_DOWN 0x00000001 /* Key was pressed down */
+#define KEY_REPEAT 0x00000002 /* Key was repeated */
+#define KEY_SCAN_VALID 0x00000020 /* Scancode is valid */
+#define KEY_SYM_VALID 0x00000040 /* Key symbol is valid */
+#define KEY_CAP_VALID 0x00000080 /* Key cap is valid */
+#define KEY_DEAD 0x40000000 /* Key symbol is a DEAD key */
+#define KEY_OEM_CAP 0x80000000 /* Key cap is an OEM scan code from keyboard */
+
+#endif /* __QNXNTO__ */
diff --git a/board/MAI/bios_emulator/scitech/src/pm/qnx/pm.c b/board/MAI/bios_emulator/scitech/src/pm/qnx/pm.c
new file mode 100644
index 0000000000..c2b41eb09f
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/qnx/pm.c
@@ -0,0 +1,891 @@
+/****************************************************************************
+*
+* 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: QNX
+*
+* 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 "mtrr.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <sys/mman.h>
+#include "qnx/vbios.h"
+#ifndef __QNXNTO__
+#include <sys/seginfo.h>
+#include <sys/console.h>
+#include <conio.h>
+#include <i86.h>
+#else
+#include <sys/neutrino.h>
+#include <sys/dcmd_chr.h>
+#endif
+
+/*--------------------------- Global variables ----------------------------*/
+
+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 */
+static VBIOSregs_t *VRegs = NULL; /* Pointer to VBIOS registers */
+static int raw_count = 0;
+static struct _console_ctrl *cc = NULL;
+static int console_count = 0;
+static int rmbuf_inuse = 0;
+
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+void PMAPI PM_init(void)
+{
+ char *force;
+
+ if (VRegs == NULL) {
+#ifdef __QNXNTO__
+ ThreadCtl(_NTO_TCTL_IO, 0); /* Get IO privilidge */
+#endif
+ force = getenv("VBIOS_METHOD");
+ VRegs = VBIOSinit(force ? atoi(force) : 0);
+ }
+#ifndef __QNXNTO__
+ MTRR_init();
+#endif
+}
+
+ibool PMAPI PM_haveBIOSAccess(void)
+{ return VRegs != NULL; }
+
+long PMAPI PM_getOSType(void)
+{ return _OS_QNX; }
+
+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);
+ 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;
+}
+
+static int term_raw(void)
+{
+ struct termios termios_p;
+
+ if (raw_count++ > 0)
+ return 0;
+
+ /* Go into "raw" input mode */
+ if (tcgetattr(STDIN_FILENO, &termios_p))
+ return -1;
+
+ termios_p.c_cc[VMIN] = 1;
+ termios_p.c_cc[VTIME] = 0;
+ termios_p.c_lflag &= ~( ECHO|ICANON|ISIG|ECHOE|ECHOK|ECHONL);
+ tcsetattr(STDIN_FILENO, TCSADRAIN, &termios_p);
+ return 0;
+}
+
+static void term_restore(void)
+{
+ struct termios termios_p;
+
+ if (raw_count-- != 1)
+ return;
+
+ tcgetattr(STDIN_FILENO, &termios_p);
+ termios_p.c_lflag |= (ECHO|ICANON|ISIG|ECHOE|ECHOK|ECHONL);
+ termios_p.c_oflag |= (OPOST);
+ tcsetattr(STDIN_FILENO, TCSADRAIN, &termios_p);
+}
+
+int PMAPI PM_kbhit(void)
+{
+ int blocking, c;
+
+ if (term_raw() == -1)
+ return 0;
+
+ /* Go into non blocking mode */
+ blocking = fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK;
+ fcntl(STDIN_FILENO, F_SETFL, blocking);
+ c = getc(stdin);
+
+ /* restore blocking mode */
+ fcntl(STDIN_FILENO, F_SETFL, blocking & ~O_NONBLOCK);
+ term_restore();
+ if (c != EOF) {
+ ungetc(c, stdin);
+ return c;
+ }
+ clearerr(stdin);
+ return 0;
+}
+
+int PMAPI PM_getch(void)
+{
+ int c;
+
+ if (term_raw() == -1)
+ return (0);
+ c = getc(stdin);
+#if defined(__QNX__) && !defined(__QNXNTO__)
+ if (c == 0xA)
+ c = 0x0D;
+ else if (c == 0x7F)
+ c = 0x08;
+#endif
+ term_restore();
+ return c;
+}
+
+PM_HWND PMAPI PM_openConsole(
+ PM_HWND hwndUser,
+ int device,
+ int xRes,
+ int yRes,
+ int bpp,
+ ibool fullScreen)
+{
+#ifndef __QNXNTO__
+ int fd;
+
+ if (console_count++)
+ return 0;
+ if ((fd = open("/dev/con1", O_RDWR)) == -1)
+ return -1;
+ cc = console_open(fd, O_RDWR);
+ close(fd);
+ if (cc == NULL)
+ return -1;
+#endif
+ return 1;
+}
+
+int PMAPI PM_getConsoleStateSize(void)
+{
+ return PM_getVGAStateSize() + sizeof(int) * 3;
+}
+
+void PMAPI PM_saveConsoleState(void *stateBuf,int console_id)
+{
+#ifdef __QNXNTO__
+ int fd;
+ int flags;
+
+ if ((fd = open("/dev/con1", O_RDWR)) == -1)
+ return;
+ flags = _CONCTL_INVISIBLE_CHG | _CONCTL_INVISIBLE;
+ devctl(fd, DCMD_CHR_SERCTL, &flags, sizeof flags, 0);
+ close(fd);
+#else
+ uchar *buf = &((uchar*)stateBuf)[PM_getVGAStateSize()];
+
+ /* Save QNX 4 console state */
+ console_read(cc, -1, 0, NULL, 0,
+ (int *)buf+1, (int *)buf+2, NULL);
+ *(int *)buf = console_ctrl(cc, -1,
+ CONSOLE_NORESIZE | CONSOLE_NOSWITCH | CONSOLE_INVISIBLE,
+ CONSOLE_NORESIZE | CONSOLE_NOSWITCH | CONSOLE_INVISIBLE);
+
+ /* Save state of VGA registers */
+ PM_saveVGAState(stateBuf);
+#endif
+}
+
+void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
+{
+ /* TODO: Implement support for console switching if possible */
+}
+
+void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND hwndConsole)
+{
+#ifdef __QNXNTO__
+ int fd;
+ int flags;
+
+ if ((fd = open("/dev/con1", O_RDWR)) == -1)
+ return;
+ flags = _CONCTL_INVISIBLE_CHG;
+ devctl(fd, DCMD_CHR_SERCTL, &flags, sizeof flags, 0);
+ close(fd);
+#else
+ uchar *buf = &((uchar*)stateBuf)[PM_getVGAStateSize()];
+
+ /* Restore the state of the VGA compatible registers */
+ PM_restoreVGAState(stateBuf);
+
+ /* Restore QNX 4 console state */
+ console_ctrl(cc, -1, *(int *)buf,
+ CONSOLE_NORESIZE | CONSOLE_NOSWITCH | CONSOLE_INVISIBLE);
+ console_write(cc, -1, 0, NULL, 0,
+ (int *)buf+1, (int *)buf+2, NULL);
+#endif
+}
+
+void PMAPI PM_closeConsole(PM_HWND hwndConsole)
+{
+#ifndef __QNXNTO__
+ if (--console_count == 0) {
+ console_close(cc);
+ cc = NULL;
+ }
+#endif
+}
+
+void PM_setOSCursorLocation(int x,int y)
+{
+ if (!cc)
+ return;
+#ifndef __QNXNTO__
+ console_write(cc, -1, 0, NULL, 0, &y, &x, NULL);
+#endif
+}
+
+void PM_setOSScreenWidth(int width,int height)
+{
+}
+
+ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler ih, int frequency)
+{
+ // TODO: Implement this for QNX
+ return false;
+}
+
+void PMAPI PM_setRealTimeClockFrequency(int frequency)
+{
+ // TODO: Implement this for QNX
+}
+
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ // TODO: Implement this for QNX
+}
+
+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");
+#ifdef __QNXNTO__
+#ifdef __X86__
+ return env ? env : "/nto/scitech/x86/bin";
+#elif defined (__PPC__)
+ return env ? env : "/nto/scitech/ppcbe/bin";
+#elif defined (__MIPS__)
+#ifdef __BIGENDIAN__
+ return env ? env : "/nto/scitech/mipsbe/bin";
+#else
+ return env ? env : "/nto/scitech/mipsle/bin";
+#endif
+#elif defined (__SH__)
+#ifdef __BIGENDIAN__
+ return env ? env : "/nto/scitech/shbe/bin";
+#else
+ return env ? env : "/nto/scitech/shle/bin";
+#endif
+#elif defined (__ARM__)
+ return env ? env : "/nto/scitech/armle/bin";
+#endif
+#else /* QNX 4 */
+ return env ? env : "/qnx4/scitech/bin";
+#endif
+}
+
+const char * PMAPI PM_getNucleusConfigPath(void)
+{
+ static char path[512];
+ char *env;
+#ifdef __QNXNTO__
+ char temp[64];
+ gethostname(temp, sizeof (temp));
+ temp[sizeof (temp) - 1] = '\0'; /* Paranoid */
+ sprintf(path,"/etc/config/scitech/%s/config", temp);
+#else
+ sprintf(path,"/etc/config/scitech/%d/config", getnid());
+#endif
+ if ((env = getenv("NUCLEUS_PATH")) != NULL) {
+ strcpy(path,env);
+ PM_backslash(path);
+ strcat(path,"config");
+ }
+ return path;
+}
+
+const char * PMAPI PM_getUniqueID(void)
+{
+ static char buf[128];
+#ifdef __QNXNTO__
+ gethostname(buf, sizeof (buf));
+#else
+ sprintf(buf,"node%d", getnid());
+#endif
+ return buf;
+}
+
+const char * PMAPI PM_getMachineName(void)
+{
+ static char buf[128];
+#ifdef __QNXNTO__
+ gethostname(buf, sizeof (buf));
+#else
+ sprintf(buf,"node%d", getnid());
+#endif
+ return buf;
+}
+
+void * PMAPI PM_getBIOSPointer(void)
+{
+ return PM_mapRealPointer(0, 0x400);
+}
+
+void * PMAPI PM_getA0000Pointer(void)
+{
+ static void *ptr = NULL;
+ void *freeptr;
+ unsigned offset, i, maplen;
+
+ if (ptr != NULL)
+ return ptr;
+
+ /* Some trickery is required to get the linear address 64K aligned */
+ for (i = 0; i < 5; i++) {
+ ptr = PM_mapPhysicalAddr(0xA0000,0xFFFF,true);
+ offset = 0x10000 - ((unsigned)ptr % 0x10000);
+ if (!offset)
+ break;
+ munmap(ptr, 0x10000);
+ maplen = 0x10000 + offset;
+ freeptr = PM_mapPhysicalAddr(0xA0000-offset, maplen-1,true);
+ ptr = (void *)(offset + (unsigned)freeptr);
+ if (0x10000 - ((unsigned)ptr % 0x10000))
+ break;
+ munmap(freeptr, maplen);
+ }
+ if (i == 5) {
+ printf("Could not get a 64K aligned linear address for A0000 region\n");
+ exit(1);
+ }
+ return ptr;
+}
+
+void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{
+ uchar_t *p;
+ unsigned o;
+ unsigned prot = PROT_READ|PROT_WRITE|(isCached?0:PROT_NOCACHE);
+#ifdef __PAGESIZE
+ int pagesize = __PAGESIZE;
+#else
+ int pagesize = 4096;
+#endif
+ int rounddown = base % pagesize;
+#ifndef __QNXNTO__
+ static int __VidFD = -1;
+#endif
+
+ if (rounddown) {
+ if (base < rounddown)
+ return NULL;
+ base -= rounddown;
+ limit += rounddown;
+ }
+
+#ifndef __QNXNTO__
+ if (__VidFD < 0) {
+ if ((__VidFD = shm_open( "Physical", O_RDWR, 0777 )) == -1) {
+ perror( "Cannot open Physical memory" );
+ exit(1);
+ }
+ }
+ o = base & 0xFFF;
+ limit = (limit + o + 0xFFF) & ~0xFFF;
+ if ((int)(p = mmap( 0, limit, prot, MAP_SHARED,
+ __VidFD, base )) == -1 ) {
+ return NULL;
+ }
+ p += o;
+#else
+ if ((p = mmap(0, limit, prot, MAP_PHYS | MAP_SHARED,
+ NOFD, base)) == MAP_FAILED) {
+ return (void *)-1;
+ }
+#endif
+ return (p + rounddown);
+}
+
+void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
+{
+ 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: Implement this!
+ 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)
+{
+ void *p;
+
+ PM_init();
+
+ if ((p = VBIOSgetmemptr(r_seg, r_off, VRegs)) == (void *)-1)
+ return NULL;
+ return p;
+}
+
+void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
+{
+ if (size > 1024) {
+ printf("PM_allocRealSeg: can't handle %d bytes\n", size);
+ return 0;
+ }
+ if (rmbuf_inuse != 0) {
+ printf("PM_allocRealSeg: transfer area already in use\n");
+ return 0;
+ }
+ PM_init();
+ rmbuf_inuse = 1;
+ *r_seg = VBIOS_TransBufVSeg(VRegs);
+ *r_off = VBIOS_TransBufVOff(VRegs);
+ return (void*)VBIOS_TransBufPtr(VRegs);
+}
+
+void PMAPI PM_freeRealSeg(void *mem)
+{
+ if (rmbuf_inuse == 0) {
+ printf("PM_freeRealSeg: nothing was allocated\n");
+ return;
+ }
+ rmbuf_inuse = 0;
+}
+
+void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
+{
+ PM_init();
+ if (VRegs == NULL)
+ return;
+
+ VRegs->l.eax = regs->eax;
+ VRegs->l.ebx = regs->ebx;
+ VRegs->l.ecx = regs->ecx;
+ VRegs->l.edx = regs->edx;
+ VRegs->l.esi = regs->esi;
+ VRegs->l.edi = regs->edi;
+
+ VBIOSint(intno, VRegs, 1024);
+
+ regs->eax = VRegs->l.eax;
+ regs->ebx = VRegs->l.ebx;
+ regs->ecx = VRegs->l.ecx;
+ regs->edx = VRegs->l.edx;
+ regs->esi = VRegs->l.esi;
+ regs->edi = VRegs->l.edi;
+ regs->flags = VRegs->w.flags & 0x1;
+}
+
+int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
+{
+ PM_init();
+ if (VRegs == NULL)
+ return 0;
+
+ VRegs->l.eax = in->e.eax;
+ VRegs->l.ebx = in->e.ebx;
+ VRegs->l.ecx = in->e.ecx;
+ VRegs->l.edx = in->e.edx;
+ VRegs->l.esi = in->e.esi;
+ VRegs->l.edi = in->e.edi;
+
+ VBIOSint(intno, VRegs, 1024);
+
+ out->e.eax = VRegs->l.eax;
+ out->e.ebx = VRegs->l.ebx;
+ out->e.ecx = VRegs->l.ecx;
+ out->e.edx = VRegs->l.edx;
+ out->e.esi = VRegs->l.esi;
+ out->e.edi = VRegs->l.edi;
+ out->x.cflag = VRegs->w.flags & 0x1;
+
+ return out->x.ax;
+}
+
+int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
+ RMSREGS *sregs)
+{
+ PM_init();
+ if (VRegs == NULL)
+ return 0;
+
+ 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;
+ return 0;
+ }
+ else {
+ VRegs->l.eax = in->e.eax;
+ VRegs->l.ebx = in->e.ebx;
+ VRegs->l.ecx = in->e.ecx;
+ VRegs->l.edx = in->e.edx;
+ VRegs->l.esi = in->e.esi;
+ VRegs->l.edi = in->e.edi;
+ VRegs->w.es = sregs->es;
+ VRegs->w.ds = sregs->ds;
+
+ VBIOSint(intno, VRegs, 1024);
+
+ out->e.eax = VRegs->l.eax;
+ out->e.ebx = VRegs->l.ebx;
+ out->e.ecx = VRegs->l.ecx;
+ out->e.edx = VRegs->l.edx;
+ out->e.esi = VRegs->l.esi;
+ out->e.edi = VRegs->l.edi;
+ out->x.cflag = VRegs->w.flags & 0x1;
+ sregs->es = VRegs->w.es;
+ sregs->ds = VRegs->w.ds;
+
+ return out->x.ax;
+ }
+}
+
+void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
+ RMSREGS *sregs)
+{
+ PM_init();
+ if (VRegs == NULL)
+ return;
+
+ VRegs->l.eax = in->e.eax;
+ VRegs->l.ebx = in->e.ebx;
+ VRegs->l.ecx = in->e.ecx;
+ VRegs->l.edx = in->e.edx;
+ VRegs->l.esi = in->e.esi;
+ VRegs->l.edi = in->e.edi;
+ VRegs->w.es = sregs->es;
+ VRegs->w.ds = sregs->ds;
+
+ VBIOScall(seg, off, VRegs, 1024);
+
+ in->e.eax = VRegs->l.eax;
+ in->e.ebx = VRegs->l.ebx;
+ in->e.ecx = VRegs->l.ecx;
+ in->e.edx = VRegs->l.edx;
+ in->e.esi = VRegs->l.esi;
+ in->e.edi = VRegs->l.edi;
+ in->x.cflag = VRegs->w.flags & 0x1;
+ sregs->es = VRegs->w.es;
+ sregs->ds = VRegs->w.ds;
+}
+
+void PMAPI PM_availableMemory(ulong *physical,ulong *total)
+{
+#ifndef __QNXNTO__
+ *physical = *total = _memavl();
+#endif
+}
+
+void * PMAPI PM_allocLockedMem(
+ uint size,
+ ulong *physAddr,
+ ibool contiguous,
+ ibool below16M)
+{
+ // TODO: Implement this on QNX
+ return NULL;
+}
+
+void PMAPI PM_freeLockedMem(
+ void *p,
+ uint size,
+ ibool contiguous)
+{
+ // TODO: Implement this on QNX
+}
+
+void * PMAPI PM_allocPage(
+ ibool locked)
+{
+ // TODO: Implement this on QNX
+ return NULL;
+}
+
+void PMAPI PM_freePage(
+ void *p)
+{
+ // TODO: Implement this on QNX
+}
+
+void PMAPI PM_setBankA(int bank)
+{
+ PM_init();
+ if (VRegs == NULL)
+ return;
+
+ VRegs->l.eax = 0x4F05;
+ VRegs->l.ebx = 0x0000;
+ VRegs->l.edx = bank;
+ VBIOSint(0x10, VRegs, 1024);
+}
+
+void PMAPI PM_setBankAB(int bank)
+{
+ PM_init();
+ if (VRegs == NULL)
+ return;
+
+ VRegs->l.eax = 0x4F05;
+ VRegs->l.ebx = 0x0000;
+ VRegs->l.edx = bank;
+ VBIOSint(0x10, VRegs, 1024);
+
+ VRegs->l.eax = 0x4F05;
+ VRegs->l.ebx = 0x0001;
+ VRegs->l.edx = bank;
+ VBIOSint(0x10, VRegs, 1024);
+}
+
+void PMAPI PM_setCRTStart(int x,int y,int waitVRT)
+{
+ PM_init();
+ if (VRegs == NULL)
+ return;
+
+ VRegs->l.eax = 0x4F07;
+ VRegs->l.ebx = waitVRT;
+ VRegs->l.ecx = x;
+ VRegs->l.edx = y;
+ VBIOSint(0x10, VRegs, 1024);
+}
+
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *copyOfBIOS,
+ ulong BIOSLen)
+{
+ (void)axVal;
+ (void)BIOSPhysAddr;
+ (void)copyOfBIOS;
+ (void)BIOSLen;
+ return false;
+}
+
+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)
+{
+ // QNX handles IOPL selection at the program link level.
+ return level;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+RETURNS:
+Error code describing the result.
+
+REMARKS:
+Function to enable write combining for the specified region of memory.
+****************************************************************************/
+int PMAPI PM_enableWriteCombine(
+ ulong base,
+ ulong size,
+ uint type)
+{
+#ifndef __QNXNTO__
+ return MTRR_enableWriteCombine(base,size,type);
+#else
+ return PM_MTRR_NOT_SUPPORTED;
+#endif
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/qnx/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/qnx/vflat.c
new file mode 100644
index 0000000000..579ef2c95c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/qnx/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/qnx/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/qnx/ztimer.c
new file mode 100644
index 0000000000..d2740971f9
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/qnx/ztimer.c
@@ -0,0 +1,91 @@
+/****************************************************************************
+*
+* 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: QNX
+*
+* Description: QNX specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+void __ZTimerInit(void)
+{
+}
+
+/****************************************************************************
+REMARKS:
+Use the gettimeofday() function to get microsecond precision (probably less
+though)
+****************************************************************************/
+static ulong __ULZReadTime(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return (ts.tv_nsec / 1000 + ts.tv_sec * 1000000);
+}
+
+/****************************************************************************
+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; }
diff --git a/board/MAI/bios_emulator/scitech/src/pm/rttarget/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/rttarget/cpuinfo.c
new file mode 100644
index 0000000000..3d6dd44313
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/rttarget/cpuinfo.c
@@ -0,0 +1,94 @@
+/****************************************************************************
+*
+* 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: RTTarget-32
+*
+* Description: Module to implement OS specific services to measure the
+* CPU frequency.
+*
+****************************************************************************/
+
+/*---------------------------- Global variables ---------------------------*/
+
+static ibool havePerformanceCounter;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Increase the thread priority to maximum, if possible.
+****************************************************************************/
+static int SetMaxThreadPriority(void)
+{
+ int oldPriority;
+ HANDLE hThread = GetCurrentThread();
+
+ oldPriority = GetThreadPriority(hThread);
+ if (oldPriority != THREAD_PRIORITY_ERROR_RETURN)
+ SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
+ return oldPriority;
+}
+
+/****************************************************************************
+REMARKS:
+Restore the original thread priority.
+****************************************************************************/
+static void RestoreThreadPriority(
+ int oldPriority)
+{
+ HANDLE hThread = GetCurrentThread();
+
+ if (oldPriority != THREAD_PRIORITY_ERROR_RETURN)
+ SetThreadPriority(hThread, oldPriority);
+}
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ if (!QueryPerformanceFrequency((LARGE_INTEGER*)freq)) {
+ havePerformanceCounter = false;
+ freq->low = 100000;
+ freq->high = 0;
+ }
+ else
+ havePerformanceCounter = true;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ if (havePerformanceCounter) \
+ QueryPerformanceCounter((LARGE_INTEGER*)t); \
+ else { \
+ (t)->low = timeGetTime() * 100; \
+ (t)->high = 0; \
+ } \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/rttarget/event.c b/board/MAI/bios_emulator/scitech/src/pm/rttarget/event.c
new file mode 100644
index 0000000000..e9aba21b9f
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/rttarget/event.c
@@ -0,0 +1,287 @@
+/****************************************************************************
+*
+* 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: RTTarget-32
+*
+* Description: Win32 implementation for the SciTech cross platform
+* event library.
+*
+****************************************************************************/
+
+/*---------------------------- Global Variables ---------------------------*/
+
+static ushort keyUpMsg[256] = {0}; /* Table of key up messages */
+static int rangeX,rangeY; /* Range of mouse coordinates */
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* These are not used under Win32 */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flags)
+
+/****************************************************************************
+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)
+{ return timeGetTime(); }
+
+/****************************************************************************
+REMARKS:
+Pumps all messages in the message queue from Win32 into our event queue.
+****************************************************************************/
+void _EVT_pumpMessages(void)
+{
+ MSG msg;
+ MSG charMsg;
+ event_t evt;
+
+ while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ memset(&evt,0,sizeof(evt));
+ switch (msg.message) {
+ case WM_MOUSEMOVE:
+ evt.what = EVT_MOUSEMOVE;
+ break;
+ case WM_LBUTTONDBLCLK:
+ evt.what = EVT_MOUSEDOWN;
+ evt.message = EVT_LEFTBMASK | EVT_DBLCLICK;
+ break;
+ case WM_LBUTTONDOWN:
+ evt.what = EVT_MOUSEDOWN;
+ evt.message = EVT_LEFTBMASK;
+ break;
+ case WM_LBUTTONUP:
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_LEFTBMASK;
+ break;
+ case WM_RBUTTONDBLCLK:
+ evt.what = EVT_MOUSEDOWN | EVT_DBLCLICK;
+ evt.message = EVT_RIGHTBMASK;
+ break;
+ case WM_RBUTTONDOWN:
+ evt.what = EVT_MOUSEDOWN;
+ evt.message = EVT_RIGHTBMASK;
+ break;
+ case WM_RBUTTONUP:
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_RIGHTBMASK;
+ break;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ if (HIWORD(msg.lParam) & KF_REPEAT) {
+ evt.what = EVT_KEYREPEAT;
+ }
+ else {
+ evt.what = EVT_KEYDOWN;
+ }
+ break;
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ evt.what = EVT_KEYUP;
+ break;
+ }
+
+ /* Convert mouse event modifier flags */
+ if (evt.what & EVT_MOUSEEVT) {
+ evt.where_x = msg.pt.x;
+ evt.where_y = msg.pt.y;
+ if (evt.what == EVT_MOUSEMOVE) {
+ if (oldMove != -1) {
+ evtq[oldMove].where_x = evt.where_x;/* Modify existing one */
+ evtq[oldMove].where_y = evt.where_y;
+ evt.what = 0;
+ }
+ else {
+ oldMove = freeHead; /* Save id of this move event */
+ }
+ }
+ else
+ oldMove = -1;
+ if (msg.wParam & MK_LBUTTON)
+ evt.modifiers |= EVT_LEFTBUT;
+ if (msg.wParam & MK_RBUTTON)
+ evt.modifiers |= EVT_RIGHTBUT;
+ if (msg.wParam & MK_SHIFT)
+ evt.modifiers |= EVT_SHIFTKEY;
+ if (msg.wParam & MK_CONTROL)
+ evt.modifiers |= EVT_CTRLSTATE;
+ }
+
+ /* Convert keyboard codes */
+ TranslateMessage(&msg);
+ if (evt.what & EVT_KEYEVT) {
+ int scanCode = (msg.lParam >> 16) & 0xFF;
+ if (evt.what == EVT_KEYUP) {
+ /* Get message for keyup code from table of cached down values */
+ evt.message = keyUpMsg[scanCode];
+ keyUpMsg[scanCode] = 0;
+ }
+ else {
+ if (PeekMessage(&charMsg,NULL,WM_CHAR,WM_CHAR,PM_REMOVE))
+ evt.message = charMsg.wParam;
+ if (PeekMessage(&charMsg,NULL,WM_SYSCHAR,WM_SYSCHAR,PM_REMOVE))
+ evt.message = charMsg.wParam;
+ evt.message |= ((msg.lParam >> 8) & 0xFF00);
+ keyUpMsg[scanCode] = (ushort)evt.message;
+ }
+ if (evt.what == EVT_KEYREPEAT)
+ evt.message |= (msg.lParam << 16);
+ if (HIWORD(msg.lParam) & KF_ALTDOWN)
+ evt.modifiers |= EVT_ALTSTATE;
+ if (GetKeyState(VK_SHIFT) & 0x8000U)
+ evt.modifiers |= EVT_SHIFTKEY;
+ if (GetKeyState(VK_CONTROL) & 0x8000U)
+ evt.modifiers |= EVT_CTRLSTATE;
+ oldMove = -1;
+ }
+
+ if (evt.what != 0) {
+ /* Add time stamp and add the event to the queue */
+ evt.when = msg.time;
+ if (count < EVENTQSIZE) {
+ addEvent(&evt);
+ }
+ }
+ DispatchMessage(&msg);
+ }
+}
+
+/****************************************************************************
+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 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:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort()
+{
+ EVT_exit();
+ PM_fatalError("Unhandled exception!");
+}
+
+/****************************************************************************
+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)
+{
+ /* Initialise the event queue */
+ _mouseMove = mouseMove;
+ initEventQueue();
+ memset(keyUpMsg,0,sizeof(keyUpMsg));
+
+ /* Catch program termination signals so we can clean up properly */
+ signal(SIGABRT, _EVT_abort);
+ signal(SIGFPE, _EVT_abort);
+ signal(SIGINT, _EVT_abort);
+}
+
+/****************************************************************************
+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)
+{
+ rangeX = xRes;
+ rangeY = yRes;
+}
+
+/****************************************************************************
+REMARKS
+Modifes the mouse coordinates as necessary if scaling to OS coordinates,
+and sets the OS mouse cursor position.
+****************************************************************************/
+void _EVT_setMousePos(
+ int *x,
+ int *y)
+{
+ SetCursorPos(*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 Win32
+}
+
+/****************************************************************************
+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 Win32
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+ /* Restore signal handlers */
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/rttarget/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/rttarget/oshdr.h
new file mode 100644
index 0000000000..1352dadad6
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/rttarget/oshdr.h
@@ -0,0 +1,34 @@
+/****************************************************************************
+*
+* 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: RTTarget-32
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
+
+#define WIN32_LEAN_AND_MEAN
+#define STRICT
+#include <windows.h>
+#include <mmsystem.h>
diff --git a/board/MAI/bios_emulator/scitech/src/pm/rttarget/pm.c b/board/MAI/bios_emulator/scitech/src/pm/rttarget/pm.c
new file mode 100644
index 0000000000..e6c1fbd8b3
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/rttarget/pm.c
@@ -0,0 +1,701 @@
+/****************************************************************************
+*
+* 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: RTTarget-32
+*
+* 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>
+#define WIN32_LEAN_AND_MEAN
+#define STRICT
+#include <windows.h>
+#include <mmsystem.h>
+#ifdef __BORLANDC__
+#pragma warn -par
+#endif
+
+/*--------------------------- Global variables ----------------------------*/
+
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+void MTRR_init(void);
+
+/****************************************************************************
+REMARKS:
+Initialise the PM library.
+****************************************************************************/
+void PMAPI PM_init(void)
+{
+ // TODO: dO any special init code in here.
+ MTRR_init();
+}
+
+/****************************************************************************
+REMARKS:
+Return the operating system type identifier.
+****************************************************************************/
+long PMAPI PM_getOSType(void)
+{
+ return _OS_RTTARGET;
+}
+
+/****************************************************************************
+REMARKS:
+Return the runtime type identifier.
+****************************************************************************/
+int PMAPI PM_getModeType(void)
+{
+ return PM_386;
+}
+
+/****************************************************************************
+REMARKS:
+Add a file directory separator to the end of the filename.
+****************************************************************************/
+void PMAPI PM_backslash(
+ char *s)
+{
+ uint pos = strlen(s);
+ if (s[pos-1] != '\\') {
+ s[pos] = '\\';
+ s[pos+1] = '\0';
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Add a user defined PM_fatalError cleanup function.
+****************************************************************************/
+void PMAPI PM_setFatalErrorCleanup(
+ void (PMAPIP cleanup)(void))
+{
+ fatalErrorCleanup = cleanup;
+}
+
+/****************************************************************************
+REMARKS:
+Report a fatal error condition and halt the program.
+****************************************************************************/
+void PMAPI PM_fatalError(
+ const char *msg)
+{
+ if (fatalErrorCleanup)
+ fatalErrorCleanup();
+ // TODO: Display a fatal error message and exit!
+// MessageBox(NULL,msg,"Fatal Error!", MB_ICONEXCLAMATION);
+ exit(1);
+}
+
+/****************************************************************************
+REMARKS:
+Allocate the real mode VESA transfer buffer for communicating with the BIOS.
+****************************************************************************/
+void * PMAPI PM_getVESABuf(
+ uint *len,
+ uint *rseg,
+ uint *roff)
+{
+ /* No BIOS access for the RTTarget */
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Check if a key has been pressed.
+****************************************************************************/
+int PMAPI PM_kbhit(void)
+{
+ // TODO: Need to check if a key is waiting on the keyboard queue
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Wait for and return the next keypress.
+****************************************************************************/
+int PMAPI PM_getch(void)
+{
+ // TODO: Need to obtain the next keypress, and block until one is hit
+ return 0xD;
+}
+
+/****************************************************************************
+REMARKS:
+Set the location of the OS console cursor.
+****************************************************************************/
+void PM_setOSCursorLocation(
+ int x,
+ int y)
+{
+ /* Nothing to do for RTTarget-32 */
+}
+
+/****************************************************************************
+REMARKS:
+Set the width of the OS console.
+****************************************************************************/
+void PM_setOSScreenWidth(
+ int width,
+ int height)
+{
+ /* Nothing to do for RTTarget-32 */
+}
+
+/****************************************************************************
+REMARKS:
+Set the real time clock handler (used for software stereo modes).
+****************************************************************************/
+ibool PMAPI PM_setRealTimeClockHandler(
+ PM_intHandler ih,
+ int frequency)
+{
+ /* Not supported for RTTarget-32 */
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Set the real time clock frequency (for stereo modes).
+****************************************************************************/
+void PMAPI PM_setRealTimeClockFrequency(
+ int frequency)
+{
+ /* Not supported under RTTarget-32 */
+}
+
+/****************************************************************************
+REMARKS:
+Restore the original real time clock handler.
+****************************************************************************/
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ /* Not supported under RTTarget-32 */
+}
+
+/****************************************************************************
+REMARKS:
+Return the current operating system path or working directory.
+****************************************************************************/
+char * PMAPI PM_getCurrentPath(
+ char *path,
+ int maxLen)
+{
+ return getcwd(path,maxLen);
+}
+
+/****************************************************************************
+REMARKS:
+Return the drive letter for the boot drive.
+****************************************************************************/
+char PMAPI PM_getBootDrive(void)
+{
+ return 'c';
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the VBE/AF driver files.
+****************************************************************************/
+const char * PMAPI PM_getVBEAFPath(void)
+{
+ return "c:\\";
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the Nucleus driver files.
+****************************************************************************/
+const char * PMAPI PM_getNucleusPath(void)
+{
+ // TODO: Point this at the path when the Nucleus drivers will be found
+ return "c:\\nucleus";
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the Nucleus configuration files.
+****************************************************************************/
+const char * PMAPI PM_getNucleusConfigPath(void)
+{
+ static char path[256];
+ strcpy(path,PM_getNucleusPath());
+ PM_backslash(path);
+ strcat(path,"config");
+ return path;
+}
+
+/****************************************************************************
+REMARKS:
+Return a unique identifier for the machine if possible.
+****************************************************************************/
+const char * PMAPI PM_getUniqueID(void)
+{
+ return PM_getMachineName();
+}
+
+/****************************************************************************
+REMARKS:
+Get the name of the machine on the network.
+****************************************************************************/
+const char * PMAPI PM_getMachineName(void)
+{
+ /* Not necessary for RTTarget-32 */
+ return "Unknown";
+}
+
+/****************************************************************************
+REMARKS:
+Return a pointer to the real mode BIOS data area.
+****************************************************************************/
+void * PMAPI PM_getBIOSPointer(void)
+{
+ /* Not used for RTTarget-32 */
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Return a pointer to 0xA0000 physical VGA graphics framebuffer.
+****************************************************************************/
+void * PMAPI PM_getA0000Pointer(void)
+{
+ static void *bankPtr;
+ if (!bankPtr)
+ bankPtr = PM_mapPhysicalAddr(0xA0000,0xFFFF,true);
+ return bankPtr;
+}
+
+/****************************************************************************
+REMARKS:
+Map a physical address to a linear address in the callers process.
+****************************************************************************/
+void * PMAPI PM_mapPhysicalAddr(
+ ulong base,
+ ulong limit,
+ ibool isCached)
+{
+ // TODO: Map a physical memory address to a linear address
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a physical address mapping allocated by PM_mapPhysicalAddr.
+****************************************************************************/
+void PMAPI PM_freePhysicalAddr(
+ void *ptr,
+ ulong limit)
+{
+ // TODO: Free the physical address mapping
+}
+
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{
+ // TODO: This function should find the physical address of a linear
+ // address.
+ return 0xFFFFFFFFUL;
+}
+
+void PMAPI PM_sleep(ulong milliseconds)
+{
+ Sleep(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;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of (unnamed) shared memory.
+****************************************************************************/
+void * PMAPI PM_mallocShared(
+ long size)
+{
+ return PM_malloc(size);
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of shared memory.
+****************************************************************************/
+void PMAPI PM_freeShared(
+ void *ptr)
+{
+ PM_free(ptr);
+}
+
+/****************************************************************************
+REMARKS:
+Map a linear memory address to the calling process address space. The
+address will have been allocated in another process using the
+PM_mapPhysicalAddr function.
+****************************************************************************/
+void * PMAPI PM_mapToProcess(
+ void *base,
+ ulong limit)
+{
+ return base;
+}
+
+/****************************************************************************
+REMARKS:
+Map a real mode pointer to a protected mode pointer.
+****************************************************************************/
+void * PMAPI PM_mapRealPointer(
+ uint r_seg,
+ uint r_off)
+{
+ /* Not used for RTTarget-32 */
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of real mode memory
+****************************************************************************/
+void * PMAPI PM_allocRealSeg(
+ uint size,
+ uint *r_seg,
+ uint *r_off)
+{
+ /* Not used for RTTarget-32 */
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of real mode memory.
+****************************************************************************/
+void PMAPI PM_freeRealSeg(
+ void *mem)
+{
+ /* Not used for RTTarget-32 */
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt (parameters in DPMI compatible structure)
+****************************************************************************/
+void PMAPI DPMI_int86(
+ int intno,
+ DPMI_regs *regs)
+{
+ /* Not used for RTTarget-32 */
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt.
+****************************************************************************/
+int PMAPI PM_int86(
+ int intno,
+ RMREGS *in,
+ RMREGS *out)
+{
+ /* Not used for RTTarget-32 */
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt.
+****************************************************************************/
+int PMAPI PM_int86x(
+ int intno,
+ RMREGS *in,
+ RMREGS *out,
+ RMSREGS *sregs)
+{
+ /* Not used for RTTarget-32 */
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Call a real mode far function.
+****************************************************************************/
+void PMAPI PM_callRealMode(
+ uint seg,
+ uint off,
+ RMREGS *in,
+ RMSREGS *sregs)
+{
+ /* Not used for RTTarget-32 */
+}
+
+/****************************************************************************
+REMARKS:
+Return the amount of available memory.
+****************************************************************************/
+void PMAPI PM_availableMemory(
+ ulong *physical,
+ ulong *total)
+{
+ // TODO: Figure out how to determine the available memory. Not entirely
+ // critical so returning 0 is OK.
+ *physical = *total = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of locked, physical memory for DMA operations.
+****************************************************************************/
+void * PMAPI PM_allocLockedMem(
+ uint size,
+ ulong *physAddr,
+ ibool contiguous,
+ ibool below16M)
+{
+ // TODO: Allocate a block of locked, phsyically contigous memory for DMA
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of locked physical memory.
+****************************************************************************/
+void PMAPI PM_freeLockedMem(
+ void *p,
+ uint size,
+
+ ibool contiguous)
+{
+ // TODO: Free a locked memory buffer
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display banks.
+****************************************************************************/
+void PMAPI PM_setBankA(
+ int bank)
+{
+ /* Not used for RTTarget-32 */
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display banks.
+****************************************************************************/
+void PMAPI PM_setBankAB(
+ int bank)
+{
+ /* Not used for RTTarget-32 */
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display start address.
+****************************************************************************/
+void PMAPI PM_setCRTStart(
+ int x,
+ int y,
+ int waitVRT)
+{
+ /* Not used for RTTarget-32 */
+}
+
+/****************************************************************************
+REMARKS:
+Execute the POST on the secondary BIOS for a controller.
+****************************************************************************/
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *mappedBIOS)
+{
+ /* Not used for RTTarget-32 */
+ return false;
+}
+
+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;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+ulong PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ // TODO: This function should start a directory enumeration search
+ // given the filename (with wildcards). The data should be
+ // converted and returned in the findData standard form.
+ (void)filename;
+ (void)findData;
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ ulong handle,
+ PM_findData *findData)
+{
+ // TODO: This function should find the next file in directory enumeration
+ // search given the search criteria defined in the call to
+ // PM_findFirstFile. The data should be converted and returned
+ // in the findData standard form.
+ (void)handle;
+ (void)findData;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ ulong handle)
+{
+ // TODO: This function should close the find process. This may do
+ // nothing for some OS'es.
+ (void)handle;
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ if (drive == 3)
+ return true;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ (void)drive;
+ getcwd(dir,len);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+ // TODO: Set the file attributes for a file
+ (void)filename;
+ (void)attrib;
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+ return mkdir(filename) == 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+ return rmdir(filename) == 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/rttarget/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/rttarget/vflat.c
new file mode 100644
index 0000000000..dd9dfe6826
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/rttarget/vflat.c
@@ -0,0 +1,48 @@
+/****************************************************************************
+*
+* 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: RTTarget-32
+*
+* Description: Dummy module; no virtual framebuffer for this OS
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#ifdef __BORLANDC__
+#pragma warn -par
+#endif
+
+ibool PMAPI VF_available(void)
+{
+ return false;
+}
+
+void * PMAPI VF_init(ulong baseAddr,int bankSize,int codeLen,void *bankFunc)
+{
+ return NULL;
+}
+
+void PMAPI VF_exit(void)
+{
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/rttarget/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/rttarget/ztimer.c
new file mode 100644
index 0000000000..52472c385a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/rttarget/ztimer.c
@@ -0,0 +1,136 @@
+/****************************************************************************
+*
+* 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: RTTarget-32
+*
+* Description: OS specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+/*---------------------------- Global variables ---------------------------*/
+
+static CPU_largeInteger countFreq;
+static ibool havePerformanceCounter;
+static ulong start,finish;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+void __ZTimerInit(void)
+{
+#ifdef NO_ASSEMBLER
+ havePerformanceCounter = false;
+#else
+ havePerformanceCounter = QueryPerformanceFrequency((LARGE_INTEGER*)&countFreq);
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Start the Zen Timer counting.
+****************************************************************************/
+static void __LZTimerOn(
+ LZTimerObject *tm)
+{
+ if (havePerformanceCounter)
+ QueryPerformanceCounter((LARGE_INTEGER*)&tm->start);
+ else
+ tm->start.low = timeGetTime();
+}
+
+/****************************************************************************
+REMARKS:
+Compute the lap time since the timer was started.
+****************************************************************************/
+static ulong __LZTimerLap(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger tmLap,tmCount;
+
+ if (havePerformanceCounter) {
+ QueryPerformanceCounter((LARGE_INTEGER*)&tmLap);
+ _CPU_diffTime64(&tm->start,&tmLap,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,countFreq.low);
+ }
+ else {
+ tmLap.low = timeGetTime();
+ return (tmLap.low - tm->start.low) * 1000L;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Stop the Zen Timer counting.
+****************************************************************************/
+static void __LZTimerOff(
+ LZTimerObject *tm)
+{
+ if (havePerformanceCounter)
+ QueryPerformanceCounter((LARGE_INTEGER*)&tm->end);
+ else
+ tm->end.low = timeGetTime();
+}
+
+/****************************************************************************
+REMARKS:
+Compute the elapsed time in microseconds between start and end timings.
+****************************************************************************/
+static ulong __LZTimerCount(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger tmCount;
+
+ if (havePerformanceCounter) {
+ _CPU_diffTime64(&tm->start,&tm->end,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,countFreq.low);
+ }
+ else
+ return (tm->end.low - tm->start.low) * 1000L;
+}
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 1000
+
+/****************************************************************************
+REMARKS:
+Read the Long Period timer from the OS
+****************************************************************************/
+static ulong __ULZReadTime(void)
+{ return timeGetTime(); }
+
+/****************************************************************************
+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; }
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/_event.asm b/board/MAI/bios_emulator/scitech/src/pm/smx/_event.asm
new file mode 100644
index 0000000000..da62b1f712
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/_event.asm
@@ -0,0 +1,175 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler
+;* Environment: IBM PC (MS DOS)
+;*
+;* Description: Assembly language support routines for the event module.
+;*
+;****************************************************************************
+
+ ideal
+
+include "scitech.mac" ; Memory model macros
+
+ifdef flatmodel
+
+header _event ; Set up memory model
+
+begdataseg _event
+
+ cextern _EVT_biosPtr,DPTR
+
+ cpublic _EVT_dataStart
+
+ifdef USE_NASM
+%define KB_HEAD WORD esi+01Ah ; Keyboard buffer head in BIOS data area
+%define KB_TAIL WORD esi+01Ch ; Keyboard buffer tail in BIOS data area
+%define KB_START WORD esi+080h ; Start of keyboard buffer in BIOS data area
+%define KB_END WORD esi+082h ; End of keyboard buffer in BIOS data area
+else
+KB_HEAD EQU WORD esi+01Ah ; Keyboard buffer head in BIOS data area
+KB_TAIL EQU WORD esi+01Ch ; Keyboard buffer tail in BIOS data area
+KB_START EQU WORD esi+080h ; Start of keyboard buffer in BIOS data area
+KB_END EQU WORD esi+082h ; End of keyboard buffer in BIOS data area
+endif
+
+ cpublic _EVT_dataEnd
+
+enddataseg _event
+
+begcodeseg _event ; Start of code segment
+
+ cpublic _EVT_codeStart
+
+;----------------------------------------------------------------------------
+; int _EVT_getKeyCode(void)
+;----------------------------------------------------------------------------
+; Returns the key code for the next available key by extracting it from
+; the BIOS keyboard buffer.
+;----------------------------------------------------------------------------
+cprocstart _EVT_getKeyCode
+
+ enter_c
+
+ mov esi,[_EVT_biosPtr]
+ xor ebx,ebx
+ xor eax,eax
+ mov bx,[KB_HEAD]
+ cmp bx,[KB_TAIL]
+ jz @@Done
+ xor eax,eax
+ mov ax,[esi+ebx] ; EAX := character from keyboard buffer
+ inc _bx
+ inc _bx
+ cmp bx,[KB_END] ; Hit the end of the keyboard buffer?
+ jl @@1
+ mov bx,[KB_START]
+@@1: mov [KB_HEAD],bx ; Update keyboard buffer head pointer
+
+@@Done: leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int _EVT_disableInt(void);
+;----------------------------------------------------------------------------
+; Return processor interrupt status and disable interrupts.
+;----------------------------------------------------------------------------
+cprocstart _EVT_disableInt
+
+ pushf ; Put flag word on stack
+ cli ; Disable interrupts!
+ pop eax ; deposit flag word in return register
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _EVT_restoreInt(int ps);
+;----------------------------------------------------------------------------
+; Restore processor interrupt status.
+;----------------------------------------------------------------------------
+cprocstart _EVT_restoreInt
+
+ ARG ps:UINT
+
+ push ebp
+ mov ebp,esp ; Set up stack frame
+ push [DWORD ps]
+ popf ; Restore processor status (and interrupts)
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int EVT_rdinx(int port,int index)
+;----------------------------------------------------------------------------
+; Reads an indexed register value from an I/O port.
+;----------------------------------------------------------------------------
+cprocstart EVT_rdinx
+
+ ARG port:UINT, index:UINT
+
+ push ebp
+ mov ebp,esp
+ mov edx,[port]
+ mov al,[BYTE index]
+ out dx,al
+ inc dx
+ in al,dx
+ movzx eax,al
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void EVT_wrinx(int port,int index,int value)
+;----------------------------------------------------------------------------
+; Writes an indexed register value to an I/O port.
+;----------------------------------------------------------------------------
+cprocstart EVT_wrinx
+
+ ARG port:UINT, index:UINT, value:UINT
+
+ push ebp
+ mov ebp,esp
+ mov edx,[port]
+ mov al,[BYTE index]
+ mov ah,[BYTE value]
+ out dx,ax
+ pop ebp
+ ret
+
+cprocend
+
+ cpublic _EVT_codeEnd
+
+endcodeseg _event
+
+endif
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/_lztimer.asm b/board/MAI/bios_emulator/scitech/src/pm/smx/_lztimer.asm
new file mode 100644
index 0000000000..068eea65d2
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/_lztimer.asm
@@ -0,0 +1,58 @@
+;****************************************************************************
+;*
+;* 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: NASM or TASM Assembler
+;* Environment: smx 32 bit intel CPU
+;*
+;* Description: SMX does not support 486's, so this module is not necessary.
+;*
+;* All registers and all flags are preserved by all routines, except
+;* interrupts which are always turned on
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac"
+
+header _lztimer
+
+begdataseg _lztimer
+
+enddataseg _lztimer
+
+begcodeseg _lztimer ; Start of code segment
+
+cprocstart LZ_disable
+ cli
+ ret
+cprocend
+
+cprocstart LZ_enable
+ sti
+ ret
+cprocend
+
+endcodeseg _lztimer
+
+ END
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/_pm.asm b/board/MAI/bios_emulator/scitech/src/pm/smx/_pm.asm
new file mode 100644
index 0000000000..1c7cb21864
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/_pm.asm
@@ -0,0 +1,448 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: 32-bit SMX embedded systems development
+;*
+;* Description: Low level assembly support for the PM library specific to
+;* SMX.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pm ; Set up memory model
+
+begdataseg _pm
+
+ cextern _PM_savedDS,USHORT
+
+intel_id db "GenuineIntel" ; Intel vendor ID
+
+enddataseg _pm
+
+begcodeseg _pm ; Start of code segment
+
+;----------------------------------------------------------------------------
+; void PM_segread(PMSREGS *sregs)
+;----------------------------------------------------------------------------
+; Read the current value of all segment registers
+;----------------------------------------------------------------------------
+cprocstartdll16 PM_segread
+
+ ARG sregs:DPTR
+
+ enter_c
+
+ mov ax,es
+ _les _si,[sregs]
+ mov [_ES _si],ax
+ mov [_ES _si+2],cs
+ mov [_ES _si+4],ss
+ mov [_ES _si+6],ds
+ mov [_ES _si+8],fs
+ mov [_ES _si+10],gs
+
+ leave_c
+ ret
+
+cprocend
+
+; Create a table of the 256 different interrupt calls that we can jump
+; into
+
+ifdef USE_NASM
+
+%assign intno 0
+
+intTable:
+%rep 256
+ db 0CDh
+ db intno
+%assign intno intno + 1
+ ret
+ nop
+%endrep
+
+else
+
+intno = 0
+
+intTable:
+ REPT 256
+ db 0CDh
+ db intno
+intno = intno + 1
+ ret
+ nop
+ ENDM
+
+endif
+
+;----------------------------------------------------------------------------
+; _PM_genInt - Generate the appropriate interrupt
+;----------------------------------------------------------------------------
+cprocnear _PM_genInt
+
+ push _ax ; Save _ax
+ push _bx ; Save _bx
+ mov ebx,[UINT esp+12] ; EBX := interrupt number
+ mov _ax,offset intTable ; Point to interrupt generation table
+ shl _bx,2 ; _BX := index into table
+ add _ax,_bx ; _AX := pointer to interrupt code
+ xchg eax,[esp+4] ; Restore eax, and set for int
+ pop _bx ; restore _bx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_int386x(int intno, PMREGS *in, PMREGS *out,PMSREGS *sregs)
+;----------------------------------------------------------------------------
+; Issues a software interrupt in protected mode. This routine has been
+; written to allow user programs to load CS and DS with different values
+; other than the default.
+;----------------------------------------------------------------------------
+cprocstartdll16 PM_int386x
+
+ ARG intno:UINT, inptr:DPTR, outptr:DPTR, sregs:DPTR
+
+ LOCAL flags:UINT, sv_ds:UINT, sv_esi:ULONG = LocalSize
+
+ enter_c
+ push ds
+ push es ; Save segment registers
+ push fs
+ push gs
+
+ _lds _si,[sregs] ; DS:_SI -> Load segment registers
+ mov es,[_si]
+ mov bx,[_si+6]
+ mov [sv_ds],_bx ; Save value of user DS on stack
+ mov fs,[_si+8]
+ mov gs,[_si+10]
+
+ _lds _si,[inptr] ; Load CPU registers
+ mov eax,[_si]
+ mov ebx,[_si+4]
+ mov ecx,[_si+8]
+ mov edx,[_si+12]
+ mov edi,[_si+20]
+ mov esi,[_si+16]
+
+ push ds ; Save value of DS
+ push _bp ; Some interrupts trash this!
+ clc ; Generate the interrupt
+ push [UINT intno]
+ mov ds,[WORD sv_ds] ; Set value of user's DS selector
+ call _PM_genInt
+ pop _bp ; Pop intno from stack (flags unchanged)
+ pop _bp ; Restore value of stack frame pointer
+ pop ds ; Restore value of DS
+
+ pushf ; Save flags for later
+ pop [UINT flags]
+ push esi ; Save ESI for later
+ pop [DWORD sv_esi]
+ push ds ; Save DS for later
+ pop [UINT sv_ds]
+
+ _lds _si,[outptr] ; Save CPU registers
+ mov [_si],eax
+ mov [_si+4],ebx
+ mov [_si+8],ecx
+ mov [_si+12],edx
+ push [DWORD sv_esi]
+ pop [DWORD _si+16]
+ mov [_si+20],edi
+
+ mov _bx,[flags] ; Return flags
+ and ebx,1h ; Isolate carry flag
+ mov [_si+24],ebx ; Save carry flag status
+
+ _lds _si,[sregs] ; Save segment registers
+ mov [_si],es
+ mov _bx,[sv_ds]
+ mov [_si+6],bx ; Get returned DS from stack
+ mov [_si+8],fs
+ mov [_si+10],gs
+
+ pop gs ; Restore segment registers
+ pop fs
+ pop es
+ pop ds
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_saveDS(void)
+;----------------------------------------------------------------------------
+; Save the value of DS into a section of the code segment, so that we can
+; quickly load this value at a later date in the PM_loadDS() routine from
+; inside interrupt handlers etc. The method to do this is different
+; depending on the DOS extender being used.
+;----------------------------------------------------------------------------
+cprocstartdll16 PM_saveDS
+
+ mov [_PM_savedDS],ds ; Store away in data segment
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_loadDS(void)
+;----------------------------------------------------------------------------
+; Routine to load the DS register with the default value for the current
+; DOS extender. Only the DS register is loaded, not the ES register, so
+; if you wish to call C code, you will need to also load the ES register
+; in 32 bit protected mode.
+;----------------------------------------------------------------------------
+cprocstartdll16 PM_loadDS
+
+ mov ds,[cs:_PM_savedDS] ; We can access the proper DS through CS
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setBankA(int bank)
+;----------------------------------------------------------------------------
+cprocstart PM_setBankA
+
+ ARG bank:UINT
+
+ push ebp
+ mov ebp,esp
+ push ebx
+ mov _bx,0
+ mov _ax,4F05h
+ mov _dx,[bank]
+ int 10h
+ pop ebx
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setBankAB(int bank)
+;----------------------------------------------------------------------------
+cprocstart PM_setBankAB
+
+ ARG bank:UINT
+
+ push ebp
+ mov ebp,esp
+ push ebx
+ mov _bx,0
+ mov _ax,4F05h
+ mov _dx,[bank]
+ int 10h
+ mov _bx,1
+ mov _ax,4F05h
+ mov _dx,[bank]
+ int 10h
+ pop ebx
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setCRTStart(int x,int y,int waitVRT)
+;----------------------------------------------------------------------------
+cprocstart PM_setCRTStart
+
+ ARG x:UINT, y:UINT, waitVRT:UINT
+
+ push ebp
+ mov ebp,esp
+ push ebx
+ mov _bx,[waitVRT]
+ mov _cx,[x]
+ mov _dx,[y]
+ mov _ax,4F07h
+ int 10h
+ pop ebx
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int _PM_inp(int port)
+;----------------------------------------------------------------------------
+; Reads a byte from the specified port
+;----------------------------------------------------------------------------
+cprocstart _PM_inp
+
+ ARG port:UINT
+
+ push _bp
+ mov _bp,_sp
+ xor _ax,_ax
+ mov _dx,[port]
+ in al,dx
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_outp(int port,int value)
+;----------------------------------------------------------------------------
+; Write a byte to the specified port.
+;----------------------------------------------------------------------------
+cprocstart _PM_outp
+
+ ARG port:UINT, value:UINT
+
+ push _bp
+ mov _bp,_sp
+ mov _dx,[port]
+ mov _ax,[value]
+ out dx,al
+ pop _bp
+ ret
+
+cprocend
+
+; Macro to delay briefly to ensure that enough time has elapsed between
+; successive I/O accesses so that the device being accessed can respond
+; to both accesses even on a very fast PC.
+
+ifdef USE_NASM
+%macro DELAY 0
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+%endmacro
+%macro IODELAYN 1
+%rep %1
+ DELAY
+%endrep
+%endmacro
+else
+macro DELAY
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+endm
+macro IODELAYN N
+ rept N
+ DELAY
+ endm
+endm
+endif
+
+;----------------------------------------------------------------------------
+; uchar _PM_readCMOS(int index)
+;----------------------------------------------------------------------------
+; Read the value of a specific CMOS register. We do this with both
+; normal interrupts and NMI disabled.
+;----------------------------------------------------------------------------
+cprocstart _PM_readCMOS
+
+ ARG index:UINT
+
+ push _bp
+ mov _bp,_sp
+ pushfd
+ mov al,[BYTE index]
+ or al,80h ; Add disable NMI flag
+ cli
+ out 70h,al
+ IODELAYN 5
+ in al,71h
+ mov ah,al
+ xor al,al
+ IODELAYN 5
+ out 70h,al ; Re-enable NMI
+ sti
+ mov al,ah ; Return value in AL
+ popfd
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_writeCMOS(int index,uchar value)
+;----------------------------------------------------------------------------
+; Read the value of a specific CMOS register. We do this with both
+; normal interrupts and NMI disabled.
+;----------------------------------------------------------------------------
+cprocstart _PM_writeCMOS
+
+ ARG index:UINT, value:UCHAR
+
+ push _bp
+ mov _bp,_sp
+ pushfd
+ mov al,[BYTE index]
+ or al,80h ; Add disable NMI flag
+ cli
+ out 70h,al
+ IODELAYN 5
+ mov al,[value]
+ out 71h,al
+ xor al,al
+ IODELAYN 5
+ out 70h,al ; Re-enable NMI
+ sti
+ popfd
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; _PM_getPDB - Return the Page Table Directory Base address
+;----------------------------------------------------------------------------
+cprocstart _PM_getPDB
+
+ mov eax,cr3
+ and eax,0FFFFF000h
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; _PM_flushTLB - Flush the Translation Lookaside buffer
+;----------------------------------------------------------------------------
+cprocstart PM_flushTLB
+
+ wbinvd ; Flush the CPU cache
+ mov eax,cr3
+ mov cr3,eax ; Flush the TLB
+ ret
+
+cprocend
+
+endcodeseg _pm
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/_pmsmx.asm b/board/MAI/bios_emulator/scitech/src/pm/smx/_pmsmx.asm
new file mode 100644
index 0000000000..8352ce30c1
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/_pmsmx.asm
@@ -0,0 +1,933 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: 32-bit SMX embedded systems development
+;*
+;* Description: Low level assembly support for the PM library specific to
+;* SMX interrupt handling.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pmsmx ; Set up memory model
+
+; Define the size of our local stacks. For real mode code they cant be
+; that big, but for 32 bit protected mode code we can make them nice and
+; large so that complex C functions can be used.
+
+MOUSE_STACK EQU 4096
+TIMER_STACK EQU 4096
+KEY_STACK EQU 1024
+INT10_STACK EQU 1024
+
+ifdef USE_NASM
+
+; Macro to load DS and ES registers with correct value.
+
+%imacro LOAD_DS 0
+ mov ds,[cs:_PM_savedDS]
+ mov es,[cs:_PM_savedDS]
+%endmacro
+
+; Note that interrupts we disable interrupts during the following stack
+; %imacro for correct operation, but we do not enable them again. Normally
+; these %imacros are used within interrupt handlers so interrupts should
+; already be off. We turn them back on explicitly later if the user code
+; needs them to be back on.
+
+; Macro to switch to a new local stack.
+
+%imacro NEWSTK 1
+ cli
+ mov [seg_%1],ss
+ mov [ptr_%1],_sp
+ mov [TempSeg],ds
+ mov ss,[TempSeg]
+ mov _sp,offset %1
+%endmacro
+
+; %imacro to switch back to the old stack.
+
+%imacro RESTSTK 1
+ cli
+ mov ss,[seg_%1]
+ mov _sp,[ptr_%1]
+%endmacro
+
+; %imacro to swap the current stack with the one saved away.
+
+%imacro SWAPSTK 1
+ cli
+ mov ax,ss
+ xchg ax,[seg_%1]
+ mov ss,ax
+ xchg _sp,[ptr_%1]
+%endmacro
+
+else
+
+; Macro to load DS and ES registers with correct value.
+
+MACRO LOAD_DS
+ mov ds,[cs:_PM_savedDS]
+ mov es,[cs:_PM_savedDS]
+ENDM
+
+; Note that interrupts we disable interrupts during the following stack
+; macro for correct operation, but we do not enable them again. Normally
+; these macros are used within interrupt handlers so interrupts should
+; already be off. We turn them back on explicitly later if the user code
+; needs them to be back on.
+
+; Macro to switch to a new local stack.
+
+MACRO NEWSTK stkname
+ cli
+ mov [seg_&stkname&],ss
+ mov [ptr_&stkname&],_sp
+ mov [TempSeg],ds
+ mov ss,[TempSeg]
+ mov _sp,offset stkname
+ENDM
+
+; Macro to switch back to the old stack.
+
+MACRO RESTSTK stkname
+ cli
+ mov ss,[seg_&stkname&]
+ mov _sp,[ptr_&stkname&]
+ENDM
+
+; Macro to swap the current stack with the one saved away.
+
+MACRO SWAPSTK stkname
+ cli
+ mov ax,ss
+ xchg ax,[seg_&stkname&]
+ mov ss,ax
+ xchg _sp,[ptr_&stkname&]
+ENDM
+
+endif
+
+begdataseg _pmsmx
+
+ cextern _PM_savedDS,USHORT
+ cextern _PM_critHandler,CPTR
+ cextern _PM_breakHandler,CPTR
+ cextern _PM_timerHandler,CPTR
+ cextern _PM_rtcHandler,CPTR
+ cextern _PM_keyHandler,CPTR
+ cextern _PM_key15Handler,CPTR
+ cextern _PM_mouseHandler,CPTR
+ cextern _PM_int10Handler,CPTR
+
+ cextern _PM_ctrlCPtr,DPTR
+ cextern _PM_ctrlBPtr,DPTR
+ cextern _PM_critPtr,DPTR
+
+ cextern _PM_prevTimer,FCPTR
+ cextern _PM_prevRTC,FCPTR
+ cextern _PM_prevKey,FCPTR
+ cextern _PM_prevKey15,FCPTR
+ cextern _PM_prevBreak,FCPTR
+ cextern _PM_prevCtrlC,FCPTR
+ cextern _PM_prevCritical,FCPTR
+ cextern _PM_prevRealTimer,ULONG
+ cextern _PM_prevRealRTC,ULONG
+ cextern _PM_prevRealKey,ULONG
+ cextern _PM_prevRealKey15,ULONG
+ cextern _PM_prevRealInt10,ULONG
+
+cpublic _PM_pmsmxDataStart
+
+; Allocate space for all of the local stacks that we need. These stacks
+; are not very large, but should be large enough for most purposes
+; (generally you want to handle these interrupts quickly, simply storing
+; the information for later and then returning). If you need bigger
+; stacks then change the appropriate value in here.
+
+ ALIGN 4
+ dclb MOUSE_STACK ; Space for local stack (small)
+MsStack: ; Stack starts at end!
+ptr_MsStack DUINT 0 ; Place to store old stack offset
+seg_MsStack dw 0 ; Place to store old stack segment
+
+ ALIGN 4
+ dclb INT10_STACK ; Space for local stack (small)
+Int10Stack: ; Stack starts at end!
+ptr_Int10Stack DUINT 0 ; Place to store old stack offset
+seg_Int10Stack dw 0 ; Place to store old stack segment
+
+ ALIGN 4
+ dclb TIMER_STACK ; Space for local stack (small)
+TmStack: ; Stack starts at end!
+ptr_TmStack DUINT 0 ; Place to store old stack offset
+seg_TmStack dw 0 ; Place to store old stack segment
+
+ ALIGN 4
+ dclb TIMER_STACK ; Space for local stack (small)
+RtcStack: ; Stack starts at end!
+ptr_RtcStack DUINT 0 ; Place to store old stack offset
+seg_RtcStack dw 0 ; Place to store old stack segment
+RtcInside dw 0 ; Are we still handling current interrupt
+
+ ALIGN 4
+ dclb KEY_STACK ; Space for local stack (small)
+KyStack: ; Stack starts at end!
+ptr_KyStack DUINT 0 ; Place to store old stack offset
+seg_KyStack dw 0 ; Place to store old stack segment
+KyInside dw 0 ; Are we still handling current interrupt
+
+ ALIGN 4
+ dclb KEY_STACK ; Space for local stack (small)
+Ky15Stack: ; Stack starts at end!
+ptr_Ky15Stack DUINT 0 ; Place to store old stack offset
+seg_Ky15Stack dw 0 ; Place to store old stack segment
+
+TempSeg dw 0 ; Place to store stack segment
+
+cpublic _PM_pmsmxDataEnd
+
+enddataseg _pmsmx
+
+begcodeseg _pmsmx ; Start of code segment
+
+cpublic _PM_pmsmxCodeStart
+
+;----------------------------------------------------------------------------
+; PM_mouseISR - Mouse interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Interrupt subroutine called by the mouse driver upon interrupts, to
+; dispatch control to high level C based subroutines. Interrupts are on
+; when we call the user code.
+;
+; It is _extremely_ important to save the state of the extended registers
+; as these may well be trashed by the routines called from here and not
+; restored correctly by the mouse interface module.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. For mouse handlers this is not a
+; problem, as the mouse driver arbitrates calls to the user mouse
+; handler for us.
+;
+; Entry: AX - Condition mask giving reason for call
+; BX - Mouse button state
+; CX - Horizontal cursor coordinate
+; DX - Vertical cursor coordinate
+; SI - Horizontal mickey value
+; DI - Vertical mickey value
+;
+;----------------------------------------------------------------------------
+cprocfar _PM_mouseISR
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+ NEWSTK MsStack ; Switch to local stack
+
+; Call the installed high level C code routine
+
+ clrhi dx ; Clear out high order values
+ clrhi cx
+ clrhi bx
+ clrhi ax
+ sgnhi si
+ sgnhi di
+
+ push _di
+ push _si
+ push _dx
+ push _cx
+ push _bx
+ push _ax
+ sti ; Enable interrupts
+ call [CPTR _PM_mouseHandler]
+ _add sp,12,24
+
+ RESTSTK MsStack ; Restore previous stack
+
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ ret ; We are done!!
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_timerISR - Timer interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the timer interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. Make sure your C code executes as
+; quickly as possible, since a timer overrun will simply hang the
+; system.
+;----------------------------------------------------------------------------
+cprocfar _PM_timerISR
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+
+ NEWSTK TmStack ; Switch to local stack
+ call [CPTR _PM_timerHandler]
+ RESTSTK TmStack ; Restore previous stack
+
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_chainPrevTimer - Chain to previous timer interrupt and return
+;----------------------------------------------------------------------------
+; Chains to the previous timer interrupt routine and returns control
+; back to the high level interrupt handler.
+;----------------------------------------------------------------------------
+cprocstart PM_chainPrevTimer
+
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealTimer]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+ ret
+else
+ SWAPSTK TmStack ; Swap back to previous stack
+ pushf ; Save state of interrupt flag
+ pushf ; Push flags on stack to simulate interrupt
+ifdef USE_NASM
+ call far dword [_PM_prevTimer]
+else
+ call [_PM_prevTimer]
+endif
+ popf ; Restore state of interrupt flag
+ SWAPSTK TmStack ; Swap back to C stack again
+ ret
+endif
+
+cprocend
+
+; Macro to delay briefly to ensure that enough time has elapsed between
+; successive I/O accesses so that the device being accessed can respond
+; to both accesses even on a very fast PC.
+
+ifdef USE_NASM
+%macro DELAY 0
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+%endmacro
+%macro IODELAYN 1
+%rep %1
+ DELAY
+%endrep
+%endmacro
+else
+macro DELAY
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+endm
+macro IODELAYN N
+ rept N
+ DELAY
+ endm
+endm
+endif
+
+;----------------------------------------------------------------------------
+; PM_rtcISR - Real time clock interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the timer interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. Make sure your C code executes as
+; quickly as possible, since a timer overrun will simply hang the
+; system.
+;----------------------------------------------------------------------------
+cprocfar _PM_rtcISR
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+; Clear priority interrupt controller and re-enable interrupts so we
+; dont lock things up for long.
+
+ mov al,20h
+ out 0A0h,al
+ out 020h,al
+
+; Clear real-time clock timeout
+
+ in al,70h ; Read CMOS index register
+ push _ax ; and save for later
+ IODELAYN 3
+ mov al,0Ch
+ out 70h,al
+ IODELAYN 5
+ in al,71h
+
+; Call the C interrupt handler function
+
+ LOAD_DS ; Load DS register
+ cmp [BYTE RtcInside],1 ; Check for mutual exclusion
+ je @@Exit
+ mov [BYTE RtcInside],1
+ sti ; Re-enable interrupts
+ NEWSTK RtcStack ; Switch to local stack
+ call [CPTR _PM_rtcHandler]
+ RESTSTK RtcStack ; Restore previous stack
+ mov [BYTE RtcInside],0
+
+@@Exit: pop _ax
+ out 70h,al ; Restore CMOS index register
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_keyISR - keyboard interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the keyboard interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. However we ensure within this routine
+; mutual exclusion to the keyboard handling routine.
+;----------------------------------------------------------------------------
+cprocfar _PM_keyISR
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+
+ cmp [BYTE KyInside],1 ; Check for mutual exclusion
+ je @@Reissued
+
+ mov [BYTE KyInside],1
+ NEWSTK KyStack ; Switch to local stack
+ call [CPTR _PM_keyHandler] ; Call C code
+ RESTSTK KyStack ; Restore previous stack
+ mov [BYTE KyInside],0
+
+@@Exit: popad ; Restore all extended registers
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+; When the BIOS keyboard handler needs to change the SHIFT status lights
+; on the keyboard, in the process of doing this the keyboard controller
+; re-issues another interrupt, while the current handler is still executing.
+; If we recieve another interrupt while still handling the current one,
+; then simply chain directly to the previous handler.
+;
+; Note that for most DOS extenders, the real mode interrupt handler that we
+; install takes care of this for us.
+
+@@Reissued:
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealKey]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+else
+ pushf
+ifdef USE_NASM
+ call far dword [_PM_prevKey]
+else
+ call [_PM_prevKey]
+endif
+endif
+ jmp @@Exit
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_chainPrevkey - Chain to previous key interrupt and return
+;----------------------------------------------------------------------------
+; Chains to the previous key interrupt routine and returns control
+; back to the high level interrupt handler.
+;----------------------------------------------------------------------------
+cprocstart PM_chainPrevKey
+
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealKey]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+ ret
+else
+
+; YIKES! For some strange reason, when execution returns from the
+; previous keyboard handler, interrupts are re-enabled!! Since we expect
+; interrupts to remain off during the duration of our handler, this can
+; cause havoc. However our stack macros always turn off interrupts, so they
+; will be off when we exit this routine. Obviously there is a tiny weeny
+; window when interrupts will be enabled, but there is nothing we can
+; do about this.
+
+ SWAPSTK KyStack ; Swap back to previous stack
+ pushf ; Push flags on stack to simulate interrupt
+ifdef USE_NASM
+ call far dword [_PM_prevKey]
+else
+ call [_PM_prevKey]
+endif
+ SWAPSTK KyStack ; Swap back to C stack again
+ ret
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_key15ISR - Int 15h keyboard interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; This routine gets called if we have been called to handle the Int 15h
+; keyboard interrupt callout from real mode.
+;
+; Entry: AX - Hardware scan code to process
+; Exit: AX - Hardware scan code to process (0 to ignore)
+;----------------------------------------------------------------------------
+cprocfar _PM_key15ISR
+
+ push ds
+ push es
+ LOAD_DS
+ cmp ah,4Fh
+ jnz @@NotOurs ; Quit if not keyboard callout
+
+ pushad
+ cld ; Clear direction flag
+ xor ah,ah ; AX := scan code
+ NEWSTK Ky15Stack ; Switch to local stack
+ push _ax
+ call [CPTR _PM_key15Handler] ; Call C code
+ _add sp,2,4
+ RESTSTK Ky15Stack ; Restore previous stack
+ test ax,ax
+ jz @@1
+ stc ; Set carry to process as normal
+ jmp @@2
+@@1: clc ; Clear carry to ignore scan code
+@@2: popad
+ jmp @@Exit ; We are done
+
+@@NotOurs:
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealKey15]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+else
+ pushf
+ifdef USE_NASM
+ call far dword [_PM_prevKey15]
+else
+ call [_PM_prevKey15]
+endif
+endif
+@@Exit: pop es
+ pop ds
+ retf 4
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_breakISR - Control Break interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the Ctrl-Break interrupt. We simply set
+; the Ctrl-Break flag to a 1 and leave (note that this is accessed through
+; a far pointer, as it may well be located in conventional memory).
+;----------------------------------------------------------------------------
+cprocfar _PM_breakISR
+
+ sti
+ push ds ; Save value of DS
+ push es
+ push _bx
+
+ LOAD_DS ; Load DS register
+ mov ebx,[_PM_ctrlBPtr]
+ mov [UINT _ES _bx],1
+
+; Run alternate break handler code if installed
+
+ cmp [CPTR _PM_breakHandler],0
+ je @@Exit
+
+ pushad
+ mov _ax,1
+ push _ax
+ call [CPTR _PM_breakHandler] ; Call C code
+ pop _ax
+ popad
+
+@@Exit: pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_ctrlBreakHit(int clearFlag)
+;----------------------------------------------------------------------------
+; Returns the current state of the Ctrl-Break flag and possibly clears it.
+;----------------------------------------------------------------------------
+cprocstart PM_ctrlBreakHit
+
+ ARG clearFlag:UINT
+
+ enter_c
+ pushf ; Save interrupt status
+ push es
+ mov ebx,[_PM_ctrlBPtr]
+ cli ; No interrupts thanks!
+ mov _ax,[_ES _bx]
+ test [BYTE clearFlag],1
+ jz @@Done
+ mov [UINT _ES _bx],0
+
+@@Done: pop es
+ popf ; Restore interrupt status
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_ctrlCISR - Control Break interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the Ctrl-C interrupt. We simply set
+; the Ctrl-C flag to a 1 and leave (note that this is accessed through
+; a far pointer, as it may well be located in conventional memory).
+;----------------------------------------------------------------------------
+cprocfar _PM_ctrlCISR
+
+ sti
+ push ds ; Save value of DS
+ push es
+ push _bx
+
+ LOAD_DS ; Load DS register
+ mov ebx,[_PM_ctrlCPtr]
+ mov [UINT _ES _bx],1
+
+; Run alternate break handler code if installed
+
+ cmp [CPTR _PM_breakHandler],0
+ je @@Exit
+
+ pushad
+ mov _ax,0
+ push _ax
+ call [CPTR _PM_breakHandler] ; Call C code
+ pop _ax
+ popad
+
+@@Exit: pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+ iretd
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_ctrlCHit(int clearFlag)
+;----------------------------------------------------------------------------
+; Returns the current state of the Ctrl-C flag and possibly clears it.
+;----------------------------------------------------------------------------
+cprocstart PM_ctrlCHit
+
+ ARG clearFlag:UINT
+
+ enter_c
+ pushf ; Save interrupt status
+ push es
+ mov ebx,[_PM_ctrlCPtr]
+ cli ; No interrupts thanks!
+ mov _ax,[_ES _bx]
+ test [BYTE clearFlag],1
+ jz @@Done
+ mov [UINT _ES _bx],0
+
+@@Done:
+ pop es
+ popf ; Restore interrupt status
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_criticalISR - Control Error handler interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Interrupt handler for the MSDOS Critical Error interrupt, to dispatch
+; control to high level C based subroutines. We save the state of all
+; registers in this routine, and switch to a local stack. We also pass
+; the values of the AX and DI registers to the as pointers, so that the
+; values can be modified before returning to MSDOS.
+;----------------------------------------------------------------------------
+cprocfar _PM_criticalISR
+
+ sti
+ push ds ; Save value of DS
+ push es
+ push _bx ; Save register values changed
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+ mov ebx,[_PM_critPtr]
+ mov [_ES _bx],ax
+ mov [_ES _bx+2],di
+
+; Run alternate critical handler code if installed
+
+ cmp [CPTR _PM_critHandler],0
+ je @@NoAltHandler
+
+ pushad
+ push _di
+ push _ax
+ call [CPTR _PM_critHandler] ; Call C code
+ _add sp,4,8
+ popad
+
+ pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+@@NoAltHandler:
+ mov ax,3 ; Tell MSDOS to fail the operation
+ pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_criticalError(int *axVal,int *diVal,int clearFlag)
+;----------------------------------------------------------------------------
+; Returns the current state of the critical error flags, and the values that
+; MSDOS passed in the AX and DI registers to our handler.
+;----------------------------------------------------------------------------
+cprocstart PM_criticalError
+
+ ARG axVal:DPTR, diVal:DPTR, clearFlag:UINT
+
+ enter_c
+ pushf ; Save interrupt status
+ push es
+ mov ebx,[_PM_critPtr]
+ cli ; No interrupts thanks!
+ xor _ax,_ax
+ xor _di,_di
+ mov ax,[_ES _bx]
+ mov di,[_ES _bx+2]
+ test [BYTE clearFlag],1
+ jz @@NoClear
+ mov [ULONG _ES _bx],0
+@@NoClear:
+ _les _bx,[axVal]
+ mov [_ES _bx],_ax
+ _les _bx,[diVal]
+ mov [_ES _bx],_di
+ pop es
+ popf ; Restore interrupt status
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setMouseHandler(int mask, PM_mouseHandler mh)
+;----------------------------------------------------------------------------
+cprocstart _PM_setMouseHandler
+
+ ARG mouseMask:UINT
+
+ enter_c
+ push es
+
+ mov ax,0Ch ; AX := Function 12 - install interrupt sub
+ mov _cx,[mouseMask] ; CX := mouse mask
+ mov _dx,offset _PM_mouseISR
+ push cs
+ pop es ; ES:_DX -> mouse handler
+ int 33h ; Call mouse driver
+
+ pop es
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_mousePMCB(void)
+;----------------------------------------------------------------------------
+; Mouse realmode callback routine. Upon entry to this routine, we recieve
+; the following from the DPMI server:
+;
+; Entry: DS:_SI -> Real mode stack at time of call
+; ES:_DI -> Real mode register data structure
+; SS:_SP -> Locked protected mode stack to use
+;----------------------------------------------------------------------------
+cprocfar _PM_mousePMCB
+
+ pushad
+ mov eax,[es:_di+1Ch] ; Load register values from real mode
+ mov ebx,[es:_di+10h]
+ mov ecx,[es:_di+18h]
+ mov edx,[es:_di+14h]
+ mov esi,[es:_di+04h]
+ mov edi,[es:_di]
+ call _PM_mouseISR ; Call the mouse handler
+ popad
+
+ mov ax,[ds:_si]
+ mov [es:_di+2Ah],ax ; Plug in return IP address
+ mov ax,[ds:_si+2]
+ mov [es:_di+2Ch],ax ; Plug in return CS value
+ add [WORD es:_di+2Eh],4 ; Remove return address from stack
+ iret ; Go back to real mode!
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_int10PMCB(void)
+;----------------------------------------------------------------------------
+; int10 realmode callback routine. Upon entry to this routine, we recieve
+; the following from the DPMI server:
+;
+; Entry: DS:ESI -> Real mode stack at time of call
+; ES:EDI -> Real mode register data structure
+; SS:ESP -> Locked protected mode stack to use
+;----------------------------------------------------------------------------
+cprocfar _PM_int10PMCB
+
+ pushad
+ push ds
+ push es
+ push fs
+
+ pushfd
+ pop eax
+ mov [es:edi+20h],ax ; Save return flag status
+ mov ax,[ds:esi]
+ mov [es:edi+2Ah],ax ; Plug in return IP address
+ mov ax,[ds:esi+2]
+ mov [es:edi+2Ch],ax ; Plug in return CS value
+ add [WORD es:edi+2Eh],4 ; Remove return address from stack
+
+; Call the install int10 handler in protected mode. This function gets called
+; with DS set to the current data selector, and ES:EDI pointing the the
+; real mode DPMI register structure at the time of the interrupt. The
+; handle must be written in assembler to be able to extract the real mode
+; register values from the structure
+
+ push es
+ pop fs ; FS:EDI -> real mode registers
+ LOAD_DS
+ NEWSTK Int10Stack ; Switch to local stack
+
+ call [_PM_int10Handler]
+
+ RESTSTK Int10Stack ; Restore previous stack
+ pop fs
+ pop es
+ pop ds
+ popad
+ iret ; Go back to real mode!
+
+cprocend
+
+cpublic _PM_pmsmxCodeEnd
+
+endcodeseg _pmsmx
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/_vflat.asm b/board/MAI/bios_emulator/scitech/src/pm/smx/_vflat.asm
new file mode 100644
index 0000000000..34985a9d8b
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/_vflat.asm
@@ -0,0 +1,652 @@
+;****************************************************************************
+;*
+;* 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.
+;*
+;* ========================================================================
+;*
+;* Based on original code Copyright 1994 Otto Chrons
+;*
+;* Language: 80386 Assembler, TASM 4.0 or later
+;* Environment: IBM PC 32 bit protected mode
+;*
+;* Description: Low level page fault handler for virtual linear framebuffers.
+;*
+;****************************************************************************
+
+ IDEAL
+ JUMPS
+
+include "scitech.mac" ; Memory model macros
+
+header _vflat ; Set up memory model
+
+VFLAT_START EQU 0F0000000h
+VFLAT_END EQU 0F03FFFFFh
+PAGE_PRESENT EQU 1
+PAGE_NOTPRESENT EQU 0
+PAGE_READ EQU 0
+PAGE_WRITE EQU 2
+
+ifdef DOS4GW
+
+;----------------------------------------------------------------------------
+; DOS4G/W flat linear framebuffer emulation.
+;----------------------------------------------------------------------------
+
+begdataseg _vflat
+
+; Near pointers to the page directory base and our page tables. All of
+; this memory is always located in the first Mb of DOS memory.
+
+PDBR dd 0 ; Page directory base register (CR3)
+accessPageAddr dd 0
+accessPageTable dd 0
+
+; CauseWay page directory & 1st page table linear addresses.
+
+CauseWayDIRLinear dd 0
+CauseWay1stLinear dd 0
+
+; Place to store a copy of the original Page Table Directory before we
+; intialised our virtual buffer code.
+
+pageDirectory: resd 1024 ; Saved page table directory
+
+ValidCS dw 0 ; Valid CS for page faults
+Ring0CS dw 0 ; Our ring 0 code selector
+LastPage dd 0 ; Last page we mapped in
+BankFuncBuf: resb 101 ; Place to store bank switch code
+BankFuncPtr dd offset BankFuncBuf
+
+INT14Gate:
+INT14Offset dd 0 ; eip of original vector
+INT14Selector dw 0 ; cs of original vector
+
+ cextern _PM_savedDS,USHORT
+ cextern VF_haveCauseWay,BOOL
+
+enddataseg _vflat
+
+begcodeseg _vflat ; Start of code segment
+
+ cextern VF_malloc,FPTR
+
+;----------------------------------------------------------------------------
+; PF_handler64k - Page fault handler for 64k banks
+;----------------------------------------------------------------------------
+; The handler below is a 32 bit ring 0 page fault handler. It receives
+; control immediately after any page fault or after an IRQ6 (hardware
+; interrupt). This provides the fastest possible handling of page faults
+; since it jump directly here. If this is a page fault, the number
+; immediately on the stack will be an error code, at offset 4 will be
+; the eip of the faulting instruction, at offset 8 will be the cs of the
+; faulting instruction. If it is a hardware interrupt, it will not have
+; the error code and the eflags will be at offset 8.
+;----------------------------------------------------------------------------
+cprocfar PF_handler64k
+
+; Check if this is a processor exeception or a page fault
+
+ push eax
+ mov ax,[cs:ValidCS] ; Use CS override to access data
+ cmp [ss:esp+12],ax ; Is this a page fault?
+ jne @@ToOldHandler ; Nope, jump to the previous handler
+
+; Get address of page fault and check if within our handlers range
+
+ mov eax,cr2 ; EBX has page fault linear address
+ cmp eax,VFLAT_START ; Is the fault less than ours?
+ jb @@ToOldHandler ; Yep, go to previous handler
+ cmp eax,VFLAT_END ; Is the fault more than ours?
+ jae @@ToOldHandler ; Yep, go to previous handler
+
+; This is our page fault, so we need to handle it
+
+ pushad
+ push ds
+ push es
+ mov ebx,eax ; EBX := page fault address
+ and ebx,invert 0FFFFh ; Mask to 64k bank boundary
+ mov ds,[cs:_PM_savedDS]; Load segment registers
+ mov es,[cs:_PM_savedDS]
+
+; Map in the page table for our virtual framebuffer area for modification
+
+ mov edi,[PDBR] ; EDI points to page directory
+ mov edx,ebx ; EDX = linear address
+ shr edx,22 ; EDX = offset to page directory
+ mov edx,[edx*4+edi] ; EDX = physical page table address
+ mov eax,edx
+ mov edx,[accessPageTable]
+ or eax,7
+ mov [edx],eax
+ mov eax,cr3
+ mov cr3,eax ; Update page table cache
+
+; Mark all pages valid for the new page fault area
+
+ mov esi,ebx ; ESI := linear address for page
+ shr esi,10
+ and esi,0FFFh ; Offset into page table
+ add esi,[accessPageAddr]
+ifdef USE_NASM
+%assign off 0
+%rep 16
+ or [DWORD esi+off],0000000001h ; Enable pages
+%assign off off+4
+%endrep
+else
+off = 0
+REPT 16
+ or [DWORD esi+off],0000000001h ; Enable pages
+off = off+4
+ENDM
+endif
+
+; Mark all pages invalid for the previously mapped area
+
+ xchg esi,[LastPage] ; Save last page for next page fault
+ test esi,esi
+ jz @@DoneMapping ; Dont update if first time round
+ifdef USE_NASM
+%assign off 0
+%rep 16
+ or [DWORD esi+off],0FFFFFFFEh ; Disable pages
+%assign off off+4
+%endrep
+else
+off = 0
+REPT 16
+ and [DWORD esi+off],0FFFFFFFEh ; Disable pages
+off = off+4
+ENDM
+endif
+
+@@DoneMapping:
+ mov eax,cr3
+ mov cr3,eax ; Flush the TLB
+
+; Now program the new SuperVGA starting bank address
+
+ mov eax,ebx ; EAX := page fault address
+ shr eax,16
+ and eax,0FFh ; Mask to 0-255
+ call [BankFuncPtr] ; Call the bank switch function
+
+ pop es
+ pop ds
+ popad
+ pop eax
+ add esp,4 ; Pop the error code from stack
+ iretd ; Return to faulting instruction
+
+@@ToOldHandler:
+ pop eax
+ifdef USE_NASM
+ jmp far dword [cs:INT14Gate]; Chain to previous handler
+else
+ jmp [FWORD cs:INT14Gate]; Chain to previous handler
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PF_handler4k - Page fault handler for 4k banks
+;----------------------------------------------------------------------------
+; The handler below is a 32 bit ring 0 page fault handler. It receives
+; control immediately after any page fault or after an IRQ6 (hardware
+; interrupt). This provides the fastest possible handling of page faults
+; since it jump directly here. If this is a page fault, the number
+; immediately on the stack will be an error code, at offset 4 will be
+; the eip of the faulting instruction, at offset 8 will be the cs of the
+; faulting instruction. If it is a hardware interrupt, it will not have
+; the error code and the eflags will be at offset 8.
+;----------------------------------------------------------------------------
+cprocfar PF_handler4k
+
+; Fill in when we have tested all the 64Kb code
+
+ifdef USE_NASM
+ jmp far dword [cs:INT14Gate]; Chain to previous handler
+else
+ jmp [FWORD cs:INT14Gate]; Chain to previous handler
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void InstallFaultHandler(void *baseAddr,int bankSize)
+;----------------------------------------------------------------------------
+; Installes the page fault handler directly int the interrupt descriptor
+; table for maximum performance. This of course requires ring 0 access,
+; but none of this stuff will run without ring 0!
+;----------------------------------------------------------------------------
+cprocstart InstallFaultHandler
+
+ ARG baseAddr:ULONG, bankSize:UINT
+
+ enter_c
+
+ mov [DWORD LastPage],0 ; No pages have been mapped
+ mov ax,cs
+ mov [ValidCS],ax ; Save CS value for page faults
+
+; Put address of our page fault handler into the IDT directly
+
+ sub esp,6 ; Allocate space on stack
+ifdef USE_NASM
+ sidt [ss:esp] ; Store pointer to IDT
+else
+ sidt [FWORD ss:esp] ; Store pointer to IDT
+endif
+ pop ax ; add esp,2
+ pop eax ; Absolute address of IDT
+ add eax,14*8 ; Point to Int #14
+
+; Note that Interrupt gates do not have the high and low word of the
+; offset in adjacent words in memory, there are 4 bytes separating them.
+
+ mov ecx,[eax] ; Get cs and low 16 bits of offset
+ mov edx,[eax+6] ; Get high 16 bits of offset in dx
+ shl edx,16
+ mov dx,cx ; edx has offset
+ mov [INT14Offset],edx ; Save offset
+ shr ecx,16
+ mov [INT14Selector],cx ; Save original cs
+ mov [eax+2],cs ; Install new cs
+ mov edx,offset PF_handler64k
+ cmp [UINT bankSize],4
+ jne @@1
+ mov edx,offset PF_handler4k
+@@1: mov [eax],dx ; Install low word of offset
+ shr edx,16
+ mov [eax+6],dx ; Install high word of offset
+
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void RemoveFaultHandler(void)
+;----------------------------------------------------------------------------
+; Closes down the virtual framebuffer services and restores the previous
+; page fault handler.
+;----------------------------------------------------------------------------
+cprocstart RemoveFaultHandler
+
+ enter_c
+
+; Remove page fault handler from IDT
+
+ sub esp,6 ; Allocate space on stack
+ifdef USE_NASM
+ sidt [ss:esp] ; Store pointer to IDT
+else
+ sidt [FWORD ss:esp] ; Store pointer to IDT
+endif
+
+ pop ax ; add esp,2
+ pop eax ; Absolute address of IDT
+ add eax,14*8 ; Point to Int #14
+ mov cx,[INT14Selector]
+ mov [eax+2],cx ; Restore original CS
+ mov edx,[INT14Offset]
+ mov [eax],dx ; Install low word of offset
+ shr edx,16
+ mov [eax+6],dx ; Install high word of offset
+
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void InstallBankFunc(int codeLen,void *bankFunc)
+;----------------------------------------------------------------------------
+; Installs the bank switch function by relocating it into our data segment
+; and making it into a callable function. We do it this way to make the
+; code identical to the way that the VflatD devices work under Windows.
+;----------------------------------------------------------------------------
+cprocstart InstallBankFunc
+
+ ARG codeLen:UINT, bankFunc:DPTR
+
+ enter_c
+
+ mov esi,[bankFunc] ; Copy the code into buffer
+ mov edi,offset BankFuncBuf
+ mov ecx,[codeLen]
+ rep movsb
+ mov [BYTE edi],0C3h ; Terminate the function with a near ret
+
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int InitPaging(void)
+;----------------------------------------------------------------------------
+; Initializes paging system. If paging is not enabled, builds a page table
+; directory and page tables for physical memory
+;
+; Exit: 0 - Successful
+; -1 - Couldn't initialize paging mechanism
+;----------------------------------------------------------------------------
+cprocstart InitPaging
+
+ push ebx
+ push ecx
+ push edx
+ push esi
+ push edi
+
+; Are we running under CauseWay?
+
+ mov ax,0FFF9h
+ int 31h
+ jc @@NotCauseway
+ cmp ecx,"CAUS"
+ jnz @@NotCauseway
+ cmp edx,"EWAY"
+ jnz @@NotCauseway
+
+ mov [BOOL VF_haveCauseWay],1
+ mov [CauseWayDIRLinear],esi
+ mov [CauseWay1stLinear],edi
+
+; Check for DPMI
+
+ mov ax,0ff00h
+ push es
+ int 31h
+ pop es
+ shr edi,2
+ and edi,3
+ cmp edi,2
+ jz @@ErrExit ; Not supported under DPMI
+
+ mov eax,[CauseWayDIRLinear]
+ jmp @@CopyCR3
+
+@@NotCauseway:
+ mov ax,cs
+ test ax,3 ; Which ring are we running
+ jnz @@ErrExit ; Needs zero ring to access
+ ; page tables (CR3)
+ mov eax,cr0 ; Load CR0
+ test eax,80000000h ; Is paging enabled?
+ jz @@ErrExit ; No, we must have paging!
+
+ mov eax,cr3 ; Load directory address
+ and eax,0FFFFF000h
+
+@@CopyCR3:
+ mov [PDBR],eax ; Save it
+ mov esi,eax
+ mov edi,offset pageDirectory
+ mov ecx,1024
+ cld
+ rep movsd ; Copy the original page table directory
+ cmp [DWORD accessPageAddr],0; Check if we have allocated page
+ jne @@HaveRealMem ; table already (we cant free it)
+
+ mov eax,0100h ; DPMI DOS allocate
+ mov ebx,8192/16
+ int 31h ; Allocate 8192 bytes
+ and eax,0FFFFh
+ shl eax,4 ; EAX points to newly allocated memory
+ add eax,4095
+ and eax,0FFFFF000h ; Page align
+ mov [accessPageAddr],eax
+
+@@HaveRealMem:
+ mov eax,[accessPageAddr] ; EAX -> page table in 1st Mb
+ shr eax,12
+ and eax,3FFh ; Page table offset
+ shl eax,2
+ cmp [BOOL VF_haveCauseWay],0
+ jz @@NotCW0
+ mov ebx,[CauseWay1stLinear]
+ jmp @@Put1st
+
+@@NotCW0:
+ mov ebx,[PDBR]
+ mov ebx,[ebx]
+ and ebx,0FFFFF000h ; Page table for 1st megabyte
+
+@@Put1st:
+ add eax,ebx
+ mov [accessPageTable],eax
+ sub eax,eax ; No error
+ jmp @@Exit
+
+@@ErrExit:
+ mov eax,-1
+
+@@Exit: pop edi
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void ClosePaging(void)
+;----------------------------------------------------------------------------
+; Closes the paging system
+;----------------------------------------------------------------------------
+cprocstart ClosePaging
+
+ push eax
+ push ecx
+ push edx
+ push esi
+ push edi
+
+ mov eax,[accessPageAddr]
+ call AccessPage ; Restore AccessPage mapping
+ mov edi,[PDBR]
+ mov esi,offset pageDirectory
+ mov ecx,1024
+ cld
+ rep movsd ; Restore the original page table directory
+
+@@Exit: pop edi
+ pop esi
+ pop edx
+ pop ecx
+ pop eax
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; long AccessPage(long phys)
+;----------------------------------------------------------------------------
+; Maps a known page to given physical memory
+; Entry: EAX - Physical memory
+; Exit: EAX - Linear memory address of mapped phys mem
+;----------------------------------------------------------------------------
+cprocstatic AccessPage
+
+ push edx
+ mov edx,[accessPageTable]
+ or eax,7
+ mov [edx],eax
+ mov eax,cr3
+ mov cr3,eax ; Update page table cache
+ mov eax,[accessPageAddr]
+ pop edx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; long GetPhysicalAddress(long linear)
+;----------------------------------------------------------------------------
+; Returns the physical address of linear address
+; Entry: EAX - Linear address to convert
+; Exit: EAX - Physical address
+;----------------------------------------------------------------------------
+cprocstatic GetPhysicalAddress
+
+ push ebx
+ push edx
+ mov edx,eax
+ shr edx,22 ; EDX is the directory offset
+ mov ebx,[PDBR]
+ mov edx,[edx*4+ebx] ; Load page table address
+ push eax
+ mov eax,edx
+ call AccessPage ; Access the page table
+ mov edx,eax
+ pop eax
+ shr eax,12
+ and eax,03FFh ; EAX offset into page table
+ mov eax,[edx+eax*4] ; Load physical address
+ and eax,0FFFFF000h
+ pop edx
+ pop ebx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void CreatePageTable(long pageDEntry)
+;----------------------------------------------------------------------------
+; Creates a page table for specific address (4MB)
+; Entry: EAX - Page directory entry (top 10-bits of address)
+;----------------------------------------------------------------------------
+cprocstatic CreatePageTable
+
+ push ebx
+ push ecx
+ push edx
+ push edi
+ mov ebx,eax ; Save address
+ mov eax,8192
+ push eax
+ call VF_malloc ; Allocate page table directory
+ add esp,4
+ add eax,0FFFh
+ and eax,0FFFFF000h ; Page align (4KB)
+ mov edi,eax ; Save page table linear address
+ sub eax,eax ; Fill with zero
+ mov ecx,1024
+ cld
+ rep stosd ; Clear page table
+ sub edi,4096
+ mov eax,edi
+ call GetPhysicalAddress
+ mov edx,[PDBR]
+ or eax,7 ; Present/write/user bit
+ mov [edx+ebx*4],eax ; Save physical address into page directory
+ mov eax,cr3
+ mov cr3,eax ; Update page table cache
+ pop edi
+ pop edx
+ pop ecx
+ pop ebx
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void MapPhysical2Linear(ulong pAddr, ulong lAddr, int pages, int flags);
+;----------------------------------------------------------------------------
+; Maps physical memory into linear memory
+; Entry: pAddr - Physical address
+; lAddr - Linear address
+; pages - Number of 4K pages to map
+; flags - Page flags
+; bit 0 = present
+; bit 1 = Read(0)/Write(1)
+;----------------------------------------------------------------------------
+cprocstart MapPhysical2Linear
+
+ ARG pAddr:ULONG, lAddr:ULONG, pages:UINT, pflags:UINT
+
+ enter_c
+
+ and [ULONG pAddr],0FFFFF000h; Page boundary
+ and [ULONG lAddr],0FFFFF000h; Page boundary
+ mov ecx,[pflags]
+ and ecx,11b ; Just two bits
+ or ecx,100b ; Supervisor bit
+ mov [pflags],ecx
+
+ mov edx,[lAddr]
+ shr edx,22 ; EDX = Directory
+ mov esi,[PDBR]
+ mov edi,[pages] ; EDI page count
+ mov ebx,[lAddr]
+
+@@CreateLoop:
+ mov ecx,[esi+edx*4] ; Load page table address
+ test ecx,1 ; Is it present?
+ jnz @@TableOK
+ mov eax,edx
+ call CreatePageTable ; Create a page table
+@@TableOK:
+ mov eax,ebx
+ shr eax,12
+ and eax,3FFh
+ sub eax,1024
+ neg eax ; EAX = page count in this table
+ inc edx ; Next table
+ mov ebx,0 ; Next time we'll map 1K pages
+ sub edi,eax ; Subtract mapped pages from page count
+ jns @@CreateLoop ; Create more tables if necessary
+
+ mov ecx,[pages] ; ECX = Page count
+ mov esi,[lAddr]
+ shr esi,12 ; Offset part isn't needed
+ mov edi,[pAddr]
+@@MappingLoop:
+ mov eax,esi
+ shr eax,10 ; EAX = offset to page directory
+ mov ebx,[PDBR]
+ mov eax,[eax*4+ebx] ; EAX = page table address
+ call AccessPage
+ mov ebx,esi
+ and ebx,3FFh ; EBX = offset to page table
+ mov edx,edi
+ add edi,4096 ; Next physical address
+ inc esi ; Next linear page
+ or edx,[pflags] ; Update flags...
+ mov [eax+ebx*4],edx ; Store page table entry
+ loop @@MappingLoop
+ mov eax,cr3
+ mov cr3,eax ; Update page table cache
+
+ leave_c
+ ret
+
+cprocend
+
+endcodeseg _vflat
+
+endif
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/smx/cpuinfo.c
new file mode 100644
index 0000000000..5447e574ec
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/cpuinfo.c
@@ -0,0 +1,72 @@
+/****************************************************************************
+*
+* 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: 32-bit SMX embedded systems development.
+*
+* Description: SMX specific code for the CPU detection module.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* External timing function */
+
+void __ZTimerInit(void);
+
+/****************************************************************************
+REMARKS:
+Do nothing for DOS because we don't have thread priorities.
+****************************************************************************/
+#define SetMaxThreadPriority() 0
+
+/****************************************************************************
+REMARKS:
+Do nothing for DOS because we don't have thread priorities.
+****************************************************************************/
+#define RestoreThreadPriority(i) (void)(i)
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ ulong resolution;
+
+ __ZTimerInit();
+ ULZTimerResolution(&resolution);
+ freq->low = (ulong)(10000000000.0 / resolution);
+ freq->high = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ (t)->low = ULZReadTime() * 10000L; \
+ (t)->high = 0; \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/event.c b/board/MAI/bios_emulator/scitech/src/pm/smx/event.c
new file mode 100644
index 0000000000..fc13bbbe42
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/event.c
@@ -0,0 +1,368 @@
+/****************************************************************************
+*
+* 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: 32-bit SMX embedded systems development
+*
+* Description: 32-bit SMX implementation for the SciTech cross platform
+* event library.
+*
+****************************************************************************/
+
+#include "smx/ps2mouse.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+ibool _VARAPI _EVT_useEvents = true; /* True to use event handling */
+ibool _VARAPI _EVT_installed = 0; /* Event handers installed? */
+uchar _VARAPI *_EVT_biosPtr = NULL; /* Pointer to the BIOS data area */
+static ibool haveMouse = false; /* True if we have a mouse */
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* External assembler functions */
+
+void EVTAPI _EVT_pollJoystick(void);
+uint EVTAPI _EVT_disableInt(void);
+uint EVTAPI _EVT_restoreInt(uint flags);
+void EVTAPI _EVT_codeStart(void);
+void EVTAPI _EVT_codeEnd(void);
+void EVTAPI _EVT_cCodeStart(void);
+void EVTAPI _EVT_cCodeEnd(void);
+int EVTAPI _EVT_getKeyCode(void);
+int EVTAPI EVT_rdinx(int port,int index);
+void EVTAPI EVT_wrinx(int port,int index,int value);
+
+/****************************************************************************
+REMARKS:
+Do nothing for DOS, because we are fully interrupt driven.
+****************************************************************************/
+#define _EVT_pumpMessages()
+
+/****************************************************************************
+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)
+{
+ return (ulong)PM_getLong(_EVT_biosPtr+0x6C) * 55UL;
+}
+
+/****************************************************************************
+REMARKS:
+Include generic raw scancode keyboard module.
+****************************************************************************/
+#include "common/keyboard.c"
+
+/****************************************************************************
+REMARKS:
+Determines if we have a mouse attached and functioning.
+****************************************************************************/
+static ibool detectMouse(void)
+{
+ return(ps2Query());
+}
+
+/****************************************************************************
+PARAMETERS:
+what - Event code
+message - Event message
+x,y - Mouse 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.
+
+NOTE: Interrupts MUST be OFF while this routine is called to ensure we have
+ mutually exclusive access to our internal data structures for
+ interrupt driven systems (like under DOS).
+****************************************************************************/
+static void addMouseEvent(
+ uint what,
+ uint message,
+ int x,
+ int y,
+ int mickeyX,
+ int mickeyY,
+ uint but_stat)
+{
+ event_t evt;
+
+ if (EVT.count < EVENTQSIZE) {
+ /* Save information in event record. */
+ evt.when = _EVT_getTicks();
+ evt.what = what;
+ evt.message = message;
+ evt.modifiers = but_stat;
+ evt.where_x = x; /* Save mouse event position */
+ evt.where_y = y;
+ evt.relative_x = mickeyX;
+ evt.relative_y = mickeyY;
+ evt.modifiers |= EVT.keyModifiers;
+ addEvent(&evt); /* Add to tail of event queue */
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+mask - Event mask
+butstate - Button state
+x - Mouse x coordinate
+y - Mouse y coordinate
+
+REMARKS:
+Mouse event handling routine. This gets called when a mouse event occurs,
+and we call the addMouseEvent() routine to add the appropriate mouse event
+to the event queue.
+
+Note: Interrupts are ON when this routine is called by the mouse driver code.
+//AM: NOTE: This function has not actually been ported from DOS yet and should not
+//AM: be installed until it is.
+****************************************************************************/
+static void EVTAPI mouseISR(
+ uint mask,
+ uint butstate,
+ int x,
+ int y,
+ int mickeyX,
+ int mickeyY)
+{
+ RMREGS regs;
+ uint ps;
+
+ if (mask & 1) {
+ /* Save the current mouse coordinates */
+ EVT.mx = x; EVT.my = y;
+
+ /* If the last event was a movement event, then modify the last
+ * event rather than post a new one, so that the queue will not
+ * become saturated. Before we modify the data structures, we
+ * MUST ensure that interrupts are off.
+ */
+ ps = _EVT_disableInt();
+ if (EVT.oldMove != -1) {
+ EVT.evtq[EVT.oldMove].where_x = x; /* Modify existing one */
+ EVT.evtq[EVT.oldMove].where_y = y;
+ EVT.evtq[EVT.oldMove].relative_x += mickeyX;
+ EVT.evtq[EVT.oldMove].relative_y += mickeyY;
+ }
+ else {
+ EVT.oldMove = EVT.freeHead; /* Save id of this move event */
+ addMouseEvent(EVT_MOUSEMOVE,0,x,y,mickeyX,mickeyY,butstate);
+ }
+ _EVT_restoreInt(ps);
+ }
+ if (mask & 0x2A) {
+ ps = _EVT_disableInt();
+ addMouseEvent(EVT_MOUSEDOWN,mask >> 1,x,y,0,0,butstate);
+ EVT.oldMove = -1;
+ _EVT_restoreInt(ps);
+ }
+ if (mask & 0x54) {
+ ps = _EVT_disableInt();
+ addMouseEvent(EVT_MOUSEUP,mask >> 2,x,y,0,0,butstate);
+ EVT.oldMove = -1;
+ _EVT_restoreInt(ps);
+ }
+ EVT.oldKey = -1;
+}
+
+/****************************************************************************
+REMARKS:
+Keyboard interrupt handler function.
+
+NOTE: Interrupts are OFF when this routine is called by the keyboard ISR,
+ and we leave them OFF the entire time. This has been modified to work
+ in conjunction with smx keyboard handler.
+****************************************************************************/
+static void EVTAPI keyboardISR(void)
+{
+ PM_chainPrevKey();
+ processRawScanCode(PM_inpb(0x60));
+ PM_outpb(0x20,0x20);
+}
+
+/****************************************************************************
+REMARKS:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort()
+{
+ EVT_exit();
+ PM_fatalError("Unhandled exception!");
+}
+
+/****************************************************************************
+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;
+
+ EVT.mouseMove = mouseMove;
+ _EVT_biosPtr = PM_getBIOSPointer();
+ EVT_resume();
+}
+
+/****************************************************************************
+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 EVTAPI EVT_resume(void)
+{
+ static int locked = 0;
+ int stat;
+ uchar mods;
+ PM_lockHandle lh;
+
+ if (_EVT_useEvents) {
+ /* Initialise the event queue and enable our interrupt handlers */
+ initEventQueue();
+ PM_setKeyHandler(keyboardISR);
+ if ((haveMouse = detectMouse()) != 0)
+ PM_setMouseHandler(0xFFFF,mouseISR);
+
+ /* Read the keyboard modifier flags from the BIOS to get the
+ * correct initialisation state. The only state we care about is
+ * the correct toggle state flags such as SCROLLLOCK, NUMLOCK and
+ * CAPSLOCK.
+ */
+ EVT.keyModifiers = 0;
+ mods = PM_getByte(_EVT_biosPtr+0x17);
+ if (mods & 0x10)
+ EVT.keyModifiers |= EVT_SCROLLLOCK;
+ if (mods & 0x20)
+ EVT.keyModifiers |= EVT_NUMLOCK;
+ if (mods & 0x40)
+ EVT.keyModifiers |= EVT_CAPSLOCK;
+
+ /* Lock all of the code and data used by our protected mode interrupt
+ * handling routines, so that it will continue to work correctly
+ * under real mode.
+ */
+ if (!locked) {
+ /* It is difficult to ensure that we lock our global data, so we
+ * do this by taking the address of a variable locking all data
+ * 2Kb on either side. This should properly cover the global data
+ * used by the module (the other alternative is to declare the
+ * variables in assembler, in which case we know it will be
+ * correct).
+ */
+ stat = !PM_lockDataPages(&EVT,sizeof(EVT),&lh);
+ stat |= !PM_lockDataPages(&_EVT_biosPtr,sizeof(_EVT_biosPtr),&lh);
+ stat |= !PM_lockCodePages((__codePtr)_EVT_cCodeStart,(int)_EVT_cCodeEnd-(int)_EVT_cCodeStart,&lh);
+ stat |= !PM_lockCodePages((__codePtr)_EVT_codeStart,(int)_EVT_codeEnd-(int)_EVT_codeStart,&lh);
+ if (stat) {
+ PM_fatalError("Page locking services failed - interrupt handling not safe!");
+ exit(1);
+ }
+ locked = 1;
+ }
+
+ _EVT_installed = true;
+ }
+}
+
+/****************************************************************************
+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)
+{
+ if (haveMouse) {
+ ps2MouseStop();
+ ps2MouseStart( 0, xRes, 0, yRes, -1, -1, -1);
+ }
+}
+
+/****************************************************************************
+REMARKS
+Modifes the mouse coordinates as necessary if scaling to OS coordinates,
+and sets the OS mouse cursor position.
+****************************************************************************/
+void _EVT_setMousePos(
+ int *x,
+ int *y)
+{
+ if (haveMouse)
+ ps2MouseMove(*x, *y);
+}
+
+/****************************************************************************
+REMARKS
+Suspends all of our event handling operations. This is also used to
+de-install the event handling code.
+****************************************************************************/
+void EVTAPI EVT_suspend(void)
+{
+ uchar mods;
+
+ if (_EVT_installed) {
+ PM_restoreKeyHandler();
+ if (haveMouse)
+ PM_restoreMouseHandler();
+
+ /* Set the keyboard modifier flags in the BIOS to our values */
+ EVT_allowLEDS(true);
+ mods = PM_getByte(_EVT_biosPtr+0x17) & ~0x70;
+ if (EVT.keyModifiers & EVT_SCROLLLOCK)
+ mods |= 0x10;
+ if (EVT.keyModifiers & EVT_NUMLOCK)
+ mods |= 0x20;
+ if (EVT.keyModifiers & EVT_CAPSLOCK)
+ mods |= 0x40;
+ PM_setByte(_EVT_biosPtr+0x17,mods);
+
+ /* Flag that we are no longer installed */
+ _EVT_installed = false;
+ }
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVTAPI EVT_exit(void)
+{
+ EVT_suspend();
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/smx/oshdr.h
new file mode 100644
index 0000000000..3ff8daa2a9
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/oshdr.h
@@ -0,0 +1,29 @@
+/****************************************************************************
+*
+* 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: 32-bit SMX embedded systems development.
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/pm.c b/board/MAI/bios_emulator/scitech/src/pm/smx/pm.c
new file mode 100644
index 0000000000..d6c95d688c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/pm.c
@@ -0,0 +1,1187 @@
+/****************************************************************************
+*
+* 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: 32 bit SMX embedded systems development.
+*
+* 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 "ztimerc.h"
+#include "event.h"
+#include "mtrr.h"
+#include "pm_help.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dos.h>
+#include <conio.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#include <sys/nearptr.h>
+#include <sys/stat.h>
+#else
+#include <direct.h>
+#endif
+#ifdef __BORLANDC__
+#pragma warn -par
+#endif
+
+/*--------------------------- Global variables ----------------------------*/
+
+typedef struct {
+ int oldMode;
+ int old50Lines;
+ } DOS_stateBuf;
+
+#define MAX_RM_BLOCKS 10
+
+static struct {
+ void *p;
+ uint tag;
+ } rmBlocks[MAX_RM_BLOCKS];
+
+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 */
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+ushort _VARAPI _PM_savedDS = 0;
+static ulong PDB = 0,*pPDB = NULL;
+static uint VXD_version = -1;
+
+/*----------------------------- Implementation ----------------------------*/
+
+ulong _ASMAPI _PM_getPDB(void);
+void _ASMAPI _PM_VxDCall(VXD_regs *regs,uint off,uint sel);
+
+/****************************************************************************
+REMARKS:
+External function to call the PMHELP helper VxD.
+****************************************************************************/
+void PMAPI PM_VxDCall(
+ VXD_regs *regs)
+{
+}
+
+/****************************************************************************
+RETURNS:
+BCD coded version number of the VxD, or 0 if not loaded (ie: 0x202 - 2.2)
+
+REMARKS:
+This function gets the version number for the VxD that we have connected to.
+****************************************************************************/
+uint PMAPI PMHELP_getVersion(void)
+{
+ return VXD_version = 0;
+}
+
+void PMAPI PM_init(void)
+{
+#ifndef REALMODE
+ MTRR_init();
+#endif
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+RETURNS:
+Error code describing the result.
+
+REMARKS:
+Function to enable write combining for the specified region of memory.
+****************************************************************************/
+int PMAPI PM_enableWriteCombine(
+ ulong base,
+ ulong size,
+ uint type)
+{
+#ifndef REALMODE
+ return MTRR_enableWriteCombine(base,size,type);
+#else
+ return PM_MTRR_NOT_SUPPORTED;
+#endif
+}
+
+ibool PMAPI PM_haveBIOSAccess(void)
+{ return false; }
+
+long PMAPI PM_getOSType(void)
+{ return _OS_SMX; }
+
+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 MGLOutput(char *);
+
+void PMAPI PM_fatalError(const char *msg)
+{
+ if (fatalErrorCleanup)
+ fatalErrorCleanup();
+ MGLOutput(msg);
+// No support for fprintf() under smx currently!
+// fprintf(stderr,"%s\n", msg);
+ 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;
+}
+
+int PMAPI PM_int386(int intno, PMREGS *in, PMREGS *out)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+ return PM_int386x(intno,in,out,&sregs);
+}
+
+/* Routines to set and get the real mode interrupt vectors, by making
+ * direct real mode calls to DOS and bypassing the DOS extenders API.
+ * This is the safest way to handle this, as some servers try to be
+ * smart about changing real mode vectors.
+ */
+
+void PMAPI _PM_getRMvect(int intno, long *realisr)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+
+ PM_saveDS();
+ regs.h.ah = 0x35;
+ regs.h.al = intno;
+ PM_int86x(0x21, &regs, &regs, &sregs);
+ *realisr = ((long)sregs.es << 16) | regs.x.bx;
+}
+
+void PMAPI _PM_setRMvect(int intno, long realisr)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+
+ PM_saveDS();
+ regs.h.ah = 0x25;
+ regs.h.al = intno;
+ sregs.ds = (int)(realisr >> 16);
+ regs.x.dx = (int)(realisr & 0xFFFF);
+ PM_int86x(0x21, &regs, &regs, &sregs);
+}
+
+void PMAPI _PM_addRealModeBlock(void *mem,uint tag)
+{
+ int i;
+
+ for (i = 0; i < MAX_RM_BLOCKS; i++) {
+ if (rmBlocks[i].p == NULL) {
+ rmBlocks[i].p = mem;
+ rmBlocks[i].tag = tag;
+ return;
+ }
+ }
+ PM_fatalError("To many real mode memory block allocations!");
+}
+
+uint PMAPI _PM_findRealModeBlock(void *mem)
+{
+ int i;
+
+ for (i = 0; i < MAX_RM_BLOCKS; i++) {
+ if (rmBlocks[i].p == mem)
+ return rmBlocks[i].tag;
+ }
+ PM_fatalError("Could not find prior real mode memory block allocation!");
+ return 0;
+}
+
+char * PMAPI PM_getCurrentPath(
+ char *path,
+ int maxLen)
+{
+ return getcwd(path,maxLen);
+}
+
+char PMAPI PM_getBootDrive(void)
+{ return 'C'; }
+
+const char * PMAPI PM_getVBEAFPath(void)
+{ return "c:\\"; }
+
+const char * PMAPI PM_getNucleusPath(void)
+{
+ static char path[256];
+ char *env;
+
+ if ((env = getenv("NUCLEUS_PATH")) != NULL)
+ return env;
+ return "c:\\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)
+{ return "SMX"; }
+
+const char * PMAPI PM_getMachineName(void)
+{ return "SMX"; }
+
+int PMAPI PM_kbhit(void)
+{
+ int hit;
+ event_t evt;
+
+ hit = EVT_peekNext(&evt,EVT_KEYDOWN | EVT_KEYREPEAT);
+ EVT_flush(~(EVT_KEYDOWN | EVT_KEYREPEAT));
+ return hit;
+}
+
+int PMAPI PM_getch(void)
+{
+ event_t evt;
+
+ EVT_halt(&evt,EVT_KEYDOWN);
+ return EVT_asciiCode(evt.message);
+}
+
+PM_HWND PMAPI PM_openConsole(PM_HWND hwndUser,int device,int xRes,int yRes,int bpp,ibool fullScreen)
+{
+ /* Not used for SMX */
+ (void)hwndUser;
+ (void)device;
+ (void)xRes;
+ (void)yRes;
+ (void)bpp;
+ (void)fullScreen;
+ return 0;
+}
+
+int PMAPI PM_getConsoleStateSize(void)
+{
+ return sizeof(DOS_stateBuf);
+}
+
+void PMAPI PM_saveConsoleState(void *stateBuf,PM_HWND hwndConsole)
+{
+ RMREGS regs;
+ DOS_stateBuf *sb = stateBuf;
+
+ /* Save the old video mode state */
+ regs.h.ah = 0x0F;
+ PM_int86(0x10,&regs,&regs);
+ sb->oldMode = regs.h.al & 0x7F;
+ sb->old50Lines = false;
+ if (sb->oldMode == 0x3) {
+ regs.x.ax = 0x1130;
+ regs.x.bx = 0;
+ regs.x.dx = 0;
+ PM_int86(0x10,&regs,&regs);
+ sb->old50Lines = (regs.h.dl == 42 || regs.h.dl == 49);
+ }
+ (void)hwndConsole;
+}
+
+void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
+{
+ /* Not used for SMX */
+ (void)saveState;
+}
+
+void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND hwndConsole)
+{
+ RMREGS regs;
+ const DOS_stateBuf *sb = stateBuf;
+
+ /* Retore 50 line mode if set */
+ if (sb->old50Lines) {
+ regs.x.ax = 0x1112;
+ regs.x.bx = 0;
+ PM_int86(0x10,&regs,&regs);
+ }
+ (void)hwndConsole;
+}
+
+void PMAPI PM_closeConsole(PM_HWND hwndConsole)
+{
+ /* Not used for SMX */
+ (void)hwndConsole;
+}
+
+void PMAPI PM_setOSCursorLocation(int x,int y)
+{
+ uchar *_biosPtr = PM_getBIOSPointer();
+ PM_setByte(_biosPtr+0x50,x);
+ PM_setByte(_biosPtr+0x51,y);
+}
+
+void PMAPI PM_setOSScreenWidth(int width,int height)
+{
+ uchar *_biosPtr = PM_getBIOSPointer();
+ PM_setWord(_biosPtr+0x4A,width);
+ PM_setWord(_biosPtr+0x4C,width*2);
+ PM_setByte(_biosPtr+0x84,height-1);
+ if (height > 25) {
+ PM_setWord(_biosPtr+0x60,0x0607);
+ PM_setByte(_biosPtr+0x85,0x08);
+ }
+ else {
+ PM_setWord(_biosPtr+0x60,0x0D0E);
+ PM_setByte(_biosPtr+0x85,0x016);
+ }
+}
+
+void * PMAPI PM_mallocShared(long size)
+{
+ return PM_malloc(size);
+}
+
+void PMAPI PM_freeShared(void *ptr)
+{
+ PM_free(ptr);
+}
+
+#define GetRMVect(intno,isr) *(isr) = ((ulong*)rmZeroPtr)[intno]
+#define SetRMVect(intno,isr) ((ulong*)rmZeroPtr)[intno] = (isr)
+
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *mappedBIOS,
+ ulong BIOSLen)
+{
+ static int firstTime = true;
+ static uchar *rmZeroPtr;
+ long Current10,Current6D,Current42;
+ RMREGS regs;
+ RMSREGS sregs;
+
+ /* Create a zero memory mapping for us to use */
+ if (firstTime) {
+ rmZeroPtr = PM_mapPhysicalAddr(0,0x7FFF,true);
+ firstTime = false;
+ }
+
+ /* Remap the secondary BIOS to 0xC0000 physical */
+ if (BIOSPhysAddr != 0xC0000L || BIOSLen > 32768) {
+ /* SMX cannot virtually remap the BIOS, so we can only work if all
+ * the secondary controllers are identical, and we then use the
+ * BIOS on the first controller for all the remaining controllers.
+ *
+ * For OS'es that do virtual memory, and remapping of 0xC0000
+ * physical (perhaps a copy on write mapping) should be all that
+ * is needed.
+ */
+ return false;
+ }
+
+ /* Save current handlers of int 10h and 6Dh */
+ GetRMVect(0x10,&Current10);
+ GetRMVect(0x6D,&Current6D);
+
+ /* POST the secondary BIOS */
+ GetRMVect(0x42,&Current42);
+ SetRMVect(0x10,Current42); /* Restore int 10h to STD-BIOS */
+ regs.x.ax = axVal;
+ PM_callRealMode(0xC000,0x0003,&regs,&sregs);
+
+ /* Restore current handlers */
+ SetRMVect(0x10,Current10);
+ SetRMVect(0x6D,Current6D);
+
+ /* Second the primary BIOS mappin 1:1 for 0xC0000 physical */
+ if (BIOSPhysAddr != 0xC0000L) {
+ /* SMX does not support this */
+ (void)mappedBIOS;
+ }
+ return true;
+}
+
+void PMAPI PM_sleep(ulong milliseconds)
+{
+ ulong microseconds = milliseconds * 1000L;
+ LZTimerObject tm;
+
+ LZTimerOnExt(&tm);
+ while (LZTimerLapExt(&tm) < microseconds)
+ ;
+ LZTimerOffExt(&tm);
+}
+
+int PMAPI PM_getCOMPort(int port)
+{
+ switch (port) {
+ case 0: return 0x3F8;
+ case 1: return 0x2F8;
+ }
+ return 0;
+}
+
+int PMAPI PM_getLPTPort(int port)
+{
+ switch (port) {
+ case 0: return 0x3BC;
+ case 1: return 0x378;
+ case 2: return 0x278;
+ }
+ return 0;
+}
+
+PM_MODULE PMAPI PM_loadLibrary(
+ const char *szDLLName)
+{
+ (void)szDLLName;
+ return NULL;
+}
+
+void * PMAPI PM_getProcAddress(
+ PM_MODULE hModule,
+ const char *szProcName)
+{
+ (void)hModule;
+ (void)szProcName;
+ return NULL;
+}
+
+void PMAPI PM_freeLibrary(
+ PM_MODULE hModule)
+{
+ (void)hModule;
+}
+
+int PMAPI PM_setIOPL(
+ int level)
+{
+ return level;
+}
+
+/****************************************************************************
+REMARKS:
+Internal function to convert the find data to the generic interface.
+****************************************************************************/
+static void convertFindData(
+ PM_findData *findData,
+ struct find_t *blk)
+{
+ ulong dwSize = findData->dwSize;
+
+ memset(findData,0,findData->dwSize);
+ findData->dwSize = dwSize;
+ if (blk->attrib & _A_RDONLY)
+ findData->attrib |= PM_FILE_READONLY;
+ if (blk->attrib & _A_SUBDIR)
+ findData->attrib |= PM_FILE_DIRECTORY;
+ if (blk->attrib & _A_ARCH)
+ findData->attrib |= PM_FILE_ARCHIVE;
+ if (blk->attrib & _A_HIDDEN)
+ findData->attrib |= PM_FILE_HIDDEN;
+ if (blk->attrib & _A_SYSTEM)
+ findData->attrib |= PM_FILE_SYSTEM;
+ findData->sizeLo = blk->size;
+ strncpy(findData->name,blk->name,PM_MAX_PATH);
+ findData->name[PM_MAX_PATH-1] = 0;
+}
+
+#define FIND_MASK (_A_RDONLY | _A_ARCH | _A_SUBDIR | _A_HIDDEN | _A_SYSTEM)
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+void * PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ struct find_t *blk;
+
+ if ((blk = PM_malloc(sizeof(*blk))) == NULL)
+ return PM_FILE_INVALID;
+ if (_dos_findfirst((char*)filename,FIND_MASK,blk) == 0) {
+ convertFindData(findData,blk);
+ return blk;
+ }
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ void *handle,
+ PM_findData *findData)
+{
+ struct find_t *blk = handle;
+
+ if (_dos_findnext(blk) == 0) {
+ convertFindData(findData,blk);
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ void *handle)
+{
+ PM_free(handle);
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ RMREGS regs;
+ regs.h.dl = (uchar)(drive - 'A' + 1);
+ regs.h.ah = 0x36; // Get disk information service
+ PM_int86(0x21,&regs,&regs);
+ return regs.x.ax != 0xFFFF; // AX = 0xFFFF if disk is invalid
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ uint oldDrive,maxDrives;
+ _dos_getdrive(&oldDrive);
+ _dos_setdrive(drive,&maxDrives);
+ getcwd(dir,len);
+ _dos_setdrive(oldDrive,&maxDrives);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+#if defined(TNT) && defined(_MSC_VER)
+ DWORD attr = 0;
+
+ if (attrib & PM_FILE_READONLY)
+ attr |= FILE_ATTRIBUTE_READONLY;
+ if (attrib & PM_FILE_ARCHIVE)
+ attr |= FILE_ATTRIBUTE_ARCHIVE;
+ if (attrib & PM_FILE_HIDDEN)
+ attr |= FILE_ATTRIBUTE_HIDDEN;
+ if (attrib & PM_FILE_SYSTEM)
+ attr |= FILE_ATTRIBUTE_SYSTEM;
+ SetFileAttributes((LPSTR)filename, attr);
+#else
+ uint attr = 0;
+
+ if (attrib & PM_FILE_READONLY)
+ attr |= _A_RDONLY;
+ if (attrib & PM_FILE_ARCHIVE)
+ attr |= _A_ARCH;
+ if (attrib & PM_FILE_HIDDEN)
+ attr |= _A_HIDDEN;
+ if (attrib & PM_FILE_SYSTEM)
+ attr |= _A_SYSTEM;
+ _dos_setfileattr(filename,attr);
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+#ifdef __GNUC__
+ return mkdir(filename,S_IRUSR) == 0;
+#else
+//AM: return mkdir(filename) == 0;
+ return(false);
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+//AM: return rmdir(filename) == 0;
+ return(false);
+}
+
+/****************************************************************************
+REMARKS:
+Allocates a block of locked, physically contiguous memory. The memory
+may be required to be below the 16Meg boundary.
+****************************************************************************/
+void * PMAPI PM_allocLockedMem(
+ uint size,
+ ulong *physAddr,
+ ibool contiguous,
+ ibool below16M)
+{
+ void *p;
+ uint r_seg,r_off;
+ PM_lockHandle lh;
+
+ /* Under DOS the only way to know the physical memory address is to
+ * allocate the memory below the 1Meg boundary as real mode memory.
+ * We also allocate 4095 bytes more memory than we need, so we can
+ * properly page align the start of the memory block for DMA operations.
+ */
+ if (size > 4096)
+ return NULL;
+ if ((p = PM_allocRealSeg((size + 0xFFF) & ~0xFFF,&r_seg,&r_off)) == NULL)
+ return NULL;
+ *physAddr = ((r_seg << 4) + r_off + 0xFFF) & ~0xFFF;
+ PM_lockDataPages(p,size*2,&lh);
+ return p;
+}
+
+void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous)
+{
+ (void)size;
+ PM_freeRealSeg(p);
+}
+
+/*-------------------------------------------------------------------------*/
+/* Generic DPMI routines common to 16/32 bit code */
+/*-------------------------------------------------------------------------*/
+
+ulong PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit)
+{
+ PMREGS r;
+ ulong physOfs;
+
+ if (physAddr < 0x100000L) {
+ /* We can't map memory below 1Mb, but the linear address are already
+ * mapped 1:1 for this memory anyway so we just return the base address.
+ */
+ return physAddr;
+ }
+
+ /* Round the physical address to a 4Kb boundary and the limit to a
+ * 4Kb-1 boundary before passing the values to DPMI as some extenders
+ * will fail the calls unless this is the case. If we round the
+ * physical address, then we also add an extra offset into the address
+ * that we return.
+ */
+ physOfs = physAddr & 4095;
+ physAddr = physAddr & ~4095;
+ limit = ((limit+physOfs+1+4095) & ~4095)-1;
+
+ r.x.ax = 0x800; /* DPMI map physical to linear */
+ r.x.bx = physAddr >> 16;
+ r.x.cx = physAddr & 0xFFFF;
+ r.x.si = limit >> 16;
+ r.x.di = limit & 0xFFFF;
+ PM_int386(0x31, &r, &r);
+ if (r.x.cflag)
+ return 0xFFFFFFFFUL;
+ return ((ulong)r.x.bx << 16) + r.x.cx + physOfs;
+}
+
+int PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr)
+{
+ PMREGS r;
+
+ r.x.ax = 7; /* DPMI set selector base address */
+ r.x.bx = sel;
+ r.x.cx = linAddr >> 16;
+ r.x.dx = linAddr & 0xFFFF;
+ PM_int386(0x31, &r, &r);
+ if (r.x.cflag)
+ return 0;
+ return 1;
+}
+
+ulong PMAPI DPMI_getSelectorBase(ushort sel)
+{
+ PMREGS r;
+
+ r.x.ax = 6; /* DPMI get selector base address */
+ r.x.bx = sel;
+ PM_int386(0x31, &r, &r);
+ return ((ulong)r.x.cx << 16) + r.x.dx;
+}
+
+int PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit)
+{
+ PMREGS r;
+
+ r.x.ax = 8; /* DPMI set selector limit */
+ r.x.bx = sel;
+ r.x.cx = limit >> 16;
+ r.x.dx = limit & 0xFFFF;
+ PM_int386(0x31, &r, &r);
+ if (r.x.cflag)
+ return 0;
+ return 1;
+}
+
+uint PMAPI DPMI_createSelector(ulong base,ulong limit)
+{
+ uint sel;
+ PMREGS r;
+
+ /* Allocate 1 descriptor */
+ r.x.ax = 0;
+ r.x.cx = 1;
+ PM_int386(0x31, &r, &r);
+ if (r.x.cflag) return 0;
+ sel = r.x.ax;
+
+ /* Set the descriptor access rights (for a 32 bit page granular
+ * segment, ring 0).
+ */
+ r.x.ax = 9;
+ r.x.bx = sel;
+ r.x.cx = 0x4093;
+ PM_int386(0x31, &r, &r);
+
+ /* Map physical memory and create selector */
+ if ((base = DPMI_mapPhysicalToLinear(base,limit)) == 0xFFFFFFFFUL)
+ return 0;
+ if (!DPMI_setSelectorBase(sel,base))
+ return 0;
+ if (!DPMI_setSelectorLimit(sel,limit))
+ return 0;
+ return sel;
+}
+
+void PMAPI DPMI_freeSelector(uint sel)
+{
+ PMREGS r;
+
+ r.x.ax = 1;
+ r.x.bx = sel;
+ PM_int386(0x31, &r, &r);
+}
+
+int PMAPI DPMI_lockLinearPages(ulong linear,ulong len)
+{
+ PMREGS r;
+
+ r.x.ax = 0x600; /* DPMI Lock Linear Region */
+ r.x.bx = (linear >> 16); /* Linear address in BX:CX */
+ r.x.cx = (linear & 0xFFFF);
+ r.x.si = (len >> 16); /* Length in SI:DI */
+ r.x.di = (len & 0xFFFF);
+ PM_int386(0x31, &r, &r);
+ return (!r.x.cflag);
+}
+
+int PMAPI DPMI_unlockLinearPages(ulong linear,ulong len)
+{
+ PMREGS r;
+
+ r.x.ax = 0x601; /* DPMI Unlock Linear Region */
+ r.x.bx = (linear >> 16); /* Linear address in BX:CX */
+ r.x.cx = (linear & 0xFFFF);
+ r.x.si = (len >> 16); /* Length in SI:DI */
+ r.x.di = (len & 0xFFFF);
+ PM_int386(0x31, &r, &r);
+ return (!r.x.cflag);
+}
+
+void * PMAPI DPMI_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{
+ PMSREGS sregs;
+ ulong linAddr;
+ ulong DSBaseAddr;
+
+ /* Get the base address for the default DS selector */
+ PM_segread(&sregs);
+ DSBaseAddr = DPMI_getSelectorBase(sregs.ds);
+ if ((base < 0x100000) && (DSBaseAddr == 0)) {
+ /* DS is zero based, so we can directly access the first 1Mb of
+ * system memory (like under DOS4GW).
+ */
+ return (void*)base;
+ }
+
+ /* Map the memory to a linear address using DPMI function 0x800 */
+ if ((linAddr = DPMI_mapPhysicalToLinear(base,limit)) == 0) {
+ if (base >= 0x100000)
+ return NULL;
+ /* If the linear address mapping fails but we are trying to
+ * map an area in the first 1Mb of system memory, then we must
+ * be running under a Windows or OS/2 DOS box. Under these
+ * environments we can use the segment wrap around as a fallback
+ * measure, as this does work properly.
+ */
+ linAddr = base;
+ }
+
+ /* Now expand the default DS selector to 4Gb so we can access it */
+ if (!DPMI_setSelectorLimit(sregs.ds,0xFFFFFFFFUL))
+ return NULL;
+
+ /* Finally enable caching for the page tables that we just mapped in,
+ * since DOS4GW and PMODE/W create the page table entries without
+ * caching enabled which hurts the performance of the linear framebuffer
+ * as it disables write combining on Pentium Pro and above processors.
+ *
+ * For those processors cache disabling is better handled through the
+ * MTRR registers anyway (we can write combine a region but disable
+ * caching) so that MMIO register regions do not screw up.
+ */
+ if (isCached) {
+ if ((PDB = _PM_getPDB()) != 0 && DSBaseAddr == 0) {
+ int startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
+ ulong pageTable,*pPageTable;
+ if (!pPDB) {
+ if (PDB >= 0x100000)
+ pPDB = (ulong*)DPMI_mapPhysicalToLinear(PDB,0xFFF);
+ else
+ pPDB = (ulong*)PDB;
+ }
+ if (pPDB) {
+ startPDB = (linAddr >> 22) & 0x3FF;
+ startPage = (linAddr >> 12) & 0x3FF;
+ endPDB = ((linAddr+limit) >> 22) & 0x3FF;
+ endPage = ((linAddr+limit) >> 12) & 0x3FF;
+ for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
+ pageTable = pPDB[iPDB] & ~0xFFF;
+ if (pageTable >= 0x100000)
+ pPageTable = (ulong*)DPMI_mapPhysicalToLinear(pageTable,0xFFF);
+ else
+ pPageTable = (ulong*)pageTable;
+ start = (iPDB == startPDB) ? startPage : 0;
+ end = (iPDB == endPDB) ? endPage : 0x3FF;
+ for (iPage = start; iPage <= end; iPage++)
+ pPageTable[iPage] &= ~0x18;
+ }
+ }
+ }
+ }
+
+ /* Now return the base address of the memory into the default DS */
+ return (void*)(linAddr - DSBaseAddr);
+}
+
+/* Some DOS extender implementations do not directly support calling a
+ * real mode procedure from protected mode. However we can simulate what
+ * we need temporarily hooking the INT 6Ah vector with a small real mode
+ * stub that will call our real mode code for us.
+ */
+
+static uchar int6AHandler[] = {
+ 0x00,0x00,0x00,0x00, /* __PMODE_callReal variable */
+ 0xFB, /* sti */
+ 0x2E,0xFF,0x1E,0x00,0x00, /* call [cs:__PMODE_callReal] */
+ 0xCF, /* iretf */
+ };
+static uchar *crPtr = NULL; /* Pointer to of int 6A handler */
+static uint crRSeg,crROff; /* Real mode seg:offset of handler */
+
+void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,
+ RMSREGS *sregs)
+{
+ uchar *p;
+ uint oldSeg,oldOff;
+
+ if (!crPtr) {
+ /* Allocate and copy the memory block only once */
+ crPtr = PM_allocRealSeg(sizeof(int6AHandler), &crRSeg, &crROff);
+ memcpy(crPtr,int6AHandler,sizeof(int6AHandler));
+ }
+ PM_setWord(crPtr,off); /* Plug in address to call */
+ PM_setWord(crPtr+2,seg);
+ p = PM_mapRealPointer(0,0x6A * 4);
+ oldOff = PM_getWord(p); /* Save old handler address */
+ oldSeg = PM_getWord(p+2);
+ PM_setWord(p,crROff+4); /* Hook 6A handler */
+ PM_setWord(p+2,crRSeg);
+ PM_int86x(0x6A, in, in, sregs); /* Call real mode code */
+ PM_setWord(p,oldOff); /* Restore old handler */
+ PM_setWord(p+2,oldSeg);
+}
+
+void * PMAPI PM_getBIOSPointer(void)
+{ return PM_mapPhysicalAddr(0x400,0xFFFF,true); }
+
+void * PMAPI PM_getA0000Pointer(void)
+{ return PM_mapPhysicalAddr(0xA0000,0xFFFF,true); }
+
+void * PMAPI PM_mapPhysicalAddr(ulong base,ulong limit,ibool isCached)
+{ return DPMI_mapPhysicalAddr(base,limit,isCached); }
+
+void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
+{
+ /* Mapping cannot be free */
+}
+
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{
+ // TODO: This function should find the physical address of a linear
+ // address.
+ (void)p;
+ return 0xFFFFFFFFUL;
+}
+
+void * PMAPI PM_mapToProcess(void *base,ulong limit)
+{
+ (void)limit;
+ return (void*)base;
+}
+
+void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
+{
+ static uchar *zeroPtr = NULL;
+
+ if (!zeroPtr)
+ zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
+ return (void*)(zeroPtr + MK_PHYS(r_seg,r_off));
+}
+
+void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
+{
+ PMREGS r;
+ void *p;
+
+ r.x.ax = 0x100; /* DPMI allocate DOS memory */
+ r.x.bx = (size + 0xF) >> 4; /* number of paragraphs */
+ PM_int386(0x31, &r, &r);
+ if (r.x.cflag)
+ return NULL; /* DPMI call failed */
+ *r_seg = r.x.ax; /* Real mode segment */
+ *r_off = 0;
+ p = PM_mapRealPointer(*r_seg,*r_off);
+ _PM_addRealModeBlock(p,r.x.dx);
+ return p;
+}
+
+void PMAPI PM_freeRealSeg(void *mem)
+{
+ PMREGS r;
+
+ r.x.ax = 0x101; /* DPMI free DOS memory */
+ r.x.dx = _PM_findRealModeBlock(mem);/* DX := selector from 0x100 */
+ PM_int386(0x31, &r, &r);
+}
+
+static DPMI_handler_t DPMI_int10 = NULL;
+
+void PMAPI DPMI_setInt10Handler(DPMI_handler_t handler)
+{
+ DPMI_int10 = handler;
+}
+
+void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
+{
+ PMREGS r;
+ PMSREGS sr;
+
+ if (intno == 0x10 && DPMI_int10) {
+ if (DPMI_int10(regs))
+ return;
+ }
+ PM_segread(&sr);
+ r.x.ax = 0x300; /* DPMI issue real interrupt */
+ r.h.bl = intno;
+ r.h.bh = 0;
+ r.x.cx = 0;
+ sr.es = sr.ds;
+ r.e.edi = (uint)regs;
+ PM_int386x(0x31, &r, &r, &sr); /* Issue the interrupt */
+}
+
+#define IN(reg) rmregs.reg = in->e.reg
+#define OUT(reg) out->e.reg = rmregs.reg
+
+int PMAPI PM_int86(int intno, RMREGS *in, RMREGS *out)
+{
+ DPMI_regs rmregs;
+
+ memset(&rmregs, 0, sizeof(rmregs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+
+// These real mode ints may cause crashes.
+//AM: DPMI_int86(intno,&rmregs); /* DPMI issue real interrupt */
+
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ out->x.cflag = rmregs.flags & 0x1;
+ return out->x.ax;
+}
+
+int PMAPI PM_int86x(int intno, RMREGS *in, RMREGS *out,
+ RMSREGS *sregs)
+{
+ DPMI_regs rmregs;
+
+ memset(&rmregs, 0, sizeof(rmregs));
+ IN(eax); IN(ebx); IN(ecx); IN(edx); IN(esi); IN(edi);
+ rmregs.es = sregs->es;
+ rmregs.ds = sregs->ds;
+
+//AM: DPMI_int86(intno,&rmregs); /* DPMI issue real interrupt */
+
+ OUT(eax); OUT(ebx); OUT(ecx); OUT(edx); OUT(esi); OUT(edi);
+ sregs->es = rmregs.es;
+ sregs->cs = rmregs.cs;
+ sregs->ss = rmregs.ss;
+ sregs->ds = rmregs.ds;
+ out->x.cflag = rmregs.flags & 0x1;
+ return out->x.ax;
+}
+
+#pragma pack(1)
+
+typedef struct {
+ uint LargestBlockAvail;
+ uint MaxUnlockedPage;
+ uint LargestLockablePage;
+ uint LinAddrSpace;
+ uint NumFreePagesAvail;
+ uint NumPhysicalPagesFree;
+ uint TotalPhysicalPages;
+ uint FreeLinAddrSpace;
+ uint SizeOfPageFile;
+ uint res[3];
+ } MemInfo;
+
+#pragma pack()
+
+void PMAPI PM_availableMemory(ulong *physical,ulong *total)
+{
+ PMREGS r;
+ PMSREGS sr;
+ MemInfo memInfo;
+
+ PM_segread(&sr);
+ r.x.ax = 0x500; /* DPMI get free memory info */
+ sr.es = sr.ds;
+ r.e.edi = (uint)&memInfo;
+ PM_int386x(0x31, &r, &r, &sr); /* Issue the interrupt */
+ *physical = memInfo.NumPhysicalPagesFree * 4096;
+ *total = memInfo.LargestBlockAvail;
+ if (*total < *physical)
+ *physical = *total;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file attributes for a specific file.
+****************************************************************************/
+uint PMAPI PM_getFileAttr(
+ const char *filename)
+{
+ // TODO: Implement this!
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_getFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this!
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_setFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this!
+ return false;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/pmsmx.c b/board/MAI/bios_emulator/scitech/src/pm/smx/pmsmx.c
new file mode 100644
index 0000000000..2596c76a36
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/pmsmx.c
@@ -0,0 +1,471 @@
+/****************************************************************************
+*
+* 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: 32-bit SMX embedded systems development
+*
+* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dos.h>
+#include "smx/ps2mouse.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+static int globalDataStart;
+
+PM_criticalHandler _VARAPI _PM_critHandler = NULL;
+PM_breakHandler _VARAPI _PM_breakHandler = NULL;
+PM_intHandler _VARAPI _PM_timerHandler = NULL;
+PM_intHandler _VARAPI _PM_rtcHandler = NULL;
+PM_intHandler _VARAPI _PM_keyHandler = NULL;
+PM_key15Handler _VARAPI _PM_key15Handler = NULL;
+PM_mouseHandler _VARAPI _PM_mouseHandler = NULL;
+PM_intHandler _VARAPI _PM_int10Handler = NULL;
+int _VARAPI _PM_mouseMask;
+
+uchar * _VARAPI _PM_ctrlCPtr; /* Location of Ctrl-C flag */
+uchar * _VARAPI _PM_ctrlBPtr; /* Location of Ctrl-Break flag */
+uchar * _VARAPI _PM_critPtr; /* Location of Critical error Bf*/
+PMFARPTR _VARAPI _PM_prevTimer = PMNULL; /* Previous timer handler */
+PMFARPTR _VARAPI _PM_prevRTC = PMNULL; /* Previous RTC handler */
+PMFARPTR _VARAPI _PM_prevKey = PMNULL; /* Previous key handler */
+PMFARPTR _VARAPI _PM_prevKey15 = PMNULL; /* Previous key15 handler */
+PMFARPTR _VARAPI _PM_prevBreak = PMNULL; /* Previous break handler */
+PMFARPTR _VARAPI _PM_prevCtrlC = PMNULL; /* Previous CtrlC handler */
+PMFARPTR _VARAPI _PM_prevCritical = PMNULL; /* Previous critical handler */
+long _VARAPI _PM_prevRealTimer; /* Previous real mode timer */
+long _VARAPI _PM_prevRealRTC; /* Previous real mode RTC */
+long _VARAPI _PM_prevRealKey; /* Previous real mode key */
+long _VARAPI _PM_prevRealKey15; /* Previous real mode key15 */
+long _VARAPI _PM_prevRealInt10; /* Previous real mode int 10h */
+static uchar _PM_oldCMOSRegA; /* CMOS register A contents */
+static uchar _PM_oldCMOSRegB; /* CMOS register B contents */
+static uchar _PM_oldRTCPIC2; /* Mask value for RTC IRQ8 */
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* Globals for locking interrupt handlers in _pmsmx.asm */
+
+extern int _ASMAPI _PM_pmsmxDataStart;
+extern int _ASMAPI _PM_pmsmxDataEnd;
+void _ASMAPI _PM_pmsmxCodeStart(void);
+void _ASMAPI _PM_pmsmxCodeEnd(void);
+
+/* Protected mode interrupt handlers, also called by PM callbacks below */
+
+void _ASMAPI _PM_timerISR(void);
+void _ASMAPI _PM_rtcISR(void);
+void _ASMAPI _PM_keyISR(void);
+void _ASMAPI _PM_key15ISR(void);
+void _ASMAPI _PM_breakISR(void);
+void _ASMAPI _PM_ctrlCISR(void);
+void _ASMAPI _PM_criticalISR(void);
+void _ASMAPI _PM_mouseISR(void);
+void _ASMAPI _PM_int10PMCB(void);
+
+/* Protected mode DPMI callback handlers */
+
+void _ASMAPI _PM_mousePMCB(void);
+
+/* Routine to install a mouse handler function */
+
+void _ASMAPI _PM_setMouseHandler(int mask);
+
+/* Routine to allocate DPMI real mode callback routines */
+
+void _ASMAPI _DPMI_allocateCallback(void (_ASMAPI *pmcode)(),void *rmregs,long *RMCB);
+void _ASMAPI _DPMI_freeCallback(long RMCB);
+
+/* DPMI helper functions in PMLITE.C */
+
+ulong PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit);
+int PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr);
+ulong PMAPI DPMI_getSelectorBase(ushort sel);
+int PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit);
+uint PMAPI DPMI_createSelector(ulong base,ulong limit);
+void PMAPI DPMI_freeSelector(uint sel);
+int PMAPI DPMI_lockLinearPages(ulong linear,ulong len);
+int PMAPI DPMI_unlockLinearPages(ulong linear,ulong len);
+
+/* Functions to read and write CMOS registers */
+
+uchar PMAPI _PM_readCMOS(int index);
+void PMAPI _PM_writeCMOS(int index,uchar value);
+
+/*-------------------------------------------------------------------------*/
+/* Generic routines common to all environments */
+/*-------------------------------------------------------------------------*/
+
+void PMAPI PM_resetMouseDriver(int hardReset)
+{
+ ps2MouseReset();
+}
+
+void PMAPI PM_setRealTimeClockFrequency(int frequency)
+{
+ static short convert[] = {
+ 8192,
+ 4096,
+ 2048,
+ 1024,
+ 512,
+ 256,
+ 128,
+ 64,
+ 32,
+ 16,
+ 8,
+ 4,
+ 2,
+ -1,
+ };
+ int i;
+
+ /* First clear any pending RTC timeout if not cleared */
+ _PM_readCMOS(0x0C);
+ if (frequency == 0) {
+ /* Disable RTC timout */
+ _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,_PM_oldCMOSRegB & 0x0F);
+ }
+ else {
+ /* Convert frequency value to RTC clock indexes */
+ for (i = 0; convert[i] != -1; i++) {
+ if (convert[i] == frequency)
+ break;
+ }
+
+ /* Set RTC timout value and enable timeout */
+ _PM_writeCMOS(0x0A,(_PM_oldCMOSRegA & 0xF0) | (i+3));
+ _PM_writeCMOS(0x0B,(_PM_oldCMOSRegB & 0x0F) | 0x40);
+ }
+}
+
+static void PMAPI lockPMHandlers(void)
+{
+ static int locked = 0;
+ int stat = 0;
+ PM_lockHandle lh;
+
+ /* Lock all of the code and data used by our protected mode interrupt
+ * handling routines, so that it will continue to work correctly
+ * under real mode.
+ */
+ if (!locked) {
+ PM_saveDS();
+ stat = !PM_lockDataPages(&globalDataStart-2048,4096,&lh);
+ stat |= !PM_lockDataPages(&_PM_pmsmxDataStart,(int)&_PM_pmsmxDataEnd - (int)&_PM_pmsmxDataStart,&lh);
+ stat |= !PM_lockCodePages((__codePtr)_PM_pmsmxCodeStart,(int)_PM_pmsmxCodeEnd-(int)_PM_pmsmxCodeStart,&lh);
+ if (stat) {
+ printf("Page locking services failed - interrupt handling not safe!\n");
+ exit(1);
+ }
+ locked = 1;
+ }
+}
+
+void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
+{
+ PMREGS regs;
+
+ regs.x.ax = 0x204;
+ regs.h.bl = intno;
+ PM_int386(0x31,&regs,&regs);
+ isr->sel = regs.x.cx;
+ isr->off = regs.e.edx;
+}
+
+void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
+{
+ PMSREGS sregs;
+ PMREGS regs;
+
+ PM_saveDS();
+ regs.x.ax = 0x205; /* Set protected mode vector */
+ regs.h.bl = intno;
+ PM_segread(&sregs);
+ regs.x.cx = sregs.cs;
+ regs.e.edx = (uint)isr;
+ PM_int386(0x31,&regs,&regs);
+}
+
+void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
+{
+ PMREGS regs;
+
+ regs.x.ax = 0x205;
+ regs.h.bl = intno;
+ regs.x.cx = isr.sel;
+ regs.e.edx = isr.off;
+ PM_int386(0x31,&regs,&regs);
+}
+
+static long prevRealBreak; /* Previous real mode break handler */
+static long prevRealCtrlC; /* Previous real mode CtrlC handler */
+static long prevRealCritical; /* Prev real mode critical handler */
+
+int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
+{
+ lockPMHandlers(); /* Ensure our handlers are locked */
+
+ _PM_mouseHandler = mh;
+ return 0;
+}
+
+void PMAPI PM_restoreMouseHandler(void)
+{
+ if (_PM_mouseHandler)
+ _PM_mouseHandler = NULL;
+}
+
+static void getISR(int intno, PMFARPTR *pmisr, long *realisr)
+{
+ PM_getPMvect(intno,pmisr);
+}
+
+static void restoreISR(int intno, PMFARPTR pmisr, long realisr)
+{
+ PM_restorePMvect(intno,pmisr);
+}
+
+static void setISR(int intno, void (* PMAPI pmisr)())
+{
+ lockPMHandlers(); /* Ensure our handlers are locked */
+ PM_setPMvect(intno,pmisr);
+}
+
+void PMAPI PM_setTimerHandler(PM_intHandler th)
+{
+ getISR(PM_IRQ0, &_PM_prevTimer, &_PM_prevRealTimer);
+ _PM_timerHandler = th;
+ setISR(PM_IRQ0, _PM_timerISR);
+}
+
+void PMAPI PM_restoreTimerHandler(void)
+{
+ if (_PM_timerHandler) {
+ restoreISR(PM_IRQ0, _PM_prevTimer, _PM_prevRealTimer);
+ _PM_timerHandler = NULL;
+ }
+}
+
+ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
+{
+ /* Save the old CMOS real time clock values */
+ _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
+ _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
+
+ /* Set the real time clock interrupt handler */
+ getISR(0x70, &_PM_prevRTC, &_PM_prevRealRTC);
+ _PM_rtcHandler = th;
+ setISR(0x70, _PM_rtcISR);
+
+ /* Program the real time clock default frequency */
+ PM_setRealTimeClockFrequency(frequency);
+
+ /* Unmask IRQ8 in the PIC2 */
+ _PM_oldRTCPIC2 = PM_inpb(0xA1);
+ PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE);
+ return true;
+}
+
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ if (_PM_rtcHandler) {
+ /* Restore CMOS registers and mask RTC clock */
+ _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
+ PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE));
+
+ /* Restore the interrupt vector */
+ restoreISR(0x70, _PM_prevRTC, _PM_prevRealRTC);
+ _PM_rtcHandler = NULL;
+ }
+}
+
+void PMAPI PM_setKeyHandler(PM_intHandler kh)
+{
+ getISR(PM_IRQ1, &_PM_prevKey, &_PM_prevRealKey);
+ _PM_keyHandler = kh;
+ setISR(PM_IRQ1, _PM_keyISR);
+}
+
+void PMAPI PM_restoreKeyHandler(void)
+{
+ if (_PM_keyHandler) {
+ restoreISR(PM_IRQ1, _PM_prevKey, _PM_prevRealKey);
+ _PM_keyHandler = NULL;
+ }
+}
+
+void PMAPI PM_setKey15Handler(PM_key15Handler kh)
+{
+ getISR(0x15, &_PM_prevKey15, &_PM_prevRealKey15);
+ _PM_key15Handler = kh;
+ setISR(0x15, _PM_key15ISR);
+}
+
+void PMAPI PM_restoreKey15Handler(void)
+{
+ if (_PM_key15Handler) {
+ restoreISR(0x15, _PM_prevKey15, _PM_prevRealKey15);
+ _PM_key15Handler = NULL;
+ }
+}
+
+/* Real mode Ctrl-C and Ctrl-Break handler. This handler simply sets a
+ * flag in the real mode code segment and exit. We save the location
+ * of this flag in real mode memory so that both the real mode and
+ * protected mode code will be modifying the same flags.
+ */
+
+static uchar ctrlHandler[] = {
+ 0x00,0x00,0x00,0x00, /* ctrlBFlag */
+ 0x66,0x2E,0xC7,0x06,0x00,0x00,
+ 0x01,0x00,0x00,0x00, /* mov [cs:ctrlBFlag],1 */
+ 0xCF, /* iretf */
+ };
+
+void PMAPI PM_installAltBreakHandler(PM_breakHandler bh)
+{
+ uint rseg,roff;
+
+ getISR(0x1B, &_PM_prevBreak, &prevRealBreak);
+ getISR(0x23, &_PM_prevCtrlC, &prevRealCtrlC);
+ _PM_breakHandler = bh;
+ setISR(0x1B, _PM_breakISR);
+ setISR(0x23, _PM_ctrlCISR);
+
+ /* Hook the real mode vectors for these handlers, as these are not
+ * normally reflected by the DPMI server up to protected mode
+ */
+ _PM_ctrlBPtr = PM_allocRealSeg(sizeof(ctrlHandler)*2, &rseg, &roff);
+ memcpy(_PM_ctrlBPtr,ctrlHandler,sizeof(ctrlHandler));
+ memcpy(_PM_ctrlBPtr+sizeof(ctrlHandler),ctrlHandler,sizeof(ctrlHandler));
+ _PM_ctrlCPtr = _PM_ctrlBPtr + sizeof(ctrlHandler);
+ _PM_setRMvect(0x1B,((long)rseg << 16) | (roff+4));
+ _PM_setRMvect(0x23,((long)rseg << 16) | (roff+sizeof(ctrlHandler)+4));
+}
+
+void PMAPI PM_installBreakHandler(void)
+{
+ PM_installAltBreakHandler(NULL);
+}
+
+void PMAPI PM_restoreBreakHandler(void)
+{
+ if (_PM_prevBreak.sel) {
+ restoreISR(0x1B, _PM_prevBreak, prevRealBreak);
+ restoreISR(0x23, _PM_prevCtrlC, prevRealCtrlC);
+ _PM_prevBreak.sel = 0;
+ _PM_breakHandler = NULL;
+ PM_freeRealSeg(_PM_ctrlBPtr);
+ }
+}
+
+/* Real mode Critical Error handler. This handler simply saves the AX and
+ * DI values in the real mode code segment and exits. We save the location
+ * of this flag in real mode memory so that both the real mode and
+ * protected mode code will be modifying the same flags.
+ */
+
+static uchar criticalHandler[] = {
+ 0x00,0x00, /* axCode */
+ 0x00,0x00, /* diCode */
+ 0x2E,0xA3,0x00,0x00, /* mov [cs:axCode],ax */
+ 0x2E,0x89,0x3E,0x02,0x00, /* mov [cs:diCode],di */
+ 0xB8,0x03,0x00, /* mov ax,3 */
+ 0xCF, /* iretf */
+ };
+
+void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch)
+{
+ uint rseg,roff;
+
+ getISR(0x24, &_PM_prevCritical, &prevRealCritical);
+ _PM_critHandler = ch;
+ setISR(0x24, _PM_criticalISR);
+
+ /* Hook the real mode vector, as this is not normally reflected by the
+ * DPMI server up to protected mode.
+ */
+ _PM_critPtr = PM_allocRealSeg(sizeof(criticalHandler)*2, &rseg, &roff);
+ memcpy(_PM_critPtr,criticalHandler,sizeof(criticalHandler));
+ _PM_setRMvect(0x24,((long)rseg << 16) | (roff+4));
+}
+
+void PMAPI PM_installCriticalHandler(void)
+{
+ PM_installAltCriticalHandler(NULL);
+}
+
+void PMAPI PM_restoreCriticalHandler(void)
+{
+ if (_PM_prevCritical.sel) {
+ restoreISR(0x24, _PM_prevCritical, prevRealCritical);
+ PM_freeRealSeg(_PM_critPtr);
+ _PM_prevCritical.sel = 0;
+ _PM_critHandler = NULL;
+ }
+}
+
+int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+ return DPMI_lockLinearPages((uint)p + DPMI_getSelectorBase(sregs.ds),len);
+}
+
+int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+ return DPMI_unlockLinearPages((uint)p + DPMI_getSelectorBase(sregs.ds),len);
+}
+
+int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+//AM: causes minor glitch with
+//AM: older versions pmEasy which don't allow DPMI 06 on
+//AM: Code selector 0x0C -- assume base is 0 which it should be.
+ return DPMI_lockLinearPages((uint)p,len);
+}
+
+int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ PMSREGS sregs;
+ PM_segread(&sregs);
+ return DPMI_unlockLinearPages((uint)p,len);
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/smx/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/smx/vflat.c
new file mode 100644
index 0000000000..579ef2c95c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/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/smx/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/smx/ztimer.c
new file mode 100644
index 0000000000..01e180bdca
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/smx/ztimer.c
@@ -0,0 +1,115 @@
+/****************************************************************************
+*
+* 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: 32-bit SMX embedded systems development
+*
+* Description: OS specific implementation for the Zen Timer functions.
+* LZTimer not supported for smx (as needed for i486 processors), only
+* ULZTimer is supported at this time.
+*
+****************************************************************************/
+
+/*---------------------------- Global smx variables -----------------------*/
+
+extern ulong _cdecl etime; /* elapsed time */
+extern ulong _cdecl xticks_per_second(void);
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* External assembler functions */
+
+void _ASMAPI LZ_disable(void);
+void _ASMAPI LZ_enable(void);
+
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+void __ZTimerInit(void)
+{
+}
+
+ulong reterr(void)
+{
+ PM_fatalError("Zen Timer not supported for smx.");
+ return(0);
+}
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOn(tm) PM_fatalError("Zen Timer not supported for smx.")
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerLap(tm) reterr()
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOff(tm) PM_fatalError("Zen Timer not supported for smx.")
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerCount(tm) reterr()
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as seconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION (ulong)(1000000/xticks_per_second())
+
+/****************************************************************************
+REMARKS:
+Read the Long Period timer value from the smx timer tick.
+****************************************************************************/
+static ulong __ULZReadTime(void)
+{
+ ulong ticks;
+ LZ_disable(); /* Turn of interrupts */
+ ticks = etime;
+ LZ_enable(); /* Turn on interrupts again */
+ return ticks;
+}
+
+/****************************************************************************
+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)
+{
+ if (finish < start)
+ finish += xticks_per_second() * 3600 *24; /* Number of ticks in 24 hours */
+ return finish - start;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/stub/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/stub/cpuinfo.c
new file mode 100644
index 0000000000..2833a72f44
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/stub/cpuinfo.c
@@ -0,0 +1,79 @@
+/****************************************************************************
+*
+* 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: *** TODO: ADD YOUR OS ENVIRONMENT NAME HERE ***
+*
+* Description: Module to implement OS specific services to measure the
+* CPU frequency.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Increase the thread priority to maximum, if possible.
+****************************************************************************/
+static int SetMaxThreadPriority(void)
+{
+ // TODO: If you have thread priorities, increase it to maximum for the
+ // thread for timing the CPU frequency.
+ return oldPriority;
+}
+
+/****************************************************************************
+REMARKS:
+Restore the original thread priority.
+****************************************************************************/
+static void RestoreThreadPriority(
+ int priority)
+{
+ // TODO: Restore the original thread priority on exit.
+}
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ // TODO: Return the frequency of the counter in here. You should try to
+ // normalise this value to be around 100,000 ticks per second.
+ freq->low = 0;
+ freq->high = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+
+TODO: Implement this to read the counter. It should be done as a macro
+ for accuracy.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ (t)->low = 0; \
+ (t)->high = 0; \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/stub/event.c b/board/MAI/bios_emulator/scitech/src/pm/stub/event.c
new file mode 100644
index 0000000000..8e805d060f
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/stub/event.c
@@ -0,0 +1,199 @@
+/****************************************************************************
+*
+* 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: *** TODO: ADD YOUR OS ENVIRONMENT NAME HERE ***
+*
+* Description: **** implementation for the SciTech cross platform
+* event library.
+*
+****************************************************************************/
+
+/*---------------------------- Global Variables ---------------------------*/
+
+static ushort keyUpMsg[256] = {0};/* Table of key up messages */
+static int rangeX,rangeY; /* Range of mouse coordinates */
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* These are not used under non-DOS systems */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flags)
+
+/****************************************************************************
+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)
+{
+ // TODO: Implement this for your OS!
+}
+
+/****************************************************************************
+REMARKS:
+Pumps all messages in the application message queue into our event queue.
+****************************************************************************/
+static void _EVT_pumpMessages(void)
+{
+ // TODO: The purpose of this function is to read all keyboard and mouse
+ // events from the OS specific event queue, translate them and post
+ // them into the SciTech event queue.
+ //
+ // NOTE: There are a couple of important things that this function must
+ // take care of:
+ //
+ // 1. Support for KEYDOWN, KEYREPEAT and KEYUP is required.
+ //
+ // 2. Support for reading hardware scan code as well as ASCII
+ // translated values is required. Games use the scan codes rather
+ // than ASCII values. Scan codes go into the high order byte of the
+ // keyboard message field.
+ //
+ // 3. Support for at least reading mouse motion data (mickeys) from the
+ // mouse is required. Using the mickey values, we can then translate
+ // to mouse cursor coordinates scaled to the range of the current
+ // graphics display mode. Mouse values are scaled based on the
+ // global 'rangeX' and 'rangeY'.
+ //
+ // 4. Support for a timestamp for the events is required, which is
+ // defined as the number of milliseconds since some event (usually
+ // system startup). This is the timestamp when the event occurred
+ // (ie: at interrupt time) not when it was stuff into the SciTech
+ // event queue.
+ //
+ // 5. Support for mouse double click events. If the OS has a native
+ // mechanism to determine this, it should be used. Otherwise the
+ // time stamp information will be used by the generic event code
+ // to generate double click events.
+}
+
+/****************************************************************************
+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 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:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort()
+{
+ EVT_exit();
+ PM_fatalError("Unhandled exception!");
+}
+
+/****************************************************************************
+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)
+{
+ /* Initialise the event queue */
+ _mouseMove = mouseMove;
+ initEventQueue();
+ memset(keyUpMsg,0,sizeof(keyUpMsg));
+
+ // TODO: Do any OS specific initialisation here
+
+ /* Catch program termination signals so we can clean up properly */
+ signal(SIGABRT, _EVT_abort);
+ signal(SIGFPE, _EVT_abort);
+ signal(SIGINT, _EVT_abort);
+}
+
+/****************************************************************************
+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)
+{
+ rangeX = xRes;
+ rangeY = yRes;
+}
+
+/****************************************************************************
+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 non DOS systems
+}
+
+/****************************************************************************
+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 non DOS systems
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+ /* Restore signal handlers */
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+
+ // TODO: Do any OS specific cleanup in here
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/stub/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/stub/oshdr.h
new file mode 100644
index 0000000000..81a20aaf15
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/stub/oshdr.h
@@ -0,0 +1,33 @@
+/****************************************************************************
+*
+* 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: BeOS
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
+
+// TODO: This is where you include OS specific headers for the event handling
+// library. You may leave this empty if you have no OS specific headers
+// to include.
diff --git a/board/MAI/bios_emulator/scitech/src/pm/stub/pm.c b/board/MAI/bios_emulator/scitech/src/pm/stub/pm.c
new file mode 100644
index 0000000000..51656b05e3
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/stub/pm.c
@@ -0,0 +1,980 @@
+/****************************************************************************
+*
+* 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: *** TODO: ADD YOUR OS ENVIRONMENT NAME HERE ***
+*
+* 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>
+
+// TODO: Include any OS specific headers here!
+
+/*--------------------------- Global variables ----------------------------*/
+
+// TODO: If you support access to the BIOS, the following VESABuf globals
+// keep track of a single VESA transfer buffer. If you don't support
+// access to the BIOS, remove these variables.
+
+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 */
+
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the PM library.
+****************************************************************************/
+void PMAPI PM_init(void)
+{
+ // TODO: Do any initialisation in here. This includes getting IOPL
+ // access for the process calling PM_init. This will get called
+ // more than once.
+
+ // TODO: If you support the supplied MTRR register stuff (you need to
+ // be at ring 0 for this!), you should initialise it in here.
+
+/* MTRR_init(); */
+}
+
+/****************************************************************************
+REMARKS:
+Return the operating system type identifier.
+****************************************************************************/
+long PMAPI PM_getOSType(void)
+{
+ // TODO: Change this to return the define for your OS from drvlib/os.h
+ return _OS_MYOS;
+}
+
+/****************************************************************************
+REMARKS:
+Return the runtime type identifier (always PM_386 for protected mode)
+****************************************************************************/
+int PMAPI PM_getModeType(void)
+{ return PM_386; }
+
+/****************************************************************************
+REMARKS:
+Add a file directory separator to the end of the filename.
+****************************************************************************/
+void PMAPI PM_backslash(
+ char *s)
+{
+ uint pos = strlen(s);
+ if (s[pos-1] != '/') {
+ s[pos] = '/';
+ s[pos+1] = '\0';
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Add a user defined PM_fatalError cleanup function.
+****************************************************************************/
+void PMAPI PM_setFatalErrorCleanup(
+ void (PMAPIP cleanup)(void))
+{
+ fatalErrorCleanup = cleanup;
+}
+
+/****************************************************************************
+REMARKS:
+Report a fatal error condition and halt the program.
+****************************************************************************/
+void PMAPI PM_fatalError(
+ const char *msg)
+{
+ // TODO: If you are running in a GUI environment without a console,
+ // this needs to be changed to bring up a fatal error message
+ // box and terminate the program.
+ if (fatalErrorCleanup)
+ fatalErrorCleanup();
+ fprintf(stderr,"%s\n", msg);
+ exit(1);
+}
+
+/****************************************************************************
+REMARKS:
+Exit handler to kill the VESA transfer buffer.
+****************************************************************************/
+static void ExitVBEBuf(void)
+{
+ // TODO: If you do not have BIOS access, remove this function.
+ if (VESABuf_ptr)
+ PM_freeRealSeg(VESABuf_ptr);
+ VESABuf_ptr = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate the real mode VESA transfer buffer for communicating with the BIOS.
+****************************************************************************/
+void * PMAPI PM_getVESABuf(
+ uint *len,
+ uint *rseg,
+ uint *roff)
+{
+ // TODO: If you do not have BIOS access, simply delete the guts of
+ // this function and return NULL.
+ 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;
+}
+
+/****************************************************************************
+REMARKS:
+Check if a key has been pressed.
+****************************************************************************/
+int PMAPI PM_kbhit(void)
+{
+ // TODO: This function checks if a key is available to be read. This
+ // should be implemented, but is mostly used by the test programs
+ // these days.
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Wait for and return the next keypress.
+****************************************************************************/
+int PMAPI PM_getch(void)
+{
+ // TODO: This returns the ASCII code of the key pressed. This
+ // should be implemented, but is mostly used by the test programs
+ // these days.
+ return 0xD;
+}
+
+/****************************************************************************
+REMARKS:
+Open a fullscreen console mode for output.
+****************************************************************************/
+int PMAPI PM_openConsole(void)
+{
+ // TODO: Opens up a fullscreen console for graphics output. If your
+ // console does not have graphics/text modes, this can be left
+ // empty. The main purpose of this is to disable console switching
+ // when in graphics modes if you can switch away from fullscreen
+ // consoles (if you want to allow switching, this can be done
+ // elsewhere with a full save/restore state of the graphics mode).
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Return the size of the state buffer used to save the console state.
+****************************************************************************/
+int PMAPI PM_getConsoleStateSize(void)
+{
+ // TODO: Returns the size of the console state buffer used to save the
+ // state of the console before going into graphics mode. This is
+ // used to restore the console back to normal when we are done.
+ return 1;
+}
+
+/****************************************************************************
+REMARKS:
+Save the state of the console into the state buffer.
+****************************************************************************/
+void PMAPI PM_saveConsoleState(
+ void *stateBuf,
+ int console_id)
+{
+ // TODO: Saves the state of the console into the state buffer. This is
+ // used to restore the console back to normal when we are done.
+ // We will always restore 80x25 text mode after being in graphics
+ // mode, so if restoring text mode is all you need to do this can
+ // be left empty.
+}
+
+/****************************************************************************
+REMARKS:
+Restore the state of the console from the state buffer.
+****************************************************************************/
+void PMAPI PM_restoreConsoleState(
+ const void *stateBuf,
+ int console_id)
+{
+ // TODO: Restore the state of the console from the state buffer. This is
+ // used to restore the console back to normal when we are done.
+ // We will always restore 80x25 text mode after being in graphics
+ // mode, so if restoring text mode is all you need to do this can
+ // be left empty.
+}
+
+/****************************************************************************
+REMARKS:
+Close the console and return to non-fullscreen console mode.
+****************************************************************************/
+void PMAPI PM_closeConsole(
+ int console_id)
+{
+ // TODO: Close the console when we are done, going back to text mode.
+}
+
+/****************************************************************************
+REMARKS:
+Set the location of the OS console cursor.
+****************************************************************************/
+void PM_setOSCursorLocation(
+ int x,
+ int y)
+{
+ // TODO: Set the OS console cursor location to the new value. This is
+ // generally used for new OS ports (used mostly for DOS).
+}
+
+/****************************************************************************
+REMARKS:
+Set the width of the OS console.
+****************************************************************************/
+void PM_setOSScreenWidth(
+ int width,
+ int height)
+{
+ // TODO: Set the OS console screen width. This is generally unused for
+ // new OS ports.
+}
+
+/****************************************************************************
+REMARKS:
+Set the real time clock handler (used for software stereo modes).
+****************************************************************************/
+ibool PMAPI PM_setRealTimeClockHandler(
+ PM_intHandler ih,
+ int frequency)
+{
+ // TODO: Install a real time clock interrupt handler. Normally this
+ // will not be supported from most OS'es in user land, so an
+ // alternative mechanism is needed to enable software stereo.
+ // Hence leave this unimplemented unless you have a high priority
+ // mechanism to call the 32-bit callback when the real time clock
+ // interrupt fires.
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Set the real time clock frequency (for stereo modes).
+****************************************************************************/
+void PMAPI PM_setRealTimeClockFrequency(
+ int frequency)
+{
+ // TODO: Set the real time clock interrupt frequency. Used for stereo
+ // LC shutter glasses when doing software stereo. Usually sets
+ // the frequency to around 2048 Hz.
+}
+
+/****************************************************************************
+REMARKS:
+Restore the original real time clock handler.
+****************************************************************************/
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ // TODO: Restores the real time clock handler.
+}
+
+/****************************************************************************
+REMARKS:
+Return the current operating system path or working directory.
+****************************************************************************/
+char * PMAPI PM_getCurrentPath(
+ char *path,
+ int maxLen)
+{
+ return getcwd(path,maxLen);
+}
+
+/****************************************************************************
+REMARKS:
+Return the drive letter for the boot drive.
+****************************************************************************/
+char PMAPI PM_getBootDrive(void)
+{
+ // TODO: Return the boot drive letter for the OS. Normally this is 'c'
+ // for DOS based OS'es and '/' for Unices.
+ return '/';
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the VBE/AF driver files (legacy and not used).
+****************************************************************************/
+const char * PMAPI PM_getVBEAFPath(void)
+{
+ return PM_getNucleusConfigPath();
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the Nucleus driver files.
+****************************************************************************/
+const char * PMAPI PM_getNucleusPath(void)
+{
+ // TODO: Change this to the default path to Nucleus driver files. The
+ // following is the default for Unices.
+ char *env = getenv("NUCLEUS_PATH");
+ return env ? env : "/usr/lib/nucleus";
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the Nucleus configuration files.
+****************************************************************************/
+const char * PMAPI PM_getNucleusConfigPath(void)
+{
+ static char path[256];
+ strcpy(path,PM_getNucleusPath());
+ PM_backslash(path);
+ strcat(path,"config");
+ return path;
+}
+
+/****************************************************************************
+REMARKS:
+Return a unique identifier for the machine if possible.
+****************************************************************************/
+const char * PMAPI PM_getUniqueID(void)
+{
+ // TODO: Return a unique ID for the machine. If a unique ID is not
+ // available, return the machine name.
+ static char buf[128];
+ gethostname(buf, 128);
+ return buf;
+}
+
+/****************************************************************************
+REMARKS:
+Get the name of the machine on the network.
+****************************************************************************/
+const char * PMAPI PM_getMachineName(void)
+{
+ // TODO: Return the network machine name for the machine.
+ static char buf[128];
+ gethostname(buf, 128);
+ return buf;
+}
+
+/****************************************************************************
+REMARKS:
+Return a pointer to the real mode BIOS data area.
+****************************************************************************/
+void * PMAPI PM_getBIOSPointer(void)
+{
+ // TODO: This returns a pointer to the real mode BIOS data area. If you
+ // do not support BIOS access, you can simply return NULL here.
+ if (!zeroPtr)
+ zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF,true);
+ return (void*)(zeroPtr + 0x400);
+}
+
+/****************************************************************************
+REMARKS:
+Return a pointer to 0xA0000 physical VGA graphics framebuffer.
+****************************************************************************/
+void * PMAPI PM_getA0000Pointer(void)
+{
+ static void *bankPtr;
+ if (!bankPtr)
+ bankPtr = PM_mapPhysicalAddr(0xA0000,0xFFFF,true);
+ return bankPtr;
+}
+
+/****************************************************************************
+REMARKS:
+Map a physical address to a linear address in the callers process.
+****************************************************************************/
+void * PMAPI PM_mapPhysicalAddr(
+ ulong base,
+ ulong limit,
+ ibool isCached)
+{
+ // TODO: This function maps a physical memory address to a linear
+ // address in the address space of the calling process.
+
+ // NOTE: This function *must* be able to handle any phsyical base
+ // address, and hence you will have to handle rounding of
+ // the physical base address to a page boundary (ie: 4Kb on
+ // x86 CPU's) to be able to properly map in the memory
+ // region.
+
+ // NOTE: If possible the isCached bit should be used to ensure that
+ // the PCD (Page Cache Disable) and PWT (Page Write Through)
+ // bits are set to disable caching for a memory mapping used
+ // for MMIO register access. We also disable caching using
+ // the MTRR registers for Pentium Pro and later chipsets so if
+ // MTRR support is enabled for your OS then you can safely ignore
+ // the isCached flag and always enable caching in the page
+ // tables.
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a physical address mapping allocated by PM_mapPhysicalAddr.
+****************************************************************************/
+void PMAPI PM_freePhysicalAddr(
+ void *ptr,
+ ulong limit)
+{
+ // TODO: This function will free a physical memory mapping previously
+ // allocated with PM_mapPhysicalAddr() if at all possible. If
+ // you can't free physical memory mappings, simply do nothing.
+}
+
+/****************************************************************************
+REMARKS:
+Find the physical address of a linear memory address in current process.
+****************************************************************************/
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{
+ // TODO: This function should find the physical address of a linear
+ // address.
+ return 0xFFFFFFFFUL;
+}
+
+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;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of (unnamed) shared memory.
+****************************************************************************/
+void * PMAPI PM_mallocShared(
+ long size)
+{
+ // TODO: This is used to allocate memory that is shared between process
+ // that all access the common Nucleus drivers via a common display
+ // driver DLL. If your OS does not support shared memory (or if
+ // the display driver does not need to allocate shared memory
+ // for each process address space), this should just call PM_malloc.
+ return PM_malloc(size);
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of shared memory.
+****************************************************************************/
+void PMAPI PM_freeShared(
+ void *ptr)
+{
+ // TODO: Free the shared memory block. This will be called in the context
+ // of the original calling process that allocated the shared
+ // memory with PM_mallocShared. Simply call PM_free if you do not
+ // need this.
+ PM_free(ptr);
+}
+
+/****************************************************************************
+REMARKS:
+Map a linear memory address to the calling process address space. The
+address will have been allocated in another process using the
+PM_mapPhysicalAddr function.
+****************************************************************************/
+void * PMAPI PM_mapToProcess(
+ void *base,
+ ulong limit)
+{
+ // TODO: This function is used to map a physical memory mapping
+ // previously allocated with PM_mapPhysicalAddr into the
+ // address space of the calling process. If the memory mapping
+ // allocated by PM_mapPhysicalAddr is global to all processes,
+ // simply return the pointer.
+
+ // NOTE: This function must also handle rounding to page boundaries,
+ // since this function is used to map in shared memory buffers
+ // allocated with PM_mapPhysicalAddr(). Hence if you aligned
+ // the physical address above, then you also need to do it here.
+ return base;
+}
+
+/****************************************************************************
+REMARKS:
+Map a real mode pointer to a protected mode pointer.
+****************************************************************************/
+void * PMAPI PM_mapRealPointer(
+ uint r_seg,
+ uint r_off)
+{
+ // TODO: This function maps a real mode memory pointer into the
+ // calling processes address space as a 32-bit near pointer. If
+ // you do not support BIOS access, simply return NULL here.
+ if (!zeroPtr)
+ zeroPtr = PM_mapPhysicalAddr(0,0xFFFFF);
+ return (void*)(zeroPtr + MK_PHYS(r_seg,r_off));
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of real mode memory
+****************************************************************************/
+void * PMAPI PM_allocRealSeg(
+ uint size,
+ uint *r_seg,
+ uint *r_off)
+{
+ // TODO: This function allocates a block of real mode memory for the
+ // calling process used to communicate with real mode BIOS
+ // functions. If you do not support BIOS access, simply return
+ // NULL here.
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of real mode memory.
+****************************************************************************/
+void PMAPI PM_freeRealSeg(
+ void *mem)
+{
+ // TODO: Frees a previously allocated real mode memory block. If you
+ // do not support BIOS access, this function should be empty.
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt (parameters in DPMI compatible structure)
+****************************************************************************/
+void PMAPI DPMI_int86(
+ int intno,
+ DPMI_regs *regs)
+{
+ // TODO: This function calls the real mode BIOS using the passed in
+ // register structure. If you do not support real mode BIOS
+ // access, this function should be empty.
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt.
+****************************************************************************/
+int PMAPI PM_int86(
+ int intno,
+ RMREGS *in,
+ RMREGS *out)
+{
+ // TODO: This function calls the real mode BIOS using the passed in
+ // register structure. If you do not support real mode BIOS
+ // access, this function should return 0.
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt.
+****************************************************************************/
+int PMAPI PM_int86x(
+ int intno,
+ RMREGS *in,
+ RMREGS *out,
+ RMSREGS *sregs)
+{
+ // TODO: This function calls the real mode BIOS using the passed in
+ // register structure. If you do not support real mode BIOS
+ // access, this function should return 0.
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Call a real mode far function.
+****************************************************************************/
+void PMAPI PM_callRealMode(
+ uint seg,
+ uint off,
+ RMREGS *in,
+ RMSREGS *sregs)
+{
+ // TODO: This function calls a real mode far function with a far call.
+ // If you do not support BIOS access, this function should be
+ // empty.
+}
+
+/****************************************************************************
+REMARKS:
+Return the amount of available memory.
+****************************************************************************/
+void PMAPI PM_availableMemory(
+ ulong *physical,
+ ulong *total)
+{
+ // TODO: Report the amount of available memory, both the amount of
+ // physical memory left and the amount of virtual memory left.
+ // If the OS does not provide these services, report 0's.
+ *physical = *total = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of locked, physical memory for DMA operations.
+****************************************************************************/
+void * PMAPI PM_allocLockedMem(
+ uint size,
+ ulong *physAddr,
+ ibool contiguous,
+ ibool below16M)
+{
+ // TODO: Allocate a block of locked, physical memory of the specified
+ // size. This is used for bus master operations. If this is not
+ // supported by the OS, return NULL and bus mastering will not
+ // be used.
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of locked physical memory.
+****************************************************************************/
+void PMAPI PM_freeLockedMem(
+ void *p,
+ uint size,
+ ibool contiguous)
+{
+ // TODO: Free a memory block allocated with PM_allocLockedMem.
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display banks.
+****************************************************************************/
+void PMAPI PM_setBankA(
+ int bank)
+{
+ RMREGS regs;
+
+ // TODO: This does a bank switch function by calling the real mode
+ // VESA BIOS. If you do not support BIOS access, this function should
+ // be empty.
+ regs.x.ax = 0x4F05;
+ regs.x.bx = 0x0000;
+ regs.x.dx = bank;
+ PM_int86(0x10,&regs,&regs);
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display banks.
+****************************************************************************/
+void PMAPI PM_setBankAB(
+ int bank)
+{
+ RMREGS regs;
+
+ // TODO: This does a bank switch function by calling the real mode
+ // VESA BIOS. If you do not support BIOS access, this function should
+ // be empty.
+ regs.x.ax = 0x4F05;
+ regs.x.bx = 0x0000;
+ regs.x.dx = bank;
+ PM_int86(0x10,&regs,&regs);
+ regs.x.ax = 0x4F05;
+ regs.x.bx = 0x0001;
+ regs.x.dx = bank;
+ PM_int86(0x10,&regs,&regs);
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display start address.
+****************************************************************************/
+void PMAPI PM_setCRTStart(
+ int x,
+ int y,
+ int waitVRT)
+{
+ RMREGS regs;
+
+ // TODO: This changes the display start address by calling the real mode
+ // VESA BIOS. If you do not support BIOS access, this function
+ // should be empty.
+ regs.x.ax = 0x4F07;
+ regs.x.bx = waitVRT;
+ regs.x.cx = x;
+ regs.x.dx = y;
+ PM_int86(0x10,&regs,&regs);
+}
+
+/****************************************************************************
+REMARKS:
+Enable write combining for the memory region.
+****************************************************************************/
+ibool PMAPI PM_enableWriteCombine(
+ ulong base,
+ ulong length,
+ uint type)
+{
+ // TODO: This function should enable Pentium Pro and Pentium II MTRR
+ // write combining for the passed in physical memory base address
+ // and length. Normally this is done via calls to an OS specific
+ // device driver as this can only be done at ring 0.
+ //
+ // NOTE: This is a *very* important function to implement! If you do
+ // not implement, graphics performance on the latest Intel chips
+ // will be severly impaired. For sample code that can be used
+ // directly in a ring 0 device driver, see the MSDOS implementation
+ // which includes assembler code to do this directly (if the
+ // program is running at ring 0).
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Execute the POST on the secondary BIOS for a controller.
+****************************************************************************/
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *mappedBIOS)
+{
+ // TODO: This function is used to run the BIOS POST code on a secondary
+ // controller to initialise it for use. This is not necessary
+ // for multi-controller operation, but it will make it a lot
+ // more convenicent for end users (otherwise they have to boot
+ // the system once with the secondary controller as primary, and
+ // then boot with both controllers installed).
+ //
+ // Even if you don't support full BIOS access, it would be
+ // adviseable to be able to POST the secondary controllers in the
+ // system using this function as a minimum requirement. Some
+ // graphics hardware has registers that contain values that only
+ // the BIOS knows about, which makes bring up a card from cold
+ // reset difficult if the BIOS has not POST'ed it.
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Load an OS specific shared library or DLL. If the OS does not support
+shared libraries, simply return NULL.
+****************************************************************************/
+PM_MODULE PMAPI PM_loadLibrary(
+ const char *szDLLName)
+{
+ // TODO: This function should load a native shared library from disk
+ // given the path to the library.
+ (void)szDLLName;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Get the address of a named procedure from a shared library.
+****************************************************************************/
+void * PMAPI PM_getProcAddress(
+ PM_MODULE hModule,
+ const char *szProcName)
+{
+ // TODO: This function should return the address of a named procedure
+ // from a native shared library.
+ (void)hModule;
+ (void)szProcName;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Unload a shared library.
+****************************************************************************/
+void PMAPI PM_freeLibrary(
+ PM_MODULE hModule)
+{
+ // TODO: This function free a previously loaded native shared library.
+ (void)hModule;
+}
+
+/****************************************************************************
+REMARKS:
+Enable requested I/O privledge level (usually only to set to a value of
+3, and then restore it back again). If the OS is protected this function
+must be implemented in order to enable I/O port access for ring 3
+applications. The function should return the IOPL level active before
+the switch occurred so it can be properly restored.
+****************************************************************************/
+int PMAPI PM_setIOPL(
+ int level)
+{
+ // TODO: This function should enable IOPL for the task (if IOPL is
+ // not always enabled for the app through some other means).
+ return level;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+void *PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ // TODO: This function should start a directory enumeration search
+ // given the filename (with wildcards). The data should be
+ // converted and returned in the findData standard form.
+ (void)filename;
+ (void)findData;
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ void *handle,
+ PM_findData *findData)
+{
+ // TODO: This function should find the next file in directory enumeration
+ // search given the search criteria defined in the call to
+ // PM_findFirstFile. The data should be converted and returned
+ // in the findData standard form.
+ (void)handle;
+ (void)findData;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ void *handle)
+{
+ // TODO: This function should close the find process. This may do
+ // nothing for some OS'es.
+ (void)handle;
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ if (drive == 3)
+ return true;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ (void)drive;
+ getcwd(dir,len);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+ // TODO: Set the file attributes for a file
+ (void)filename;
+ (void)attrib;
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+ return mkdir(filename) == 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+ return rmdir(filename) == 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/stub/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/stub/vflat.c
new file mode 100644
index 0000000000..579ef2c95c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/stub/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/stub/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/stub/ztimer.c
new file mode 100644
index 0000000000..9bad6c0975
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/stub/ztimer.c
@@ -0,0 +1,111 @@
+/****************************************************************************
+*
+* 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: *** TODO: ADD YOUR OS ENVIRONMENT NAME HERE ***
+*
+* Description: OS specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+void __ZTimerInit(void)
+{
+ // TODO: Do any specific internal initialisation in here
+}
+
+/****************************************************************************
+REMARKS:
+Start the Zen Timer counting.
+****************************************************************************/
+static void __LZTimerOn(
+ LZTimerObject *tm)
+{
+ // TODO: Start the Zen Timer counting. This should be a macro if
+ // possible.
+}
+
+/****************************************************************************
+REMARKS:
+Compute the lap time since the timer was started.
+****************************************************************************/
+static ulong __LZTimerLap(
+ LZTimerObject *tm)
+{
+ // TODO: Compute the lap time between the current time and when the
+ // timer was started.
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Stop the Zen Timer counting.
+****************************************************************************/
+static void __LZTimerOff(
+ LZTimerObject *tm)
+{
+ // TODO: Stop the timer counting. Should be a macro if possible.
+}
+
+/****************************************************************************
+REMARKS:
+Compute the elapsed time in microseconds between start and end timings.
+****************************************************************************/
+static ulong __LZTimerCount(
+ LZTimerObject *tm)
+{
+ // TODO: Compute the elapsed time and return it. Always microseconds.
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 1
+
+/****************************************************************************
+REMARKS:
+Read the Long Period timer from the OS
+****************************************************************************/
+static ulong __ULZReadTime(void)
+{
+ // TODO: Read the long period timer from the OS. The resolution of this
+ // timer should be around 1/20 of a second for timing long
+ // periods if possible.
+}
+
+/****************************************************************************
+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; }
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/altbrk.c b/board/MAI/bios_emulator/scitech/src/pm/tests/altbrk.c
new file mode 100644
index 0000000000..5d899b7a67
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/altbrk.c
@@ -0,0 +1,90 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to install a C based
+* control C/break interrupt handler. Note that this
+* alternate version does not work with all extenders.
+*
+* Functions tested: PM_installAltBreakHandler()
+* PM_restoreBreakHandler()
+*
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+volatile int breakHit = false;
+volatile int ctrlCHit = false;
+
+#pragma off (check_stack) /* No stack checking under Watcom */
+
+void PMAPI breakHandler(uint bHit)
+{
+ if (bHit)
+ breakHit = true;
+ else
+ ctrlCHit = true;
+}
+
+int main(void)
+{
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ PM_installAltBreakHandler(breakHandler);
+ printf("Control C/Break interrupt handler installed\n");
+ while (1) {
+ if (ctrlCHit) {
+ printf("Code termimated with Ctrl-C.\n");
+ break;
+ }
+ if (breakHit) {
+ printf("Code termimated with Ctrl-Break.\n");
+ break;
+ }
+ if (PM_kbhit() && PM_getch() == 0x1B) {
+ printf("No break code detected!\n");
+ break;
+ }
+ printf("Hit Ctrl-C or Ctrl-Break to exit!\n");
+ }
+
+ PM_restoreBreakHandler();
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/altcrit.c b/board/MAI/bios_emulator/scitech/src/pm/tests/altcrit.c
new file mode 100644
index 0000000000..c5390f68a9
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/altcrit.c
@@ -0,0 +1,85 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to install a C based
+* critical error handler.
+*
+* Functions tested: PM_installCriticalHandler()
+* PM_criticalError()
+* PM_restoreCriticalHandler()
+*
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+volatile uint criticalError = false;
+volatile uint axValue;
+volatile uint diValue;
+
+#pragma off (check_stack) /* No stack checking under Watcom */
+
+uint PMAPI criticalHandler(uint axVal,uint diVal)
+{
+ criticalError = true;
+ axValue = axVal;
+ diValue = diVal;
+ return 3; /* Tell MS-DOS to fail the operation */
+}
+
+int main(void)
+{
+ FILE *f;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ PM_installAltCriticalHandler(criticalHandler);
+ printf("Critical Error handler installed - trying to read from A: drive...\n");
+ f = fopen("a:\bog.bog","rb");
+ if (f) fclose(f);
+ if (criticalError) {
+ printf("Critical error occured on INT 21h function %02X!\n",
+ axValue >> 8);
+ }
+ else
+ printf("Critical error was not caught!\n");
+ PM_restoreCriticalHandler();
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/biosptr.c b/board/MAI/bios_emulator/scitech/src/pm/tests/biosptr.c
new file mode 100644
index 0000000000..43668487af
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/biosptr.c
@@ -0,0 +1,92 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to manipulate the
+* BIOS data area from protected mode using the PM
+* library. Compile and link with the appropriate command
+* line for your DOS extender.
+*
+* Functions tested: PM_getBIOSSelector()
+* PM_getLong()
+* PM_getByte()
+* PM_getWord()
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+/* Macros to obtain values from the BIOS data area */
+
+#define TICKS() PM_getLong(bios+0x6C)
+#define KB_STAT PM_getByte(bios+0x17)
+#define KB_HEAD PM_getWord(bios+0x1A)
+#define KB_TAIL PM_getWord(bios+0x1C)
+
+/* Macros for working with the keyboard buffer */
+
+#define KB_HIT() (KB_HEAD != KB_TAIL)
+#define CTRL() (KB_STAT & 4)
+#define SHIFT() (KB_STAT & 2)
+#define ESC 0x1B
+
+/* Selector for BIOS data area */
+
+uchar *bios;
+
+int main(void)
+{
+ int c,done = 0;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ bios = PM_getBIOSPointer();
+ printf("Hit any key to test, Ctrl-Shift-Esc to quit\n");
+ while (!done) {
+ if (KB_HIT()) {
+ c = PM_getch();
+ if (c == 0) PM_getch();
+ printf("TIME=%-8lX ST=%02X CHAR=%02X ", TICKS(), KB_STAT, c);
+ printf("\n");
+ if ((c == ESC) && SHIFT() && CTRL())/* Ctrl-Shift-Esc */
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/block.c b/board/MAI/bios_emulator/scitech/src/pm/tests/block.c
new file mode 100644
index 0000000000..e948872956
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/block.c
@@ -0,0 +1,69 @@
+/****************************************************************************
+*
+* 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: Test program for the PM_blockUntilTimeout function.
+*
+****************************************************************************/
+
+#include <stdio.h>
+#include "pmapi.h"
+
+#define DELAY_MSECS 1100
+#define LOOPS 5
+
+/*-------------------------- Implementation -------------------------------*/
+
+/* The following routine takes a long count in microseconds and outputs
+ * a string representing the count in seconds. It could be modified to
+ * return a pointer to a static string representing the count rather
+ * than printing it out.
+ */
+
+void ReportTime(ulong count)
+{
+ ulong secs;
+
+ secs = count / 1000000L;
+ count = count - secs * 1000000L;
+ printf("Time taken: %lu.%06lu seconds\n",secs,count);
+}
+
+int main(void)
+{
+ int i;
+
+ printf("Detecting processor information ...");
+ fflush(stdout);
+ printf("\n\n%s\n", CPU_getProcessorName());
+ ZTimerInit();
+ LZTimerOn();
+ for (i = 0; i < LOOPS; i++) {
+ PM_blockUntilTimeout(DELAY_MSECS);
+ ReportTime(LZTimerLap());
+ }
+ LZTimerOff();
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/brk.c b/board/MAI/bios_emulator/scitech/src/pm/tests/brk.c
new file mode 100644
index 0000000000..3561fee921
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/brk.c
@@ -0,0 +1,78 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to install a C based
+* control C/break interrupt handler.
+*
+* Functions tested: PM_installBreakHandler()
+* PM_ctrlCHit()
+* PM_ctrlBreakHit()
+* PM_restoreBreakHandler()
+*
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+int main(void)
+{
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ PM_installBreakHandler();
+ printf("Control C/Break interrupt handler installed\n");
+ while (1) {
+ if (PM_ctrlCHit(1)) {
+ printf("Code termimated with Ctrl-C.\n");
+ break;
+ }
+ if (PM_ctrlBreakHit(1)) {
+ printf("Code termimated with Ctrl-Break.\n");
+ break;
+ }
+ if (PM_kbhit() && PM_getch() == 0x1B) {
+ printf("No break code detected!\n");
+ break;
+ }
+ printf("Hit Ctrl-C or Ctrl-Break to exit!\n");
+ }
+
+ PM_restoreBreakHandler();
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/callreal.c b/board/MAI/bios_emulator/scitech/src/pm/tests/callreal.c
new file mode 100644
index 0000000000..3897ce9999
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/callreal.c
@@ -0,0 +1,107 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to call a real mode
+* procedure. We simply copy a terribly simple assembly
+* language routine into a real mode block that we allocate,
+* and then attempt to call the routine and verify that it
+* was successful.
+*
+* Functions tested: PM_allocRealSeg()
+* PM_freeRealSeg()
+* PM_callRealMode()
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "pmapi.h"
+
+/* Block of real mode code we will eventually call */
+
+static unsigned char realModeCode[] = {
+ 0x93, /* xchg ax,bx */
+ 0x87, 0xCA, /* xchg cx,dx */
+ 0xCB /* retf */
+ };
+
+int main(void)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+ uchar *p;
+ unsigned r_seg,r_off;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ /* Allocate a the block of real mode memory */
+ if ((p = PM_allocRealSeg(sizeof(realModeCode), &r_seg, &r_off)) == NULL) {
+ printf("Unable to allocate real mode memory!\n");
+ exit(1);
+ }
+
+ /* Copy the real mode code */
+ memcpy(p,realModeCode,sizeof(realModeCode));
+
+ /* Now call the real mode code */
+ regs.x.ax = 1;
+ regs.x.bx = 2;
+ regs.x.cx = 3;
+ regs.x.dx = 4;
+ regs.x.si = 5;
+ regs.x.di = 6;
+ sregs.es = 7;
+ sregs.ds = 8;
+ PM_callRealMode(r_seg,r_off,&regs,&sregs);
+ if (regs.x.ax != 2 || regs.x.bx != 1 || regs.x.cx != 4 || regs.x.dx != 3
+ || regs.x.si != 5 || regs.x.di != 6 || sregs.es != 7
+ || sregs.ds != 8) {
+ printf("Real mode call failed!\n");
+ printf("\n");
+ printf("ax = %04X, bx = %04X, cx = %04X, dx = %04X\n",
+ regs.x.ax,regs.x.bx,regs.x.cx,regs.x.dx);
+ printf("si = %04X, di = %04X, es = %04X, ds = %04X\n",
+ regs.x.si,regs.x.di,sregs.es,sregs.ds);
+ }
+ else
+ printf("Real mode call succeeded!\n");
+
+ /* Free the memory we allocated */
+ PM_freeRealSeg(p);
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/checks.c b/board/MAI/bios_emulator/scitech/src/pm/tests/checks.c
new file mode 100644
index 0000000000..81737e17d7
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/checks.c
@@ -0,0 +1,100 @@
+/****************************************************************************
+*
+* 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: Main module for building checked builds of products with
+* assertions and trace code.
+*
+****************************************************************************/
+
+#include "scitech.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __WINDOWS__
+#define WIN32_LEAN_AND_MEAN
+#define STRICT
+#include <windows.h>
+#endif
+
+#ifdef CHECKED
+
+/*---------------------------- Global variables ---------------------------*/
+
+#define LOGFILE "\\scitech.log"
+
+void (*_CHK_fail)(int fatal,const char *msg,const char *cond,const char *file,int line) = _CHK_defaultFail;
+
+/*---------------------------- Implementation -----------------------------*/
+
+/****************************************************************************
+DESCRIPTION:
+Handles fatal error and warning conditions for checked builds.
+
+HEADER:
+scitech.h
+
+REMARKS:
+This function is called whenever an inline check or warning fails in any
+of the SciTech runtime libraries. Warning conditions simply cause the
+condition to be logged to the log file and send to the system debugger
+under Window. Fatal error conditions do all of the above, and then
+terminate the program with a fatal error conditions.
+
+This handler may be overriden by the user code if necessary to replace it
+with a different handler (the MGL for instance overrides this and replaces
+it with a handler that does an MGL_exit() before terminating the application
+so that it will clean up correctly.
+****************************************************************************/
+void _CHK_defaultFail(
+ int fatal,
+ const char *msg,
+ const char *cond,
+ const char *file,
+ int line)
+{
+ char buf[256];
+ FILE *log = fopen(LOGFILE, "at+");
+
+ sprintf(buf,msg,cond,file,line);
+ if (log) {
+ fputs(buf,log);
+ fflush(log);
+ fclose(log);
+#ifdef __WINDOWS__
+ OutputDebugStr(buf);
+#endif
+ }
+ if (fatal) {
+#ifdef __WINDOWS__
+ MessageBox(NULL, buf,"Fatal Error!",MB_ICONEXCLAMATION);
+#else
+ fputs(buf,stderr);
+#endif
+ exit(-1);
+ }
+}
+
+#endif /* CHECKED */
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/cpu.c b/board/MAI/bios_emulator/scitech/src/pm/tests/cpu.c
new file mode 100644
index 0000000000..34abb2418d
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/cpu.c
@@ -0,0 +1,46 @@
+/****************************************************************************
+*
+* 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: Test program for the CPU detection code.
+*
+****************************************************************************/
+
+#include "ztimer.h"
+#include "pmapi.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/*----------------------------- Implementation ----------------------------*/
+
+int main(void)
+{
+ printf("Detecting processor information ...");
+ fflush(stdout);
+ printf("\n\n%s\n", CPU_getProcessorName());
+ if (CPU_haveRDTSC())
+ printf("\nProcessor supports Read Time Stamp Counter performance timer.\n");
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/critical.c b/board/MAI/bios_emulator/scitech/src/pm/tests/critical.c
new file mode 100644
index 0000000000..21ec9946f7
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/critical.c
@@ -0,0 +1,70 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to install a C based
+* critical error handler.
+*
+* Functions tested: PM_installAltCriticalHandler()
+* PM_restoreCriticalHandler()
+*
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+int main(void)
+{
+ FILE *f;
+ int axcode,dicode;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ PM_installCriticalHandler();
+ printf("Critical Error handler installed - trying to read from A: drive...\n");
+ f = fopen("a:\bog.bog","rb");
+ if (f) fclose(f);
+ if (PM_criticalError(&axcode,&dicode,1)) {
+ printf("Critical error occured on INT 21h function %02X!\n",
+ axcode >> 8);
+ }
+ else printf("Critical error was not caught!\n");
+ PM_restoreCriticalHandler();
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/getch.c b/board/MAI/bios_emulator/scitech/src/pm/tests/getch.c
new file mode 100644
index 0000000000..c70f7ee3c3
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/getch.c
@@ -0,0 +1,501 @@
+/****************************************************************************
+*
+* 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: Test program to test out the cross platform event handling
+* library.
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "pmapi.h"
+#include "event.h"
+
+/* Translation table for key codes */
+
+typedef struct {
+ int code;
+ char *name;
+ } KeyEntry;
+
+KeyEntry ASCIICodes[] = {
+ {ASCII_ctrlA ,"ASCII_ctrlA"},
+ {ASCII_ctrlB ,"ASCII_ctrlB"},
+ {ASCII_ctrlC ,"ASCII_ctrlC"},
+ {ASCII_ctrlD ,"ASCII_ctrlD"},
+ {ASCII_ctrlE ,"ASCII_ctrlE"},
+ {ASCII_ctrlF ,"ASCII_ctrlF"},
+ {ASCII_ctrlG ,"ASCII_ctrlG"},
+ {ASCII_backspace ,"ASCII_backspace"},
+ {ASCII_ctrlH ,"ASCII_ctrlH"},
+ {ASCII_tab ,"ASCII_tab"},
+ {ASCII_ctrlI ,"ASCII_ctrlI"},
+ {ASCII_ctrlJ ,"ASCII_ctrlJ"},
+ {ASCII_ctrlK ,"ASCII_ctrlK"},
+ {ASCII_ctrlL ,"ASCII_ctrlL"},
+ {ASCII_enter ,"ASCII_enter"},
+ {ASCII_ctrlM ,"ASCII_ctrlM"},
+ {ASCII_ctrlN ,"ASCII_ctrlN"},
+ {ASCII_ctrlO ,"ASCII_ctrlO"},
+ {ASCII_ctrlP ,"ASCII_ctrlP"},
+ {ASCII_ctrlQ ,"ASCII_ctrlQ"},
+ {ASCII_ctrlR ,"ASCII_ctrlR"},
+ {ASCII_ctrlS ,"ASCII_ctrlS"},
+ {ASCII_ctrlT ,"ASCII_ctrlT"},
+ {ASCII_ctrlU ,"ASCII_ctrlU"},
+ {ASCII_ctrlV ,"ASCII_ctrlV"},
+ {ASCII_ctrlW ,"ASCII_ctrlW"},
+ {ASCII_ctrlX ,"ASCII_ctrlX"},
+ {ASCII_ctrlY ,"ASCII_ctrlY"},
+ {ASCII_ctrlZ ,"ASCII_ctrlZ"},
+ {ASCII_esc ,"ASCII_esc"},
+ {ASCII_space ,"ASCII_space"},
+ {ASCII_exclamation ,"ASCII_exclamation"},
+ {ASCII_quote ,"ASCII_quote"},
+ {ASCII_pound ,"ASCII_pound"},
+ {ASCII_dollar ,"ASCII_dollar"},
+ {ASCII_percent ,"ASCII_percent"},
+ {ASCII_ampersand ,"ASCII_ampersand"},
+ {ASCII_apostrophe ,"ASCII_apostrophe"},
+ {ASCII_leftBrace ,"ASCII_leftBrace"},
+ {ASCII_rightBrace ,"ASCII_rightBrace"},
+ {ASCII_times ,"ASCII_times"},
+ {ASCII_plus ,"ASCII_plus"},
+ {ASCII_comma ,"ASCII_comma"},
+ {ASCII_minus ,"ASCII_minus"},
+ {ASCII_period ,"ASCII_period"},
+ {ASCII_divide ,"ASCII_divide"},
+ {ASCII_0 ,"ASCII_0"},
+ {ASCII_1 ,"ASCII_1"},
+ {ASCII_2 ,"ASCII_2"},
+ {ASCII_3 ,"ASCII_3"},
+ {ASCII_4 ,"ASCII_4"},
+ {ASCII_5 ,"ASCII_5"},
+ {ASCII_6 ,"ASCII_6"},
+ {ASCII_7 ,"ASCII_7"},
+ {ASCII_8 ,"ASCII_8"},
+ {ASCII_9 ,"ASCII_9"},
+ {ASCII_colon ,"ASCII_colon"},
+ {ASCII_semicolon ,"ASCII_semicolon"},
+ {ASCII_lessThan ,"ASCII_lessThan"},
+ {ASCII_equals ,"ASCII_equals"},
+ {ASCII_greaterThan ,"ASCII_greaterThan"},
+ {ASCII_question ,"ASCII_question"},
+ {ASCII_at ,"ASCII_at"},
+ {ASCII_A ,"ASCII_A"},
+ {ASCII_B ,"ASCII_B"},
+ {ASCII_C ,"ASCII_C"},
+ {ASCII_D ,"ASCII_D"},
+ {ASCII_E ,"ASCII_E"},
+ {ASCII_F ,"ASCII_F"},
+ {ASCII_G ,"ASCII_G"},
+ {ASCII_H ,"ASCII_H"},
+ {ASCII_I ,"ASCII_I"},
+ {ASCII_J ,"ASCII_J"},
+ {ASCII_K ,"ASCII_K"},
+ {ASCII_L ,"ASCII_L"},
+ {ASCII_M ,"ASCII_M"},
+ {ASCII_N ,"ASCII_N"},
+ {ASCII_O ,"ASCII_O"},
+ {ASCII_P ,"ASCII_P"},
+ {ASCII_Q ,"ASCII_Q"},
+ {ASCII_R ,"ASCII_R"},
+ {ASCII_S ,"ASCII_S"},
+ {ASCII_T ,"ASCII_T"},
+ {ASCII_U ,"ASCII_U"},
+ {ASCII_V ,"ASCII_V"},
+ {ASCII_W ,"ASCII_W"},
+ {ASCII_X ,"ASCII_X"},
+ {ASCII_Y ,"ASCII_Y"},
+ {ASCII_Z ,"ASCII_Z"},
+ {ASCII_leftSquareBrace ,"ASCII_leftSquareBrace"},
+ {ASCII_backSlash ,"ASCII_backSlash"},
+ {ASCII_rightSquareBrace ,"ASCII_rightSquareBrace"},
+ {ASCII_caret ,"ASCII_caret"},
+ {ASCII_underscore ,"ASCII_underscore"},
+ {ASCII_leftApostrophe ,"ASCII_leftApostrophe"},
+ {ASCII_a ,"ASCII_a"},
+ {ASCII_b ,"ASCII_b"},
+ {ASCII_c ,"ASCII_c"},
+ {ASCII_d ,"ASCII_d"},
+ {ASCII_e ,"ASCII_e"},
+ {ASCII_f ,"ASCII_f"},
+ {ASCII_g ,"ASCII_g"},
+ {ASCII_h ,"ASCII_h"},
+ {ASCII_i ,"ASCII_i"},
+ {ASCII_j ,"ASCII_j"},
+ {ASCII_k ,"ASCII_k"},
+ {ASCII_l ,"ASCII_l"},
+ {ASCII_m ,"ASCII_m"},
+ {ASCII_n ,"ASCII_n"},
+ {ASCII_o ,"ASCII_o"},
+ {ASCII_p ,"ASCII_p"},
+ {ASCII_q ,"ASCII_q"},
+ {ASCII_r ,"ASCII_r"},
+ {ASCII_s ,"ASCII_s"},
+ {ASCII_t ,"ASCII_t"},
+ {ASCII_u ,"ASCII_u"},
+ {ASCII_v ,"ASCII_v"},
+ {ASCII_w ,"ASCII_w"},
+ {ASCII_x ,"ASCII_x"},
+ {ASCII_y ,"ASCII_y"},
+ {ASCII_z ,"ASCII_z"},
+ {ASCII_leftCurlyBrace ,"ASCII_leftCurlyBrace"},
+ {ASCII_verticalBar ,"ASCII_verticalBar"},
+ {ASCII_rightCurlyBrace ,"ASCII_rightCurlyBrace"},
+ {ASCII_tilde ,"ASCII_tilde"},
+ {0 ,"ASCII_unknown"},
+ };
+
+KeyEntry ScanCodes[] = {
+ {KB_padEnter ,"KB_padEnter"},
+ {KB_padMinus ,"KB_padMinus"},
+ {KB_padPlus ,"KB_padPlus"},
+ {KB_padTimes ,"KB_padTimes"},
+ {KB_padDivide ,"KB_padDivide"},
+ {KB_padLeft ,"KB_padLeft"},
+ {KB_padRight ,"KB_padRight"},
+ {KB_padUp ,"KB_padUp"},
+ {KB_padDown ,"KB_padDown"},
+ {KB_padInsert ,"KB_padInsert"},
+ {KB_padDelete ,"KB_padDelete"},
+ {KB_padHome ,"KB_padHome"},
+ {KB_padEnd ,"KB_padEnd"},
+ {KB_padPageUp ,"KB_padPageUp"},
+ {KB_padPageDown ,"KB_padPageDown"},
+ {KB_padCenter ,"KB_padCenter"},
+ {KB_F1 ,"KB_F1"},
+ {KB_F2 ,"KB_F2"},
+ {KB_F3 ,"KB_F3"},
+ {KB_F4 ,"KB_F4"},
+ {KB_F5 ,"KB_F5"},
+ {KB_F6 ,"KB_F6"},
+ {KB_F7 ,"KB_F7"},
+ {KB_F8 ,"KB_F8"},
+ {KB_F9 ,"KB_F9"},
+ {KB_F10 ,"KB_F10"},
+ {KB_F11 ,"KB_F11"},
+ {KB_F12 ,"KB_F12"},
+ {KB_left ,"KB_left"},
+ {KB_right ,"KB_right"},
+ {KB_up ,"KB_up"},
+ {KB_down ,"KB_down"},
+ {KB_insert ,"KB_insert"},
+ {KB_delete ,"KB_delete"},
+ {KB_home ,"KB_home"},
+ {KB_end ,"KB_end"},
+ {KB_pageUp ,"KB_pageUp"},
+ {KB_pageDown ,"KB_pageDown"},
+ {KB_capsLock ,"KB_capsLock"},
+ {KB_numLock ,"KB_numLock"},
+ {KB_scrollLock ,"KB_scrollLock"},
+ {KB_leftShift ,"KB_leftShift"},
+ {KB_rightShift ,"KB_rightShift"},
+ {KB_leftCtrl ,"KB_leftCtrl"},
+ {KB_rightCtrl ,"KB_rightCtrl"},
+ {KB_leftAlt ,"KB_leftAlt"},
+ {KB_rightAlt ,"KB_rightAlt"},
+ {KB_leftWindows ,"KB_leftWindows"},
+ {KB_rightWindows ,"KB_rightWindows"},
+ {KB_menu ,"KB_menu"},
+ {KB_sysReq ,"KB_sysReq"},
+ {KB_esc ,"KB_esc"},
+ {KB_1 ,"KB_1"},
+ {KB_2 ,"KB_2"},
+ {KB_3 ,"KB_3"},
+ {KB_4 ,"KB_4"},
+ {KB_5 ,"KB_5"},
+ {KB_6 ,"KB_6"},
+ {KB_7 ,"KB_7"},
+ {KB_8 ,"KB_8"},
+ {KB_9 ,"KB_9"},
+ {KB_0 ,"KB_0"},
+ {KB_minus ,"KB_minus"},
+ {KB_equals ,"KB_equals"},
+ {KB_backSlash ,"KB_backSlash"},
+ {KB_backspace ,"KB_backspace"},
+ {KB_tab ,"KB_tab"},
+ {KB_Q ,"KB_Q"},
+ {KB_W ,"KB_W"},
+ {KB_E ,"KB_E"},
+ {KB_R ,"KB_R"},
+ {KB_T ,"KB_T"},
+ {KB_Y ,"KB_Y"},
+ {KB_U ,"KB_U"},
+ {KB_I ,"KB_I"},
+ {KB_O ,"KB_O"},
+ {KB_P ,"KB_P"},
+ {KB_leftSquareBrace ,"KB_leftSquareBrace"},
+ {KB_rightSquareBrace ,"KB_rightSquareBrace"},
+ {KB_enter ,"KB_enter"},
+ {KB_A ,"KB_A"},
+ {KB_S ,"KB_S"},
+ {KB_D ,"KB_D"},
+ {KB_F ,"KB_F"},
+ {KB_G ,"KB_G"},
+ {KB_H ,"KB_H"},
+ {KB_J ,"KB_J"},
+ {KB_K ,"KB_K"},
+ {KB_L ,"KB_L"},
+ {KB_semicolon ,"KB_semicolon"},
+ {KB_apostrophe ,"KB_apostrophe"},
+ {KB_Z ,"KB_Z"},
+ {KB_X ,"KB_X"},
+ {KB_C ,"KB_C"},
+ {KB_V ,"KB_V"},
+ {KB_B ,"KB_B"},
+ {KB_N ,"KB_N"},
+ {KB_M ,"KB_M"},
+ {KB_comma ,"KB_comma"},
+ {KB_period ,"KB_period"},
+ {KB_divide ,"KB_divide"},
+ {KB_space ,"KB_space"},
+ {KB_tilde ,"KB_tilde"},
+ {0 ,"KB_unknown"},
+ };
+
+/****************************************************************************
+PARAMETERS:
+x - X coordinate of the mouse cursor position (screen coordinates)
+y - Y coordinate of the mouse cursor position (screen coordinates)
+
+REMARKS:
+This gets called periodically to move the mouse. It will get called when
+the mouse may not have actually moved, so check if it has before redrawing
+it.
+****************************************************************************/
+void EVTAPI moveMouse(
+ int x,
+ int y)
+{
+}
+
+/****************************************************************************
+PARAMETERS:
+code - Code to translate
+keys - Table of translation key values to look up
+
+REMARKS:
+Simple function to look up the printable name for the keyboard code.
+****************************************************************************/
+KeyEntry *FindKey(
+ int code,
+ KeyEntry *keys)
+{
+ KeyEntry *key;
+
+ for (key = keys; key->code != 0; key++) {
+ if (key->code == code)
+ break;
+ }
+ return key;
+}
+
+/****************************************************************************
+PARAMETERS:
+evt - Event to display modifiers for
+
+REMARKS:
+Function to display shift modifiers flags
+****************************************************************************/
+void DisplayModifiers(
+ event_t *evt)
+{
+ if (evt->modifiers & EVT_LEFTBUT)
+ printf(", LBUT");
+ if (evt->modifiers & EVT_RIGHTBUT)
+ printf(", RBUT");
+ if (evt->modifiers & EVT_MIDDLEBUT)
+ printf(", MBUT");
+ if (evt->modifiers & EVT_SHIFTKEY) {
+ if (evt->modifiers & EVT_LEFTSHIFT)
+ printf(", LSHIFT");
+ if (evt->modifiers & EVT_RIGHTSHIFT)
+ printf(", RSHIFT");
+ }
+ if (evt->modifiers & EVT_CTRLSTATE) {
+ if (evt->modifiers & EVT_LEFTCTRL)
+ printf(", LCTRL");
+ if (evt->modifiers & EVT_RIGHTCTRL)
+ printf(", RCTRL");
+ }
+ if (evt->modifiers & EVT_ALTSTATE) {
+ if (evt->modifiers & EVT_LEFTALT)
+ printf(", LALT");
+ if (evt->modifiers & EVT_RIGHTALT)
+ printf(", RALT");
+ }
+}
+
+/****************************************************************************
+PARAMETERS:
+msg - Message to display for type of event
+evt - Event to display
+
+REMARKS:
+Function to display the status of the keyboard event to the screen.
+****************************************************************************/
+void DisplayKey(
+ char *msg,
+ event_t *evt)
+{
+ KeyEntry *ascii,*scan;
+ char ch = EVT_asciiCode(evt->message);
+
+ ascii = FindKey(ch,ASCIICodes);
+ scan = FindKey(EVT_scanCode(evt->message),ScanCodes);
+ printf("%s: 0x%04X -> %s, %s, '%c'",
+ msg, (int)evt->message & 0xFFFF, scan->name, ascii->name, isprint(ch) ? ch : ' ');
+ DisplayModifiers(evt);
+ printf("\n");
+}
+
+/****************************************************************************
+PARAMETERS:
+msg - Message to display for type of event
+evt - Event to display
+
+REMARKS:
+Function to display the status of the mouse event to the screen.
+****************************************************************************/
+void DisplayMouse(
+ char *msg,
+ event_t *evt)
+{
+ printf("%s: ", msg);
+ if (evt->message & EVT_LEFTBMASK)
+ printf("LEFT ");
+ if (evt->message & EVT_RIGHTBMASK)
+ printf("RIGHT ");
+ if (evt->message & EVT_MIDDLEBMASK)
+ printf("MIDDLE ");
+ printf("abs(%d,%d), rel(%d,%d)", evt->where_x, evt->where_y, evt->relative_x, evt->relative_y);
+ DisplayModifiers(evt);
+ if (evt->message & EVT_DBLCLICK)
+ printf(", DBLCLICK");
+ printf("\n");
+}
+
+/****************************************************************************
+PARAMETERS:
+msg - Message to display for type of event
+evt - Event to display
+
+REMARKS:
+Function to display the status of the joystick event to the screen.
+****************************************************************************/
+void DisplayJoy(
+ char *msg,
+ event_t *evt)
+{
+ printf("%s: Joy1(%4d,%4d,%c%c), Joy2(%4d,%4d,%c%c)\n", msg,
+ evt->where_x,evt->where_y,
+ (evt->message & EVT_JOY1_BUTTONA) ? 'A' : 'a',
+ (evt->message & EVT_JOY1_BUTTONB) ? 'B' : 'b',
+ evt->relative_x,evt->relative_y,
+ (evt->message & EVT_JOY2_BUTTONA) ? 'A' : 'a',
+ (evt->message & EVT_JOY2_BUTTONB) ? 'B' : 'b');
+}
+
+/****************************************************************************
+REMARKS:
+Joystick calibration routine
+****************************************************************************/
+void CalibrateJoy(void)
+{
+ event_t evt;
+ if(EVT_joyIsPresent()){
+ printf("Joystick Calibration\nMove the joystick to the upper left corner and press any button.\n");
+ EVT_halt(&evt, EVT_JOYCLICK);
+ EVT_halt(&evt, EVT_JOYCLICK);
+ EVT_joySetUpperLeft();
+ printf("Move the joystick to the lower right corner and press any button.\n");
+ EVT_halt(&evt, EVT_JOYCLICK);
+ EVT_halt(&evt, EVT_JOYCLICK);
+ EVT_joySetLowerRight();
+ printf("Move the joystick to center position and press any button.\n");
+ EVT_halt(&evt, EVT_JOYCLICK);
+ EVT_halt(&evt, EVT_JOYCLICK);
+ EVT_joySetCenter();
+ printf("Joystick calibrated\n");
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Main program entry point
+****************************************************************************/
+int main(void)
+{
+ event_t evt;
+ ibool done = false;
+ PM_HWND hwndConsole;
+
+ hwndConsole = PM_openConsole(0,0,0,0,0,true);
+ EVT_init(&moveMouse);
+ EVT_setMouseRange(1024,768);
+ CalibrateJoy();
+ do {
+ EVT_pollJoystick();
+ if (EVT_getNext(&evt,EVT_EVERYEVT)) {
+ switch (evt.what) {
+ case EVT_KEYDOWN:
+ DisplayKey("EVT_KEYDOWN ", &evt);
+ if (EVT_scanCode(evt.message) == KB_esc)
+ done = true;
+ break;
+ case EVT_KEYREPEAT:
+ DisplayKey("EVT_KEYREPEAT", &evt);
+ break;
+ case EVT_KEYUP:
+ DisplayKey("EVT_KEYUP ", &evt);
+ break;
+ case EVT_MOUSEDOWN:
+ DisplayMouse("EVT_MOUSEDOWN", &evt);
+ break;
+ case EVT_MOUSEAUTO:
+ DisplayMouse("EVT_MOUSEAUTO", &evt);
+ break;
+ case EVT_MOUSEUP:
+ DisplayMouse("EVT_MOUSEUP ", &evt);
+ break;
+ case EVT_MOUSEMOVE:
+ DisplayMouse("EVT_MOUSEMOVE", &evt);
+ break;
+ case EVT_JOYCLICK:
+ DisplayJoy("EVT_JOYCLICK ", &evt);
+ break;
+ case EVT_JOYMOVE:
+ DisplayJoy("EVT_JOYMOVE ", &evt);
+ break;
+ }
+ }
+ } while (!done);
+ EVT_exit();
+ PM_closeConsole(hwndConsole);
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/isvesa.c b/board/MAI/bios_emulator/scitech/src/pm/tests/isvesa.c
new file mode 100644
index 0000000000..9c02452bb3
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/isvesa.c
@@ -0,0 +1,110 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to allocate real mode
+* memory and to call real mode interrupt handlers such as
+* the VESA VBE BIOS from protected mode. Compile and link
+* with the appropriate command line for your DOS extender.
+*
+* Functions tested: PM_getVESABuf()
+* PM_mapRealPointer()
+* PM_int86x()
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "pmapi.h"
+
+/* SuperVGA information block */
+
+#pragma pack(1)
+
+typedef struct {
+ char VESASignature[4]; /* 'VESA' 4 byte signature */
+ short VESAVersion; /* VBE version number */
+ ulong OEMStringPtr; /* Far pointer to OEM string */
+ ulong Capabilities; /* Capabilities of video card */
+ ulong VideoModePtr; /* Far pointer to supported modes */
+ short TotalMemory; /* Number of 64kb memory blocks */
+ char reserved[236]; /* Pad to 256 byte block size */
+ } VgaInfoBlock;
+
+#pragma pack()
+
+int main(void)
+{
+ RMREGS regs;
+ RMSREGS sregs;
+ VgaInfoBlock vgaInfo;
+ ushort *mode;
+ uint vgLen;
+ uchar *vgPtr;
+ unsigned r_vgseg,r_vgoff;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ /* Allocate a 256 byte block of real memory for communicating with
+ * the VESA BIOS.
+ */
+ if ((vgPtr = PM_getVESABuf(&vgLen,&r_vgseg,&r_vgoff)) == NULL) {
+ printf("Unable to allocate VESA memory buffer!\n");
+ exit(1);
+ }
+
+ /* Call the VESA VBE to see if it is out there */
+ regs.x.ax = 0x4F00;
+ regs.x.di = r_vgoff;
+ sregs.es = r_vgseg;
+ memcpy(vgPtr,"VBE2",4);
+ PM_int86x(0x10, &regs, &regs, &sregs);
+ memcpy(&vgaInfo,vgPtr,sizeof(VgaInfoBlock));
+ if (regs.x.ax == 0x4F && strncmp(vgaInfo.VESASignature,"VESA",4) == 0) {
+ printf("VESA VBE version %d.%d BIOS detected\n\n",
+ vgaInfo.VESAVersion >> 8, vgaInfo.VESAVersion & 0xF);
+ printf("Available video modes:\n");
+ mode = PM_mapRealPointer(vgaInfo.VideoModePtr >> 16, vgaInfo.VideoModePtr & 0xFFFF);
+ while (*mode != 0xFFFF) {
+ printf(" %04hXh (%08X)\n", *mode, (int)mode);
+ mode++;
+ }
+ }
+ else
+ printf("VESA VBE not found\n");
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/key.c b/board/MAI/bios_emulator/scitech/src/pm/tests/key.c
new file mode 100644
index 0000000000..cf89f79fb7
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/key.c
@@ -0,0 +1,92 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to install a C based
+* keyboard interrupt handler.
+*
+* Functions tested: PM_setKeyHandler()
+* PM_chainPrevKey()
+* PM_restoreKeyHandler()
+*
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+volatile long count = 0;
+
+#pragma off (check_stack) /* No stack checking under Watcom */
+
+void PMAPI keyHandler(void)
+{
+ count++;
+ PM_chainPrevKey(); /* Chain to previous handler */
+}
+
+int main(void)
+{
+ int ch;
+ PM_lockHandle lh;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ /* Install our timer handler and lock handler pages in memory. It is
+ * difficult to get the size of a function in C, but we know our
+ * function is well less than 100 bytes (and an entire 4k page will
+ * need to be locked by the server anyway).
+ */
+ PM_lockCodePages((__codePtr)keyHandler,100,&lh);
+ PM_lockDataPages((void*)&count,sizeof(count),&lh);
+ PM_installBreakHandler(); /* We *DONT* want Ctrl-Breaks! */
+ PM_setKeyHandler(keyHandler);
+ printf("Keyboard interrupt handler installed - Type some characters and\n");
+ printf("hit ESC to exit\n");
+ while ((ch = PM_getch()) != 0x1B) {
+ printf("%c", ch);
+ fflush(stdout);
+ }
+
+ PM_restoreKeyHandler();
+ PM_restoreBreakHandler();
+ PM_unlockDataPages((void*)&count,sizeof(count),&lh);
+ PM_unlockCodePages((__codePtr)keyHandler,100,&lh);
+ printf("\n\nKeyboard handler was called %ld times\n", count);
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/key15.c b/board/MAI/bios_emulator/scitech/src/pm/tests/key15.c
new file mode 100644
index 0000000000..5c0d27a174
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/key15.c
@@ -0,0 +1,96 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to install a C based
+* keyboard Int 15h interrupt handler. This is an alternate
+* way to intercept scancodes from the keyboard by hooking
+* the Int 15h keyboard intercept callout.
+*
+* Functions tested: PM_setKey15Handler()
+* PM_restoreKey15Handler()
+*
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+volatile long count = 0;
+volatile short lastScanCode = 0;
+
+#pragma off (check_stack) /* No stack checking under Watcom */
+
+short PMAPI keyHandler(short scanCode)
+{
+ count++;
+ lastScanCode = scanCode;
+ return scanCode; /* Let BIOS process as normal */
+}
+
+int main(void)
+{
+ int ch;
+ PM_lockHandle lh;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ /* Install our timer handler and lock handler pages in memory. It is
+ * difficult to get the size of a function in C, but we know our
+ * function is well less than 100 bytes (and an entire 4k page will
+ * need to be locked by the server anyway).
+ */
+ PM_lockCodePages((__codePtr)keyHandler,100,&lh);
+ PM_lockDataPages((void*)&count,sizeof(count),&lh);
+ PM_installBreakHandler(); /* We *DONT* want Ctrl-Break's! */
+ PM_setKey15Handler(keyHandler);
+ printf("Keyboard interrupt handler installed - Type some characters and\n");
+ printf("hit ESC to exit\n");
+ while ((ch = PM_getch()) != 0x1B) {
+ printf("%c", ch);
+ fflush(stdout);
+ }
+
+ PM_restoreKey15Handler();
+ PM_restoreBreakHandler();
+ PM_unlockDataPages((void*)&count,sizeof(count),&lh);
+ PM_unlockCodePages((__codePtr)keyHandler,100,&lh);
+ printf("\n\nKeyboard handler was called %ld times\n", count);
+ printf("Last scan code %04X\n", lastScanCode);
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/memtest.c b/board/MAI/bios_emulator/scitech/src/pm/tests/memtest.c
new file mode 100644
index 0000000000..221bfb1a02
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/memtest.c
@@ -0,0 +1,106 @@
+/****************************************************************************
+*
+* 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: Test program to determine just how much memory can be
+* allocated with the compiler in use. Compile and link
+* with the appropriate command line for your DOS extender.
+*
+* Functions tested: PM_malloc()
+* PM_availableMemory()
+*
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "pmapi.h"
+
+#ifdef __16BIT__
+#define MAXALLOC 64
+#else
+#define MAXALLOC 2000
+#endif
+
+int main(void)
+{
+ int i;
+ ulong allocs;
+ ulong physical,total;
+ char *p,*pa[MAXALLOC];
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ printf("Memory available at start:\n");
+ PM_availableMemory(&physical,&total);
+ printf(" Physical memory: %ld Kb\n", physical / 1024);
+ printf(" Total (including virtual): %ld Kb\n", total / 1024);
+ printf("\n");
+ for (allocs = i = 0; i < MAXALLOC; i++) {
+ if ((pa[i] = PM_malloc(10*1024)) != 0) { /* in 10k blocks */
+ p = pa[allocs];
+ memset(p, 0, 10*1024); /* touch every byte */
+ *p = 'x'; /* do something, anything with */
+ p[1023] = 'y'; /* the allocated memory */
+ allocs++;
+ printf("Allocated %lu bytes\r", 10*(allocs << 10));
+ }
+ else break;
+ if (PM_kbhit() && (PM_getch() == 0x1B))
+ break;
+ }
+
+ printf("\n\nAllocated total of %lu bytes\n", 10 * (allocs << 10));
+
+ printf("\nMemory available at end:\n");
+ PM_availableMemory(&physical,&total);
+ printf(" Physical memory: %ld Kb\n", physical / 1024);
+ printf(" Total (including virtual): %ld Kb\n", total / 1024);
+
+ for (i = allocs-1; i >= 0; i--)
+ PM_free(pa[i]);
+
+ printf("\nMemory available after freeing all blocks (note that under protected mode\n");
+ printf("this will most likely not be correct after freeing blocks):\n\n");
+ PM_availableMemory(&physical,&total);
+ printf(" Physical memory: %ld Kb\n", physical / 1024);
+ printf(" Total (including virtual): %ld Kb\n", total / 1024);
+
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/mouse.c b/board/MAI/bios_emulator/scitech/src/pm/tests/mouse.c
new file mode 100644
index 0000000000..5b426517c8
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/mouse.c
@@ -0,0 +1,109 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to install an assembly
+* language mouse interrupt handler. We use assembly language
+* as it must be a far function and should swap to a local
+* 32 bit stack if it is going to call any C based code (which
+* we do in this example).
+*
+* Functions tested: PM_installMouseHandler()
+* PM_int86()
+*
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+volatile long count = 0;
+
+#pragma off (check_stack) /* No stack checking under Watcom */
+
+void PMAPI mouseHandler(
+ uint mask,
+ uint butstate,
+ int x,
+ int y,
+ int mickeyX,
+ int mickeyY)
+{
+ mask = mask; /* We dont use any of the parameters */
+ butstate = butstate;
+ x = x;
+ y = y;
+ mickeyX = mickeyX;
+ mickeyY = mickeyY;
+ count++;
+}
+
+int main(void)
+{
+ RMREGS regs;
+ PM_lockHandle lh;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ regs.x.ax = 33; /* Mouse function 33 - Software reset */
+ PM_int86(0x33,&regs,&regs);
+ if (regs.x.bx == 0) {
+ printf("No mouse installed.\n");
+ exit(1);
+ }
+
+ /* Install our mouse handler and lock handler pages in memory. It is
+ * difficult to get the size of a function in C, but we know our
+ * function is well less than 100 bytes (and an entire 4k page will
+ * need to be locked by the server anyway).
+ */
+ PM_lockCodePages((__codePtr)mouseHandler,100,&lh);
+ PM_lockDataPages((void*)&count,sizeof(count),&lh);
+ if (!PM_setMouseHandler(0xFFFF, mouseHandler)) {
+ printf("Unable to install mouse handler!\n");
+ exit(1);
+ }
+ printf("Mouse handler installed - Hit any key to exit\n");
+ PM_getch();
+
+ PM_restoreMouseHandler();
+ PM_unlockDataPages((void*)&count,sizeof(count),&lh);
+ PM_unlockCodePages((__codePtr)mouseHandler,100,&lh);
+ printf("Mouse handler was called %ld times\n", count);
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/restore.c b/board/MAI/bios_emulator/scitech/src/pm/tests/restore.c
new file mode 100644
index 0000000000..b808052c02
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/restore.c
@@ -0,0 +1,82 @@
+/****************************************************************************
+*
+* 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: Linux/QNX
+*
+* Description: Program to restore the console state state from a previously
+* saved state if the program crashed while the console
+* was in graphics mode.
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+void setVideoMode(int mode)
+{
+ RMREGS r;
+
+ r.x.ax = mode;
+ PM_int86(0x10, &r, &r);
+}
+
+int main(void)
+{
+ PM_HWND hwndConsole;
+ ulong stateSize;
+ void *stateBuf;
+ FILE *f;
+
+ /* Write the saved console state buffer to disk */
+ if ((f = fopen("/etc/pmsave.dat","rb")) == NULL) {
+ printf("Unable to open /etc/pmsave.dat for reading!\n");
+ return -1;
+ }
+ fread(&stateSize,1,sizeof(stateSize),f);
+ if (stateSize != PM_getConsoleStateSize()) {
+ printf("Size mismatch in /etc/pmsave.dat!\n");
+ return -1;
+ }
+ if ((stateBuf = PM_malloc(stateSize)) == NULL) {
+ printf("Unable to allocate console state buffer!\n");
+ return -1;
+ }
+ fread(stateBuf,1,stateSize,f);
+ fclose(f);
+
+ /* Open the console */
+ hwndConsole = PM_openConsole(0,0,0,0,0,true);
+
+ /* Forcibly set 80x25 text mode using the BIOS */
+ setVideoMode(0x3);
+
+ /* Restore the previous console state */
+ PM_restoreConsoleState(stateBuf,0);
+ PM_closeConsole(hwndConsole);
+ PM_free(stateBuf);
+ printf("Console state successfully restored from /etc/pmsave.dat\n");
+ return 0;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/rtc.c b/board/MAI/bios_emulator/scitech/src/pm/tests/rtc.c
new file mode 100644
index 0000000000..07c6eaafd4
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/rtc.c
@@ -0,0 +1,92 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to install a C based
+* Real Time Clock interrupt handler.
+*
+* Functions tested: PM_setRealTimeClockHandler()
+* PM_restoreRealTimeClockHandler()
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+volatile long count = 0;
+
+#pragma off (check_stack) /* No stack checking under Watcom */
+
+void PMAPI RTCHandler(void)
+{
+ count++;
+}
+
+int main(void)
+{
+ long oldCount;
+ PM_lockHandle lh;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ /* Install our timer handler and lock handler pages in memory. It is
+ * difficult to get the size of a function in C, but we know our
+ * function is well less than 100 bytes (and an entire 4k page will
+ * need to be locked by the server anyway).
+ */
+ PM_lockCodePages((__codePtr)RTCHandler,100,&lh);
+ PM_lockDataPages((void*)&count,sizeof(count),&lh);
+ PM_installBreakHandler(); /* We *DONT* want Ctrl-Breaks! */
+ PM_setRealTimeClockHandler(RTCHandler,128);
+ printf("RealTimeClock interrupt handler installed - Hit ESC to exit\n");
+ oldCount = count;
+ while (1) {
+ if (PM_kbhit() && (PM_getch() == 0x1B))
+ break;
+ if (count != oldCount) {
+ printf("Tick, Tock: %ld\n", count);
+ oldCount = count;
+ }
+ }
+
+ PM_restoreRealTimeClockHandler();
+ PM_restoreBreakHandler();
+ PM_unlockDataPages((void*)&count,sizeof(count),&lh);
+ PM_unlockCodePages((__codePtr)RTCHandler,100,&lh);
+ printf("RealTimeClock handler was called %ld times\n", count);
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/save.c b/board/MAI/bios_emulator/scitech/src/pm/tests/save.c
new file mode 100644
index 0000000000..be96968f62
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/save.c
@@ -0,0 +1,70 @@
+/****************************************************************************
+*
+* 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: Linux/QNX
+*
+* Description: Program to save the console state state so that it can
+* be later restored if the program crashed while the console
+* was in graphics mode.
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+int main(void)
+{
+ PM_HWND hwndConsole;
+ ulong stateSize;
+ void *stateBuf;
+ FILE *f;
+
+ /* Allocate a buffer to save console state and save the state */
+ hwndConsole = PM_openConsole(0,0,0,0,0,true);
+ stateSize = PM_getConsoleStateSize();
+ if ((stateBuf = PM_malloc(stateSize)) == NULL) {
+ PM_closeConsole(hwndConsole);
+ printf("Unable to allocate console state buffer!\n");
+ return -1;
+ }
+ PM_saveConsoleState(stateBuf,0);
+
+ /* Restore the console state on exit */
+ PM_restoreConsoleState(stateBuf,0);
+ PM_closeConsole(hwndConsole);
+
+ /* Write the saved console state buffer to disk */
+ if ((f = fopen("/etc/pmsave.dat","wb")) == NULL)
+ printf("Unable to open /etc/pmsave/dat for writing!\n");
+ else {
+ fwrite(&stateSize,1,sizeof(stateSize),f);
+ fwrite(stateBuf,1,stateSize,f);
+ fclose(f);
+ printf("Console state successfully saved to /etc/pmsave.dat\n");
+ }
+ PM_free(stateBuf);
+ return 0;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/showpci.c b/board/MAI/bios_emulator/scitech/src/pm/tests/showpci.c
new file mode 100644
index 0000000000..8222b86024
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/showpci.c
@@ -0,0 +1,253 @@
+/****************************************************************************
+*
+* 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: Test program to test the PCI library functions.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "pcilib.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+/*------------------------- Global Variables ------------------------------*/
+
+static int NumPCI = -1;
+static PCIDeviceInfo *PCI;
+static int *BridgeIndex;
+static int *DeviceIndex;
+static int NumBridges;
+static PCIDeviceInfo *AGPBridge = NULL;
+static int NumDevices;
+
+/*-------------------------- Implementation -------------------------------*/
+
+/****************************************************************************
+REMARKS:
+Enumerates the PCI bus and dumps the PCI configuration information to the
+log file.
+****************************************************************************/
+static void EnumeratePCI(void)
+{
+ int i,index;
+ PCIDeviceInfo *info;
+
+ printf("Displaying enumeration of PCI bus (%d devices, %d display devices)\n",
+ NumPCI, NumDevices);
+ for (index = 0; index < NumDevices; index++)
+ printf(" Display device %d is PCI device %d\n",index,DeviceIndex[index]);
+ printf("\n");
+ printf("Bus Slot Fnc DeviceID SubSystem Rev Class IRQ Int Cmd\n");
+ for (i = 0; i < NumPCI; i++) {
+ printf("%2d %2d %2d %04X:%04X %04X:%04X %02X %02X:%02X %02X %02X %04X ",
+ PCI[i].slot.p.Bus,
+ PCI[i].slot.p.Device,
+ PCI[i].slot.p.Function,
+ PCI[i].VendorID,
+ PCI[i].DeviceID,
+ PCI[i].u.type0.SubSystemVendorID,
+ PCI[i].u.type0.SubSystemID,
+ PCI[i].RevID,
+ PCI[i].BaseClass,
+ PCI[i].SubClass,
+ PCI[i].u.type0.InterruptLine,
+ PCI[i].u.type0.InterruptPin,
+ PCI[i].Command);
+ for (index = 0; index < NumDevices; index++) {
+ if (DeviceIndex[index] == i)
+ break;
+ }
+ if (index < NumDevices)
+ printf("<- %d\n", index);
+ else
+ printf("\n");
+ }
+ printf("\n");
+ printf("DeviceID Stat Ifc Cch Lat Hdr BIST\n");
+ for (i = 0; i < NumPCI; i++) {
+ printf("%04X:%04X %04X %02X %02X %02X %02X %02X ",
+ PCI[i].VendorID,
+ PCI[i].DeviceID,
+ PCI[i].Status,
+ PCI[i].Interface,
+ PCI[i].CacheLineSize,
+ PCI[i].LatencyTimer,
+ PCI[i].HeaderType,
+ PCI[i].BIST);
+ for (index = 0; index < NumDevices; index++) {
+ if (DeviceIndex[index] == i)
+ break;
+ }
+ if (index < NumDevices)
+ printf("<- %d\n", index);
+ else
+ printf("\n");
+ }
+ printf("\n");
+ printf("DeviceID Base10h Base14h Base18h Base1Ch Base20h Base24h ROMBase\n");
+ for (i = 0; i < NumPCI; i++) {
+ printf("%04X:%04X %08lX %08lX %08lX %08lX %08lX %08lX %08lX ",
+ PCI[i].VendorID,
+ PCI[i].DeviceID,
+ PCI[i].u.type0.BaseAddress10,
+ PCI[i].u.type0.BaseAddress14,
+ PCI[i].u.type0.BaseAddress18,
+ PCI[i].u.type0.BaseAddress1C,
+ PCI[i].u.type0.BaseAddress20,
+ PCI[i].u.type0.BaseAddress24,
+ PCI[i].u.type0.ROMBaseAddress);
+ for (index = 0; index < NumDevices; index++) {
+ if (DeviceIndex[index] == i)
+ break;
+ }
+ if (index < NumDevices)
+ printf("<- %d\n", index);
+ else
+ printf("\n");
+ }
+ printf("\n");
+ printf("DeviceID BAR10Len BAR14Len BAR18Len BAR1CLen BAR20Len BAR24Len ROMLen\n");
+ for (i = 0; i < NumPCI; i++) {
+ printf("%04X:%04X %08lX %08lX %08lX %08lX %08lX %08lX %08lX ",
+ PCI[i].VendorID,
+ PCI[i].DeviceID,
+ PCI[i].u.type0.BaseAddress10Len,
+ PCI[i].u.type0.BaseAddress14Len,
+ PCI[i].u.type0.BaseAddress18Len,
+ PCI[i].u.type0.BaseAddress1CLen,
+ PCI[i].u.type0.BaseAddress20Len,
+ PCI[i].u.type0.BaseAddress24Len,
+ PCI[i].u.type0.ROMBaseAddressLen);
+ for (index = 0; index < NumDevices; index++) {
+ if (DeviceIndex[index] == i)
+ break;
+ }
+ if (index < NumDevices)
+ printf("<- %d\n", index);
+ else
+ printf("\n");
+ }
+ printf("\n");
+ printf("Displaying enumeration of %d bridge devices\n",NumBridges);
+ printf("\n");
+ printf("DeviceID P# S# B# IOB IOL MemBase MemLimit PreBase PreLimit Ctrl\n");
+ for (i = 0; i < NumBridges; i++) {
+ info = (PCIDeviceInfo*)&PCI[BridgeIndex[i]];
+ printf("%04X:%04X %02X %02X %02X %04X %04X %08X %08X %08X %08X %04X\n",
+ info->VendorID,
+ info->DeviceID,
+ info->u.type1.PrimaryBusNumber,
+ info->u.type1.SecondayBusNumber,
+ info->u.type1.SubordinateBusNumber,
+ ((u16)info->u.type1.IOBase << 8) & 0xF000,
+ info->u.type1.IOLimit ?
+ ((u16)info->u.type1.IOLimit << 8) | 0xFFF : 0,
+ ((u32)info->u.type1.MemoryBase << 16) & 0xFFF00000,
+ info->u.type1.MemoryLimit ?
+ ((u32)info->u.type1.MemoryLimit << 16) | 0xFFFFF : 0,
+ ((u32)info->u.type1.PrefetchableMemoryBase << 16) & 0xFFF00000,
+ info->u.type1.PrefetchableMemoryLimit ?
+ ((u32)info->u.type1.PrefetchableMemoryLimit << 16) | 0xFFFFF : 0,
+ info->u.type1.BridgeControl);
+ }
+ printf("\n");
+}
+
+/****************************************************************************
+RETURNS:
+Number of display devices found.
+
+REMARKS:
+This function enumerates the number of available display devices on the
+PCI bus, and returns the number found.
+****************************************************************************/
+static int PCI_enumerateDevices(void)
+{
+ int i,j;
+ PCIDeviceInfo *info;
+
+ // If this is the first time we have been called, enumerate all
+ // devices on the PCI bus.
+ if (NumPCI == -1) {
+ if ((NumPCI = PCI_getNumDevices()) == 0)
+ return -1;
+ PCI = malloc(NumPCI * sizeof(PCI[0]));
+ BridgeIndex = malloc(NumPCI * sizeof(BridgeIndex[0]));
+ DeviceIndex = malloc(NumPCI * sizeof(DeviceIndex[0]));
+ if (!PCI || !BridgeIndex || !DeviceIndex)
+ return -1;
+ for (i = 0; i < NumPCI; i++)
+ PCI[i].dwSize = sizeof(PCI[i]);
+ if (PCI_enumerate(PCI) == 0)
+ return -1;
+
+ // Build a list of all PCI bridge devices
+ for (i = 0,NumBridges = 0,BridgeIndex[0] = -1; i < NumPCI; i++) {
+ if (PCI[i].BaseClass == PCI_BRIDGE_CLASS)
+ BridgeIndex[NumBridges++] = i;
+ }
+
+ // Now build a list of all display class devices
+ for (i = 0,NumDevices = 1,DeviceIndex[0] = -1; i < NumPCI; i++) {
+ if (PCI_IS_DISPLAY_CLASS(&PCI[i])) {
+ if ((PCI[i].Command & 0x3) == 0x3)
+ DeviceIndex[0] = i;
+ else
+ DeviceIndex[NumDevices++] = i;
+ if (PCI[i].slot.p.Bus != 0) {
+ // This device is on a different bus than the primary
+ // PCI bus, so it is probably an AGP device. Find the
+ // AGP bus device that controls that bus so we can
+ // control it.
+ for (j = 0; j < NumBridges; j++) {
+ info = (PCIDeviceInfo*)&PCI[BridgeIndex[j]];
+ if (info->u.type1.SecondayBusNumber == PCI[i].slot.p.Bus) {
+ AGPBridge = info;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Enumerate all PCI and bridge devices to standard output
+ EnumeratePCI();
+ }
+ return NumDevices;
+}
+
+int main(void)
+{
+ // Enumerate all PCI devices
+ PM_init();
+ if (PCI_enumerateDevices() < 1) {
+ printf("No PCI display devices found!\n");
+ return -1;
+ }
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/tick.c b/board/MAI/bios_emulator/scitech/src/pm/tests/tick.c
new file mode 100644
index 0000000000..ee1014fb9f
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/tick.c
@@ -0,0 +1,94 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to install a C based
+* timer interrupt handler.
+*
+* Functions tested: PM_setTimerHandler()
+* PM_chainPrevTimer();
+* PM_restoreTimerHandler()
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+volatile long count = 0;
+
+#pragma off (check_stack) /* No stack checking under Watcom */
+
+void PMAPI timerHandler(void)
+{
+ PM_chainPrevTimer(); /* Chain to previous handler */
+ count++;
+}
+
+int main(void)
+{
+ long oldCount;
+ PM_lockHandle lh;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ /* Install our timer handler and lock handler pages in memory. It is
+ * difficult to get the size of a function in C, but we know our
+ * function is well less than 100 bytes (and an entire 4k page will
+ * need to be locked by the server anyway).
+ */
+ PM_lockCodePages((__codePtr)timerHandler,100,&lh);
+ PM_lockDataPages((void*)&count,sizeof(count),&lh);
+ PM_installBreakHandler(); /* We *DONT* want Ctrl-Breaks! */
+ PM_setTimerHandler(timerHandler);
+ printf("Timer interrupt handler installed - Hit ESC to exit\n");
+ oldCount = count;
+ while (1) {
+ if (PM_kbhit() && (PM_getch() == 0x1B))
+ break;
+ if (count != oldCount) {
+ printf("Tick, Tock: %ld\n", count);
+ oldCount = count;
+ }
+ }
+
+ PM_restoreTimerHandler();
+ PM_restoreBreakHandler();
+ PM_unlockDataPages((void*)&count,sizeof(count),&lh);
+ PM_unlockCodePages((__codePtr)timerHandler,100,&lh);
+ printf("Timer handler was called %ld times\n", count);
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/timerc.c b/board/MAI/bios_emulator/scitech/src/pm/tests/timerc.c
new file mode 100644
index 0000000000..55e95a85d6
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/timerc.c
@@ -0,0 +1,87 @@
+/****************************************************************************
+*
+* 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: Test program for the Zen Timer Library.
+*
+****************************************************************************/
+
+#include <stdio.h>
+#include "pmapi.h"
+#include "ztimer.h"
+
+#define DELAY_SECS 10
+
+/*-------------------------- Implementation -------------------------------*/
+
+/* The following routine takes a long count in microseconds and outputs
+ * a string representing the count in seconds. It could be modified to
+ * return a pointer to a static string representing the count rather
+ * than printing it out.
+ */
+
+void ReportTime(ulong count)
+{
+ ulong secs;
+
+ secs = count / 1000000L;
+ count = count - secs * 1000000L;
+ printf("Time taken: %lu.%06lu seconds\n",secs,count);
+}
+
+int i,j; /* NON register variables! */
+
+int main(void)
+{
+#ifdef LONG_TEST
+ ulong start,finish;
+#endif
+
+ printf("Processor type: %d %ld MHz\n", CPU_getProcessorType(), CPU_getProcessorSpeed(true));
+
+ ZTimerInit();
+
+ /* Test the long period Zen Timer (we don't check for overflow coz
+ * it would take tooooo long!)
+ */
+
+ LZTimerOn();
+ for (j = 0; j < 10; j++)
+ for (i = 0; i < 20000; i++)
+ i = i;
+ LZTimerOff();
+ ReportTime(LZTimerCount());
+
+ /* Test the ultra long period Zen Timer */
+#ifdef LONG_TEST
+ start = ULZReadTime();
+ delay(DELAY_SECS * 1000);
+ finish = ULZReadTime();
+ printf("Delay of %d secs took %d 1/10ths of a second\n",
+ DELAY_SECS,ULZElapsedTime(start,finish));
+#endif
+
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/timercpp.cpp b/board/MAI/bios_emulator/scitech/src/pm/tests/timercpp.cpp
new file mode 100644
index 0000000000..1258a4bb10
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/timercpp.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+*
+* 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: C++ 3.0
+* Environment: Any
+*
+* Description: Test program for the Zen Timer Library C++ interface.
+*
+****************************************************************************/
+
+#include <iostream.h>
+#include "pmapi.h"
+#include "ztimer.h"
+
+/*-------------------------- Implementation -------------------------------*/
+
+int i,j,k; /* NON register variables! */
+
+void dummy() {}
+
+int main(void)
+{
+ LZTimer ltimer;
+ ULZTimer ultimer;
+
+ ZTimerInit();
+
+ /* Test the long period Zen Timer (we don't check for overflow coz
+ * it would take tooooo long!)
+ */
+
+ cout << endl;
+ ultimer.restart();
+ ltimer.start();
+ for (j = 0; j < 10; j++)
+ for (i = 0; i < 20000; i++)
+ dummy();
+ ltimer.stop();
+ ultimer.stop();
+ cout << "LCount: " << ltimer.count() << endl;
+ cout << "Time: " << ltimer << " secs\n";
+ cout << "ULCount: " << ultimer.count() << endl;
+ cout << "ULTime: " << ultimer << " secs\n";
+
+ cout << endl << "Timing ... \n";
+ ultimer.restart();
+ ltimer.restart();
+ for (j = 0; j < 200; j++)
+ for (i = 0; i < 20000; i++)
+ dummy();
+ ltimer.stop();
+ ultimer.stop();
+ cout << "LCount: " << ltimer.count() << endl;
+ cout << "Time: " << ltimer << " secs\n";
+ cout << "ULCount: " << ultimer.count() << endl;
+ cout << "ULTime: " << ultimer << " secs\n";
+
+ /* Test the lap function of the long period Zen Timer */
+
+ cout << endl << "Timing ... \n";
+ ultimer.restart();
+ ltimer.restart();
+ for (j = 0; j < 20; j++) {
+ for (k = 0; k < 10; k++)
+ for (i = 0; i < 20000; i++)
+ dummy();
+ cout << "lap: " << ltimer.lap() << endl;
+ }
+ ltimer.stop();
+ ultimer.stop();
+ cout << "LCount: " << ltimer.count() << endl;
+ cout << "Time: " << ltimer << " secs\n";
+ cout << "ULCount: " << ultimer.count() << endl;
+ cout << "ULTime: " << ultimer << " secs\n";
+
+#ifdef LONG_TEST
+ /* Test the ultra long period Zen Timer */
+
+ ultimer.start();
+ delay(DELAY_SECS * 1000);
+ ultimer.stop();
+ cout << "Delay of " << DELAY_SECS << " secs took " << ultimer.count()
+ << " 1/10ths of a second\n";
+ cout << "Time: " << ultimer << " secs\n";
+#endif
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/uswc.c b/board/MAI/bios_emulator/scitech/src/pm/tests/uswc.c
new file mode 100644
index 0000000000..0892e25f3a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/uswc.c
@@ -0,0 +1,311 @@
+/****************************************************************************
+*
+* 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: Simple test program to test the write combine functions.
+*
+* Note that this program should never be used in a production
+* environment, because write combining needs to be handled
+* with more intimate knowledge of the display hardware than
+* you can obtain by simply examining the PCI configuration
+* space.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "pcilib.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+/*------------------------- Global Variables ------------------------------*/
+
+static int NumPCI = -1;
+static PCIDeviceInfo *PCI;
+static int *BridgeIndex;
+static int *DeviceIndex;
+static int NumBridges;
+static PCIDeviceInfo *AGPBridge = NULL;
+static int NumDevices;
+
+/*-------------------------- Implementation -------------------------------*/
+
+/****************************************************************************
+RETURNS:
+Number of display devices found.
+
+REMARKS:
+This function enumerates the number of available display devices on the
+PCI bus, and returns the number found.
+****************************************************************************/
+static int PCI_enumerateDevices(void)
+{
+ int i,j;
+ PCIDeviceInfo *info;
+
+ // If this is the first time we have been called, enumerate all
+ // devices on the PCI bus.
+ if (NumPCI == -1) {
+ if ((NumPCI = PCI_getNumDevices()) == 0)
+ return -1;
+ PCI = malloc(NumPCI * sizeof(PCI[0]));
+ BridgeIndex = malloc(NumPCI * sizeof(BridgeIndex[0]));
+ DeviceIndex = malloc(NumPCI * sizeof(DeviceIndex[0]));
+ if (!PCI || !BridgeIndex || !DeviceIndex)
+ return -1;
+ for (i = 0; i < NumPCI; i++)
+ PCI[i].dwSize = sizeof(PCI[i]);
+ if (PCI_enumerate(PCI) == 0)
+ return -1;
+
+ // Build a list of all PCI bridge devices
+ for (i = 0,NumBridges = 0,BridgeIndex[0] = -1; i < NumPCI; i++) {
+ if (PCI[i].BaseClass == PCI_BRIDGE_CLASS)
+ BridgeIndex[NumBridges++] = i;
+ }
+
+ // Now build a list of all display class devices
+ for (i = 0,NumDevices = 1,DeviceIndex[0] = -1; i < NumPCI; i++) {
+ if (PCI_IS_DISPLAY_CLASS(&PCI[i])) {
+ if ((PCI[i].Command & 0x3) == 0x3)
+ DeviceIndex[0] = i;
+ else
+ DeviceIndex[NumDevices++] = i;
+ if (PCI[i].slot.p.Bus != 0) {
+ // This device is on a different bus than the primary
+ // PCI bus, so it is probably an AGP device. Find the
+ // AGP bus device that controls that bus so we can
+ // control it.
+ for (j = 0; j < NumBridges; j++) {
+ info = (PCIDeviceInfo*)&PCI[BridgeIndex[j]];
+ if (info->u.type1.SecondayBusNumber == PCI[i].slot.p.Bus) {
+ AGPBridge = info;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return NumDevices;
+}
+
+/****************************************************************************
+REMARKS:
+Enumerates useful information about attached display devices.
+****************************************************************************/
+static void ShowDisplayDevices(void)
+{
+ int i,index;
+
+ printf("Displaying enumeration of %d PCI display devices\n", NumDevices);
+ printf("\n");
+ printf("DeviceID SubSystem Base10h (length ) Base14h (length )\n");
+ for (index = 0; index < NumDevices; index++) {
+ i = DeviceIndex[index];
+ printf("%04X:%04X %04X:%04X %08lX (%6ld KB) %08lX (%6ld KB)\n",
+ PCI[i].VendorID,
+ PCI[i].DeviceID,
+ PCI[i].u.type0.SubSystemVendorID,
+ PCI[i].u.type0.SubSystemID,
+ PCI[i].u.type0.BaseAddress10,
+ PCI[i].u.type0.BaseAddress10Len / 1024,
+ PCI[i].u.type0.BaseAddress14,
+ PCI[i].u.type0.BaseAddress14Len / 1024);
+ }
+ printf("\n");
+}
+
+/****************************************************************************
+REMARKS:
+Dumps the value for a write combine region to the display.
+****************************************************************************/
+static char *DecodeWCType(
+ uint type)
+{
+ static char *names[] = {
+ "UNCACHABLE",
+ "WRCOMB",
+ "UNKNOWN",
+ "UNKNOWN",
+ "WRTHROUGH",
+ "WRPROT",
+ "WRBACK",
+ };
+ if (type <= PM_MTRR_MAX)
+ return names[type];
+ return "UNKNOWN";
+}
+
+/****************************************************************************
+REMARKS:
+Dumps the value for a write combine region to the display.
+****************************************************************************/
+static void PMAPI EnumWriteCombine(
+ ulong base,
+ ulong length,
+ uint type)
+{
+ printf("%08lX %-10ld %s\n", base, length / 1024, DecodeWCType(type));
+}
+
+/****************************************************************************
+PARAMETERS:
+err - Error to log
+
+REMARKS:
+Function to log an error message if the MTRR write combining attempt failed.
+****************************************************************************/
+static void LogMTRRError(
+ int err)
+{
+ if (err == PM_MTRR_ERR_OK)
+ return;
+ switch (err) {
+ case PM_MTRR_NOT_SUPPORTED:
+ printf("Failed: MTRR is not supported by host CPU\n");
+ break;
+ case PM_MTRR_ERR_PARAMS:
+ printf("Failed: Invalid parameters passed to PM_enableWriteCombined!\n");
+ break;
+ case PM_MTRR_ERR_NOT_4KB_ALIGNED:
+ printf("Failed: Address is not 4Kb aligned!\n");
+ break;
+ case PM_MTRR_ERR_BELOW_1MB:
+ printf("Failed: Addresses below 1Mb cannot be write combined!\n");
+ break;
+ case PM_MTRR_ERR_NOT_ALIGNED:
+ printf("Failed: Address is not correctly aligned for processor!\n");
+ break;
+ case PM_MTRR_ERR_OVERLAP:
+ printf("Failed: Address overlaps an existing region!\n");
+ break;
+ case PM_MTRR_ERR_TYPE_MISMATCH:
+ printf("Failed: Adress is contained with existing region, but type is different!\n");
+ break;
+ case PM_MTRR_ERR_NONE_FREE:
+ printf("Failed: Out of MTRR registers!\n");
+ break;
+ case PM_MTRR_ERR_NOWRCOMB:
+ printf("Failed: This processor does not support write combining!\n");
+ break;
+ case PM_MTRR_ERR_NO_OS_SUPPORT:
+ printf("Failed: MTRR is not supported by host OS\n");
+ break;
+ default:
+ printf("Failed: UNKNOWN ERROR!\n");
+ break;
+ }
+ exit(-1);
+}
+
+/****************************************************************************
+REMARKS:
+Shows all write combine regions.
+****************************************************************************/
+static void ShowWriteCombine(void)
+{
+ printf("Base Length(KB) Type\n");
+ LogMTRRError(PM_enumWriteCombine(EnumWriteCombine));
+ printf("\n");
+}
+
+/****************************************************************************
+REMARKS:
+Dumps the value for a write combine region to the display.
+****************************************************************************/
+static void EnableWriteCombine(void)
+{
+ int i,index;
+
+ for (index = 0; index < NumDevices; index++) {
+ i = DeviceIndex[index];
+ if (PCI[i].u.type0.BaseAddress10 & 0x8) {
+ LogMTRRError(PM_enableWriteCombine(
+ PCI[i].u.type0.BaseAddress10 & 0xFFFFFFF0,
+ PCI[i].u.type0.BaseAddress10Len,
+ PM_MTRR_WRCOMB));
+ }
+ if (PCI[i].u.type0.BaseAddress14 & 0x8) {
+ LogMTRRError(PM_enableWriteCombine(
+ PCI[i].u.type0.BaseAddress14 & 0xFFFFFFF0,
+ PCI[i].u.type0.BaseAddress14Len,
+ PM_MTRR_WRCOMB));
+ }
+ }
+ printf("\n");
+ ShowDisplayDevices();
+ ShowWriteCombine();
+}
+
+/****************************************************************************
+REMARKS:
+Dumps the value for a write combine region to the display.
+****************************************************************************/
+static void DisableWriteCombine(void)
+{
+ int i,index;
+
+ for (index = 0; index < NumDevices; index++) {
+ i = DeviceIndex[index];
+ if (PCI[i].u.type0.BaseAddress10 & 0x8) {
+ LogMTRRError(PM_enableWriteCombine(
+ PCI[i].u.type0.BaseAddress10 & 0xFFFFFFF0,
+ PCI[i].u.type0.BaseAddress10Len,
+ PM_MTRR_UNCACHABLE));
+ }
+ if (PCI[i].u.type0.BaseAddress14 & 0x8) {
+ LogMTRRError(PM_enableWriteCombine(
+ PCI[i].u.type0.BaseAddress14 & 0xFFFFFFF0,
+ PCI[i].u.type0.BaseAddress14Len,
+ PM_MTRR_UNCACHABLE));
+ }
+ }
+ printf("\n");
+ ShowDisplayDevices();
+ ShowWriteCombine();
+}
+
+int main(int argc,char *argv[])
+{
+ PM_init();
+ if (PCI_enumerateDevices() < 1) {
+ printf("No PCI display devices found!\n");
+ return -1;
+ }
+ if (argc < 2) {
+ printf("usage: uswc [-show -on -off]\n\n");
+ ShowDisplayDevices();
+ return -1;
+ }
+ if (stricmp(argv[1],"-show") == 0)
+ ShowWriteCombine();
+ else if (stricmp(argv[1],"-on") == 0)
+ EnableWriteCombine();
+ else if (stricmp(argv[1],"-off") == 0)
+ DisableWriteCombine();
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/vftest.c b/board/MAI/bios_emulator/scitech/src/pm/tests/vftest.c
new file mode 100644
index 0000000000..633a76d2b7
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/vftest.c
@@ -0,0 +1,78 @@
+/****************************************************************************
+*
+* 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.
+*
+* ========================================================================
+*
+* Filename: $Workfile$
+* Version: $Revision: 1.1 $
+*
+* Language: ANSI C
+* Environment: any
+*
+* Description: Test program to test the VFlat virtual framebuffer functions.
+*
+* Functions tested: VF_available()
+* VF_init()
+* VF_exit()
+*
+* $Date: 2002/10/02 15:35:21 $ $Author: hfrieden $
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+uchar code[] = {
+ 0xC3, /* ret */
+ };
+
+int main(void)
+{
+ void *vfBuffer;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ if (!VF_available()) {
+ printf("Virtual Linear Framebuffer not available.\n");
+ exit(1);
+ }
+
+ vfBuffer = VF_init(0xA0000,64,sizeof(code),code);
+ if (!vfBuffer) {
+ printf("Failure to initialise Virtual Linear Framebuffer!\n");
+ exit(1);
+ }
+ VF_exit();
+ printf("Virtual Linear Framebuffer set up successfully!\n");
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/tests/video.c b/board/MAI/bios_emulator/scitech/src/pm/tests/video.c
new file mode 100644
index 0000000000..7f6f67f67e
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/tests/video.c
@@ -0,0 +1,200 @@
+/****************************************************************************
+*
+* 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: Test program to check the ability to generate real mode
+* interrupts and to be able to obtain direct access to the
+* video memory from protected mode. Compile and link with
+* the appropriate command line for your DOS extender.
+*
+* Functions tested: PM_getBIOSSelector()
+* PM_mapPhysicalAddr()
+* PM_int86()
+*
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "pmapi.h"
+
+uchar *bios; /* Pointer to BIOS data area */
+uchar *videoPtr; /* Pointer to VGA framebuffer */
+void *stateBuf; /* Console state save buffer */
+
+/* Routine to return the current video mode number */
+
+int getVideoMode(void)
+{
+ return PM_getByte(bios+0x49);
+}
+
+/* Routine to set a specified video mode */
+
+void setVideoMode(int mode)
+{
+ RMREGS r;
+
+ r.x.ax = mode;
+ PM_int86(0x10, &r, &r);
+}
+
+/* Routine to clear a rectangular region on the display by calling the
+ * video BIOS.
+ */
+
+void clearScreen(int startx, int starty, int endx, int endy, unsigned char attr)
+{
+ RMREGS r;
+
+ r.x.ax = 0x0600;
+ r.h.bh = attr;
+ r.h.cl = startx;
+ r.h.ch = starty;
+ r.h.dl = endx;
+ r.h.dh = endy;
+ PM_int86(0x10, &r, &r);
+}
+
+/* Routine to fill a rectangular region on the display using direct
+ * video writes.
+ */
+
+#define SCREEN(x,y) (videoPtr + ((y) * 160) + ((x) << 1))
+
+void fill(int startx, int starty, int endx, int endy, unsigned char c,
+ unsigned char attr)
+{
+ unsigned char *v;
+ int x,y;
+
+ for (y = starty; y <= endy; y++) {
+ v = SCREEN(startx,y);
+ for (x = startx; x <= endx; x++) {
+ *v++ = c;
+ *v++ = attr;
+ }
+ }
+}
+
+/* Routine to display a single character using direct video writes */
+
+void writeChar(int x, int y, unsigned char c, unsigned char attr)
+{
+ unsigned char *v = SCREEN(x,y);
+ *v++ = c;
+ *v = attr;
+}
+
+/* Routine to draw a border around a rectangular area using direct video
+ * writes.
+ */
+
+static unsigned char border_chars[] = {
+ 186, 205, 201, 187, 200, 188 /* double box chars */
+ };
+
+void border(int startx, int starty, int endx, int endy, unsigned char attr)
+{
+ unsigned char *v;
+ unsigned char *b;
+ int i;
+
+ b = border_chars;
+
+ for (i = starty+1; i < endy; i++) {
+ writeChar(startx, i, *b, attr);
+ writeChar(endx, i, *b, attr);
+ }
+ b++;
+ for (i = startx+1, v = SCREEN(startx+1, starty); i < endx; i++) {
+ *v++ = *b;
+ *v++ = attr;
+ }
+ for (i = startx+1, v = SCREEN(startx+1, endy); i < endx; i++) {
+ *v++ = *b;
+ *v++ = attr;
+ }
+ b++;
+ writeChar(startx, starty, *b++, attr);
+ writeChar(endx, starty, *b++, attr);
+ writeChar(startx, endy, *b++, attr);
+ writeChar(endx, endy, *b++, attr);
+}
+
+int main(void)
+{
+ int orgMode;
+ PM_HWND hwndConsole;
+
+ printf("Program running in ");
+ switch (PM_getModeType()) {
+ case PM_realMode:
+ printf("real mode.\n\n");
+ break;
+ case PM_286:
+ printf("16 bit protected mode.\n\n");
+ break;
+ case PM_386:
+ printf("32 bit protected mode.\n\n");
+ break;
+ }
+
+ hwndConsole = PM_openConsole(0,0,0,0,0,true);
+ printf("Hit any key to start 80x25 text mode and perform some direct video output.\n");
+ PM_getch();
+
+ /* Allocate a buffer to save console state and save the state */
+ if ((stateBuf = PM_malloc(PM_getConsoleStateSize())) == NULL) {
+ printf("Unable to allocate console state buffer!\n");
+ exit(1);
+ }
+ PM_saveConsoleState(stateBuf,0);
+ bios = PM_getBIOSPointer();
+ orgMode = getVideoMode();
+ setVideoMode(0x3);
+ if ((videoPtr = PM_mapPhysicalAddr(0xB8000,0xFFFF,true)) == NULL) {
+ printf("Unable to obtain pointer to framebuffer!\n");
+ exit(1);
+ }
+
+ /* Draw some text on the screen */
+ fill(0, 0, 79, 24, 176, 0x1E);
+ border(0, 0, 79, 24, 0x1F);
+ PM_getch();
+ clearScreen(0, 0, 79, 24, 0x7);
+
+ /* Restore the console state on exit */
+ PM_restoreConsoleState(stateBuf,0);
+ PM_free(stateBuf);
+ PM_closeConsole(hwndConsole);
+
+ /* Display useful status information */
+ printf("\n");
+ printf("Original Video Mode = %02X\n", orgMode);
+ printf("BIOS Pointer = %08X\n", (int)bios);
+ printf("Video Memory = %08X\n", (int)videoPtr);
+ return 0;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vdd/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/vdd/cpuinfo.c
new file mode 100644
index 0000000000..3460b72456
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vdd/cpuinfo.c
@@ -0,0 +1,66 @@
+/****************************************************************************
+*
+* 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: 32-bit OS/2 VDD
+*
+* Description: VDD specific code for the CPU detection module.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Do nothing for VDD's
+****************************************************************************/
+#define SetMaxThreadPriority() 0
+
+/****************************************************************************
+REMARKS:
+Do nothing for VDD's
+****************************************************************************/
+#define RestoreThreadPriority(i) (void)(i)
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ freq->low = 100000;
+ freq->high = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ ULONG count; \
+ count = VDHQuerySysValue(0, VDHGSV_MSECSBOOT); \
+ (t)->low = count * 100; \
+ (t)->high = 0; \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vdd/fileio.c b/board/MAI/bios_emulator/scitech/src/pm/vdd/fileio.c
new file mode 100644
index 0000000000..dbbaf37dfa
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vdd/fileio.c
@@ -0,0 +1,359 @@
+/****************************************************************************
+*
+* 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: 32-bit OS/2 VDD
+*
+* Description: C library compatible I/O functions for use within a VDD.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "vddfile.h"
+
+/*------------------------ Main Code Implementation -----------------------*/
+
+#define EOF -1
+
+/* NB: none of the file VDHs are available during the DOS session */
+/* initialzation context! */
+
+/* Macros for Open/Close APIs to allow using this module in both VDDs and */
+/* normal OS/2 applications. Unfortunately VDHRead/Write/Seek don't map to */
+/* their Dos* counterparts so cleanly. */
+#ifdef __OS2_VDD__
+#define _OS2Open VDHOpen
+#define _OS2Close VDHClose
+#else
+#define _OS2Open DosOpen
+#define _OS2Close DosClose
+#endif
+
+/****************************************************************************
+REMARKS:
+VDD implementation of the ANSI C fopen function.
+****************************************************************************/
+FILE * fopen(
+ const char *filename,
+ const char *mode)
+{
+ FILE *f = PM_malloc(sizeof(FILE));
+ long oldpos;
+ ULONG rc, ulAction;
+ ULONG omode, oflags;
+
+ if (f != NULL) {
+ f->offset = 0;
+ f->text = (mode[1] == 't' || mode[2] == 't');
+ f->writemode = (mode[0] == 'w') || (mode[0] == 'a');
+ f->unputc = EOF;
+ f->endp = f->buf + sizeof(f->buf);
+ f->curp = f->startp = f->buf;
+
+ if (mode[0] == 'r') {
+ #ifdef __OS2_VDD__
+ omode = VDHOPEN_ACCESS_READONLY | VDHOPEN_SHARE_DENYNONE;
+ oflags = VDHOPEN_ACTION_OPEN_IF_EXISTS | VDHOPEN_ACTION_FAIL_IF_NEW;
+ #else
+ omode = OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE;
+ oflags = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
+ #endif
+ }
+ else if (mode[0] == 'w') {
+ #ifdef __OS2_VDD__
+ omode = VDHOPEN_ACCESS_WRITEONLY | VDHOPEN_SHARE_DENYWRITE;
+ oflags = VDHOPEN_ACTION_REPLACE_IF_EXISTS | VDHOPEN_ACTION_CREATE_IF_NEW;
+ #else
+ omode = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE;
+ oflags = OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
+ #endif
+ }
+ else {
+ #ifdef __OS2_VDD__
+ omode = VDHOPEN_ACCESS_READWRITE | VDHOPEN_SHARE_DENYWRITE;
+ oflags = VDHOPEN_ACTION_OPEN_IF_EXISTS | VDHOPEN_ACTION_CREATE_IF_NEW;
+ #else
+ omode = OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYWRITE;
+ oflags = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
+ #endif
+ }
+ rc = _OS2Open((PSZ)filename, (PHFILE)&f->handle, &ulAction, 0, VDHOPEN_FILE_NORMAL, oflags, omode, NULL);
+ if (rc != 0) {
+ PM_free(f);
+ return NULL;
+ }
+
+ #ifdef __OS2_VDD__
+ f->filesize = VDHSeek((HFILE)f->handle, 0, VDHSK_END_OF_FILE);
+ #else
+ rc = DosSetFilePtr((HFILE)f->handle, 0, FILE_END, &f->filesize);
+ #endif
+
+ if (mode[0] == 'a')
+ fseek(f,0,2);
+ }
+ return f;
+}
+
+/****************************************************************************
+REMARKS:
+VDD implementation of the ANSI C fread function. Note that unlike Windows VxDs,
+OS/2 VDDs are not limited to 64K reads or writes.
+****************************************************************************/
+size_t fread(
+ void *ptr,
+ size_t size,
+ size_t n,
+ FILE *f)
+{
+ char *buf = ptr;
+ int bytes,readbytes,totalbytes = 0;
+
+ /* First copy any data already read into our buffer */
+ if ((bytes = (f->curp - f->startp)) > 0) {
+ memcpy(buf,f->curp,bytes);
+ f->startp = f->curp = f->buf;
+ buf += bytes;
+ totalbytes += bytes;
+ bytes = (size * n) - bytes;
+ }
+ else
+ bytes = size * n;
+ if (bytes) {
+ #ifdef __OS2_VDD__
+ readbytes = VDHRead((HFILE)f->handle, buf, bytes);
+ #else
+ DosRead((HFILE)f->handle, buf, bytes, &readbytes);
+ #endif
+ totalbytes += readbytes;
+ f->offset += readbytes;
+ }
+ return totalbytes / size;
+}
+
+/****************************************************************************
+REMARKS:
+VDD implementation of the ANSI C fwrite function.
+****************************************************************************/
+size_t fwrite(
+ void *ptr,
+ size_t size,
+ size_t n,
+ FILE *f)
+{
+ char *buf = ptr;
+ int bytes,writtenbytes,totalbytes = 0;
+
+ /* Flush anything already in the buffer */
+ if (!f->writemode)
+ return 0;
+ fflush(f);
+ bytes = size * n;
+ #ifdef __OS2_VDD__
+ writtenbytes = VDHWrite((HFILE)f->handle, buf, bytes);
+ #else
+ DosWrite((HFILE)f->handle, buf, bytes, &writtenbytes);
+ #endif
+ totalbytes += writtenbytes;
+ f->offset += writtenbytes;
+ if (f->offset > f->filesize)
+ f->filesize = f->offset;
+ return totalbytes / size;
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C fflush function.
+****************************************************************************/
+int fflush(
+ FILE *f)
+{
+ ULONG bytes;
+
+ /* First copy any data already written into our buffer */
+ if (f->writemode && (bytes = (f->curp - f->startp)) > 0) {
+ #ifdef __OS2_VDD__
+ bytes = VDHWrite((HFILE)f->handle, f->startp, bytes);
+ #else
+ DosWrite((HFILE)f->handle, f->startp, bytes, &bytes);
+ #endif
+ f->offset += bytes;
+ if (f->offset > f->filesize)
+ f->filesize = f->offset;
+ f->startp = f->curp = f->buf;
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+VDD implementation of the ANSI C fseek function.
+****************************************************************************/
+int fseek(
+ FILE *f,
+ long int offset,
+ int whence)
+{
+ fflush(f);
+
+ if (whence == 0)
+ f->offset = offset;
+ else if (whence == 1)
+ f->offset += offset;
+ else if (whence == 2)
+ f->offset = f->filesize + offset;
+
+ #ifdef __OS2_VDD__
+ VDHSeek((HFILE)f->handle, f->offset, VDHSK_ABSOLUTE);
+ #else
+ DosSetFilePtr((HFILE)f->handle, f->offset, FILE_BEGIN, NULL);
+ #endif
+
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+VDD implementation of the ANSI C ftell function.
+****************************************************************************/
+long ftell(
+ FILE *f)
+{
+ long offset;
+
+ offset = (f->curp - f->startp);
+ offset += f->offset;
+ return offset;
+}
+
+/****************************************************************************
+REMARKS:
+VDD implementation of the ANSI C feof function.
+****************************************************************************/
+int feof(
+ FILE *f)
+{
+ return (f->offset == f->filesize);
+}
+
+/****************************************************************************
+REMARKS:
+Read a single character from the input file buffer, including translation
+of the character in text transation modes.
+****************************************************************************/
+static int __getc(
+ FILE *f)
+{
+ int c;
+
+ if (f->unputc != EOF) {
+ c = f->unputc;
+ f->unputc = EOF;
+ }
+ else {
+ if (f->startp == f->curp) {
+ int bytes = fread(f->buf,1,sizeof(f->buf),f);
+ if (bytes == 0)
+ return EOF;
+ f->curp = f->startp + bytes;
+ }
+ c = *f->startp++;
+ if (f->text && c == '\r') {
+ int nc = __getc(f);
+ if (nc != '\n')
+ f->unputc = nc;
+ }
+ }
+ return c;
+}
+
+/****************************************************************************
+REMARKS:
+Write a single character from to input buffer, including translation of the
+character in text transation modes.
+****************************************************************************/
+static int __putc(int c,FILE *f)
+{
+ int count = 1;
+ if (f->text && c == '\n') {
+ __putc('\r',f);
+ count = 2;
+ }
+ if (f->curp == f->endp)
+ fflush(f);
+ *f->curp++ = c;
+ return count;
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C fgets function.
+****************************************************************************/
+char *fgets(
+ char *s,
+ int n,
+ FILE *f)
+{
+ int c = 0;
+ char *cs;
+
+ cs = s;
+ while (--n > 0 && (c = __getc(f)) != EOF) {
+ *cs++ = c;
+ if (c == '\n')
+ break;
+ }
+ if (c == EOF && cs == s)
+ return NULL;
+ *cs = '\0';
+ return s;
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C fputs function.
+****************************************************************************/
+int fputs(
+ const char *s,
+ FILE *f)
+{
+ int r = 0;
+ int c;
+
+ while ((c = *s++) != 0)
+ r = __putc(c, f);
+ return r;
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C fclose function.
+****************************************************************************/
+int fclose(
+ FILE *f)
+{
+ fflush(f);
+ _OS2Close((HFILE)f->handle);
+ PM_free(f);
+ return 0;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vdd/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/vdd/oshdr.h
new file mode 100644
index 0000000000..03286bdc2e
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vdd/oshdr.h
@@ -0,0 +1,29 @@
+/****************************************************************************
+*
+* 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: 32-bit OS/2 VDD
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vdd/pm.c b/board/MAI/bios_emulator/scitech/src/pm/vdd/pm.c
new file mode 100644
index 0000000000..32177f810d
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vdd/pm.c
@@ -0,0 +1,1050 @@
+/****************************************************************************
+*
+* 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: 32-bit OS/2 VDD
+*
+* 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 "sdd/sddhelp.h"
+#include "mtrr.h"
+
+#define TRACE(a)
+
+/*--------------------------- Global variables ----------------------------*/
+
+#define MAX_MEMORY_SHARED 100
+#define MAX_MEMORY_MAPPINGS 100
+
+// TODO: I think the global and linear members will be the same, but not sure yet.
+typedef struct {
+ void *linear;
+ ulong global;
+ ulong length;
+ int npages;
+ } memshared;
+
+typedef struct {
+ ulong physical;
+ ulong linear;
+ ulong length;
+ int npages;
+ ibool isCached;
+ } mmapping;
+
+static int numMappings = 0;
+static memshared shared[MAX_MEMORY_MAPPINGS] = {0};
+static mmapping maps[MAX_MEMORY_MAPPINGS];
+ibool _PM_haveBIOS = TRUE;
+char _PM_cntPath[PM_MAX_PATH] = ""; /* there just isn't any */
+uchar *_PM_rmBufAddr = NULL;
+ushort _VARAPI PM_savedDS = 0; /* why can't I use the underscore prefix? */
+
+HVDHSEM hevFarCallRet = NULL;
+HVDHSEM hevIRet = NULL;
+HHOOK hhookUserReturnHook = NULL;
+HHOOK hhookUserIRetHook = NULL;
+
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* Functions to read and write CMOS registers */
+
+ulong PMAPI _PM_getPDB(void);
+uchar PMAPI _PM_readCMOS(int index);
+void PMAPI _PM_writeCMOS(int index,uchar value);
+
+VOID HOOKENTRY UserReturnHook(PVOID pRefData, PCRF pcrf);
+VOID HOOKENTRY UserIRetHook(PVOID pRefData, PCRF pcrf);
+
+void PMAPI PM_init(void)
+{
+ MTRR_init();
+
+ // Initialize VDD-specific data
+ // Note: PM_init must be (obviously) called in VDM task context!
+ VDHCreateSem(&hevFarCallRet, VDH_EVENTSEM);
+ VDHCreateSem(&hevIRet, VDH_EVENTSEM);
+ hhookUserReturnHook = VDHAllocHook(VDH_RETURN_HOOK, (PFNARM)UserReturnHook, 0);
+ hhookUserIRetHook = VDHAllocHook(VDH_RETURN_HOOK, (PFNARM)UserIRetHook, 0);
+
+ if ((hevIRet == NULL) || (hevFarCallRet == NULL) ||
+ (hhookUserReturnHook == NULL) || (hhookUserIRetHook == NULL)) {
+ // something failed, we can't go on
+ // TODO: take some action here!
+ }
+}
+
+/* Do some cleaning up */
+void PMAPI PM_exit(void)
+{
+ /* Note: Hooks allocated during or after VDM creation are deallocated automatically */
+ if (hevIRet != NULL)
+ VDHDestroySem(hevIRet);
+
+ if (hevFarCallRet != NULL)
+ VDHDestroySem(hevFarCallRet);
+}
+
+ibool PMAPI PM_haveBIOSAccess(void)
+{ return _PM_haveBIOS; }
+
+long PMAPI PM_getOSType(void)
+{ return /*_OS_OS2VDD*/ _OS_OS2; } //FIX!!
+
+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();
+// Fatal_Error_Handler(msg,0); TODO: implement somehow!
+}
+
+/****************************************************************************
+PARAMETERS:
+len - Place to store the length of the buffer
+rseg - Place to store the real mode segment of the buffer
+roff - Place to store the real mode offset of the buffer
+
+REMARKS:
+This function returns the address and length of the global VESA transfer
+buffer.
+****************************************************************************/
+void * PMAPI PM_getVESABuf(
+ uint *len,
+ uint *rseg,
+ uint *roff)
+{
+ if (_PM_rmBufAddr) {
+ *len = 0; //VESA_BUF_SIZE;
+ *rseg = (ulong)(_PM_rmBufAddr) >> 4;
+ *roff = (ulong)(_PM_rmBufAddr) & 0xF;
+ return _PM_rmBufAddr;
+ }
+ return NULL;
+}
+
+int PMAPI PM_int386(int intno, PMREGS *in, PMREGS *out)
+{
+ /* Unused in VDDs */
+ return 0;
+}
+
+char * PMAPI PM_getCurrentPath(char *path,int maxLen)
+{
+ strncpy(path, _PM_cntPath, maxLen);
+ path[maxLen - 1] = 0;
+ return path;
+}
+
+char PMAPI PM_getBootDrive(void)
+{
+ ulong boot = 3;
+ boot = VDHQuerySysValue(0, VDHGSV_BOOTDRV);
+ return (char)('a' + boot - 1);
+}
+
+const char * PMAPI PM_getVBEAFPath(void)
+{
+ static char path[CCHMAXPATH];
+ strcpy(path,"x:\\");
+ path[0] = PM_getBootDrive();
+ return path;
+}
+
+const char * PMAPI PM_getNucleusPath(void)
+{
+ static char path[CCHMAXPATH];
+ strcpy(path,"x:\\os2\\drivers");
+ path[0] = PM_getBootDrive();
+ PM_backslash(path);
+ strcat(path,"nucleus");
+ return path;
+}
+
+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)
+{ return PM_getMachineName(); }
+
+const char * PMAPI PM_getMachineName(void)
+{
+ return "Unknown";
+}
+
+int PMAPI PM_kbhit(void)
+{ return 1; }
+
+int PMAPI PM_getch(void)
+{ return 0; }
+
+PM_HWND PMAPI PM_openConsole(PM_HWND hwndUser,int device,int xRes,int yRes,int bpp,ibool fullScreen)
+{
+ /* Unused in VDDs */
+ return NULL;
+}
+
+int PMAPI PM_getConsoleStateSize(void)
+{
+ /* Unused in VDDs */
+ return 1;
+}
+
+void PMAPI PM_saveConsoleState(void *stateBuf,PM_HWND hwndConsole)
+{
+ /* Unused in VDDs */
+}
+
+void PMAPI PM_setSuspendAppCallback(int (_ASMAPIP saveState)(int flags))
+{
+ /* Unused in VDDs */
+}
+
+void PMAPI PM_restoreConsoleState(const void *stateBuf,PM_HWND hwndConsole)
+{
+ /* Unused in VDDs */
+}
+
+void PMAPI PM_closeConsole(PM_HWND hwndConsole)
+{
+ /* Unused in VDDs */
+}
+
+void PMAPI PM_setOSCursorLocation(int x,int y)
+{
+ uchar *_biosPtr = PM_getBIOSPointer();
+ PM_setByte(_biosPtr+0x50,x);
+ PM_setByte(_biosPtr+0x51,y);
+}
+
+void PMAPI PM_setOSScreenWidth(int width,int height)
+{
+ uchar *_biosPtr = PM_getBIOSPointer();
+ PM_setByte(_biosPtr+0x4A,width);
+ PM_setByte(_biosPtr+0x84,height-1);
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of shared memory. For OS/2 VDD we allocate shared memory
+as locked, global memory that is accessible from any memory context
+(including interrupt time context), which allows us to load our important
+data structure and code such that we can access it directly from a ring
+0 interrupt context.
+****************************************************************************/
+void * PMAPI PM_mallocShared(long size)
+{
+ ULONG nPages = (size + 0xFFF) >> 12;
+ int i;
+
+ /* First find a free slot in our shared memory table */
+ for (i = 0; i < MAX_MEMORY_SHARED; i++) {
+ if (shared[i].linear == 0)
+ break;
+ }
+ if (i < MAX_MEMORY_SHARED) {
+ shared[i].linear = VDHAllocPages(NULL, nPages, VDHAP_SYSTEM | VDHAP_FIXED);
+ shared[i].npages = nPages;
+ shared[i].global = (ULONG)shared[i].linear;
+ return (void*)shared[i].global;
+ }
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of shared memory
+****************************************************************************/
+void PMAPI PM_freeShared(void *p)
+{
+ int i;
+
+ /* Find a shared memory block in our table and free it */
+ for (i = 0; i < MAX_MEMORY_SHARED; i++) {
+ if (shared[i].global == (ulong)p) {
+ VDHFreePages(shared[i].linear);
+ shared[i].linear = 0;
+ break;
+ }
+ }
+}
+
+void * PMAPI PM_mapToProcess(void *base,ulong limit)
+{ return (void*)base; }
+
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *mappedBIOS,
+ ulong BIOSLen)
+{
+ // TODO: Figure out how to do this
+ return false;
+}
+
+void * PMAPI PM_getBIOSPointer(void)
+{ return (void*)0x400; }
+
+void * PMAPI PM_getA0000Pointer(void)
+{ return PM_mapPhysicalAddr(0xA0000,0xFFFF,true); }
+
+/****************************************************************************
+PARAMETERS:
+base - Physical base address of the memory to maps in
+limit - Limit of physical memory to region to maps in
+
+RETURNS:
+Linear address of the newly mapped memory.
+
+REMARKS:
+Maps a physical memory range to a linear memory range.
+****************************************************************************/
+ulong MapPhysicalToLinear(
+ ulong base,
+ ulong limit,
+ int *npages)
+{
+ ulong linear,length = limit+1;
+ int i,ppage,flags;
+#if 0
+ ppage = base >> 12;
+ *npages = (length + (base & 0xFFF) + 4095) >> 12;
+ flags = PR_FIXED | PR_STATIC;
+ if (base == 0xA0000) {
+ /* We require the linear address to be aligned to a 64Kb boundary
+ * for mapping the banked framebuffer (so we can do efficient
+ * carry checking for bank changes in the assembler code). The only
+ * way to ensure this is to force the linear address to be aligned
+ * to a 4Mb boundary.
+ */
+ flags |= PR_4MEG;
+ }
+ if ((linear = (ulong)PageReserve(PR_SYSTEM,*npages,flags)) == (ulong)-1)
+ return 0;
+ if (!PageCommitPhys(linear >> 12,*npages,ppage,PC_INCR | PC_USER | PC_WRITEABLE))
+ return 0;
+#endif
+ return linear + (base & 0xFFF);
+}
+
+/****************************************************************************
+PARAMETERS:
+base - Physical base address of the memory to map in
+limit - Limit of physical memory to region to map in
+isCached - True if the memory should be cached, false if not
+
+RETURNS:
+Linear address of the newly mapped memory.
+
+REMARKS:
+This function maps physical memory to linear memory, which can then be used
+to create a selector or used directly from 32-bit protected mode programs.
+This is better than DPMI 0x800, since it allows you to maps physical
+memory below 1Mb, which gets this memory out of the way of the Windows VxD's
+sticky paws.
+
+NOTE: If the memory is not expected to be cached, this function will
+ directly re-program the PCD (Page Cache Disable) bit in the
+ page tables. There does not appear to be a mechanism in the VMM
+ to control this bit via the regular interface.
+****************************************************************************/
+void * PMAPI PM_mapPhysicalAddr(
+ ulong base,
+ ulong limit,
+ ibool isCached)
+{
+ ulong linear,length = limit+1;
+ int i,npages;
+ ulong PDB,*pPDB;
+
+ /* Search table of existing mappings to see if we have already mapped
+ * a region of memory that will serve this purpose.
+ */
+ for (i = 0; i < numMappings; i++) {
+ if (maps[i].physical == base && maps[i].length == length && maps[i].isCached == isCached)
+ return (void*)maps[i].linear;
+ }
+ if (numMappings == MAX_MEMORY_MAPPINGS)
+ return NULL;
+
+ /* We did not find any previously mapped memory region, so map it in.
+ * Note that we do not use MapPhysToLinear, since this function appears
+ * to have problems mapping memory in the 1Mb physical address space.
+ * Hence we use PageReserve and PageCommitPhys.
+ */
+ if ((linear = MapPhysicalToLinear(base,limit,&npages)) == 0)
+ return NULL;
+ maps[numMappings].physical = base;
+ maps[numMappings].length = length;
+ maps[numMappings].linear = linear;
+ maps[numMappings].npages = npages;
+ maps[numMappings].isCached = isCached;
+ numMappings++;
+
+#if 0
+ /* Finally disable caching where necessary */
+ if (!isCached && (PDB = _PM_getPDB()) != 0) {
+ int startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
+ ulong pageTable,*pPageTable;
+
+ if (PDB >= 0x100000)
+ pPDB = (ulong*)MapPhysicalToLinear(PDB,0xFFF,&npages);
+ else
+ pPDB = (ulong*)PDB;
+ if (pPDB) {
+ startPDB = (linear >> 22) & 0x3FF;
+ startPage = (linear >> 12) & 0x3FF;
+ endPDB = ((linear+limit) >> 22) & 0x3FF;
+ endPage = ((linear+limit) >> 12) & 0x3FF;
+ for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
+ pageTable = pPDB[iPDB] & ~0xFFF;
+ if (pageTable >= 0x100000)
+ pPageTable = (ulong*)MapPhysicalToLinear(pageTable,0xFFF,&npages);
+ else
+ pPageTable = (ulong*)pageTable;
+ start = (iPDB == startPDB) ? startPage : 0;
+ end = (iPDB == endPDB) ? endPage : 0x3FF;
+ for (iPage = start; iPage <= end; iPage++)
+ pPageTable[iPage] |= 0x10;
+ PageFree((ulong)pPageTable,PR_STATIC);
+ }
+ PageFree((ulong)pPDB,PR_STATIC);
+ }
+ }
+#endif
+ return (void*)linear;
+}
+
+void PMAPI PM_freePhysicalAddr(void *ptr,ulong limit)
+{
+ /* We never free the mappings */
+}
+
+void PMAPI PM_sleep(ulong milliseconds)
+{
+ /* We never sleep in a VDD */
+}
+
+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;
+}
+
+ulong PMAPI PM_getPhysicalAddr(void *p)
+{
+ // TODO: This function should find the physical address of a linear
+ // address.
+ return 0xFFFFFFFFUL;
+}
+
+void PMAPI _PM_freeMemoryMappings(void)
+{
+ int i;
+// for (i = 0; i < numMappings; i++)
+// PageFree(maps[i].linear,PR_STATIC);
+}
+
+void * PMAPI PM_mapRealPointer(uint r_seg,uint r_off)
+{ return (void*)MK_PHYS(r_seg,r_off); }
+
+void * PMAPI PM_allocRealSeg(uint size,uint *r_seg,uint *r_off)
+{ return NULL; }
+
+void PMAPI PM_freeRealSeg(void *mem)
+{ }
+
+void PMAPI DPMI_int86(int intno, DPMI_regs *regs)
+{
+ /* Unsed in VDDs */
+}
+
+/****************************************************************************
+REMARKS:
+Load the V86 registers in the client state, and save the original state
+before loading the registers.
+****************************************************************************/
+static void LoadV86Registers(
+ PCRF saveRegs,
+ RMREGS *in,
+ RMSREGS *sregs)
+{
+ PCRF pcrf; // current client register frame
+
+ // get pointer to registers
+ pcrf = (PCRF)VDHQuerySysValue(CURRENT_VDM, VDHLSV_PCRF);
+
+ // Note: We could do VDHPushRegs instead but this should be safer as it
+ // doesn't rely on the VDM session having enough free stack space.
+ *saveRegs = *pcrf; // save all registers
+
+ pcrf->crf_eax = in->e.eax; // load new values
+ pcrf->crf_ebx = in->e.ebx;
+ pcrf->crf_ecx = in->e.ecx;
+ pcrf->crf_edx = in->e.edx;
+ pcrf->crf_esi = in->e.esi;
+ pcrf->crf_edi = in->e.edi;
+ pcrf->crf_es = sregs->es;
+ pcrf->crf_ds = sregs->ds;
+
+}
+
+/****************************************************************************
+REMARKS:
+Read the V86 registers from the client state and restore the original state.
+****************************************************************************/
+static void ReadV86Registers(
+ PCRF saveRegs,
+ RMREGS *out,
+ RMSREGS *sregs)
+{
+ PCRF pcrf; // current client register frame
+
+ // get pointer to registers
+ pcrf = (PCRF)VDHQuerySysValue(CURRENT_VDM, VDHLSV_PCRF);
+
+ // read new register values
+ out->e.eax = pcrf->crf_eax;
+ out->e.ebx = pcrf->crf_ebx;
+ out->e.ecx = pcrf->crf_ecx;
+ out->e.edx = pcrf->crf_edx;
+ out->e.esi = pcrf->crf_esi;
+ out->e.edi = pcrf->crf_edi;
+ sregs->es = pcrf->crf_es;
+ sregs->ds = pcrf->crf_ds;
+
+ // restore original client registers
+ *pcrf = *saveRegs;
+}
+
+/****************************************************************************
+REMARKS: Used for far calls into V86 code
+****************************************************************************/
+VOID HOOKENTRY UserReturnHook(
+ PVOID pRefData,
+ PCRF pcrf )
+{
+ VDHPostEventSem(hevFarCallRet);
+}
+
+/****************************************************************************
+REMARKS: Used for calling BIOS interrupts
+****************************************************************************/
+VOID HOOKENTRY UserIRetHook(
+ PVOID pRefData,
+ PCRF pcrf )
+{
+ VDHPostEventSem(hevIRet);
+}
+
+/****************************************************************************
+REMARKS:
+Call a V86 real mode function with the specified register values
+loaded before the call. The call returns with a far ret.
+Must be called from within a DOS session context!
+****************************************************************************/
+void PMAPI PM_callRealMode(
+ uint seg,
+ uint off,
+ RMREGS *regs,
+ RMSREGS *sregs)
+{
+ CRF saveRegs;
+ FPFN fnAddress;
+ ULONG rc;
+
+ TRACE("SDDHELP: Entering PM_callRealMode()\n");
+ LoadV86Registers(SSToDS(&saveRegs),regs,sregs);
+
+ // set up return hook for call
+ rc = VDHArmReturnHook(hhookUserReturnHook, VDHARH_CSEIP_HOOK);
+
+ VDHResetEventSem(hevFarCallRet);
+
+ // the address is a 16:32 pointer
+ OFFSETOF32(fnAddress) = off;
+ SEGMENTOF32(fnAddress) = seg;
+ rc = VDHPushFarCall(fnAddress);
+ VDHYield(0);
+
+ // wait until the V86 call returns - our return hook posts the semaphore
+ rc = VDHWaitEventSem(hevFarCallRet, SEM_INDEFINITE_WAIT);
+
+ ReadV86Registers(SSToDS(&saveRegs),regs,sregs);
+ TRACE("SDDHELP: Exiting PM_callRealMode()\n");
+}
+
+/****************************************************************************
+REMARKS:
+Issue a V86 real mode interrupt with the specified register values
+loaded before the interrupt.
+Must be called from within a DOS session context!
+****************************************************************************/
+int PMAPI PM_int86(
+ int intno,
+ RMREGS *in,
+ RMREGS *out)
+{
+ RMSREGS sregs = {0};
+ CRF saveRegs;
+ ushort oldDisable;
+ ULONG rc;
+
+ memset(SSToDS(&sregs), 0, sizeof(sregs));
+
+#if 0 // do we need this??
+ /* Disable pass-up to our VDD handler so we directly call BIOS */
+ TRACE("SDDHELP: Entering PM_int86()\n");
+ if (disableTSRFlag) {
+ oldDisable = *disableTSRFlag;
+ *disableTSRFlag = 0;
+ }
+#endif
+
+ LoadV86Registers(SSToDS(&saveRegs), in, SSToDS(&sregs));
+
+ VDHResetEventSem(hevIRet);
+ rc = VDHPushInt(intno);
+
+ // set up return hook for interrupt
+ rc = VDHArmReturnHook(hhookUserIRetHook, VDHARH_NORMAL_IRET);
+
+ VDHYield(0);
+
+ // wait until the V86 IRETs - our return hook posts the semaphore
+ rc = VDHWaitEventSem(hevIRet, 5000); //SEM_INDEFINITE_WAIT);
+
+ ReadV86Registers(SSToDS(&saveRegs), out, SSToDS(&sregs));
+
+#if 0
+ /* Re-enable pass-up to our VDD handler if previously enabled */
+ if (disableTSRFlag)
+ *disableTSRFlag = oldDisable;
+#endif
+
+ TRACE("SDDHELP: Exiting PM_int86()\n");
+ return out->x.ax;
+
+}
+
+/****************************************************************************
+REMARKS:
+Issue a V86 real mode interrupt with the specified register values
+loaded before the interrupt.
+****************************************************************************/
+int PMAPI PM_int86x(
+ int intno,
+ RMREGS *in,
+ RMREGS *out,
+ RMSREGS *sregs)
+{
+ CRF saveRegs;
+ ushort oldDisable;
+ ULONG rc;
+
+#if 0
+ /* Disable pass-up to our VxD handler so we directly call BIOS */
+ TRACE("SDDHELP: Entering PM_int86x()\n");
+ if (disableTSRFlag) {
+ oldDisable = *disableTSRFlag;
+ *disableTSRFlag = 0;
+ }
+#endif
+ LoadV86Registers(SSToDS(&saveRegs), in, sregs);
+
+ VDHResetEventSem(hevIRet);
+ rc = VDHPushInt(intno);
+
+ // set up return hook for interrupt
+ rc = VDHArmReturnHook(hhookUserIRetHook, VDHARH_NORMAL_IRET);
+
+ VDHYield(0);
+
+ // wait until the V86 IRETs - our return hook posts the semaphore
+ rc = VDHWaitEventSem(hevIRet, 5000); //SEM_INDEFINITE_WAIT);
+
+ ReadV86Registers(SSToDS(&saveRegs), out, sregs);
+
+#if 0
+ /* Re-enable pass-up to our VxD handler if previously enabled */
+ if (disableTSRFlag)
+ *disableTSRFlag = oldDisable;
+#endif
+
+ TRACE("SDDHELP: Exiting PM_int86x()\n");
+ return out->x.ax;
+}
+
+void PMAPI PM_availableMemory(ulong *physical,ulong *total)
+{ *physical = *total = 0; }
+
+/****************************************************************************
+REMARKS:
+Allocates a block of locked physical memory.
+****************************************************************************/
+void * PMAPI PM_allocLockedMem(
+ uint size,
+ ulong *physAddr,
+ ibool contiguous,
+ ibool below16M)
+{
+ ULONG flags = VDHAP_SYSTEM;
+ ULONG nPages = (size + 0xFFF) >> 12;
+
+ flags |= (physAddr != NULL) ? VDHAP_PHYSICAL : VDHAP_FIXED;
+
+ return VDHAllocPages(physAddr, nPages, VDHAP_SYSTEM | VDHAP_PHYSICAL);
+}
+
+/****************************************************************************
+REMARKS:
+Frees a block of locked physical memory.
+****************************************************************************/
+void PMAPI PM_freeLockedMem(
+ void *p,
+ uint size,
+ ibool contiguous)
+{
+ if (p)
+ VDHFreePages((PVOID)p);
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ ULONG lockHandle;
+
+ // TODO: the lock handle is essential for the unlock operation!!
+ lockHandle = VDHLockMem(p, len, 0, (PVOID)VDHLM_NO_ADDR, NULL);
+
+ if (lockHandle != NULL)
+ return 0;
+ else
+ return 1;
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ // TODO: implement - use a table of lock handles?
+ // VDHUnlockPages(lockHandle);
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ return PM_lockDataPages((void*)p,len,lh);
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ return PM_unlockDataPages((void*)p,len,lh);
+}
+
+/****************************************************************************
+REMARKS:
+OS specific shared libraries not supported inside a VDD
+****************************************************************************/
+PM_MODULE PMAPI PM_loadLibrary(
+ const char *szDLLName)
+{
+ (void)szDLLName;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+OS specific shared libraries not supported inside a VDD
+****************************************************************************/
+void * PMAPI PM_getProcAddress(
+ PM_MODULE hModule,
+ const char *szProcName)
+{
+ (void)hModule;
+ (void)szProcName;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+OS specific shared libraries not supported inside a VDD
+****************************************************************************/
+void PMAPI PM_freeLibrary(
+ PM_MODULE hModule)
+{
+ (void)hModule;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+void *PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ // TODO: This function should start a directory enumeration search
+ // given the filename (with wildcards). The data should be
+ // converted and returned in the findData standard form.
+ (void)filename;
+ (void)findData;
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ void *handle,
+ PM_findData *findData)
+{
+ // TODO: This function should find the next file in directory enumeration
+ // search given the search criteria defined in the call to
+ // PM_findFirstFile. The data should be converted and returned
+ // in the findData standard form.
+ (void)handle;
+ (void)findData;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ void *handle)
+{
+ // TODO: This function should close the find process. This may do
+ // nothing for some OS'es.
+ (void)handle;
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ // Not applicable in a VDD
+ (void)drive;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ // Not applicable in a VDD
+ (void)drive;
+ (void)dir;
+ (void)len;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+RETURNS:
+Error code describing the result.
+
+REMARKS:
+Function to enable write combining for the specified region of memory.
+****************************************************************************/
+int PMAPI PM_enableWriteCombine(
+ ulong base,
+ ulong size,
+ uint type)
+{
+ return MTRR_enableWriteCombine(base,size,type);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+ // TODO: Implement this ?
+ (void)filename;
+ (void)attrib;
+ PM_fatalError("PM_setFileAttr not implemented!");
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file attributes for a specific file.
+****************************************************************************/
+uint PMAPI PM_getFileAttr(
+ const char *filename)
+{
+ // TODO: Implement this ?
+ (void)filename;
+ PM_fatalError("PM_getFileAttr not implemented!");
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+ // TODO: Implement this ?
+ (void)filename;
+ PM_fatalError("PM_mkdir not implemented!");
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+ // TODO: Implement this ?
+ (void)filename;
+ PM_fatalError("PM_rmdir not implemented!");
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_getFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this ?
+ (void)filename;
+ (void)gmTime;
+ (void)time;
+ PM_fatalError("PM_getFileTime not implemented!");
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_setFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this ?
+ (void)filename;
+ (void)gmTime;
+ (void)time;
+ PM_fatalError("PM_setFileTime not implemented!");
+ return false;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vdd/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/vdd/vflat.c
new file mode 100644
index 0000000000..10c63e3405
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vdd/vflat.c
@@ -0,0 +1,45 @@
+/****************************************************************************
+*
+* 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)
+{
+ return NULL;
+}
+
+void PMAPI VF_exit(void)
+{
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vdd/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/vdd/ztimer.c
new file mode 100644
index 0000000000..631f6558ee
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vdd/ztimer.c
@@ -0,0 +1,103 @@
+/****************************************************************************
+*
+* 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: 32-bit OS/2 VDD
+*
+* Description: OS specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+/*---------------------------- Global variables ---------------------------*/
+
+static ulong frequency = 1193180;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+#define __ZTimerInit()
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOn(tm) VTD_Get_Real_Time(&tm->start.high,&tm->start.low)
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+static ulong __LZTimerLap(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger lap,count;
+ VTD_Get_Real_Time(&lap.high,&lap.low);
+ _CPU_diffTime64(&tm->start,&lap,&count);
+ return _CPU_calcMicroSec(&count,frequency);
+}
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOff(tm) VTD_Get_Real_Time(&tm->end.high,&tm->end.low)
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+static ulong __LZTimerCount(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger tmCount;
+ _CPU_diffTime64(&tm->start,&tm->end,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,frequency);
+}
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 1000
+
+/****************************************************************************
+REMARKS:
+Read the Long Period timer value from the BIOS timer tick.
+****************************************************************************/
+static ulong __ULZReadTime(void)
+{
+ return VDHQuerySysValue(0, VDHGSV_MSECSBOOT);
+}
+
+/****************************************************************************
+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; }
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vxd/_pm.asm b/board/MAI/bios_emulator/scitech/src/pm/vxd/_pm.asm
new file mode 100644
index 0000000000..64a7cecb2d
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vxd/_pm.asm
@@ -0,0 +1,299 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: 32-bit Windows VxD
+;*
+;* Description: Low level assembly support for the PM library specific to
+;* Windows VxDs.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pm ; Set up memory model
+
+begdataseg _pm
+
+ cextern _PM_savedDS,USHORT
+
+enddataseg _pm
+
+P586
+
+begcodeseg _pm ; Start of code segment
+
+;----------------------------------------------------------------------------
+; void PM_segread(PMSREGS *sregs)
+;----------------------------------------------------------------------------
+; Read the current value of all segment registers
+;----------------------------------------------------------------------------
+cprocstart PM_segread
+
+ ARG sregs:DPTR
+
+ enter_c
+
+ mov ax,es
+ _les _si,[sregs]
+ mov [_ES _si],ax
+ mov [_ES _si+2],cs
+ mov [_ES _si+4],ss
+ mov [_ES _si+6],ds
+ mov [_ES _si+8],fs
+ mov [_ES _si+10],gs
+
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_int386x(int intno, PMREGS *in, PMREGS *out,PMSREGS *sregs)
+;----------------------------------------------------------------------------
+; Issues a software interrupt in protected mode. This routine has been
+; written to allow user programs to load CS and DS with different values
+; other than the default.
+;----------------------------------------------------------------------------
+cprocstart PM_int386x
+
+; Not used for VxDs
+
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_saveDS(void)
+;----------------------------------------------------------------------------
+; Save the value of DS into a section of the code segment, so that we can
+; quickly load this value at a later date in the PM_loadDS() routine from
+; inside interrupt handlers etc. The method to do this is different
+; depending on the DOS extender being used.
+;----------------------------------------------------------------------------
+cprocstart PM_saveDS
+
+ mov [_PM_savedDS],ds ; Store away in data segment
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_loadDS(void)
+;----------------------------------------------------------------------------
+; Routine to load the DS register with the default value for the current
+; DOS extender. Only the DS register is loaded, not the ES register, so
+; if you wish to call C code, you will need to also load the ES register
+; in 32 bit protected mode.
+;----------------------------------------------------------------------------
+cprocstart PM_loadDS
+
+ mov ds,[cs:_PM_savedDS] ; We can access the proper DS through CS
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setBankA(int bank)
+;----------------------------------------------------------------------------
+cprocstart PM_setBankA
+
+; Not used for VxDs
+
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setBankAB(int bank)
+;----------------------------------------------------------------------------
+cprocstart PM_setBankAB
+
+; Not used for VxDs
+
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setCRTStart(int x,int y,int waitVRT)
+;----------------------------------------------------------------------------
+cprocstart PM_setCRTStart
+
+; Not used for VxDs
+
+ ret
+
+cprocend
+
+; Macro to delay briefly to ensure that enough time has elapsed between
+; successive I/O accesses so that the device being accessed can respond
+; to both accesses even on a very fast PC.
+
+ifdef USE_NASM
+%macro DELAY 0
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+%endmacro
+%macro IODELAYN 1
+%rep %1
+ DELAY
+%endrep
+%endmacro
+else
+macro DELAY
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+endm
+macro IODELAYN N
+ rept N
+ DELAY
+ endm
+endm
+endif
+
+;----------------------------------------------------------------------------
+; uchar _PM_readCMOS(int index)
+;----------------------------------------------------------------------------
+; Read the value of a specific CMOS register. We do this with both
+; normal interrupts and NMI disabled.
+;----------------------------------------------------------------------------
+cprocstart _PM_readCMOS
+
+ ARG index:UINT
+
+ push _bp
+ mov _bp,_sp
+ pushfd
+ mov al,[BYTE index]
+ or al,80h ; Add disable NMI flag
+ cli
+ out 70h,al
+ IODELAYN 5
+ in al,71h
+ mov ah,al
+ xor al,al
+ IODELAYN 5
+ out 70h,al ; Re-enable NMI
+ mov al,ah ; Return value in AL
+ popfd
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void _PM_writeCMOS(int index,uchar value)
+;----------------------------------------------------------------------------
+; Read the value of a specific CMOS register. We do this with both
+; normal interrupts and NMI disabled.
+;----------------------------------------------------------------------------
+cprocstart _PM_writeCMOS
+
+ ARG index:UINT, value:UCHAR
+
+ push _bp
+ mov _bp,_sp
+ pushfd
+ mov al,[BYTE index]
+ or al,80h ; Add disable NMI flag
+ cli
+ out 70h,al
+ IODELAYN 5
+ mov al,[value]
+ out 71h,al
+ xor al,al
+ IODELAYN 5
+ out 70h,al ; Re-enable NMI
+ popfd
+ pop _bp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; double _ftol(double f)
+;----------------------------------------------------------------------------
+; Calls to __ftol are generated by the Borland C++ compiler for code
+; that needs to convert a floating point type to an integral type.
+;
+; Input: floating point number on the top of the '87.
+;
+; Output: a (signed or unsigned) long in EAX
+; All other registers preserved.
+;-----------------------------------------------------------------------
+cprocstart _ftol
+
+ LOCAL temp1:WORD, temp2:QWORD = LocalSize
+
+ push ebp
+ mov ebp,esp
+ sub esp,LocalSize
+
+ fstcw [temp1] ; save the control word
+ fwait
+ mov al,[BYTE temp1+1]
+ or [BYTE temp1+1],0Ch ; set rounding control to chop
+ fldcw [temp1]
+ fistp [temp2] ; convert to 64-bit integer
+ mov [BYTE temp1+1],al
+ fldcw [temp1] ; restore the control word
+ mov eax,[DWORD temp2] ; return LS 32 bits
+ mov edx,[DWORD temp2+4] ; MS 32 bits
+
+ mov esp,ebp
+ pop ebp
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; _PM_getPDB - Return the Page Table Directory Base address
+;----------------------------------------------------------------------------
+cprocstart _PM_getPDB
+
+ mov eax,cr3
+ and eax,0FFFFF000h
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; Flush the Translation Lookaside buffer
+;----------------------------------------------------------------------------
+cprocstart PM_flushTLB
+
+ wbinvd ; Flush the CPU cache
+ mov eax,cr3
+ mov cr3,eax ; Flush the TLB
+ ret
+
+cprocend
+
+endcodeseg _pm
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vxd/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/vxd/cpuinfo.c
new file mode 100644
index 0000000000..3c7eaaeaac
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vxd/cpuinfo.c
@@ -0,0 +1,66 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows VxD
+*
+* Description: VxD specific code for the CPU detection module.
+*
+****************************************************************************/
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Do nothing for VxD's
+****************************************************************************/
+#define SetMaxThreadPriority() 0
+
+/****************************************************************************
+REMARKS:
+Do nothing for VxD's
+****************************************************************************/
+#define RestoreThreadPriority(i) (void)(i)
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ freq->low = 1193180;
+ freq->high = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ CPU_largeInteger count; \
+ VTD_Get_Real_Time(&count.high,&count.low); \
+ (t)->low = count.low; \
+ (t)->high = count.high; \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vxd/fileio.c b/board/MAI/bios_emulator/scitech/src/pm/vxd/fileio.c
new file mode 100644
index 0000000000..e2ff585839
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vxd/fileio.c
@@ -0,0 +1,305 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows VxD
+*
+* Description: C library compatible I/O functions for use within a VxD.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "vxdfile.h"
+
+/*------------------------ Main Code Implementation -----------------------*/
+
+#define EOF -1
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C fopen function.
+****************************************************************************/
+FILE * fopen(
+ const char *filename,
+ const char *mode)
+{
+ FILE *f = PM_malloc(sizeof(FILE));
+ long oldpos;
+
+ if (f) {
+ f->offset = 0;
+ f->text = (mode[1] == 't' || mode[2] == 't');
+ f->writemode = (mode[0] == 'w') || (mode[0] == 'a');
+ if (initComplete) {
+ WORD omode,error;
+ BYTE action;
+
+ if (mode[0] == 'r') {
+ omode = OPEN_ACCESS_READONLY | OPEN_SHARE_COMPATIBLE;
+ action = ACTION_IFEXISTS_OPEN | ACTION_IFNOTEXISTS_FAIL;
+ }
+ else if (mode[0] == 'w') {
+ omode = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_COMPATIBLE;
+ action = ACTION_IFEXISTS_TRUNCATE | ACTION_IFNOTEXISTS_CREATE;
+ }
+ else {
+ omode = OPEN_ACCESS_READWRITE | OPEN_SHARE_COMPATIBLE;
+ action = ACTION_IFEXISTS_OPEN | ACTION_IFNOTEXISTS_CREATE;
+ }
+ f->handle = (int)R0_OpenCreateFile(false,(char*)filename,omode,ATTR_NORMAL,action,0,&error,&action);
+ if (f->handle == 0) {
+ PM_free(f);
+ return NULL;
+ }
+ f->filesize = R0_GetFileSize((HANDLE)f->handle,&error);
+ if (mode[0] == 'a')
+ fseek(f,0,2);
+ }
+ else {
+ int oflag,pmode;
+
+ if (mode[0] == 'r') {
+ pmode = _S_IREAD;
+ oflag = _O_RDONLY;
+ }
+ else if (mode[0] == 'w') {
+ pmode = _S_IWRITE;
+ oflag = _O_WRONLY | _O_CREAT | _O_TRUNC;
+ }
+ else {
+ pmode = _S_IWRITE;
+ oflag = _O_RDWR | _O_CREAT | _O_APPEND;
+ }
+ if (f->text)
+ oflag |= _O_TEXT;
+ else
+ oflag |= _O_BINARY;
+ if ((f->handle = i_open(filename,oflag,pmode)) == -1) {
+ PM_free(f);
+ return NULL;
+ }
+ oldpos = i_lseek(f->handle,0,1);
+ f->filesize = i_lseek(f->handle,0,2);
+ i_lseek(f->handle,oldpos,0);
+ }
+ }
+ return f;
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C fread function. Note that the VxD file I/O
+functions are layered on DOS, so can only read up to 64K at a time. Since
+we are expected to handle much larger chunks than this, we handle larger
+blocks automatically in here.
+****************************************************************************/
+size_t fread(
+ void *ptr,
+ size_t size,
+ size_t n,
+ FILE *f)
+{
+ char *buf = ptr;
+ WORD error;
+ int bytes = size * n;
+ int readbytes,totalbytes = 0;
+
+ while (bytes > 0x10000) {
+ if (initComplete) {
+ readbytes = R0_ReadFile(false,(HANDLE)f->handle,buf,0x8000,f->offset,&error);
+ readbytes += R0_ReadFile(false,(HANDLE)f->handle,buf+0x8000,0x8000,f->offset+0x8000,&error);
+ }
+ else {
+ readbytes = i_read(f->handle,buf,0x8000);
+ readbytes += i_read(f->handle,buf+0x8000,0x8000);
+ }
+ totalbytes += readbytes;
+ f->offset += readbytes;
+ buf += 0x10000;
+ bytes -= 0x10000;
+ }
+ if (bytes) {
+ if (initComplete)
+ readbytes = R0_ReadFile(false,(HANDLE)f->handle,buf,bytes,f->offset,&error);
+ else
+ readbytes = i_read(f->handle,buf,bytes);
+ totalbytes += readbytes;
+ f->offset += readbytes;
+ }
+ return totalbytes / size;
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C fwrite function. Note that the VxD file I/O
+functions are layered on DOS, so can only read up to 64K at a time. Since
+we are expected to handle much larger chunks than this, we handle larger
+blocks automatically in here.
+****************************************************************************/
+size_t fwrite(
+ const void *ptr,
+ size_t size,
+ size_t n,
+ FILE *f)
+{
+ const char *buf = ptr;
+ WORD error;
+ int bytes = size * n;
+ int writtenbytes,totalbytes = 0;
+
+ if (!f->writemode)
+ return 0;
+ while (bytes > 0x10000) {
+ if (initComplete) {
+ writtenbytes = R0_WriteFile(false,(HANDLE)f->handle,buf,0x8000,f->offset,&error);
+ writtenbytes += R0_WriteFile(false,(HANDLE)f->handle,buf+0x8000,0x8000,f->offset+0x8000,&error);
+ }
+ else {
+ writtenbytes = i_write(f->handle,buf,0x8000);
+ writtenbytes += i_write(f->handle,buf+0x8000,0x8000);
+ }
+ totalbytes += writtenbytes;
+ f->offset += writtenbytes;
+ buf += 0x10000;
+ bytes -= 0x10000;
+ }
+ if (initComplete)
+ writtenbytes = R0_WriteFile(false,(HANDLE)f->handle,buf,bytes,f->offset,&error);
+ else
+ writtenbytes = i_write(f->handle,buf,bytes);
+ totalbytes += writtenbytes;
+ f->offset += writtenbytes;
+ if (f->offset > f->filesize)
+ f->filesize = f->offset;
+ return totalbytes / size;
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C fflush function.
+****************************************************************************/
+int fflush(
+ FILE *f)
+{
+ // Nothing to do since we are not doing buffered file I/O
+ (void)f;
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C fseek function.
+****************************************************************************/
+int fseek(
+ FILE *f,
+ long int offset,
+ int whence)
+{
+ if (whence == 0)
+ f->offset = offset;
+ else if (whence == 1)
+ f->offset += offset;
+ else if (whence == 2)
+ f->offset = f->filesize + offset;
+ if (!initComplete)
+ i_lseek(f->handle,f->offset,0);
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C ftell function.
+****************************************************************************/
+long ftell(
+ FILE *f)
+{
+ return f->offset;
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C feof function.
+****************************************************************************/
+int feof(
+ FILE *f)
+{
+ return (f->offset == f->filesize);
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C fgets function.
+****************************************************************************/
+char *fgets(
+ char *s,
+ int n,
+ FILE *f)
+{
+ int len;
+ char *cs;
+
+ // Read the entire buffer into memory (our functions are unbuffered!)
+ if ((len = fread(s,1,n,f)) == 0)
+ return NULL;
+
+ // Search for '\n' or end of string
+ if (n > len)
+ n = len;
+ cs = s;
+ while (--n > 0) {
+ if (*cs == '\n')
+ break;
+ cs++;
+ }
+ *cs = '\0';
+ return s;
+}
+
+/****************************************************************************
+REMARKS:
+NT driver implementation of the ANSI C fputs function.
+****************************************************************************/
+int fputs(
+ const char *s,
+ FILE *f)
+{
+ return fwrite(s,1,strlen(s),f);
+}
+
+/****************************************************************************
+REMARKS:
+VxD implementation of the ANSI C fclose function.
+****************************************************************************/
+int fclose(
+ FILE *f)
+{
+ WORD error;
+
+ if (initComplete)
+ R0_CloseFile((HANDLE)f->handle,&error);
+ else
+ i_close(f->handle);
+ PM_free(f);
+ return 0;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vxd/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/vxd/oshdr.h
new file mode 100644
index 0000000000..7efc0f9f85
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vxd/oshdr.h
@@ -0,0 +1,29 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows VxD
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vxd/pm.c b/board/MAI/bios_emulator/scitech/src/pm/vxd/pm.c
new file mode 100644
index 0000000000..8d00df9065
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vxd/pm.c
@@ -0,0 +1,1360 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows VxD
+*
+* 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 "sdd/sddhelp.h"
+#include "mtrr.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+#define MAX_MEMORY_SHARED 100
+#define MAX_MEMORY_MAPPINGS 100
+
+typedef struct {
+ void *linear;
+ ulong global;
+ ulong length;
+ int npages;
+ } memshared;
+
+typedef struct {
+ ulong physical;
+ ulong linear;
+ ulong length;
+ int npages;
+ ibool isCached;
+ } mmapping;
+
+static int numMappings = 0;
+static memshared shared[MAX_MEMORY_MAPPINGS] = {0};
+static mmapping maps[MAX_MEMORY_MAPPINGS];
+extern ibool _PM_haveBIOS;
+char _PM_cntPath[PM_MAX_PATH] = "";
+char _PM_nucleusPath[PM_MAX_PATH] = "";
+uchar *_PM_rmBufAddr = NULL;
+ushort _VARAPI _PM_savedDS = 0;
+static uchar _PM_oldCMOSRegA;
+static uchar _PM_oldCMOSRegB;
+PM_intHandler _PM_rtcHandler = NULL;
+IRQHANDLE RTCIRQHandle = 0;
+VPICD_HWInt_THUNK RTCInt_Thunk;
+
+static char *szWindowsKey = "Software\\Microsoft\\Windows\\CurrentVersion";
+static char *szSystemRoot = "SystemRoot";
+static char *szMachineNameKey = "System\\CurrentControlSet\\control\\ComputerName\\ComputerName";
+static char *szMachineName = "ComputerName";
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* Functions to read and write CMOS registers */
+
+ulong PMAPI _PM_getPDB(void);
+uchar PMAPI _PM_readCMOS(int index);
+void PMAPI _PM_writeCMOS(int index,uchar value);
+
+/****************************************************************************
+REMARKS:
+PM_malloc override function for Nucleus drivers loaded in VxD's.
+****************************************************************************/
+void * VXD_malloc(
+ size_t size)
+{
+ return PM_mallocShared(size);
+}
+
+/****************************************************************************
+REMARKS:
+PM_calloc override function for Nucleus drivers loaded in VxD's.
+****************************************************************************/
+void * VXD_calloc(
+ size_t nelem,
+ size_t size)
+{
+ void *p = PM_mallocShared(nelem * size);
+ if (p)
+ memset(p,0,nelem * size);
+ return p;
+}
+
+/****************************************************************************
+REMARKS:
+PM_realloc override function for Nucleus drivers loaded in VxD's.
+****************************************************************************/
+void * VXD_realloc(
+ void *ptr,
+ size_t size)
+{
+ void *p = PM_mallocShared(size);
+ if (p) {
+ memcpy(p,ptr,size);
+ PM_freeShared(ptr);
+ }
+ return p;
+}
+
+/****************************************************************************
+REMARKS:
+PM_free override function for Nucleus drivers loaded in VxD's.
+****************************************************************************/
+void VXD_free(
+ void *p)
+{
+ PM_freeShared(p);
+}
+
+/****************************************************************************
+REMARKS:
+Initialise the PM library.
+****************************************************************************/
+void PMAPI PM_init(void)
+{
+ /* Override the default memory allocators for all Nucleus drivers
+ * loaded in SDDHELP/PMHELP. We do this so that we can ensure all memory
+ * dynamically allocated by Nucleus drivers and internal C runtime
+ * library functions are shared memory blocks that all processes
+ * connecting to SDDHELP can see.
+ */
+ PM_useLocalMalloc(VXD_malloc,VXD_calloc,VXD_realloc,VXD_free);
+
+ /* Initialiase the MTRR module */
+ MTRR_init();
+}
+
+ibool PMAPI PM_haveBIOSAccess(void)
+{ return _PM_haveBIOS; }
+
+long PMAPI PM_getOSType(void)
+{ return _OS_WIN32VXD; }
+
+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();
+ Fatal_Error_Handler(msg,0);
+}
+
+/****************************************************************************
+PARAMETERS:
+len - Place to store the length of the buffer
+rseg - Place to store the real mode segment of the buffer
+roff - Place to store the real mode offset of the buffer
+
+REMARKS:
+This function returns the address and length of the global VESA transfer
+buffer that is used for communicating with the VESA BIOS functions from
+Win16 and Win32 programs under Windows.
+****************************************************************************/
+void * PMAPI PM_getVESABuf(
+ uint *len,
+ uint *rseg,
+ uint *roff)
+{
+ /* If the VxD is dynamically loaded we will not have a real mode
+ * transfer buffer to return, so we fail the call.
+ */
+ if (_PM_rmBufAddr) {
+ *len = VESA_BUF_SIZE;
+ *rseg = (ulong)(_PM_rmBufAddr) >> 4;
+ *roff = (ulong)(_PM_rmBufAddr) & 0xF;
+ return _PM_rmBufAddr;
+ }
+ return NULL;
+}
+
+int PMAPI PM_int386(
+ int intno,
+ PMREGS *in,
+ PMREGS *out)
+{
+ /* Unused in VxDs */
+ return 0;
+}
+
+void PMAPI _PM_getRMvect(
+ int intno,
+ long *realisr)
+{
+ WORD seg;
+ DWORD off;
+
+ Get_V86_Int_Vector(intno,&seg,&off);
+ *realisr = ((long)seg << 16) | (off & 0xFFFF);
+}
+
+void PMAPI _PM_setRMvect(
+ int intno,
+ long realisr)
+{
+ Set_V86_Int_Vector(intno,realisr >> 16,realisr & 0xFFFF);
+}
+
+char * PMAPI PM_getCurrentPath(
+ char *path,
+ int maxLen)
+{
+ strncpy(path,_PM_cntPath,maxLen);
+ path[maxLen-1] = 0;
+ return path;
+}
+
+char PMAPI PM_getBootDrive(void)
+{ return 'c'; }
+
+const char * PMAPI PM_getVBEAFPath(void)
+{ return "c:\\"; }
+
+/****************************************************************************
+PARAMETERS:
+szKey - Key to query (can contain version number formatting)
+szValue - Value to get information for
+value - Place to store the registry key data read
+size - Size of the string buffer to read into
+
+RETURNS:
+true if the key was found, false if not.
+****************************************************************************/
+static ibool REG_queryString(
+ char *szKey,
+ char *szValue,
+ char *value,
+ ulong size)
+{
+ HKEY hKey;
+ ulong type;
+ ibool status = false;
+
+ memset(value,0,sizeof(value));
+ if (RegOpenKey(HKEY_LOCAL_MACHINE,szKey,&hKey) == ERROR_SUCCESS) {
+ if (RegQueryValueEx(hKey,(PCHAR)szValue,(ulong*)NULL,(ulong*)&type,value,(ulong*)&size) == ERROR_SUCCESS)
+ status = true;
+ RegCloseKey(hKey);
+ }
+ return status;
+}
+
+const char * PMAPI PM_getNucleusPath(void)
+{
+ static char path[256];
+
+ if (strlen(_PM_nucleusPath) > 0) {
+ strcpy(path,_PM_nucleusPath);
+ PM_backslash(path);
+ return path;
+ }
+ if (!REG_queryString(szWindowsKey,szSystemRoot,path,sizeof(path)))
+ strcpy(path,"c:\\windows");
+ PM_backslash(path);
+ strcat(path,"system\\nucleus");
+ return path;
+}
+
+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)
+{ return PM_getMachineName(); }
+
+const char * PMAPI PM_getMachineName(void)
+{
+ static char name[256];
+ if (REG_queryString(szMachineNameKey,szMachineName,name,sizeof(name)))
+ return name;
+ return "Unknown";
+}
+
+int PMAPI PM_kbhit(void)
+{ return 1; }
+
+int PMAPI PM_getch(void)
+{ return 0; }
+
+PM_HWND PMAPI PM_openConsole(
+ PM_HWND hwndUser,
+ int device,
+ int xRes,
+ int yRes,
+ int bpp,
+ ibool fullScreen)
+{
+ /* Unused in VxDs */
+ return NULL;
+}
+
+int PMAPI PM_getConsoleStateSize(void)
+{
+ /* Unused in VxDs */
+ return 1;
+}
+
+void PMAPI PM_saveConsoleState(
+ void *stateBuf,
+ PM_HWND hwndConsole)
+{
+ /* Unused in VxDs */
+}
+
+void PMAPI PM_setSuspendAppCallback(
+ int (_ASMAPIP saveState)(
+ int flags))
+{
+ /* Unused in VxDs */
+}
+
+void PMAPI PM_restoreConsoleState(
+ const void *stateBuf,
+ PM_HWND hwndConsole)
+{
+ /* Unused in VxDs */
+}
+
+void PMAPI PM_closeConsole(
+ PM_HWND hwndConsole)
+{
+ /* Unused in VxDs */
+}
+
+void PM_setOSCursorLocation(
+ int x,
+ int y)
+{
+ uchar *_biosPtr = PM_getBIOSPointer();
+ PM_setByte(_biosPtr+0x50,x);
+ PM_setByte(_biosPtr+0x51,y);
+}
+
+void PM_setOSScreenWidth(
+ int width,
+ int height)
+{
+ uchar *_biosPtr = PM_getBIOSPointer();
+ PM_setByte(_biosPtr+0x4A,width);
+ PM_setByte(_biosPtr+0x84,height-1);
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of shared memory. For Win9x we allocate shared memory
+as locked, global memory that is accessible from any memory context
+(including interrupt time context), which allows us to load our important
+data structure and code such that we can access it directly from a ring
+0 interrupt context.
+****************************************************************************/
+void * PMAPI PM_mallocShared(
+ long size)
+{
+ MEMHANDLE hMem;
+ DWORD pgNum,nPages = (size + 0xFFF) >> 12;
+ int i;
+
+ /* First find a free slot in our shared memory table */
+ for (i = 0; i < MAX_MEMORY_SHARED; i++) {
+ if (shared[i].linear == 0)
+ break;
+ }
+ if (i < MAX_MEMORY_SHARED) {
+ PageAllocate(nPages,PG_SYS,0,0,0,0,NULL,0,&hMem,&shared[i].linear);
+ shared[i].npages = nPages;
+ pgNum = (ulong)shared[i].linear >> 12;
+ shared[i].global = LinPageLock(pgNum,nPages,PAGEMAPGLOBAL);
+ return (void*)shared[i].global;
+ }
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of shared memory
+****************************************************************************/
+void PMAPI PM_freeShared(void *p)
+{
+ int i;
+
+ /* Find a shared memory block in our table and free it */
+ for (i = 0; i < MAX_MEMORY_SHARED; i++) {
+ if (shared[i].global == (ulong)p) {
+ LinPageUnLock(shared[i].global >> 12,shared[i].npages,PAGEMAPGLOBAL);
+ PageFree((ulong)shared[i].linear,0);
+ shared[i].linear = 0;
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Maps a shared memory block into process address space. Does nothing since
+the memory blocks are already globally7 mapped into all processes.
+****************************************************************************/
+void * PMAPI PM_mapToProcess(
+ void *base,
+ ulong limit)
+{
+ return (void*)base;
+}
+
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *mappedBIOS,
+ ulong BIOSLen)
+{
+ // TODO: Figure out how to do this
+ return false;
+}
+
+void * PMAPI PM_getBIOSPointer(void)
+{ return (void*)0x400; }
+
+void * PMAPI PM_getA0000Pointer(void)
+{ return PM_mapPhysicalAddr(0xA0000,0xFFFF,true); }
+
+/****************************************************************************
+PARAMETERS:
+base - Physical base address of the memory to maps in
+limit - Limit of physical memory to region to maps in
+
+RETURNS:
+Linear address of the newly mapped memory.
+
+REMARKS:
+Maps a physical memory range to a linear memory range.
+****************************************************************************/
+ulong _PM_mapPhysicalToLinear(
+ ulong base,
+ ulong limit,
+ int *npages)
+{
+ ulong linear,length = limit+1;
+ int i,ppage,flags;
+
+ if (base < 0x100000) {
+ /* Windows 9x is zero based for the first meg of memory */
+ return base;
+ }
+ ppage = base >> 12;
+ *npages = (length + (base & 0xFFF) + 4095) >> 12;
+ flags = PR_FIXED | PR_STATIC;
+ if (base == 0xA0000) {
+ /* We require the linear address to be aligned to a 64Kb boundary
+ * for mapping the banked framebuffer (so we can do efficient
+ * carry checking for bank changes in the assembler code). The only
+ * way to ensure this is to force the linear address to be aligned
+ * to a 4Mb boundary.
+ */
+ flags |= PR_4MEG;
+ }
+ if ((linear = (ulong)PageReserve(PR_SYSTEM,*npages,flags)) == (ulong)-1)
+ return 0xFFFFFFFF;
+ if (!PageCommitPhys(linear >> 12,*npages,ppage,PC_INCR | PC_USER | PC_WRITEABLE))
+ return 0xFFFFFFFF;
+ return linear + (base & 0xFFF);
+}
+
+// Page table flags
+
+#define PAGE_FLAGS_PRESENT 0x00000001
+#define PAGE_FLAGS_WRITEABLE 0x00000002
+#define PAGE_FLAGS_USER 0x00000004
+#define PAGE_FLAGS_WRITE_THROUGH 0x00000008
+#define PAGE_FLAGS_CACHE_DISABLE 0x00000010
+#define PAGE_FLAGS_ACCESSED 0x00000020
+#define PAGE_FLAGS_DIRTY 0x00000040
+#define PAGE_FLAGS_4MB 0x00000080
+
+/****************************************************************************
+PARAMETERS:
+base - Physical base address of the memory to maps in
+limit - Limit of physical memory to region to maps in
+isCached - True if the memory should be cached, false if not
+
+RETURNS:
+Linear address of the newly mapped memory.
+
+REMARKS:
+This function maps physical memory to linear memory, which can then be used
+to create a selector or used directly from 32-bit protected mode programs.
+This is better than DPMI 0x800, since it allows you to maps physical
+memory below 1Mb, which gets this memory out of the way of the Windows VDD's
+sticky paws.
+
+NOTE: If the memory is not expected to be cached, this function will
+ directly re-program the PCD (Page Cache Disable) bit in the
+ page tables. There does not appear to be a mechanism in the VMM
+ to control this bit via the regular interface.
+****************************************************************************/
+void * PMAPI PM_mapPhysicalAddr(
+ ulong base,
+ ulong limit,
+ ibool isCached)
+{
+ ulong linear,length = limit+1;
+ int i,npages;
+ ulong PDB,*pPDB;
+
+ /* Search table of existing mappings to see if we have already mapped
+ * a region of memory that will serve this purpose.
+ */
+ for (i = 0; i < numMappings; i++) {
+ if (maps[i].physical == base && maps[i].length == length && maps[i].isCached == isCached)
+ return (void*)maps[i].linear;
+ }
+ if (numMappings == MAX_MEMORY_MAPPINGS)
+ return NULL;
+
+ /* We did not find any previously mapped memory region, so maps it in.
+ * Note that we do not use MapPhysToLinear, since this function appears
+ * to have problems mapping memory in the 1Mb physical address space.
+ * Hence we use PageReserve and PageCommitPhys.
+ */
+ if ((linear = _PM_mapPhysicalToLinear(base,limit,&npages)) == 0xFFFFFFFF)
+ return NULL;
+ maps[numMappings].physical = base;
+ maps[numMappings].length = length;
+ maps[numMappings].linear = linear;
+ maps[numMappings].npages = npages;
+ maps[numMappings].isCached = isCached;
+ numMappings++;
+
+ /* Finally disable caching where necessary */
+ if (!isCached && (PDB = _PM_getPDB()) != 0) {
+ int startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
+ ulong pageTable,*pPageTable;
+ pPDB = (ulong*)_PM_mapPhysicalToLinear(PDB,0xFFF,&npages);
+ if (pPDB) {
+ startPDB = (linear >> 22) & 0x3FF;
+ startPage = (linear >> 12) & 0x3FF;
+ endPDB = ((linear+limit) >> 22) & 0x3FF;
+ endPage = ((linear+limit) >> 12) & 0x3FF;
+ for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
+ // Set the bits in the page directory entry - required as per
+ // Pentium 4 manual. This also takes care of the 4MB page entries
+ pPDB[iPDB] = pPDB[iPDB] |= (PAGE_FLAGS_WRITE_THROUGH | PAGE_FLAGS_CACHE_DISABLE);
+ if (!(pPDB[iPDB] & PAGE_FLAGS_4MB)) {
+ // If we are dealing with 4KB pages then we need to iterate
+ // through each of the page table entries
+ pageTable = pPDB[iPDB] & ~0xFFF;
+ pPageTable = (ulong*)_PM_mapPhysicalToLinear(pageTable,0xFFF,&npages);
+ start = (iPDB == startPDB) ? startPage : 0;
+ end = (iPDB == endPDB) ? endPage : 0x3FF;
+ for (iPage = start; iPage <= end; iPage++)
+ pPageTable[iPage] |= (PAGE_FLAGS_WRITE_THROUGH | PAGE_FLAGS_CACHE_DISABLE);
+ PageFree((ulong)pPageTable,PR_STATIC);
+ }
+ }
+ PageFree((ulong)pPDB,PR_STATIC);
+ PM_flushTLB();
+ }
+ }
+ return (void*)linear;
+}
+
+void PMAPI PM_freePhysicalAddr(
+ void *ptr,
+ ulong limit)
+{
+ /* We never free the mappings */
+}
+
+void PMAPI PM_sleep(ulong milliseconds)
+{
+ /* We never sleep in a VxD */
+}
+
+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;
+ case 2: return 0x3E8;
+ case 3: return 0x2E8;
+ }
+ 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;
+}
+
+ulong PMAPI PM_getPhysicalAddr(
+ void *p)
+{
+ DWORD pte;
+
+ // Touch the memory before calling CopyPageTable. For some reason
+ // we need to do this on Windows 9x, otherwise the memory may not
+ // be paged in correctly. Of course if the passed in pointer is
+ // invalid, this function will fault, but we shouldn't be passed bogus
+ // pointers anyway ;-)
+ pte = *((ulong*)p);
+
+ // Return assembled address value only if VMM service succeeds
+ if (CopyPageTable(((DWORD)p) >> 12, 1, (PVOID*)&pte, 0))
+ return (pte & ~0xFFF) | (((DWORD)p) & 0xFFF);
+
+ // Return failure to the caller!
+ return 0xFFFFFFFFUL;
+}
+
+ibool PMAPI PM_getPhysicalAddrRange(
+ void *p,
+ ulong length,
+ ulong *physAddress)
+{
+ int i;
+ ulong linear = (ulong)p & ~0xFFF;
+
+ for (i = (length + 0xFFF) >> 12; i > 0; i--) {
+ if ((*physAddress++ = PM_getPhysicalAddr((void*)linear)) == 0xFFFFFFFF)
+ return false;
+ linear += 4096;
+ }
+ return true;
+}
+
+void PMAPI _PM_freeMemoryMappings(void)
+{
+ int i;
+ for (i = 0; i < numMappings; i++)
+ PageFree(maps[i].linear,PR_STATIC);
+}
+
+void * PMAPI PM_mapRealPointer(
+ uint r_seg,
+ uint r_off)
+{
+ return (void*)MK_PHYS(r_seg,r_off);
+}
+
+void * PMAPI PM_allocRealSeg(
+ uint size,
+ uint *r_seg,
+ uint *r_off)
+{
+ return NULL;
+}
+
+void PMAPI PM_freeRealSeg(
+ void *mem)
+{
+}
+
+void PMAPI DPMI_int86(
+ int intno,
+ DPMI_regs *regs)
+{
+ /* Unsed in VxD's */
+}
+
+/****************************************************************************
+REMARKS:
+Load the V86 registers in the client state, and save the original state
+before loading the registers.
+****************************************************************************/
+static void LoadV86Registers(
+ CLIENT_STRUCT *saveRegs,
+ RMREGS *in,
+ RMSREGS *sregs)
+{
+ CLIENT_STRUCT newRegs;
+
+ Save_Client_State(saveRegs);
+ newRegs = *saveRegs;
+ newRegs.CRS.Client_EAX = in->e.eax;
+ newRegs.CRS.Client_EBX = in->e.ebx;
+ newRegs.CRS.Client_ECX = in->e.ecx;
+ newRegs.CRS.Client_EDX = in->e.edx;
+ newRegs.CRS.Client_ESI = in->e.esi;
+ newRegs.CRS.Client_EDI = in->e.edi;
+ newRegs.CRS.Client_ES = sregs->es;
+ newRegs.CRS.Client_DS = sregs->ds;
+ Restore_Client_State(&newRegs);
+}
+
+/****************************************************************************
+REMARKS:
+Read the V86 registers from the client state and restore the original state.
+****************************************************************************/
+static void ReadV86Registers(
+ CLIENT_STRUCT *saveRegs,
+ RMREGS *out,
+ RMSREGS *sregs)
+{
+ CLIENT_STRUCT newRegs;
+
+ Save_Client_State(&newRegs);
+ out->e.eax = newRegs.CRS.Client_EAX;
+ out->e.ebx = newRegs.CRS.Client_EBX;
+ out->e.ecx = newRegs.CRS.Client_ECX;
+ out->e.edx = newRegs.CRS.Client_EDX;
+ out->e.esi = newRegs.CRS.Client_ESI;
+ out->e.edi = newRegs.CRS.Client_EDI;
+ sregs->es = newRegs.CRS.Client_ES;
+ sregs->ds = newRegs.CRS.Client_DS;
+ Restore_Client_State(saveRegs);
+}
+
+/****************************************************************************
+REMARKS:
+Call a V86 real mode function with the specified register values
+loaded before the call. The call returns with a far ret.
+****************************************************************************/
+void PMAPI PM_callRealMode(
+ uint seg,
+ uint off,
+ RMREGS *regs,
+ RMSREGS *sregs)
+{
+ CLIENT_STRUCT saveRegs;
+
+ /* Bail if we do not have BIOS access (ie: the VxD was dynamically
+ * loaded, and not statically loaded.
+ */
+ if (!_PM_haveBIOS)
+ return;
+
+ _TRACE("SDDHELP: Entering PM_callRealMode()\n");
+ Begin_Nest_V86_Exec();
+ LoadV86Registers(&saveRegs,regs,sregs);
+ Simulate_Far_Call(seg, off);
+ Resume_Exec();
+ ReadV86Registers(&saveRegs,regs,sregs);
+ End_Nest_Exec();
+ _TRACE("SDDHELP: Exiting PM_callRealMode()\n");
+}
+
+/****************************************************************************
+REMARKS:
+Issue a V86 real mode interrupt with the specified register values
+loaded before the interrupt.
+****************************************************************************/
+int PMAPI PM_int86(
+ int intno,
+ RMREGS *in,
+ RMREGS *out)
+{
+ RMSREGS sregs = {0};
+ CLIENT_STRUCT saveRegs;
+ ushort oldDisable;
+
+ /* Bail if we do not have BIOS access (ie: the VxD was dynamically
+ * loaded, and not statically loaded.
+ */
+ if (!_PM_haveBIOS) {
+ *out = *in;
+ return out->x.ax;
+ }
+
+ /* Disable pass-up to our VxD handler so we directly call BIOS */
+ _TRACE("SDDHELP: Entering PM_int86()\n");
+ if (disableTSRFlag) {
+ oldDisable = *disableTSRFlag;
+ *disableTSRFlag = 0;
+ }
+ Begin_Nest_V86_Exec();
+ LoadV86Registers(&saveRegs,in,&sregs);
+ Exec_Int(intno);
+ ReadV86Registers(&saveRegs,out,&sregs);
+ End_Nest_Exec();
+
+ /* Re-enable pass-up to our VxD handler if previously enabled */
+ if (disableTSRFlag)
+ *disableTSRFlag = oldDisable;
+
+ _TRACE("SDDHELP: Exiting PM_int86()\n");
+ return out->x.ax;
+}
+
+/****************************************************************************
+REMARKS:
+Issue a V86 real mode interrupt with the specified register values
+loaded before the interrupt.
+****************************************************************************/
+int PMAPI PM_int86x(
+ int intno,
+ RMREGS *in,
+ RMREGS *out,
+ RMSREGS *sregs)
+{
+ CLIENT_STRUCT saveRegs;
+ ushort oldDisable;
+
+ /* Bail if we do not have BIOS access (ie: the VxD was dynamically
+ * loaded, and not statically loaded.
+ */
+ if (!_PM_haveBIOS) {
+ *out = *in;
+ return out->x.ax;
+ }
+
+ /* Disable pass-up to our VxD handler so we directly call BIOS */
+ _TRACE("SDDHELP: Entering PM_int86x()\n");
+ if (disableTSRFlag) {
+ oldDisable = *disableTSRFlag;
+ *disableTSRFlag = 0;
+ }
+ Begin_Nest_V86_Exec();
+ LoadV86Registers(&saveRegs,in,sregs);
+ Exec_Int(intno);
+ ReadV86Registers(&saveRegs,out,sregs);
+ End_Nest_Exec();
+
+ /* Re-enable pass-up to our VxD handler if previously enabled */
+ if (disableTSRFlag)
+ *disableTSRFlag = oldDisable;
+
+ _TRACE("SDDHELP: Exiting PM_int86x()\n");
+ return out->x.ax;
+}
+
+/****************************************************************************
+REMARKS:
+Returns available memory. Not possible under Windows.
+****************************************************************************/
+void PMAPI PM_availableMemory(
+ ulong *physical,
+ ulong *total)
+{
+ *physical = *total = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Allocates a block of locked physical memory.
+****************************************************************************/
+void * PMAPI PM_allocLockedMem(
+ uint size,
+ ulong *physAddr,
+ ibool contiguous,
+ ibool below16M)
+{
+ MEMHANDLE hMem;
+ DWORD nPages = (size + 0xFFF) >> 12;
+ DWORD flags = PAGEFIXED | PAGEUSEALIGN | (contiguous ? PAGECONTIG : 0);
+ DWORD maxPhys = below16M ? 0x00FFFFFF : 0xFFFFFFFF;
+ void *p;
+
+ // TODO: This may need to be modified if the memory needs to be globally
+ // accessible. Check how we implemented PM_mallocShared() as we
+ // may need to do something similar in here.
+ PageAllocate(nPages,PG_SYS,0,0,0,maxPhys,physAddr,flags,&hMem,&p);
+
+ // TODO: We may need to modify the memory blocks to disable caching via
+ // the page tables (PCD|PWT) since DMA memory blocks *cannot* be
+ // cached!
+ return p;
+}
+
+/****************************************************************************
+REMARKS:
+Frees a block of locked physical memory.
+****************************************************************************/
+void PMAPI PM_freeLockedMem(
+ void *p,
+ uint size,
+ ibool contiguous)
+{
+ if (p)
+ PageFree((ulong)p,0);
+}
+
+/****************************************************************************
+REMARKS:
+Allocates a page aligned and page sized block of memory
+****************************************************************************/
+void * PMAPI PM_allocPage(
+ ibool locked)
+{
+ MEMHANDLE hMem;
+ void *p;
+
+ // TODO: This will need to be modified if the memory needs to be globally
+ // accessible. Check how we implemented PM_mallocShared() as we
+ // may need to do something similar in here.
+ PageAllocate(1,PG_SYS,0,0,0,0,0,PAGEFIXED,&hMem,&p);
+ return p;
+}
+
+/****************************************************************************
+REMARKS:
+Free a page aligned and page sized block of memory
+****************************************************************************/
+void PMAPI PM_freePage(
+ void *p)
+{
+ if (p)
+ PageFree((ulong)p,0);
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockDataPages(
+ void *p,
+ uint len,
+ PM_lockHandle *lh)
+{
+ DWORD pgNum = (ulong)p >> 12;
+ DWORD nPages = (len + (ulong)p - (pgNum << 12) + 0xFFF) >> 12;
+ return LinPageLock(pgNum,nPages,0);
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockDataPages(
+ void *p,
+ uint len,
+ PM_lockHandle *lh)
+{
+ DWORD pgNum = (ulong)p >> 12;
+ DWORD nPages = (len + (ulong)p - (pgNum << 12) + 0xFFF) >> 12;
+ return LinPageUnLock(pgNum,nPages,0);
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockCodePages(
+ void (*p)(),
+ uint len,
+ PM_lockHandle *lh)
+{
+ return PM_lockDataPages((void*)p,len,lh);
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockCodePages(
+ void (*p)(),
+ uint len,
+ PM_lockHandle *lh)
+{
+ return PM_unlockDataPages((void*)p,len,lh);
+}
+
+/****************************************************************************
+REMARKS:
+Set the real time clock frequency (for stereo modes).
+****************************************************************************/
+void PMAPI PM_setRealTimeClockFrequency(
+ int frequency)
+{
+ static short convert[] = {
+ 8192,
+ 4096,
+ 2048,
+ 1024,
+ 512,
+ 256,
+ 128,
+ 64,
+ 32,
+ 16,
+ 8,
+ 4,
+ 2,
+ -1,
+ };
+ int i;
+
+ /* First clear any pending RTC timeout if not cleared */
+ _PM_readCMOS(0x0C);
+ if (frequency == 0) {
+ /* Disable RTC timout */
+ _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,_PM_oldCMOSRegB & 0x0F);
+ }
+ else {
+ /* Convert frequency value to RTC clock indexes */
+ for (i = 0; convert[i] != -1; i++) {
+ if (convert[i] == frequency)
+ break;
+ }
+
+ /* Set RTC timout value and enable timeout */
+ _PM_writeCMOS(0x0A,0x20 | (i+3));
+ _PM_writeCMOS(0x0B,(_PM_oldCMOSRegB & 0x0F) | 0x40);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Real time clock interrupt handler, which calls the user registered C code.
+****************************************************************************/
+static BOOL __stdcall RTCInt_Handler(
+ VMHANDLE hVM,
+ IRQHANDLE hIRQ)
+{
+ static char inside = 0;
+
+ /* Clear priority interrupt controller and re-enable interrupts so we
+ * dont lock things up for long.
+ */
+ VPICD_Phys_EOI(hIRQ);
+
+ /* Clear real-time clock timeout */
+ _PM_readCMOS(0x0C);
+
+ /* Now call the C based interrupt handler (but check for mutual
+ * exclusion since we may still be servicing an old interrupt when a
+ * new one comes along; if that happens we ignore the old one).
+ */
+ if (!inside) {
+ inside = 1;
+ enable();
+ _PM_rtcHandler();
+ inside = 0;
+ }
+ return TRUE;
+}
+
+/****************************************************************************
+REMARKS:
+Set the real time clock handler (used for software stereo modes).
+****************************************************************************/
+ibool PMAPI PM_setRealTimeClockHandler(
+ PM_intHandler ih,
+ int frequency)
+{
+ struct VPICD_IRQ_Descriptor IRQdesc;
+
+ /* Save the old CMOS real time clock values */
+ _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
+ _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
+
+ /* Set the real time clock interrupt handler */
+ CHECK(ih != NULL);
+ _PM_rtcHandler = ih;
+ IRQdesc.VID_IRQ_Number = 0x8;
+ IRQdesc.VID_Options = 0;
+ IRQdesc.VID_Hw_Int_Proc = (DWORD)VPICD_Thunk_HWInt(RTCInt_Handler, &RTCInt_Thunk);
+ IRQdesc.VID_EOI_Proc = 0;
+ IRQdesc.VID_Virt_Int_Proc = 0;
+ IRQdesc.VID_Mask_Change_Proc= 0;
+ IRQdesc.VID_IRET_Proc = 0;
+ IRQdesc.VID_IRET_Time_Out = 500;
+ if ((RTCIRQHandle = VPICD_Virtualize_IRQ(&IRQdesc)) == 0)
+ return false;
+
+ /* Program the real time clock default frequency */
+ PM_setRealTimeClockFrequency(frequency);
+
+ /* Unmask IRQ8 in the PIC */
+ VPICD_Physically_Unmask(RTCIRQHandle);
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Restore the original real time clock handler.
+****************************************************************************/
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ if (RTCIRQHandle) {
+ /* Restore CMOS registers and mask RTC clock */
+ _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
+ _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
+
+ /* Restore the interrupt vector */
+ VPICD_Set_Auto_Masking(RTCIRQHandle);
+ VPICD_Force_Default_Behavior(RTCIRQHandle);
+ RTCIRQHandle = 0;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+OS specific shared libraries not supported inside a VxD
+****************************************************************************/
+PM_MODULE PMAPI PM_loadLibrary(
+ const char *szDLLName)
+{
+ (void)szDLLName;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+OS specific shared libraries not supported inside a VxD
+****************************************************************************/
+void * PMAPI PM_getProcAddress(
+ PM_MODULE hModule,
+ const char *szProcName)
+{
+ (void)hModule;
+ (void)szProcName;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+OS specific shared libraries not supported inside a VxD
+****************************************************************************/
+void PMAPI PM_freeLibrary(
+ PM_MODULE hModule)
+{
+ (void)hModule;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+void *PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ // TODO: This function should start a directory enumeration search
+ // given the filename (with wildcards). The data should be
+ // converted and returned in the findData standard form.
+ (void)filename;
+ (void)findData;
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ void *handle,
+ PM_findData *findData)
+{
+ // TODO: This function should find the next file in directory enumeration
+ // search given the search criteria defined in the call to
+ // PM_findFirstFile. The data should be converted and returned
+ // in the findData standard form.
+ (void)handle;
+ (void)findData;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ void *handle)
+{
+ // TODO: This function should close the find process. This may do
+ // nothing for some OS'es.
+ (void)handle;
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ // Not supported in a VxD
+ (void)drive;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ // Not supported in a VxD
+ (void)drive;
+ (void)dir;
+ (void)len;
+}
+
+/****************************************************************************
+PARAMETERS:
+base - The starting physical base address of the region
+size - The size in bytes of the region
+type - Type to place into the MTRR register
+
+RETURNS:
+Error code describing the result.
+
+REMARKS:
+Function to enable write combining for the specified region of memory.
+****************************************************************************/
+int PMAPI PM_enableWriteCombine(
+ ulong base,
+ ulong size,
+ uint type)
+{
+ return MTRR_enableWriteCombine(base,size,type);
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+ // TODO: Implement this
+ (void)filename;
+ (void)attrib;
+ PM_fatalError("PM_setFileAttr not implemented yet!");
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file attributes for a specific file.
+****************************************************************************/
+uint PMAPI PM_getFileAttr(
+ const char *filename)
+{
+ // TODO: Implement this
+ (void)filename;
+ PM_fatalError("PM_getFileAttr not implemented yet!");
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+ // TODO: Implement this
+ (void)filename;
+ PM_fatalError("PM_mkdir not implemented yet!");
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+ // TODO: Implement this
+ (void)filename;
+ PM_fatalError("PM_rmdir not implemented yet!");
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_getFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this!
+ (void)filename;
+ (void)gmTime;
+ (void)time;
+ PM_fatalError("PM_getFileTime not implemented yet!");
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_setFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ // TODO: Implement this!
+ (void)filename;
+ (void)gmTime;
+ (void)time;
+ PM_fatalError("PM_setFileTime not implemented yet!");
+ return false;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vxd/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/vxd/vflat.c
new file mode 100644
index 0000000000..901ce1cf03
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vxd/vflat.c
@@ -0,0 +1,45 @@
+/****************************************************************************
+*
+* 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)
+{
+ return NULL;
+}
+
+void PMAPI VF_exit(void)
+{
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/vxd/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/vxd/ztimer.c
new file mode 100644
index 0000000000..76df48c38b
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/vxd/ztimer.c
@@ -0,0 +1,105 @@
+/****************************************************************************
+*
+* 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: 32-bit Windows VxD
+*
+* Description: OS specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+/*---------------------------- Global variables ---------------------------*/
+
+static ulong frequency = 1193180;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+#define __ZTimerInit()
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOn(tm) VTD_Get_Real_Time(&tm->start.high,&tm->start.low)
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+static ulong __LZTimerLap(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger lap,count;
+ VTD_Get_Real_Time(&lap.high,&lap.low);
+ _CPU_diffTime64(&tm->start,&lap,&count);
+ return _CPU_calcMicroSec(&count,frequency);
+}
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+#define __LZTimerOff(tm) VTD_Get_Real_Time(&tm->end.high,&tm->end.low)
+
+/****************************************************************************
+REMARKS:
+Call the assembler Zen Timer functions to do the timing.
+****************************************************************************/
+static ulong __LZTimerCount(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger tmCount;
+ _CPU_diffTime64(&tm->start,&tm->end,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,frequency);
+}
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 1000
+
+/****************************************************************************
+REMARKS:
+Read the Long Period timer value from the BIOS timer tick.
+****************************************************************************/
+static ulong __ULZReadTime(void)
+{
+ CPU_largeInteger count;
+ VTD_Get_Real_Time(&count.high,&count.low);
+ return (count.low * 1000.0 / frequency);
+}
+
+/****************************************************************************
+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; }
diff --git a/board/MAI/bios_emulator/scitech/src/pm/win32/_pmwin32.asm b/board/MAI/bios_emulator/scitech/src/pm/win32/_pmwin32.asm
new file mode 100644
index 0000000000..7c242b5724
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/win32/_pmwin32.asm
@@ -0,0 +1,78 @@
+;****************************************************************************
+;*
+;* 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: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: Win32
+;*
+;* Description: Low level assembly support for the PM library specific
+;* to Windows.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pmwin32 ; Set up memory model
+
+begdataseg _pmwin32
+
+ cglobal _PM_ioentry
+ cglobal _PM_gdt
+_PM_ioentry dd 0 ; Offset to call gate
+_PM_gdt dw 0 ; Selector to call gate
+
+enddataseg _pmwin32
+
+begcodeseg _pmwin32 ; Start of code segment
+
+;----------------------------------------------------------------------------
+; int PM_setIOPL(int iopl)
+;----------------------------------------------------------------------------
+; Change the IOPL level for the 32-bit task. Returns the previous level
+; so it can be restored for the task correctly.
+;----------------------------------------------------------------------------
+cprocstart _PM_setIOPLViaCallGate
+
+ ARG iopl:UINT
+
+ enter_c
+ pushfd ; Save the old EFLAGS for later
+ mov ecx,[iopl] ; ECX := IOPL level
+ xor ebx,ebx ; Change IOPL level function code
+ifdef USE_NASM
+ call far dword [_PM_ioentry]
+else
+ call [FWORD _PM_ioentry]
+endif
+ pop eax
+ and eax,0011000000000000b
+ shr eax,12
+ leave_c
+ ret
+
+cprocend
+
+endcodeseg _pmwin32
+
+ END ; End of module
diff --git a/board/MAI/bios_emulator/scitech/src/pm/win32/cpuinfo.c b/board/MAI/bios_emulator/scitech/src/pm/win32/cpuinfo.c
new file mode 100644
index 0000000000..5978b9f76e
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/win32/cpuinfo.c
@@ -0,0 +1,94 @@
+/****************************************************************************
+*
+* 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: Win32
+*
+* Description: Module to implement OS specific services to measure the
+* CPU frequency.
+*
+****************************************************************************/
+
+/*---------------------------- Global variables ---------------------------*/
+
+static ibool havePerformanceCounter;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Increase the thread priority to maximum, if possible.
+****************************************************************************/
+static int SetMaxThreadPriority(void)
+{
+ int oldPriority;
+ HANDLE hThread = GetCurrentThread();
+
+ oldPriority = GetThreadPriority(hThread);
+ if (oldPriority != THREAD_PRIORITY_ERROR_RETURN)
+ SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
+ return oldPriority;
+}
+
+/****************************************************************************
+REMARKS:
+Restore the original thread priority.
+****************************************************************************/
+static void RestoreThreadPriority(
+ int oldPriority)
+{
+ HANDLE hThread = GetCurrentThread();
+
+ if (oldPriority != THREAD_PRIORITY_ERROR_RETURN)
+ SetThreadPriority(hThread, oldPriority);
+}
+
+/****************************************************************************
+REMARKS:
+Initialise the counter and return the frequency of the counter.
+****************************************************************************/
+static void GetCounterFrequency(
+ CPU_largeInteger *freq)
+{
+ if (!QueryPerformanceFrequency((LARGE_INTEGER*)freq)) {
+ havePerformanceCounter = false;
+ freq->low = 100000;
+ freq->high = 0;
+ }
+ else
+ havePerformanceCounter = true;
+}
+
+/****************************************************************************
+REMARKS:
+Read the counter and return the counter value.
+****************************************************************************/
+#define GetCounter(t) \
+{ \
+ if (havePerformanceCounter) \
+ QueryPerformanceCounter((LARGE_INTEGER*)t); \
+ else { \
+ (t)->low = timeGetTime() * 100; \
+ (t)->high = 0; \
+ } \
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/win32/ddraw.c b/board/MAI/bios_emulator/scitech/src/pm/win32/ddraw.c
new file mode 100644
index 0000000000..cf89401fe6
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/win32/ddraw.c
@@ -0,0 +1,583 @@
+/****************************************************************************
+*
+* 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: Win32
+*
+* Description: Win32 implementation for the SciTech cross platform
+* event library.
+*
+****************************************************************************/
+
+#include "event.h"
+#include "pmapi.h"
+#include "win32/oshdr.h"
+#include "nucleus/graphics.h"
+
+/*---------------------------- Global Variables ---------------------------*/
+
+/* Publicly accessible variables */
+
+int _PM_deskX,_PM_deskY;/* Desktop dimentions */
+HWND _PM_hwndConsole; /* Window handle for console */
+#ifdef __INTEL__
+uint _PM_cw_default; /* Default FPU control word */
+#endif
+
+/* Private internal variables */
+
+static HINSTANCE hInstApp = NULL;/* Application instance handle */
+static HWND hwndUser = NULL;/* User window handle */
+static HINSTANCE hInstDD = NULL; /* Handle to DirectDraw DLL */
+static LPDIRECTDRAW lpDD = NULL; /* DirectDraw object */
+static LONG oldWndStyle; /* Info about old user window */
+static LONG oldExWndStyle; /* Info about old user window */
+static int oldWinPosX; /* Old window position X coordinate */
+static int oldWinPosY; /* Old window pisition Y coordinate */
+static int oldWinSizeX; /* Old window size X */
+static int oldWinSizeY; /* Old window size Y */
+static WNDPROC oldWinProc = NULL;
+static PM_saveState_cb suspendApp = NULL;
+static ibool waitActive = false;
+static ibool isFullScreen = false;
+static ibool backInGDI = false;
+
+/* Internal strings */
+
+static char *szWinClassName = "SciTechDirectDrawWindow";
+static char *szAutoPlayKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer";
+static char *szAutoPlayValue = "NoDriveTypeAutoRun";
+
+/* Dynalinks to DirectDraw functions */
+
+static HRESULT (WINAPI *pDirectDrawCreate)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter);
+
+/*---------------------------- Implementation -----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Temporarily disables AutoPlay operation while we are running in fullscreen
+graphics modes.
+****************************************************************************/
+static void DisableAutoPlay(void)
+{
+ DWORD dwAutoPlay,dwSize = sizeof(dwAutoPlay);
+ HKEY hKey;
+
+ if (RegOpenKeyEx(HKEY_CURRENT_USER,szAutoPlayKey,0,KEY_EXECUTE | KEY_WRITE,&hKey) == ERROR_SUCCESS) {
+ RegQueryValueEx(hKey,szAutoPlayValue,NULL,NULL,(void*)&dwAutoPlay,&dwSize);
+ dwAutoPlay |= AUTOPLAY_DRIVE_CDROM;
+ RegSetValueEx(hKey,szAutoPlayValue,0,REG_DWORD,(void*)&dwAutoPlay,dwSize);
+ RegCloseKey(hKey);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Re-enables AutoPlay operation when we return to regular GDI mode.
+****************************************************************************/
+static void RestoreAutoPlay(void)
+{
+ DWORD dwAutoPlay,dwSize = sizeof(dwAutoPlay);
+ HKEY hKey;
+
+ if (RegOpenKeyEx(HKEY_CURRENT_USER,szAutoPlayKey,0,KEY_EXECUTE | KEY_WRITE,&hKey) == ERROR_SUCCESS) {
+ RegQueryValueEx(hKey,szAutoPlayValue,NULL,NULL,(void*)&dwAutoPlay,&dwSize);
+ dwAutoPlay &= ~AUTOPLAY_DRIVE_CDROM;
+ RegSetValueEx(hKey,szAutoPlayValue,0,REG_DWORD,(void*)&dwAutoPlay,dwSize);
+ RegCloseKey(hKey);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Suspends the application by switching back to the GDI desktop, allowing
+normal application code to be processed, and then waiting for the
+application activate command to bring us back to fullscreen mode with our
+window minimised.
+****************************************************************************/
+static void LeaveFullScreen(void)
+{
+ int retCode = PM_SUSPEND_APP;
+
+ if (backInGDI)
+ return;
+ if (suspendApp)
+ retCode = suspendApp(PM_DEACTIVATE);
+ RestoreAutoPlay();
+ backInGDI = true;
+
+ /* Now process messages normally until we are re-activated */
+ waitActive = true;
+ if (retCode != PM_NO_SUSPEND_APP) {
+ while (waitActive) {
+ _EVT_pumpMessages();
+ Sleep(200);
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Reactivate all the surfaces for DirectDraw and set the system back up for
+fullscreen rendering.
+****************************************************************************/
+static void RestoreFullScreen(void)
+{
+ static ibool firstTime = true;
+
+ if (firstTime) {
+ /* Clear the message queue while waiting for the surfaces to be
+ * restored.
+ */
+ firstTime = false;
+ while (1) {
+ /* Continue looping until out application has been restored
+ * and we have reset the display mode.
+ */
+ _EVT_pumpMessages();
+ if (GetActiveWindow() == _PM_hwndConsole) {
+ if (suspendApp)
+ suspendApp(PM_REACTIVATE);
+ DisableAutoPlay();
+ backInGDI = false;
+ waitActive = false;
+ firstTime = true;
+ return;
+ }
+ Sleep(200);
+ }
+ }
+}
+
+/****************************************************************************
+REMARKS:
+This function suspends the application by switching back to the GDI desktop,
+allowing normal application code to be processed and then waiting for the
+application activate command to bring us back to fullscreen mode with our
+window minimised.
+
+This version only gets called if we have not captured the screen switch in
+our activate message loops and will occur if the DirectDraw drivers lose a
+surface for some reason while rendering. This should not normally happen,
+but it is included just to be sure (it can happen on WinNT/2000 if the user
+hits the Ctrl-Alt-Del key combination). Note that this code will always
+spin loop, and we cannot disable the spin looping from this version (ie:
+if the user hits Ctrl-Alt-Del under WinNT/2000 the application main loop
+will cease to be executed until the user switches back to the application).
+****************************************************************************/
+void PMAPI PM_doSuspendApp(void)
+{
+ static ibool firstTime = true;
+
+ /* Call system DLL version if found */
+ if (_PM_imports.PM_doSuspendApp != PM_doSuspendApp) {
+ _PM_imports.PM_doSuspendApp();
+ return;
+ }
+
+ if (firstTime) {
+ if (suspendApp)
+ suspendApp(PM_DEACTIVATE);
+ RestoreAutoPlay();
+ firstTime = false;
+ backInGDI = true;
+ }
+ RestoreFullScreen();
+ firstTime = true;
+}
+
+/****************************************************************************
+REMARKS:
+Main Window proc for the full screen DirectDraw Window that we create while
+running in full screen mode. Here we capture all mouse and keyboard events
+for the window and plug them into our event queue.
+****************************************************************************/
+static LONG CALLBACK PM_winProc(
+ HWND hwnd,
+ UINT msg,
+ WPARAM wParam,
+ LONG lParam)
+{
+ switch (msg) {
+ case WM_SYSCHAR:
+ /* Stop Alt-Space from pausing our application */
+ return 0;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ if (HIWORD(lParam) & KF_REPEAT) {
+ if (msg == WM_SYSKEYDOWN)
+ return 0;
+ break;
+ }
+ /* Fall through for keydown events */
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ if (msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) {
+ if ((HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_RETURN)
+ break;
+ /* We ignore the remainder of the system keys to stop the
+ * system menu from being activated from the keyboard and pausing
+ * our app while fullscreen (ie: pressing the Alt key).
+ */
+ return 0;
+ }
+ break;
+ case WM_SYSCOMMAND:
+ switch (wParam & ~0x0F) {
+ case SC_SCREENSAVE:
+ case SC_MONITORPOWER:
+ /* Ignore screensaver requests in fullscreen modes */
+ return 0;
+ }
+ break;
+ case WM_SIZE:
+ if (waitActive && backInGDI && (wParam != SIZE_MINIMIZED)) {
+ /* Start the re-activation process */
+ PostMessage(hwnd,WM_DO_SUSPEND_APP,WM_PM_RESTORE_FULLSCREEN,0);
+ }
+ else if (!waitActive && isFullScreen && !backInGDI && (wParam == SIZE_MINIMIZED)) {
+ /* Start the de-activation process */
+ PostMessage(hwnd,WM_DO_SUSPEND_APP,WM_PM_LEAVE_FULLSCREEN,0);
+ }
+ break;
+ case WM_DO_SUSPEND_APP:
+ switch (wParam) {
+ case WM_PM_RESTORE_FULLSCREEN:
+ RestoreFullScreen();
+ break;
+ case WM_PM_LEAVE_FULLSCREEN:
+ LeaveFullScreen();
+ break;
+ }
+ return 0;
+ }
+ if (oldWinProc)
+ return oldWinProc(hwnd,msg,wParam,lParam);
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+/****************************************************************************
+PARAMETERS:
+hwnd - User window to convert
+width - Window of the fullscreen window
+height - Height of the fullscreen window
+
+RETURNS:
+Handle to converted fullscreen Window.
+
+REMARKS:
+This function takes the original user window handle and modifies the size,
+position and attributes for the window to convert it into a fullscreen
+window that we can use.
+****************************************************************************/
+static PM_HWND _PM_convertUserWindow(
+ HWND hwnd,
+ int width,
+ int height)
+{
+ RECT window;
+
+ GetWindowRect(hwnd,&window);
+ oldWinPosX = window.left;
+ oldWinPosY = window.top;
+ oldWinSizeX = window.right - window.left;
+ oldWinSizeY = window.bottom - window.top;
+ oldWndStyle = SetWindowLong(hwnd,GWL_STYLE,WS_POPUP | WS_SYSMENU);
+ oldExWndStyle = SetWindowLong(hwnd,GWL_EXSTYLE,WS_EX_APPWINDOW);
+ ShowWindow(hwnd,SW_SHOW);
+ MoveWindow(hwnd,0,0,width,height,TRUE);
+ SetWindowPos(hwnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
+ oldWinProc = (WNDPROC)SetWindowLong(hwnd,GWL_WNDPROC, (LPARAM)PM_winProc);
+ return hwnd;
+}
+
+/****************************************************************************
+PARAMETERS:
+hwnd - User window to restore
+
+REMARKS:
+This function restores the original attributes of the user window and put's
+it back into it's original state before it was converted to a fullscreen
+window.
+****************************************************************************/
+static void _PM_restoreUserWindow(
+ HWND hwnd)
+{
+ SetWindowLong(hwnd,GWL_WNDPROC, (LPARAM)oldWinProc);
+ SetWindowLong(hwnd,GWL_EXSTYLE,oldExWndStyle);
+ SetWindowLong(hwnd,GWL_STYLE,oldWndStyle);
+ SetWindowPos(hwnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
+ ShowWindow(hwnd,SW_SHOW);
+ MoveWindow(hwnd,oldWinPosX,oldWinPosY,oldWinSizeX,oldWinSizeY,TRUE);
+ oldWinProc = NULL;
+}
+
+/****************************************************************************
+PARAMETERS:
+device - Index of the device to load DirectDraw for (0 for primary)
+
+REMARKS:
+Attempts to dynamically load the DirectDraw DLL's and create the DirectDraw
+objects that we need.
+****************************************************************************/
+void * PMAPI PM_loadDirectDraw(
+ int device)
+{
+ HDC hdc;
+ int bits;
+
+ /* Call system DLL version if found */
+ if (_PM_imports.PM_loadDirectDraw != PM_loadDirectDraw)
+ return _PM_imports.PM_loadDirectDraw(device);
+
+ // TODO: Handle multi-monitor!!
+ if (device != 0)
+ return NULL;
+
+ /* Load the DirectDraw DLL if not presently loaded */
+ GET_DEFAULT_CW();
+ if (!hInstDD) {
+ hdc = GetDC(NULL);
+ bits = GetDeviceCaps(hdc,BITSPIXEL);
+ ReleaseDC(NULL,hdc);
+ if (bits < 8)
+ return NULL;
+ if ((hInstDD = LoadLibrary("ddraw.dll")) == NULL)
+ return NULL;
+ pDirectDrawCreate = (void*)GetProcAddress(hInstDD,"DirectDrawCreate");
+ if (!pDirectDrawCreate)
+ return NULL;
+ }
+
+ /* Create the DirectDraw object */
+ if (!lpDD && pDirectDrawCreate(NULL, &lpDD, NULL) != DD_OK) {
+ lpDD = NULL;
+ return NULL;
+ }
+ RESET_DEFAULT_CW();
+ return lpDD;
+}
+
+/****************************************************************************
+PARAMETERS:
+device - Index of the device to unload DirectDraw for (0 for primary)
+
+REMARKS:
+Frees any DirectDraw objects for the device. We never actually explicitly
+unload the ddraw.dll library, since unloading and reloading it is
+unnecessary since we only want to unload it when the application exits and
+that happens automatically.
+****************************************************************************/
+void PMAPI PM_unloadDirectDraw(
+ int device)
+{
+ /* Call system DLL version if found */
+ if (_PM_imports.PM_unloadDirectDraw != PM_unloadDirectDraw) {
+ _PM_imports.PM_unloadDirectDraw(device);
+ return;
+ }
+ if (lpDD) {
+ IDirectDraw_Release(lpDD);
+ lpDD = NULL;
+ }
+ (void)device;
+}
+
+/****************************************************************************
+REMARKS:
+Open a console for output to the screen, creating the main event handling
+window if necessary.
+****************************************************************************/
+PM_HWND PMAPI PM_openConsole(
+ PM_HWND hWndUser,
+ int device,
+ int xRes,
+ int yRes,
+ int bpp,
+ ibool fullScreen)
+{
+ WNDCLASS cls;
+ static ibool classRegistered = false;
+
+ /* Call system DLL version if found */
+ GA_getSystemPMImports();
+ if (_PM_imports.PM_openConsole != PM_openConsole) {
+ if (fullScreen) {
+ _PM_deskX = xRes;
+ _PM_deskY = yRes;
+ }
+ return _PM_imports.PM_openConsole(hWndUser,device,xRes,yRes,bpp,fullScreen);
+ }
+
+ /* Create the fullscreen window if necessary */
+ hwndUser = hWndUser;
+ if (fullScreen) {
+ if (!classRegistered) {
+ /* Create a Window class for the fullscreen window in here, since
+ * we need to register one that will do all our event handling for
+ * us.
+ */
+ hInstApp = GetModuleHandle(NULL);
+ cls.hCursor = LoadCursor(NULL,IDC_ARROW);
+ cls.hIcon = LoadIcon(hInstApp,MAKEINTRESOURCE(1));
+ cls.lpszMenuName = NULL;
+ cls.lpszClassName = szWinClassName;
+ cls.hbrBackground = GetStockObject(BLACK_BRUSH);
+ cls.hInstance = hInstApp;
+ cls.style = CS_DBLCLKS;
+ cls.lpfnWndProc = PM_winProc;
+ cls.cbWndExtra = 0;
+ cls.cbClsExtra = 0;
+ if (!RegisterClass(&cls))
+ return NULL;
+ classRegistered = true;
+ }
+ _PM_deskX = xRes;
+ _PM_deskY = yRes;
+ if (!hwndUser) {
+ char windowTitle[80];
+ if (LoadString(hInstApp,1,windowTitle,sizeof(windowTitle)) == 0)
+ strcpy(windowTitle,"MGL Fullscreen Application");
+ _PM_hwndConsole = CreateWindowEx(WS_EX_APPWINDOW,szWinClassName,
+ windowTitle,WS_POPUP | WS_SYSMENU,0,0,xRes,yRes,
+ NULL,NULL,hInstApp,NULL);
+ }
+ else {
+ _PM_hwndConsole = _PM_convertUserWindow(hwndUser,xRes,yRes);
+ }
+ ShowCursor(false);
+ isFullScreen = true;
+ }
+ else {
+ _PM_hwndConsole = hwndUser;
+ isFullScreen = false;
+ }
+ SetFocus(_PM_hwndConsole);
+ SetForegroundWindow(_PM_hwndConsole);
+ DisableAutoPlay();
+ (void)bpp;
+ return _PM_hwndConsole;
+}
+
+/****************************************************************************
+REMARKS:
+Find the size of the console state buffer.
+****************************************************************************/
+int PMAPI PM_getConsoleStateSize(void)
+{
+ /* Call system DLL version if found */
+ if (_PM_imports.PM_getConsoleStateSize != PM_getConsoleStateSize)
+ return _PM_imports.PM_getConsoleStateSize();
+
+ /* Not used in Windows */
+ return 1;
+}
+
+/****************************************************************************
+REMARKS:
+Save the state of the console.
+****************************************************************************/
+void PMAPI PM_saveConsoleState(
+ void *stateBuf,
+ PM_HWND hwndConsole)
+{
+ /* Call system DLL version if found */
+ if (_PM_imports.PM_saveConsoleState != PM_saveConsoleState) {
+ _PM_imports.PM_saveConsoleState(stateBuf,hwndConsole);
+ return;
+ }
+
+ /* Not used in Windows */
+ (void)stateBuf;
+ (void)hwndConsole;
+}
+
+/****************************************************************************
+REMARKS:
+Set the suspend application callback for the fullscreen console.
+****************************************************************************/
+void PMAPI PM_setSuspendAppCallback(
+ PM_saveState_cb saveState)
+{
+ /* Call system DLL version if found */
+ if (_PM_imports.PM_setSuspendAppCallback != PM_setSuspendAppCallback) {
+ _PM_imports.PM_setSuspendAppCallback(saveState);
+ return;
+ }
+ suspendApp = saveState;
+}
+
+/****************************************************************************
+REMARKS:
+Restore the console state.
+****************************************************************************/
+void PMAPI PM_restoreConsoleState(
+ const void *stateBuf,
+ PM_HWND hwndConsole)
+{
+ /* Call system DLL version if found */
+ if (_PM_imports.PM_restoreConsoleState != PM_restoreConsoleState) {
+ _PM_imports.PM_restoreConsoleState(stateBuf,hwndConsole);
+ return;
+ }
+
+ /* Not used in Windows */
+ (void)stateBuf;
+ (void)hwndConsole;
+}
+
+/****************************************************************************
+REMARKS:
+Close the fullscreen console.
+****************************************************************************/
+void PMAPI PM_closeConsole(
+ PM_HWND hwndConsole)
+{
+ /* Call system DLL version if found */
+ if (_PM_imports.PM_closeConsole != PM_closeConsole) {
+ _PM_imports.PM_closeConsole(hwndConsole);
+ return;
+ }
+ ShowCursor(true);
+ RestoreAutoPlay();
+ if (hwndUser)
+ _PM_restoreUserWindow(hwndConsole);
+ else
+ DestroyWindow(hwndConsole);
+ hwndUser = NULL;
+ _PM_hwndConsole = NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Return the DirectDraw window handle used by the application.
+****************************************************************************/
+PM_HWND PMAPI PM_getDirectDrawWindow(void)
+{
+ /* Call system DLL version if found */
+ if (_PM_imports.PM_getDirectDrawWindow != PM_getDirectDrawWindow)
+ return _PM_imports.PM_getDirectDrawWindow();
+ return _PM_hwndConsole;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/win32/event.c b/board/MAI/bios_emulator/scitech/src/pm/win32/event.c
new file mode 100644
index 0000000000..c14377dcda
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/win32/event.c
@@ -0,0 +1,460 @@
+/****************************************************************************
+*
+* 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: Win32
+*
+* Description: Win32 implementation for the SciTech cross platform
+* event library.
+*
+****************************************************************************/
+
+/*---------------------------- Global Variables ---------------------------*/
+
+static ushort keyUpMsg[256] = {0}; /* Table of key up messages */
+static int rangeX,rangeY; /* Range of mouse coordinates */
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* These are not used under Win32 */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flags) (void)(flags)
+
+/****************************************************************************
+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)
+{ return timeGetTime(); }
+
+/****************************************************************************
+REMARKS:
+Pumps all messages in the message queue from Win32 into our event queue.
+****************************************************************************/
+void _EVT_pumpMessages(void)
+{
+ MSG msg;
+ MSG charMsg;
+ event_t evt;
+
+ // TODO: Add support for DirectInput! We can't support relative mouse
+ // movement motion counters without DirectInput ;-(.
+ while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ memset(&evt,0,sizeof(evt));
+ switch (msg.message) {
+ case WM_MOUSEMOVE:
+ evt.what = EVT_MOUSEMOVE;
+ break;
+ case WM_LBUTTONDBLCLK:
+ evt.what = EVT_MOUSEDOWN;
+ evt.message = EVT_LEFTBMASK | EVT_DBLCLICK;
+ break;
+ case WM_LBUTTONDOWN:
+ evt.what = EVT_MOUSEDOWN;
+ evt.message = EVT_LEFTBMASK;
+ break;
+ case WM_LBUTTONUP:
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_LEFTBMASK;
+ break;
+ case WM_RBUTTONDBLCLK:
+ evt.what = EVT_MOUSEDOWN | EVT_DBLCLICK;
+ evt.message = EVT_RIGHTBMASK;
+ break;
+ case WM_RBUTTONDOWN:
+ evt.what = EVT_MOUSEDOWN;
+ evt.message = EVT_RIGHTBMASK;
+ break;
+ case WM_RBUTTONUP:
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_RIGHTBMASK;
+ break;
+ case WM_MBUTTONDBLCLK:
+ evt.what = EVT_MOUSEDOWN | EVT_DBLCLICK;
+ evt.message = EVT_MIDDLEBMASK;
+ break;
+ case WM_MBUTTONDOWN:
+ evt.what = EVT_MOUSEDOWN;
+ evt.message = EVT_MIDDLEBMASK;
+ break;
+ case WM_MBUTTONUP:
+ evt.what = EVT_MOUSEUP;
+ evt.message = EVT_MIDDLEBMASK;
+ break;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ if (HIWORD(msg.lParam) & KF_REPEAT) {
+ evt.what = EVT_KEYREPEAT;
+ }
+ else {
+ evt.what = EVT_KEYDOWN;
+ }
+ break;
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ evt.what = EVT_KEYUP;
+ break;
+ }
+
+ /* Convert mouse event modifier flags */
+ if (evt.what & EVT_MOUSEEVT) {
+ if (_PM_deskX) {
+ evt.where_x = ((long)msg.pt.x * rangeX) / _PM_deskX;
+ evt.where_y = ((long)msg.pt.y * rangeY) / _PM_deskY;
+ }
+ else {
+ ScreenToClient(_PM_hwndConsole, &msg.pt);
+ evt.where_x = msg.pt.x;
+ evt.where_y = msg.pt.y;
+ }
+ if (evt.what == EVT_MOUSEMOVE) {
+ /* Save the current mouse position */
+ EVT.mx = evt.where_x;
+ EVT.my = evt.where_y;
+ if (EVT.oldMove != -1) {
+ EVT.evtq[EVT.oldMove].where_x = evt.where_x;/* Modify existing one */
+ EVT.evtq[EVT.oldMove].where_y = evt.where_y;
+// EVT.evtq[EVT.oldMove].relative_x += mickeyX; // TODO!
+// EVT.evtq[EVT.oldMove].relative_y += mickeyY; // TODO!
+ evt.what = 0;
+ }
+ else {
+ EVT.oldMove = EVT.freeHead; /* Save id of this move event */
+// evt.relative_x = mickeyX; // TODO!
+// evt.relative_y = mickeyY; // TODO!
+ }
+ }
+ else
+ EVT.oldMove = -1;
+ if (msg.wParam & MK_LBUTTON)
+ evt.modifiers |= EVT_LEFTBUT;
+ if (msg.wParam & MK_RBUTTON)
+ evt.modifiers |= EVT_RIGHTBUT;
+ if (msg.wParam & MK_MBUTTON)
+ evt.modifiers |= EVT_MIDDLEBUT;
+ if (msg.wParam & MK_SHIFT)
+ evt.modifiers |= EVT_SHIFTKEY;
+ if (msg.wParam & MK_CONTROL)
+ evt.modifiers |= EVT_CTRLSTATE;
+ }
+
+ /* Convert keyboard codes */
+ TranslateMessage(&msg);
+ if (evt.what & EVT_KEYEVT) {
+ int scanCode = (msg.lParam >> 16) & 0xFF;
+ if (evt.what == EVT_KEYUP) {
+ /* Get message for keyup code from table of cached down values */
+ evt.message = keyUpMsg[scanCode];
+ keyUpMsg[scanCode] = 0;
+ }
+ else {
+ if (PeekMessage(&charMsg,NULL,WM_CHAR,WM_CHAR,PM_REMOVE))
+ evt.message = charMsg.wParam;
+ if (PeekMessage(&charMsg,NULL,WM_SYSCHAR,WM_SYSCHAR,PM_REMOVE))
+ evt.message = charMsg.wParam;
+ evt.message |= ((msg.lParam >> 8) & 0xFF00);
+ keyUpMsg[scanCode] = (ushort)evt.message;
+ }
+ if (evt.what == EVT_KEYREPEAT)
+ evt.message |= (msg.lParam << 16);
+ if (HIWORD(msg.lParam) & KF_ALTDOWN)
+ evt.modifiers |= EVT_ALTSTATE;
+ if (GetKeyState(VK_SHIFT) & 0x8000U)
+ evt.modifiers |= EVT_SHIFTKEY;
+ if (GetKeyState(VK_CONTROL) & 0x8000U)
+ evt.modifiers |= EVT_CTRLSTATE;
+ EVT.oldMove = -1;
+ }
+
+ if (evt.what != 0) {
+ /* Add time stamp and add the event to the queue */
+ evt.when = msg.time;
+ if (EVT.count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+ DispatchMessage(&msg);
+ }
+}
+
+/****************************************************************************
+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 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:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort(
+ int signal)
+{
+ (void)signal;
+ EVT_exit();
+ PM_fatalError("Unhandled exception!");
+}
+
+/****************************************************************************
+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)
+{
+ /* Initialise the event queue */
+ EVT.mouseMove = mouseMove;
+ initEventQueue();
+ memset(keyUpMsg,0,sizeof(keyUpMsg));
+
+ /* Catch program termination signals so we can clean up properly */
+ signal(SIGABRT, _EVT_abort);
+ signal(SIGFPE, _EVT_abort);
+ signal(SIGINT, _EVT_abort);
+}
+
+/****************************************************************************
+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)
+{
+ rangeX = xRes;
+ rangeY = yRes;
+}
+
+/****************************************************************************
+REMARKS
+Modifes the mouse coordinates as necessary if scaling to OS coordinates,
+and sets the OS mouse cursor position.
+****************************************************************************/
+void _EVT_setMousePos(
+ int *x,
+ int *y)
+{
+ /* Scale coordinates up to desktop coordinates first */
+ int scaledX = (*x * _PM_deskX) / rangeX;
+ int scaledY = (*y * _PM_deskY) / rangeY;
+
+ /* Scale coordinates back to screen coordinates again */
+ *x = (scaledX * rangeX) / _PM_deskX;
+ *y = (scaledY * rangeY) / _PM_deskY;
+ SetCursorPos(scaledX,scaledY);
+}
+
+/****************************************************************************
+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 Win32
+}
+
+/****************************************************************************
+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 Win32
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+ /* Restore signal handlers */
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+}
+
+/****************************************************************************
+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)
+{
+ // TODO: Implement joystick code based on DirectX!
+ return 0;
+}
+
+/****************************************************************************
+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)
+{
+}
+
+/****************************************************************************
+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)
+{
+}
+
+/****************************************************************************
+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)
+{
+}
+
+/****************************************************************************
+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)
+{
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/win32/ntservc.c b/board/MAI/bios_emulator/scitech/src/pm/win32/ntservc.c
new file mode 100644
index 0000000000..a3324d33b8
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/win32/ntservc.c
@@ -0,0 +1,259 @@
+/****************************************************************************
+*
+* SciTech Display Doctor
+*
+* Copyright (C) 1991-2001 SciTech Software, Inc.
+* All rights reserved.
+*
+* ======================================================================
+* |REMOVAL OR MODIFICATION OF THIS HEADER IS STRICTLY PROHIBITED BY LAW|
+* | |
+* |This copyrighted computer code is a proprietary trade secret of |
+* |SciTech Software, Inc., located at 505 Wall Street, Chico, CA 95928 |
+* |USA (www.scitechsoft.com). ANY UNAUTHORIZED POSSESSION, USE, |
+* |VIEWING, COPYING, MODIFICATION OR DISSEMINATION OF THIS CODE IS |
+* |STRICTLY PROHIBITED BY LAW. Unless you have current, express |
+* |written authorization from SciTech to possess or use this code, you |
+* |may be subject to civil and/or criminal penalties. |
+* | |
+* |If you received this code in error or you would like to report |
+* |improper use, please immediately contact SciTech Software, Inc. at |
+* |530-894-8400. |
+* | |
+* |REMOVAL OR MODIFICATION OF THIS HEADER IS STRICTLY PROHIBITED BY LAW|
+* ======================================================================
+*
+* Language: ANSI C
+* Environment: Windows NT, Windows 2K or Windows XP.
+*
+* Description: Main module to do the installation of the SDD and GLDirect
+* device driver components under Windows NT/2K/XP.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "win32/oshdr.h"
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+szDriverName - Actual name of the driver to install in the system
+szServiceName - Name of the service to create
+szLoadGroup - Load group for the driver (NULL for normal drivers)
+dwServiceType - Service type to create
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function does all the work to install the driver into the system.
+The driver is not however activated; for that you must use the Start_SddFilt
+function.
+****************************************************************************/
+ulong PMAPI PM_installService(
+ const char *szDriverName,
+ const char *szServiceName,
+ const char *szLoadGroup,
+ ulong dwServiceType)
+{
+ SC_HANDLE scmHandle;
+ SC_HANDLE driverHandle;
+ char szDriverPath[MAX_PATH];
+ HKEY key;
+ char keyPath[MAX_PATH];
+ ulong status;
+
+ // Obtain a handle to the service control manager requesting all access
+ if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL)
+ return GetLastError();
+
+ // Find the path to the driver in system directory
+ GetSystemDirectory(szDriverPath, sizeof(szDriverPath));
+ strcat(szDriverPath, "\\drivers\\");
+ strcat(szDriverPath, szDriverName);
+
+ // Create the service with the Service Control Manager.
+ driverHandle = CreateService(scmHandle,
+ szServiceName,
+ szServiceName,
+ SERVICE_ALL_ACCESS,
+ dwServiceType,
+ SERVICE_BOOT_START,
+ SERVICE_ERROR_NORMAL,
+ szDriverPath,
+ szLoadGroup,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ // Check to see if the driver could actually be installed.
+ if (!driverHandle) {
+ status = GetLastError();
+ CloseServiceHandle(scmHandle);
+ return status;
+ }
+
+ // Get a handle to the key for driver so that it can be altered in the
+ // next step.
+ strcpy(keyPath, "SYSTEM\\CurrentControlSet\\Services\\");
+ strcat(keyPath, szServiceName);
+ if ((status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,keyPath,0,KEY_ALL_ACCESS,&key)) != ERROR_SUCCESS) {
+ // A problem has occured. Delete the service so that it is not installed.
+ status = GetLastError();
+ DeleteService(driverHandle);
+ CloseServiceHandle(driverHandle);
+ CloseServiceHandle(scmHandle);
+ return status;
+ }
+
+ // Delete the ImagePath value in the newly created key so that the
+ // system looks for the driver in the normal location.
+ if ((status = RegDeleteValue(key, "ImagePath")) != ERROR_SUCCESS) {
+ // A problem has occurred. Delete the service so that it is not
+ // installed and will not try to start.
+ RegCloseKey(key);
+ DeleteService(driverHandle);
+ CloseServiceHandle(driverHandle);
+ CloseServiceHandle(scmHandle);
+ return status;
+ }
+
+ // Clean up and exit
+ RegCloseKey(key);
+ CloseServiceHandle(driverHandle);
+ CloseServiceHandle(scmHandle);
+ return ERROR_SUCCESS;
+}
+
+/****************************************************************************
+PARAMETERS:
+szServiceName - Name of the service to start
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function is used to start the specified service and make it active.
+****************************************************************************/
+ulong PMAPI PM_startService(
+ const char *szServiceName)
+{
+ SC_HANDLE scmHandle;
+ SC_HANDLE driverHandle;
+ SERVICE_STATUS serviceStatus;
+ ulong status;
+
+ // Obtain a handle to the service control manager requesting all access
+ if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL)
+ return GetLastError();
+
+ // Open the service with the Service Control Manager.
+ if ((driverHandle = OpenService(scmHandle,szServiceName,SERVICE_ALL_ACCESS)) == NULL) {
+ status = GetLastError();
+ CloseServiceHandle(scmHandle);
+ return status;
+ }
+
+ // Start the service
+ if (!StartService(driverHandle,0,NULL)) {
+ status = GetLastError();
+ CloseServiceHandle(driverHandle);
+ CloseServiceHandle(scmHandle);
+ return status;
+ }
+
+ // Query the service to make sure it is there
+ if (!QueryServiceStatus(driverHandle,&serviceStatus)) {
+ status = GetLastError();
+ CloseServiceHandle(driverHandle);
+ CloseServiceHandle(scmHandle);
+ return status;
+ }
+ CloseServiceHandle(driverHandle);
+ CloseServiceHandle(scmHandle);
+ return ERROR_SUCCESS;
+}
+
+/****************************************************************************
+PARAMETERS:
+szServiceName - Name of the service to stop
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function is used to stop the specified service and disable it.
+****************************************************************************/
+ulong PMAPI PM_stopService(
+ const char *szServiceName)
+{
+ SC_HANDLE scmHandle;
+ SC_HANDLE driverHandle;
+ SERVICE_STATUS serviceStatus;
+ ulong status;
+
+ // Obtain a handle to the service control manager requesting all access
+ if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL)
+ return GetLastError();
+
+ // Open the service with the Service Control Manager.
+ if ((driverHandle = OpenService(scmHandle,szServiceName,SERVICE_ALL_ACCESS)) == NULL) {
+ status = GetLastError();
+ CloseServiceHandle(scmHandle);
+ return status;
+ }
+
+ // Stop the service from running
+ if (!ControlService(driverHandle, SERVICE_CONTROL_STOP, &serviceStatus)) {
+ status = GetLastError();
+ CloseServiceHandle(driverHandle);
+ CloseServiceHandle(scmHandle);
+ return status;
+ }
+ CloseServiceHandle(driverHandle);
+ CloseServiceHandle(scmHandle);
+ return ERROR_SUCCESS;
+}
+
+/****************************************************************************
+PARAMETERS:
+szServiceName - Name of the service to remove
+
+RETURNS:
+True on success, false on failure.
+
+REMARKS:
+This function is used to remove a service completely from the system.
+****************************************************************************/
+ulong PMAPI PM_removeService(
+ const char *szServiceName)
+{
+ SC_HANDLE scmHandle;
+ SC_HANDLE driverHandle;
+ ulong status;
+
+ // Obtain a handle to the service control manager requesting all access
+ if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL)
+ return GetLastError();
+
+ // Open the service with the Service Control Manager.
+ if ((driverHandle = OpenService(scmHandle,szServiceName,SERVICE_ALL_ACCESS)) == NULL) {
+ status = GetLastError();
+ CloseServiceHandle(scmHandle);
+ return status;
+ }
+
+ // Remove the service
+ if (!DeleteService(driverHandle)) {
+ status = GetLastError();
+ CloseServiceHandle(driverHandle);
+ CloseServiceHandle(scmHandle);
+ return status;
+ }
+ CloseServiceHandle(driverHandle);
+ CloseServiceHandle(scmHandle);
+ return ERROR_SUCCESS;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/win32/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/win32/oshdr.h
new file mode 100644
index 0000000000..018c936d8a
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/win32/oshdr.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+*
+* 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: Win32
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
+
+#define WIN32_LEAN_AND_MEAN
+#define STRICT
+#include <windows.h>
+#include <mmsystem.h>
+#include <float.h>
+#define NONAMELESSUNION
+#include "pm/ddraw.h"
+
+/* Macros to save and restore the default control word. Windows 9x has
+ * some bugs in it such that calls to load any DLL's which load 16-bit
+ * DLL's cause the floating point control word to get trashed. We fix
+ * this by saving and restoring the control word across problematic
+ * calls.
+ */
+
+#if defined(__INTEL__)
+#define GET_DEFAULT_CW() \
+{ \
+ if (_PM_cw_default == 0) \
+ _PM_cw_default = _control87(0,0); \
+}
+#define RESET_DEFAULT_CW() \
+ _control87(_PM_cw_default,0xFFFFFFFF)
+#else
+#define GET_DEFAULT_CW()
+#define RESET_DEFAULT_CW()
+#endif
+
+/* Custom window messages */
+
+#define WM_DO_SUSPEND_APP WM_USER
+#define WM_PM_LEAVE_FULLSCREEN 0
+#define WM_PM_RESTORE_FULLSCREEN 1
+
+/* Macro for disabling AutoPlay on a use system */
+
+#define AUTOPLAY_DRIVE_CDROM 0x20
+
+/*--------------------------- Global Variables ----------------------------*/
+
+#ifdef __INTEL__
+extern uint _PM_cw_default; /* Default FPU control word */
+#endif
+extern int _PM_deskX,_PM_deskY; /* Desktop dimensions */
+extern HWND _PM_hwndConsole; /* Window handle for console */
+
+/*-------------------------- Internal Functions ---------------------------*/
+
+void _EVT_pumpMessages(void);
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/win32/pm.c b/board/MAI/bios_emulator/scitech/src/pm/win32/pm.c
new file mode 100644
index 0000000000..d08da4c630
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/win32/pm.c
@@ -0,0 +1,1460 @@
+/****************************************************************************
+*
+* 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: Win32
+*
+* 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.
+*
+****************************************************************************/
+
+#define WIN32_LEAN_AND_MEAN
+#define STRICT
+#include <windows.h>
+#include <mmsystem.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <direct.h>
+#include "pmapi.h"
+#include "drvlib/os/os.h"
+#include "pm_help.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+ibool _PM_haveWinNT; /* True if we are running on NT */
+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 */
+HANDLE _PM_hDevice = NULL; /* Handle to Win32 VxD */
+static ibool inited = false; /* Flags if we are initialised */
+static void (PMAPIP fatalErrorCleanup)(void) = NULL;
+
+static char *szMachineNameKey = "System\\CurrentControlSet\\control\\ComputerName\\ComputerName";
+static char *szMachineNameKeyNT = "System\\CurrentControlSet\\control\\ComputerName\\ActiveComputerName";
+static char *szMachineName = "ComputerName";
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* Macro to check for a valid, loaded version of PMHELP. We check this
+ * on demand when we need these services rather than when PM_init() is
+ * called because if we are running on DirectDraw we don't need PMHELP.VXD.
+ */
+
+#define CHECK_FOR_PMHELP() \
+{ \
+ if (_PM_hDevice == INVALID_HANDLE_VALUE) \
+ if (_PM_haveWinNT) \
+ PM_fatalError("Unable to connect to PMHELP.SYS or SDDHELP.SYS!"); \
+ else \
+ PM_fatalError("Unable to connect to PMHELP.VXD or SDDHELP.VXD!"); \
+}
+
+/****************************************************************************
+REMARKS:
+Initialise the PM library and connect to our helper device driver. If we
+cannot connect to our helper device driver, we bail out with an error
+message. Our Windows 9x VxD is dynamically loadable, so it can be loaded
+after the system has started.
+****************************************************************************/
+void PMAPI PM_init(void)
+{
+ DWORD inBuf[1]; /* Buffer to receive data from VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+ char cntPath[PM_MAX_PATH];
+ char *env;
+
+ /* Create a file handle for the static VxD if possible, otherwise
+ * dynamically load the PMHELP helper VxD. Note that if an old version
+ * of SDD is loaded, we use the PMHELP VxD instead.
+ */
+ if (!inited) {
+ /* Determine if we are running under Windows NT or not and
+ * set the global OS type variable.
+ */
+ _PM_haveWinNT = false;
+ if ((GetVersion() & 0x80000000UL) == 0)
+ _PM_haveWinNT = true;
+ ___drv_os_type = (_PM_haveWinNT) ? _OS_WINNT : _OS_WIN95;
+
+ /* Now try to connect to SDDHELP.VXD or SDDHELP.SYS */
+ _PM_hDevice = CreateFile(SDDHELP_MODULE_PATH, 0,0,0, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, 0);
+ if (_PM_hDevice != INVALID_HANDLE_VALUE) {
+ if (!DeviceIoControl(_PM_hDevice, PMHELP_GETVER32, NULL, 0,
+ outBuf, sizeof(outBuf), &count, NULL) || outBuf[0] < PMHELP_VERSION) {
+ /* Old version of SDDHELP loaded, so use PMHELP instead */
+ CloseHandle(_PM_hDevice);
+ _PM_hDevice = INVALID_HANDLE_VALUE;
+ }
+ }
+ if (_PM_hDevice == INVALID_HANDLE_VALUE) {
+ /* First try to see if there is a currently loaded PMHELP driver.
+ * This is usually the case when we are running under Windows NT/2K.
+ */
+ _PM_hDevice = CreateFile(PMHELP_MODULE_PATH, 0,0,0, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, 0);
+ if (_PM_hDevice == INVALID_HANDLE_VALUE) {
+ /* The driver was not staticly loaded, so try creating a file handle
+ * to a dynamic version of the VxD if possible. Note that on WinNT/2K we
+ * cannot support dynamically loading the drivers.
+ */
+ _PM_hDevice = CreateFile(PMHELP_VXD_PATH, 0,0,0, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, 0);
+ }
+ }
+ if (_PM_hDevice != INVALID_HANDLE_VALUE) {
+ /* Call the driver to determine the version number */
+ if (!DeviceIoControl(_PM_hDevice, PMHELP_GETVER32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL) || outBuf[0] < PMHELP_VERSION) {
+ if (_PM_haveWinNT)
+ PM_fatalError("Older version of PMHELP.SYS found!");
+ else
+ PM_fatalError("Older version of PMHELP.VXD found!");
+ }
+
+ /* Now set the current path inside the VxD so it knows what the
+ * current directory is for loading Nucleus drivers.
+ */
+ inBuf[0] = (ulong)PM_getCurrentPath(cntPath,sizeof(cntPath));
+ if (!DeviceIoControl(_PM_hDevice, PMHELP_SETCNTPATH32, inBuf, sizeof(inBuf), outBuf, sizeof(outBuf), &count, NULL))
+ PM_fatalError("Unable to set VxD current path!");
+
+ /* Now pass down the NUCLEUS_PATH environment variable to the device
+ * driver so it can use this value if it is found.
+ */
+ if ((env = getenv("NUCLEUS_PATH")) != NULL) {
+ inBuf[0] = (ulong)env;
+ if (!DeviceIoControl(_PM_hDevice, PMHELP_SETNUCLEUSPATH32, inBuf, sizeof(inBuf), outBuf, sizeof(outBuf), &count, NULL))
+ PM_fatalError("Unable to set VxD Nucleus path!");
+ }
+
+ /* Enable IOPL for ring-3 code by default if driver is present */
+ if (_PM_haveWinNT)
+ PM_setIOPL(3);
+ }
+
+ /* Indicate that we have been initialised */
+ inited = true;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+We do have BIOS access under Windows 9x, but not under Windows NT.
+****************************************************************************/
+int PMAPI PM_setIOPL(
+ int iopl)
+{
+ DWORD inBuf[1]; /* Buffer to receive data from VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+ static int cntIOPL = 0;
+ int oldIOPL = cntIOPL;
+
+ /* Enable I/O by adjusting the I/O permissions map on Windows NT */
+ if (_PM_haveWinNT) {
+ CHECK_FOR_PMHELP();
+ if (iopl == 3)
+ DeviceIoControl(_PM_hDevice, PMHELP_ENABLERING3IOPL, inBuf, sizeof(inBuf),outBuf, sizeof(outBuf), &count, NULL);
+ else
+ DeviceIoControl(_PM_hDevice, PMHELP_DISABLERING3IOPL, inBuf, sizeof(inBuf),outBuf, sizeof(outBuf), &count, NULL);
+ cntIOPL = iopl;
+ return oldIOPL;
+ }
+
+ /* We always have IOPL on Windows 9x */
+ return 3;
+}
+
+/****************************************************************************
+REMARKS:
+We do have BIOS access under Windows 9x, but not under Windows NT.
+****************************************************************************/
+ibool PMAPI PM_haveBIOSAccess(void)
+{
+ if (PM_getOSType() == _OS_WINNT)
+ return false;
+ else
+ return _PM_hDevice != INVALID_HANDLE_VALUE;
+}
+
+/****************************************************************************
+REMARKS:
+Return the operating system type identifier.
+****************************************************************************/
+long PMAPI PM_getOSType(void)
+{
+ if ((GetVersion() & 0x80000000UL) == 0)
+ return ___drv_os_type = _OS_WINNT;
+ else
+ return ___drv_os_type = _OS_WIN95;
+}
+
+/****************************************************************************
+REMARKS:
+Return the runtime type identifier.
+****************************************************************************/
+int PMAPI PM_getModeType(void)
+{
+ return PM_386;
+}
+
+/****************************************************************************
+REMARKS:
+Add a file directory separator to the end of the filename.
+****************************************************************************/
+void PMAPI PM_backslash(
+ char *s)
+{
+ uint pos = strlen(s);
+ if (s[pos-1] != '\\') {
+ s[pos] = '\\';
+ s[pos+1] = '\0';
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Add a user defined PM_fatalError cleanup function.
+****************************************************************************/
+void PMAPI PM_setFatalErrorCleanup(
+ void (PMAPIP cleanup)(void))
+{
+ fatalErrorCleanup = cleanup;
+}
+
+/****************************************************************************
+REMARKS:
+Report a fatal error condition and halt the program.
+****************************************************************************/
+void PMAPI PM_fatalError(
+ const char *msg)
+{
+ if (fatalErrorCleanup)
+ fatalErrorCleanup();
+ MessageBox(NULL,msg,"Fatal Error!", MB_ICONEXCLAMATION);
+ exit(1);
+}
+
+/****************************************************************************
+REMARKS:
+Allocate the real mode VESA transfer buffer for communicating with the BIOS.
+****************************************************************************/
+void * PMAPI PM_getVESABuf(
+ uint *len,
+ uint *rseg,
+ uint *roff)
+{
+ DWORD outBuf[4]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ /* We require the helper VxD to be loaded staticly in order to support
+ * the VESA transfer buffer. We do not support dynamically allocating
+ * real mode memory buffers from Win32 programs (we need a 16-bit DLL
+ * for this, and Windows 9x becomes very unstable if you free the
+ * memory blocks out of order).
+ */
+ if (!inited)
+ PM_init();
+ if (!VESABuf_ptr) {
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_GETVESABUF32, NULL, 0,
+ outBuf, sizeof(outBuf), &count, NULL)) {
+ if (!outBuf[0])
+ return NULL;
+ VESABuf_ptr = (void*)outBuf[0];
+ VESABuf_len = outBuf[1];
+ VESABuf_rseg = outBuf[2];
+ VESABuf_roff = outBuf[3];
+ }
+ }
+ *len = VESABuf_len;
+ *rseg = VESABuf_rseg;
+ *roff = VESABuf_roff;
+ return VESABuf_ptr;
+}
+
+/****************************************************************************
+REMARKS:
+Check if a key has been pressed.
+****************************************************************************/
+int PMAPI PM_kbhit(void)
+{
+ /* Not used in Windows */
+ return true;
+}
+
+/****************************************************************************
+REMARKS:
+Wait for and return the next keypress.
+****************************************************************************/
+int PMAPI PM_getch(void)
+{
+ /* Not used in Windows */
+ return 0xD;
+}
+
+/****************************************************************************
+REMARKS:
+Set the location of the OS console cursor.
+****************************************************************************/
+void PM_setOSCursorLocation(
+ int x,
+ int y)
+{
+ /* Nothing to do for Windows */
+ (void)x;
+ (void)y;
+}
+
+/****************************************************************************
+REMARKS:
+Set the width of the OS console.
+****************************************************************************/
+void PM_setOSScreenWidth(
+ int width,
+ int height)
+{
+ /* Nothing to do for Windows */
+ (void)width;
+ (void)height;
+}
+
+/****************************************************************************
+REMARKS:
+Set the real time clock handler (used for software stereo modes).
+****************************************************************************/
+ibool PMAPI PM_setRealTimeClockHandler(
+ PM_intHandler ih,
+ int frequency)
+{
+ /* We do not support this from Win32 programs. Rather the VxD handles
+ * this stuff it will take care of hooking the stereo flip functions at
+ * the VxD level.
+ */
+ (void)ih;
+ (void)frequency;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Set the real time clock frequency (for stereo modes).
+****************************************************************************/
+void PMAPI PM_setRealTimeClockFrequency(
+ int frequency)
+{
+ /* Not supported under Win32 */
+ (void)frequency;
+}
+
+/****************************************************************************
+REMARKS:
+Restore the original real time clock handler.
+****************************************************************************/
+void PMAPI PM_restoreRealTimeClockHandler(void)
+{
+ /* Not supported under Win32 */
+}
+
+/****************************************************************************
+REMARKS:
+Return the current operating system path or working directory.
+****************************************************************************/
+char * PMAPI PM_getCurrentPath(
+ char *path,
+ int maxLen)
+{
+ return getcwd(path,maxLen);
+}
+
+/****************************************************************************
+REMARKS:
+Query a string from the registry (extended version).
+****************************************************************************/
+static ibool REG_queryStringEx(
+ HKEY hKey,
+ const char *szValue,
+ char *value,
+ ulong size)
+{
+ DWORD type;
+
+ if (RegQueryValueEx(hKey,(PCHAR)szValue,(PDWORD)NULL,(PDWORD)&type,(LPBYTE)value,(PDWORD)&size) == ERROR_SUCCESS)
+ return true;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Query a string from the registry.
+****************************************************************************/
+static ibool REG_queryString(
+ const char *szKey,
+ const char *szValue,
+ char *value,
+ DWORD size)
+{
+ HKEY hKey;
+ ibool status = false;
+
+ memset(value,0,sizeof(value));
+ if (RegOpenKey(HKEY_LOCAL_MACHINE,szKey,&hKey) == ERROR_SUCCESS) {
+ status = REG_queryStringEx(hKey,szValue,value,size);
+ RegCloseKey(hKey);
+ }
+ return status;
+}
+
+/****************************************************************************
+REMARKS:
+Return the drive letter for the boot drive.
+****************************************************************************/
+char PMAPI PM_getBootDrive(void)
+{
+ static char path[256];
+ GetSystemDirectory(path,sizeof(path));
+ return path[0];
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the VBE/AF driver files.
+****************************************************************************/
+const char * PMAPI PM_getVBEAFPath(void)
+{
+ return "c:\\";
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the Nucleus driver files.
+****************************************************************************/
+const char * PMAPI PM_getNucleusPath(void)
+{
+ static char path[256];
+ char *env;
+
+ if ((env = getenv("NUCLEUS_PATH")) != NULL)
+ return env;
+ GetSystemDirectory(path,sizeof(path));
+ strcat(path,"\\nucleus");
+ return path;
+}
+
+/****************************************************************************
+REMARKS:
+Return the path to the Nucleus configuration files.
+****************************************************************************/
+const char * PMAPI PM_getNucleusConfigPath(void)
+{
+ static char path[256];
+ strcpy(path,PM_getNucleusPath());
+ PM_backslash(path);
+ strcat(path,"config");
+ return path;
+}
+
+/****************************************************************************
+REMARKS:
+Return a unique identifier for the machine if possible.
+****************************************************************************/
+const char * PMAPI PM_getUniqueID(void)
+{
+ return PM_getMachineName();
+}
+
+/****************************************************************************
+REMARKS:
+Get the name of the machine on the network.
+****************************************************************************/
+const char * PMAPI PM_getMachineName(void)
+{
+ static char name[256];
+
+ if (REG_queryString(szMachineNameKey,szMachineName,name,sizeof(name)))
+ return name;
+ if (REG_queryString(szMachineNameKeyNT,szMachineName,name,sizeof(name)))
+ return name;
+ return "Unknown";
+}
+
+/****************************************************************************
+REMARKS:
+Return a pointer to the real mode BIOS data area.
+****************************************************************************/
+void * PMAPI PM_getBIOSPointer(void)
+{
+ if (_PM_haveWinNT) {
+ /* On Windows NT we have to map it physically directly */
+ return PM_mapPhysicalAddr(0x400, 0x1000, true);
+ }
+ else {
+ /* For Windows 9x we can access this memory directly */
+ return (void*)0x400;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Return a pointer to 0xA0000 physical VGA graphics framebuffer.
+****************************************************************************/
+void * PMAPI PM_getA0000Pointer(void)
+{
+ if (_PM_haveWinNT) {
+ /* On Windows NT we have to map it physically directly */
+ return PM_mapPhysicalAddr(0xA0000, 0x0FFFF, false);
+ }
+ else {
+ /* Always use the 0xA0000 linear address so that we will use
+ * whatever page table mappings are set up for us (ie: for virtual
+ * bank switching.
+ */
+ return (void*)0xA0000;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Map a physical address to a linear address in the callers process.
+****************************************************************************/
+void * PMAPI PM_mapPhysicalAddr(
+ ulong base,
+ ulong limit,
+ ibool isCached)
+{
+ DWORD inBuf[3]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = base;
+ inBuf[1] = limit;
+ inBuf[2] = isCached;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_MAPPHYS32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return (void*)outBuf[0];
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a physical address mapping allocated by PM_mapPhysicalAddr.
+****************************************************************************/
+void PMAPI PM_freePhysicalAddr(
+ void *ptr,
+ ulong limit)
+{
+ /* We never free the mappings under Win32 (the VxD tracks them and
+ * reissues the same mappings until the system is rebooted).
+ */
+ (void)ptr;
+ (void)limit;
+}
+
+/****************************************************************************
+REMARKS:
+Find the physical address of a linear memory address in current process.
+****************************************************************************/
+ulong PMAPI PM_getPhysicalAddr(
+ void *p)
+{
+ DWORD inBuf[1]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = (ulong)p;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_GETPHYSICALADDR32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return outBuf[0];
+ return 0xFFFFFFFFUL;
+}
+
+/****************************************************************************
+REMARKS:
+Find the physical address of a linear memory address in current process.
+****************************************************************************/
+ibool PMAPI PM_getPhysicalAddrRange(
+ void *p,
+ ulong length,
+ ulong *physAddress)
+{
+ DWORD inBuf[3]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = (ulong)p;
+ inBuf[1] = (ulong)length;
+ inBuf[2] = (ulong)physAddress;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_GETPHYSICALADDRRANGE32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return outBuf[0];
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Sleep for the specified number of milliseconds.
+****************************************************************************/
+void PMAPI PM_sleep(
+ ulong milliseconds)
+{
+ Sleep(milliseconds);
+}
+
+/****************************************************************************
+REMARKS:
+Return the base I/O port for the specified COM port.
+****************************************************************************/
+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;
+ case 2: return 0x3E8;
+ case 3: return 0x2E8;
+ }
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Return the base I/O port for the specified LPT port.
+****************************************************************************/
+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;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of shared memory. For Win9x we allocate shared memory
+as locked, global memory that is accessible from any memory context
+(including interrupt time context), which allows us to load our important
+data structure and code such that we can access it directly from a ring
+0 interrupt context.
+****************************************************************************/
+void * PMAPI PM_mallocShared(
+ long size)
+{
+ DWORD inBuf[1]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ inBuf[0] = size;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_MALLOCSHARED32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return (void*)outBuf[0];
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of shared memory.
+****************************************************************************/
+void PMAPI PM_freeShared(
+ void *ptr)
+{
+ DWORD inBuf[1]; /* Buffer to send data to VxD */
+
+ inBuf[0] = (ulong)ptr;
+ CHECK_FOR_PMHELP();
+ DeviceIoControl(_PM_hDevice, PMHELP_FREESHARED32, inBuf, sizeof(inBuf), NULL, 0, NULL, NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Map a linear memory address to the calling process address space. The
+address will have been allocated in another process using the
+PM_mapPhysicalAddr function.
+****************************************************************************/
+void * PMAPI PM_mapToProcess(
+ void *base,
+ ulong limit)
+{
+ (void)base;
+ (void)limit;
+ return base;
+}
+
+/****************************************************************************
+REMARKS:
+Map a real mode pointer to a protected mode pointer.
+****************************************************************************/
+void * PMAPI PM_mapRealPointer(
+ uint r_seg,
+ uint r_off)
+{
+ return (void*)(MK_PHYS(r_seg,r_off));
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of real mode memory
+****************************************************************************/
+void * PMAPI PM_allocRealSeg(
+ uint size,
+ uint *r_seg,
+ uint *r_off)
+{
+ /* We do not support dynamically allocating real mode memory buffers
+ * from Win32 programs (we need a 16-bit DLL for this, and Windows
+ * 9x becomes very unstable if you free the memory blocks out of order).
+ */
+ (void)size;
+ (void)r_seg;
+ (void)r_off;
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of real mode memory.
+****************************************************************************/
+void PMAPI PM_freeRealSeg(
+ void *mem)
+{
+ /* Not supported in Windows */
+ (void)mem;
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt (parameters in DPMI compatible structure)
+****************************************************************************/
+void PMAPI DPMI_int86(
+ int intno,
+ DPMI_regs *regs)
+{
+ DWORD inBuf[2]; /* Buffer to send data to VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = intno;
+ inBuf[1] = (ulong)regs;
+ CHECK_FOR_PMHELP();
+ DeviceIoControl(_PM_hDevice, PMHELP_DPMIINT8632, inBuf, sizeof(inBuf),
+ NULL, 0, &count, NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt.
+****************************************************************************/
+int PMAPI PM_int86(
+ int intno,
+ RMREGS *in,
+ RMREGS *out)
+{
+ DWORD inBuf[3]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = intno;
+ inBuf[1] = (ulong)in;
+ inBuf[2] = (ulong)out;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_INT8632, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return outBuf[0];
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Issue a real mode interrupt.
+****************************************************************************/
+int PMAPI PM_int86x(
+ int intno,
+ RMREGS *in,
+ RMREGS *out,
+ RMSREGS *sregs)
+{
+ DWORD inBuf[4]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = intno;
+ inBuf[1] = (ulong)in;
+ inBuf[2] = (ulong)out;
+ inBuf[3] = (ulong)sregs;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_INT86X32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return outBuf[0];
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Call a real mode far function.
+****************************************************************************/
+void PMAPI PM_callRealMode(
+ uint seg,
+ uint off,
+ RMREGS *in,
+ RMSREGS *sregs)
+{
+ DWORD inBuf[4]; /* Buffer to send data to VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = seg;
+ inBuf[1] = off;
+ inBuf[2] = (ulong)in;
+ inBuf[3] = (ulong)sregs;
+ CHECK_FOR_PMHELP();
+ DeviceIoControl(_PM_hDevice, PMHELP_CALLREALMODE32, inBuf, sizeof(inBuf),
+ NULL, 0, &count, NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Return the amount of available memory.
+****************************************************************************/
+void PMAPI PM_availableMemory(
+ ulong *physical,
+ ulong *total)
+{
+ /* We don't support this under Win32 at the moment */
+ *physical = *total = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of locked, physical memory for DMA operations.
+****************************************************************************/
+void * PMAPI PM_allocLockedMem(
+ uint size,
+ ulong *physAddr,
+ ibool contiguous,
+ ibool below16M)
+{
+ DWORD inBuf[4]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = size;
+ inBuf[1] = (ulong)physAddr;
+ inBuf[2] = (ulong)contiguous;
+ inBuf[3] = (ulong)below16M;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_ALLOCLOCKED32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return (void*)outBuf[0];
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of locked physical memory.
+****************************************************************************/
+void PMAPI PM_freeLockedMem(
+ void *p,
+ uint size,
+ ibool contiguous)
+{
+ DWORD inBuf[3]; /* Buffer to send data to VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = (ulong)p;
+ inBuf[1] = size;
+ inBuf[2] = contiguous;
+ CHECK_FOR_PMHELP();
+ DeviceIoControl(_PM_hDevice, PMHELP_FREELOCKED32, inBuf, sizeof(inBuf),
+ NULL, 0, &count, NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Allocates a page aligned and page sized block of memory
+****************************************************************************/
+void * PMAPI PM_allocPage(
+ ibool locked)
+{
+ DWORD inBuf[2]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = locked;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_ALLOCPAGE32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return (void*)outBuf[0];
+ return NULL;
+}
+
+/****************************************************************************
+REMARKS:
+Free a page aligned and page sized block of memory
+****************************************************************************/
+void PMAPI PM_freePage(
+ void *p)
+{
+ DWORD inBuf[1]; /* Buffer to send data to VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = (ulong)p;
+ CHECK_FOR_PMHELP();
+ DeviceIoControl(_PM_hDevice, PMHELP_FREEPAGE32, inBuf, sizeof(inBuf),
+ NULL, 0, &count, NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ DWORD inBuf[2]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ inBuf[0] = (ulong)p;
+ inBuf[1] = len;
+ inBuf[2] = (ulong)lh;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_LOCKDATAPAGES32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return outBuf[0];
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
+{
+ DWORD inBuf[2]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ inBuf[0] = (ulong)p;
+ inBuf[1] = len;
+ inBuf[2] = (ulong)lh;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_UNLOCKDATAPAGES32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return outBuf[0];
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ DWORD inBuf[2]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ inBuf[0] = (ulong)p;
+ inBuf[1] = len;
+ inBuf[2] = (ulong)lh;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_LOCKCODEPAGES32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return outBuf[0];
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
+{
+ DWORD inBuf[2]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ inBuf[0] = (ulong)p;
+ inBuf[1] = len;
+ inBuf[2] = (ulong)lh;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_UNLOCKCODEPAGES32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return outBuf[0];
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display banks.
+****************************************************************************/
+void PMAPI PM_setBankA(
+ int bank)
+{
+ RMREGS regs;
+ regs.x.ax = 0x4F05;
+ regs.x.bx = 0x0000;
+ regs.x.dx = bank;
+ PM_int86(0x10,&regs,&regs);
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display banks.
+****************************************************************************/
+void PMAPI PM_setBankAB(
+ int bank)
+{
+ RMREGS regs;
+ regs.x.ax = 0x4F05;
+ regs.x.bx = 0x0000;
+ regs.x.dx = bank;
+ PM_int86(0x10,&regs,&regs);
+ regs.x.ax = 0x4F05;
+ regs.x.bx = 0x0001;
+ regs.x.dx = bank;
+ PM_int86(0x10,&regs,&regs);
+}
+
+/****************************************************************************
+REMARKS:
+Call the VBE/Core software interrupt to change display start address.
+****************************************************************************/
+void PMAPI PM_setCRTStart(
+ int x,
+ int y,
+ int waitVRT)
+{
+ RMREGS regs;
+ regs.x.ax = 0x4F07;
+ regs.x.bx = waitVRT;
+ regs.x.cx = x;
+ regs.x.dx = y;
+ PM_int86(0x10,&regs,&regs);
+}
+
+/****************************************************************************
+REMARKS:
+Enable write combining for the memory region.
+****************************************************************************/
+ibool PMAPI PM_enableWriteCombine(
+ ulong base,
+ ulong length,
+ uint type)
+{
+ DWORD inBuf[3]; /* Buffer to send data to VxD */
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ if (!inited)
+ PM_init();
+ inBuf[0] = base;
+ inBuf[1] = length;
+ inBuf[2] = type;
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_ENABLELFBCOMB32, inBuf, sizeof(inBuf),
+ outBuf, sizeof(outBuf), &count, NULL))
+ return outBuf[0];
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Get the page directory base register value
+****************************************************************************/
+ulong PMAPI _PM_getPDB(void)
+{
+ DWORD outBuf[1]; /* Buffer to receive data from VxD */
+ DWORD count; /* Count of bytes returned from VxD */
+
+ CHECK_FOR_PMHELP();
+ if (DeviceIoControl(_PM_hDevice, PMHELP_GETPDB32, NULL, 0,
+ outBuf, sizeof(outBuf), &count, NULL))
+ return outBuf[0];
+ return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Flush the translation lookaside buffer.
+****************************************************************************/
+void PMAPI PM_flushTLB(void)
+{
+ CHECK_FOR_PMHELP();
+ DeviceIoControl(_PM_hDevice, PMHELP_FLUSHTLB32, NULL, 0, NULL, 0, NULL, NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Execute the POST on the secondary BIOS for a controller.
+****************************************************************************/
+ibool PMAPI PM_doBIOSPOST(
+ ushort axVal,
+ ulong BIOSPhysAddr,
+ void *mappedBIOS,
+ ulong BIOSLen)
+{
+ /* This is never done by Win32 programs, but rather done by the VxD
+ * when the system boots.
+ */
+ (void)axVal;
+ (void)BIOSPhysAddr;
+ (void)mappedBIOS;
+ (void)BIOSLen;
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Load an OS specific shared library or DLL. If the OS does not support
+shared libraries, simply return NULL.
+****************************************************************************/
+PM_MODULE PMAPI PM_loadLibrary(
+ const char *szDLLName)
+{
+ return (PM_MODULE)LoadLibrary(szDLLName);
+}
+
+/****************************************************************************
+REMARKS:
+Get the address of a named procedure from a shared library.
+****************************************************************************/
+void * PMAPI PM_getProcAddress(
+ PM_MODULE hModule,
+ const char *szProcName)
+{
+ return (void*)GetProcAddress((HINSTANCE)hModule,szProcName);
+}
+
+/****************************************************************************
+REMARKS:
+Unload a shared library.
+****************************************************************************/
+void PMAPI PM_freeLibrary(
+ PM_MODULE hModule)
+{
+ FreeLibrary((HINSTANCE)hModule);
+}
+
+/****************************************************************************
+REMARKS:
+Internal function to convert the find data to the generic interface.
+****************************************************************************/
+static void convertFindData(
+ PM_findData *findData,
+ WIN32_FIND_DATA *blk)
+{
+ ulong dwSize = findData->dwSize;
+
+ memset(findData,0,findData->dwSize);
+ findData->dwSize = dwSize;
+ if (blk->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ findData->attrib |= PM_FILE_READONLY;
+ if (blk->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ findData->attrib |= PM_FILE_DIRECTORY;
+ if (blk->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
+ findData->attrib |= PM_FILE_ARCHIVE;
+ if (blk->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
+ findData->attrib |= PM_FILE_HIDDEN;
+ if (blk->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
+ findData->attrib |= PM_FILE_SYSTEM;
+ findData->sizeLo = blk->nFileSizeLow;
+ findData->sizeHi = blk->nFileSizeHigh;
+ strncpy(findData->name,blk->cFileName,PM_MAX_PATH);
+ findData->name[PM_MAX_PATH-1] = 0;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the first file matching a search criteria in a directory.
+****************************************************************************/
+void *PMAPI PM_findFirstFile(
+ const char *filename,
+ PM_findData *findData)
+{
+ WIN32_FIND_DATA blk;
+ HANDLE hfile;
+
+ if ((hfile = FindFirstFile(filename,&blk)) != INVALID_HANDLE_VALUE) {
+ convertFindData(findData,&blk);
+ return (void*)hfile;
+ }
+ return PM_FILE_INVALID;
+}
+
+/****************************************************************************
+REMARKS:
+Function to find the next file matching a search criteria in a directory.
+****************************************************************************/
+ibool PMAPI PM_findNextFile(
+ void *handle,
+ PM_findData *findData)
+{
+ WIN32_FIND_DATA blk;
+
+ if (FindNextFile((HANDLE)handle,&blk)) {
+ convertFindData(findData,&blk);
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+REMARKS:
+Function to close the find process
+****************************************************************************/
+void PMAPI PM_findClose(
+ void *handle)
+{
+ FindClose((HANDLE)handle);
+}
+
+/****************************************************************************
+REMARKS:
+Function to determine if a drive is a valid drive or not. Under Unix this
+function will return false for anything except a value of 3 (considered
+the root drive, and equivalent to C: for non-Unix systems). The drive
+numbering is:
+
+ 1 - Drive A:
+ 2 - Drive B:
+ 3 - Drive C:
+ etc
+
+****************************************************************************/
+ibool PMAPI PM_driveValid(
+ char drive)
+{
+ char buf[5];
+ int type;
+
+ sprintf(buf,"%c:\\", drive);
+ return ((type = GetDriveType(buf)) != 0 && type != 1);
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the current working directory for the specififed drive.
+Under Unix this will always return the current working directory regardless
+of what the value of 'drive' is.
+****************************************************************************/
+void PMAPI PM_getdcwd(
+ int drive,
+ char *dir,
+ int len)
+{
+ // NT stores the current directory for drive N in the magic environment
+ // variable =N: so we simply look for that environment variable.
+ char envname[4];
+
+ envname[0] = '=';
+ envname[1] = drive - 1 + 'A';
+ envname[2] = ':';
+ envname[3] = '\0';
+ if (GetEnvironmentVariable(envname,dir,len) == 0) {
+ // The current directory or the drive has not been set yet, so
+ // simply set it to the root.
+ dir[0] = envname[1];
+ dir[1] = ':';
+ dir[2] = '\\';
+ dir[3] = '\0';
+ SetEnvironmentVariable(envname,dir);
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Function to change the file attributes for a specific file.
+****************************************************************************/
+void PMAPI PM_setFileAttr(
+ const char *filename,
+ uint attrib)
+{
+ DWORD attr = 0;
+
+ if (attrib & PM_FILE_READONLY)
+ attr |= FILE_ATTRIBUTE_READONLY;
+ if (attrib & PM_FILE_ARCHIVE)
+ attr |= FILE_ATTRIBUTE_ARCHIVE;
+ if (attrib & PM_FILE_HIDDEN)
+ attr |= FILE_ATTRIBUTE_HIDDEN;
+ if (attrib & PM_FILE_SYSTEM)
+ attr |= FILE_ATTRIBUTE_SYSTEM;
+ SetFileAttributes((LPSTR)filename, attr);
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file attributes for a specific file.
+****************************************************************************/
+uint PMAPI PM_getFileAttr(
+ const char *filename)
+{
+ DWORD attr = GetFileAttributes(filename);
+ uint attrib = 0;
+
+ if (attr & FILE_ATTRIBUTE_READONLY)
+ attrib |= PM_FILE_READONLY;
+ if (attr & FILE_ATTRIBUTE_ARCHIVE)
+ attrib |= PM_FILE_ARCHIVE;
+ if (attr & FILE_ATTRIBUTE_HIDDEN)
+ attrib |= PM_FILE_HIDDEN;
+ if (attr & FILE_ATTRIBUTE_SYSTEM)
+ attrib |= PM_FILE_SYSTEM;
+ return attrib;
+}
+
+/****************************************************************************
+REMARKS:
+Function to create a directory.
+****************************************************************************/
+ibool PMAPI PM_mkdir(
+ const char *filename)
+{
+ return CreateDirectory(filename,NULL);
+}
+
+/****************************************************************************
+REMARKS:
+Function to remove a directory.
+****************************************************************************/
+ibool PMAPI PM_rmdir(
+ const char *filename)
+{
+ return RemoveDirectory(filename);
+}
+
+/****************************************************************************
+REMARKS:
+Function to get the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_getFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ HFILE f;
+ OFSTRUCT of;
+ FILETIME utcTime,localTime;
+ SYSTEMTIME sysTime;
+ ibool status = false;
+
+ of.cBytes = sizeof(of);
+ if ((f = OpenFile(filename,&of,OF_READ)) == HFILE_ERROR)
+ return false;
+ if (!GetFileTime((HANDLE)f,NULL,NULL,&utcTime))
+ goto Exit;
+ if (!gmTime) {
+ if (!FileTimeToLocalFileTime(&utcTime,&localTime))
+ goto Exit;
+ }
+ else
+ localTime = utcTime;
+ if (!FileTimeToSystemTime(&localTime,&sysTime))
+ goto Exit;
+ time->year = sysTime.wYear;
+ time->mon = sysTime.wMonth-1;
+ time->day = sysTime.wYear;
+ time->hour = sysTime.wHour;
+ time->min = sysTime.wMinute;
+ time->sec = sysTime.wSecond;
+ status = true;
+
+Exit:
+ CloseHandle((HANDLE)f);
+ return status;
+}
+
+/****************************************************************************
+REMARKS:
+Function to set the file time and date for a specific file.
+****************************************************************************/
+ibool PMAPI PM_setFileTime(
+ const char *filename,
+ ibool gmTime,
+ PM_time *time)
+{
+ HFILE f;
+ OFSTRUCT of;
+ FILETIME utcTime,localTime;
+ SYSTEMTIME sysTime;
+ ibool status = false;
+
+ of.cBytes = sizeof(of);
+ if ((f = OpenFile(filename,&of,OF_WRITE)) == HFILE_ERROR)
+ return false;
+ sysTime.wYear = time->year;
+ sysTime.wMonth = time->mon+1;
+ sysTime.wYear = time->day;
+ sysTime.wHour = time->hour;
+ sysTime.wMinute = time->min;
+ sysTime.wSecond = time->sec;
+ if (!SystemTimeToFileTime(&sysTime,&localTime))
+ goto Exit;
+ if (!gmTime) {
+ if (!LocalFileTimeToFileTime(&localTime,&utcTime))
+ goto Exit;
+ }
+ else
+ utcTime = localTime;
+ if (!SetFileTime((HANDLE)f,NULL,NULL,&utcTime))
+ goto Exit;
+ status = true;
+
+Exit:
+ CloseHandle((HANDLE)f);
+ return status;
+}
+
diff --git a/board/MAI/bios_emulator/scitech/src/pm/win32/vflat.c b/board/MAI/bios_emulator/scitech/src/pm/win32/vflat.c
new file mode 100644
index 0000000000..70491cdb80
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/win32/vflat.c
@@ -0,0 +1,53 @@
+/****************************************************************************
+*
+* 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)
+{
+ (void)baseAddr;
+ (void)bankSize;
+ (void)codeLen;
+ (void)bankFunc;
+ return NULL;
+}
+
+void PMAPI VF_exit(void)
+{
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/win32/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/win32/ztimer.c
new file mode 100644
index 0000000000..318929a2c0
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/win32/ztimer.c
@@ -0,0 +1,136 @@
+/****************************************************************************
+*
+* 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: Win32
+*
+* Description: OS specific implementation for the Zen Timer functions.
+*
+****************************************************************************/
+
+/*---------------------------- Global variables ---------------------------*/
+
+static CPU_largeInteger countFreq;
+static ibool havePerformanceCounter;
+static ulong start,finish;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Initialise the Zen Timer module internals.
+****************************************************************************/
+void __ZTimerInit(void)
+{
+#ifdef NO_ASSEMBLER
+ havePerformanceCounter = false;
+#else
+ havePerformanceCounter = QueryPerformanceFrequency((LARGE_INTEGER*)&countFreq);
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Start the Zen Timer counting.
+****************************************************************************/
+static void __LZTimerOn(
+ LZTimerObject *tm)
+{
+ if (havePerformanceCounter)
+ QueryPerformanceCounter((LARGE_INTEGER*)&tm->start);
+ else
+ tm->start.low = timeGetTime();
+}
+
+/****************************************************************************
+REMARKS:
+Compute the lap time since the timer was started.
+****************************************************************************/
+static ulong __LZTimerLap(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger tmLap,tmCount;
+
+ if (havePerformanceCounter) {
+ QueryPerformanceCounter((LARGE_INTEGER*)&tmLap);
+ _CPU_diffTime64(&tm->start,&tmLap,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,countFreq.low);
+ }
+ else {
+ tmLap.low = timeGetTime();
+ return (tmLap.low - tm->start.low) * 1000L;
+ }
+}
+
+/****************************************************************************
+REMARKS:
+Stop the Zen Timer counting.
+****************************************************************************/
+static void __LZTimerOff(
+ LZTimerObject *tm)
+{
+ if (havePerformanceCounter)
+ QueryPerformanceCounter((LARGE_INTEGER*)&tm->end);
+ else
+ tm->end.low = timeGetTime();
+}
+
+/****************************************************************************
+REMARKS:
+Compute the elapsed time in microseconds between start and end timings.
+****************************************************************************/
+static ulong __LZTimerCount(
+ LZTimerObject *tm)
+{
+ CPU_largeInteger tmCount;
+
+ if (havePerformanceCounter) {
+ _CPU_diffTime64(&tm->start,&tm->end,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,countFreq.low);
+ }
+ else
+ return (tm->end.low - tm->start.low) * 1000L;
+}
+
+/****************************************************************************
+REMARKS:
+Define the resolution of the long period timer as microseconds per timer tick.
+****************************************************************************/
+#define ULZTIMER_RESOLUTION 1000
+
+/****************************************************************************
+REMARKS:
+Read the Long Period timer from the OS
+****************************************************************************/
+static ulong __ULZReadTime(void)
+{ return timeGetTime(); }
+
+/****************************************************************************
+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; }
diff --git a/board/MAI/bios_emulator/scitech/src/pm/x11/event.c b/board/MAI/bios_emulator/scitech/src/pm/x11/event.c
new file mode 100644
index 0000000000..23b938023d
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/x11/event.c
@@ -0,0 +1,307 @@
+/****************************************************************************
+*
+* 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: Unix / X11
+*
+* Description: X11 event queue implementation for the MGL.
+* This can be used both for windowed and fullscreen (DGA) modes.
+*
+****************************************************************************/
+
+/*---------------------------- Global Variables ---------------------------*/
+
+static ushort keyUpMsg[256] = {0};/* Table of key up messages */
+static int rangeX,rangeY; /* Range of mouse coordinates */
+
+static Display *_EVT_dpy;
+static Window _EVT_win;
+
+typedef struct {
+ int keycode;
+ int scancode;
+} xkeymap;
+
+xkeymap xkeymaps[] = {
+ { 9, KB_esc},
+ {24, KB_Q},
+ {25, KB_W},
+ {26, KB_E},
+ {27, KB_R},
+ {28, KB_T},
+ {29, KB_Y},
+ {30, KB_U},
+ {31, KB_I},
+ {32, KB_O},
+ {33, KB_P},
+};
+
+/*---------------------------- Implementation -----------------------------*/
+
+/* These are not used under non-DOS systems */
+#define _EVT_disableInt() 1
+#define _EVT_restoreInt(flags)
+
+/****************************************************************************
+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 unsigned 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);
+}
+
+static int getScancode(int keycode)
+{
+ return keycode-8;
+}
+
+/****************************************************************************
+REMARKS:
+Pumps all messages in the application message queue into our event queue.
+****************************************************************************/
+#ifdef X11_CORE
+static void _EVT_pumpX11Messages(void)
+#else
+static void _EVT_pumpMessages(void)
+#endif
+{
+ // TODO: The purpose of this function is to read all keyboard and mouse
+ // events from the OS specific event queue, translate them and post
+ // them into the SciTech event queue.
+ event_t evt;
+ XEvent ev;
+ static int old_mx = 0, old_my = 0, buts = 0, c;
+ char buf[2];
+
+ while (XPending(_EVT_dpy) && XNextEvent(_EVT_dpy,&ev)) {
+ evt.when = _MGL_getTicks();
+
+ switch(ev.type){
+ case KeyPress:
+ c = getScancode(ev.xkey.keycode);
+ evt.what = EVT_KEYDOWN;
+ evt.message = c << 8;
+ XLookupString(&ev.xkey, buf, 2, NULL, NULL);
+ evt.message |= buf[0];
+ break;
+ case KeyRelease:
+ c = getScancode(ev.xkey.keycode);
+ evt.what = EVT_KEYUP;
+ evt.message = keyUpMsg[c];
+ if(count < EVENTQSIZE)
+ addEvent(&evt);
+ keyUpMsg[c] = 0;
+ repeatKey[c] = 0;
+ break;
+ case ButtonPress:
+ evt.what = EVT_MOUSEDOWN;
+ if(ev.xbutton.button == 1){
+ buts |= EVT_LEFTBUT;
+ evt.message = EVT_LEFTBMASK;
+ }else if(ev.xbutton.button == 2){
+ buts |= EVT_MIDDLEBUT;
+ evt.message = EVT_MIDDLEBMASK;
+ }else if(ev.xbutton.button == 3){
+ buts |= EVT_RIGHTBUT;
+ evt.message = EVT_RIGHTBMASK;
+ }
+ evt.modifiers = modifiers | buts;
+
+ break;
+ case ButtonRelease:
+ evt.what = EVT_MOUSEUP;
+ if(ev.xbutton.button == 1){
+ buts &= ~EVT_LEFTBUT;
+ evt.message = EVT_LEFTBMASK;
+ }else if(ev.xbutton.button == 2){
+ buts &= ~EVT_MIDDLEBUT;
+ evt.message = EVT_MIDDLEBMASK;
+ }else if(ev.xbutton.button == 3){
+ buts &= ~EVT_RIGHTBUT;
+ evt.message = EVT_RIGHTBMASK;
+ }
+ evt.modifiers = modifiers | buts;
+
+ break;
+ case MotionNotify:
+ evt.what = EVT_MOUSEMOVE;
+ evt.where_x = ev.xmotion.x;
+ evt.where_y = ev.xmotion.y;
+ evt.relative_x = evt.where_x - old_mx;
+ evt.relative_y = evt.where_y - old_my;
+ old_mx = evt.where_x;
+ old_my = evt.where_y;
+ break;
+ }
+ if (count < EVENTQSIZE)
+ addEvent(&evt);
+ }
+
+}
+
+/****************************************************************************
+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 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:
+Safely abort the event module upon catching a fatal error.
+****************************************************************************/
+void _EVT_abort()
+{
+ EVT_exit();
+ PM_fatalError("Unhandled exception!");
+}
+
+/****************************************************************************
+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.
+****************************************************************************/
+#ifdef X11_CORE
+void EVTAPI EVT_initX11(
+#else
+void EVTAPI EVT_init(
+#endif
+ _EVT_mouseMoveHandler mouseMove)
+{
+ int result, i,j,k;
+ XDeviceInfoPtr list,slist;
+
+ /* Initialise the event queue */
+ _mouseMove = mouseMove;
+ initEventQueue();
+ memset(keyUpMsg,0,sizeof(keyUpMsg));
+
+
+ /* query server for input extensions */
+ result =XQueryExtension(_EVT_dpy,"XInputExtension",&i,&j,&k);
+ if(!result) {
+ fprintf(stderr,"Your server doesn't support XInput Extensions\n");
+ fprintf(stderr,"X11 Joystick disabled\n");
+ }
+ list = XListInputDevices(_EVT_dpy,&result);
+ if (!list) {
+ fprintf(stderr,"No extended input devices found !!\n");
+ fprintf(stderr,"X11 Joystick disabled\n");
+ }
+
+
+ /* Catch program termination signals so we can clean up properly */
+ signal(SIGABRT, _EVT_abort);
+ signal(SIGFPE, _EVT_abort);
+ signal(SIGINT, _EVT_abort);
+}
+
+/****************************************************************************
+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)
+{
+ rangeX = xRes;
+ rangeY = yRes;
+}
+
+/****************************************************************************
+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 non DOS systems
+}
+
+/****************************************************************************
+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 non DOS systems
+}
+
+/****************************************************************************
+REMARKS
+Exits the event module for program terminatation.
+****************************************************************************/
+void EVT_exit(void)
+{
+ /* Restore signal handlers */
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+
+ // TODO: Do any OS specific cleanup in here
+}
+
+/****************************************************************************
+REMARKS
+Sets the current X11 display
+****************************************************************************/
+void EVT_setX11Display(Display *dpy, Window win)
+{
+ _EVT_dpy = dpy;
+ _EVT_win = win;
+}
diff --git a/board/MAI/bios_emulator/scitech/src/pm/x11/oshdr.h b/board/MAI/bios_emulator/scitech/src/pm/x11/oshdr.h
new file mode 100644
index 0000000000..45d7451be5
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/x11/oshdr.h
@@ -0,0 +1,38 @@
+/****************************************************************************
+*
+* 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: BeOS
+*
+* Description: Include file to include all OS specific header files.
+*
+****************************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <time.h>
+#include <signal.h>
+#ifdef USE_OS_JOYSTICK
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XInput.h>
+#endif
diff --git a/board/MAI/bios_emulator/scitech/src/pm/z_samples.vpj b/board/MAI/bios_emulator/scitech/src/pm/z_samples.vpj
new file mode 100644
index 0000000000..0c6c80f054
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/z_samples.vpj
@@ -0,0 +1,74 @@
+[SciTech]
+compiler=wc10-
+targetos=d32
+[COMPILER]
+version=5.0b
+MACRO=enable_current_compiler\n
+activeconfig=,getch.exe
+FILTERNAME=Source Files\n
+FILTERPATTERN=*.c;*.cpp;*.cxx;*.prg;*.pas;*.dpr;*.bas;*.java;*.sc;*.e;*.cob;*.html;*.rc\n
+FILTERASSOCIATEFILETYPES=0
+FILTERAPPCOMMAND=\n
+vcsproject=SCC:Perforce SCM://depot
+vcslocalpath=SCC:Perforce SCM:c:\
+compile=concur|capture|:Compile:&Compile,dmake %n.obj
+make=concur|capture|clear|saveall|:Build:&Build,dmake %b
+rebuild=concur|capture|clear|saveall|:Rebuild:&Rebuild,dmake -u %b
+debug=concur|capture|savenone|nochangedir|:Debug:&Debug,wdn %b
+execute=hide|savenone|nochangedir|:Execute:E&xecute,
+user1=hide|nochangedir|:User 1:User 1,
+user2=hide|nochangedir|:User 2:User 2,
+usertool_build_all=concur|capture|clear|savenone|:Build All:Build All,dmake all
+usertool_rebuild_all=concur|capture|clear|savenone|:Rebuild All:Rebuild All,dmake -u all
+usertool_clean_directory=concur|capture|savenone|:Clean Directory:&Clean Directory,dmake cleanexe
+workingdir=.
+includedirs=%(SCITECH)\include;%(PRIVATE)\include
+reffile=
+[FILES]
+tests\altbrk.c
+tests\altcrit.c
+tests\biosptr.c
+tests\block.c
+tests\brk.c
+tests\callreal.c
+tests\checks.c
+tests\cpu.c
+tests\critical.c
+tests\getch.c
+tests\isvesa.c
+tests\key.c
+tests\key15.c
+tests\memtest.c
+tests\mouse.c
+tests\rtc.c
+tests\showpci.c
+tests\tick.c
+tests\timerc.c
+tests\timercpp.cpp
+tests\uswc.c
+tests\vftest.c
+tests\video.c
+[ASSOCIATION]
+[CONFIGURATIONS]
+config=,altbrk.exe
+config=,altcrit.exe
+config=,biosptr.exe
+config=,block.exe
+config=,brk.exe
+config=,callreal.exe
+config=,cpu.exe
+config=,critical.exe
+config=,getch.exe
+config=,isvesa.exe
+config=,key.exe
+config=,key15.exe
+config=,memtest.exe
+config=,mouse.exe
+config=,rtc.exe
+config=,showpci.exe
+config=,tick.exe
+config=,timerc.exe
+config=,timercpp.exe
+config=,uswc.exe
+config=,vftest.exe
+config=,video.exe
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ztimer.c b/board/MAI/bios_emulator/scitech/src/pm/ztimer.c
new file mode 100644
index 0000000000..35081e9a36
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/ztimer.c
@@ -0,0 +1,517 @@
+/****************************************************************************
+*
+* 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: Module to implement high precision timing on each OS.
+*
+****************************************************************************/
+
+#include "ztimer.h"
+#include "pmapi.h"
+#include "oshdr.h"
+
+/*---------------------------- Global variables ---------------------------*/
+
+static LZTimerObject LZTimer;
+static ulong start,finish;
+#ifdef __INTEL__
+static long cpuSpeed = -1;
+static ibool haveRDTSC = false;
+#endif
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* External Intel assembler functions */
+#ifdef __INTEL__
+/* {secret} */
+void _ASMAPI _CPU_readTimeStamp(CPU_largeInteger *time);
+/* {secret} */
+ulong _ASMAPI _CPU_diffTime64(CPU_largeInteger *t1,CPU_largeInteger *t2,CPU_largeInteger *t);
+/* {secret} */
+ulong _ASMAPI _CPU_calcMicroSec(CPU_largeInteger *count,ulong freq);
+#endif
+
+#if defined(__SMX32__)
+#include "smx/ztimer.c"
+#elif defined(__RTTARGET__)
+#include "rttarget/ztimer.c"
+#elif defined(__REALDOS__)
+#include "dos/ztimer.c"
+#elif defined(__NT_DRIVER__)
+#include "ntdrv/ztimer.c"
+#elif defined(__WIN32_VXD__)
+#include "vxd/ztimer.c"
+#elif defined(__WINDOWS32__)
+#include "win32/ztimer.c"
+#elif defined(__OS2_VDD__)
+#include "vdd/ztimer.c"
+#elif defined(__OS2__)
+#include "os2/ztimer.c"
+#elif defined(__LINUX__)
+#include "linux/ztimer.c"
+#elif defined(__QNX__)
+#include "qnx/ztimer.c"
+#elif defined(__BEOS__)
+#include "beos/ztimer.c"
+#else
+#error Timer library not ported to this platform yet!
+#endif
+
+/*------------------------ Public interface routines ----------------------*/
+
+/****************************************************************************
+DESCRIPTION:
+Initializes the Zen Timer library (extended)
+
+PARAMETERS:
+accurate - True of the speed should be measured accurately
+
+HEADER:
+ztimer.h
+
+REMARKS:
+This function initializes the Zen Timer library, and /must/ be called before
+any of the remaining Zen Timer library functions are called. The accurate
+parameter is used to determine whether highly accurate timing should be
+used or not. If high accuracy is needed, more time is spent profiling the
+actual speed of the CPU so that we can obtain highly accurate timing
+results, but the time spent in the initialisation routine will be
+significantly longer (on the order of 5 seconds).
+****************************************************************************/
+void ZAPI ZTimerInitExt(
+ ibool accurate)
+{
+ if (cpuSpeed == -1) {
+ __ZTimerInit();
+#ifdef __INTEL__
+ cpuSpeed = CPU_getProcessorSpeedInHZ(accurate);
+ haveRDTSC = CPU_haveRDTSC() && (cpuSpeed > 0);
+#endif
+ }
+}
+
+/****************************************************************************
+DESCRIPTION:
+Initializes the Zen Timer library.
+
+HEADER:
+ztimer.h
+
+REMARKS:
+This function initializes the Zen Timer library, and /must/ be called before
+any of the remaining Zen Timer library functions are called.
+****************************************************************************/
+void ZAPI ZTimerInit(void)
+{
+ ZTimerInitExt(false);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Starts the Long Period Zen Timer counting.
+
+HEADER:
+ztimer.h
+
+PARAMETERS:
+tm - Timer object to start timing with
+
+REMARKS:
+Starts the Long Period Zen Timer counting. Once you have started the timer,
+you can stop it with LZTimerOff or you can latch the current count with
+LZTimerLap.
+
+The Long Period Zen Timer uses a number of different high precision timing
+mechanisms to obtain microsecond accurate timings results whenever possible.
+The following different techniques are used depending on the operating
+system, runtime environment and CPU on the target machine. If the target
+system has a Pentium CPU installed which supports the Read Time Stamp
+Counter instruction (RDTSC), the Zen Timer library will use this to
+obtain the maximum timing precision available.
+
+Under 32-bit Windows, if the Pentium RDTSC instruction is not available, we
+first try to use the Win32 QueryPerformanceCounter API, and if that is not
+available we fall back on the timeGetTime API which is always supported.
+
+Under 32-bit DOS, if the Pentium RDTSC instruction is not available, we
+then do all timing using the old style 8253 timer chip. The 8253 timer
+routines provide highly accurate timings results in pure DOS mode, however
+in a DOS box under Windows or other Operating Systems the virtualization
+of the timer can produce inaccurate results.
+
+Note: Because the Long Period Zen Timer stores the results in a 32-bit
+ unsigned integer, you can only time periods of up to 2^32 microseconds,
+ or about 1hr 20mins. For timing longer periods use the Ultra Long
+ Period Zen Timer.
+
+SEE ALSO:
+LZTimerOff, LZTimerLap, LZTimerCount
+****************************************************************************/
+void ZAPI LZTimerOnExt(
+ LZTimerObject *tm)
+{
+#ifdef __INTEL__
+ if (haveRDTSC) {
+ _CPU_readTimeStamp(&tm->start);
+ }
+ else
+#endif
+ __LZTimerOn(tm);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns the current count for the Long Period Zen Timer and keeps it
+running.
+
+HEADER:
+ztimer.h
+
+PARAMETERS:
+tm - Timer object to do lap timing with
+
+RETURNS:
+Count that has elapsed in microseconds.
+
+REMARKS:
+Returns the current count that has elapsed since the last call to
+LZTimerOn in microseconds. The time continues to run after this function is
+called so you can call this function repeatedly.
+
+SEE ALSO:
+LZTimerOn, LZTimerOff, LZTimerCount
+****************************************************************************/
+ulong ZAPI LZTimerLapExt(
+ LZTimerObject *tm)
+{
+#ifdef __INTEL__
+ CPU_largeInteger tmLap,tmCount;
+
+ if (haveRDTSC) {
+ _CPU_readTimeStamp(&tmLap);
+ _CPU_diffTime64(&tm->start,&tmLap,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,cpuSpeed);
+ }
+ else
+#endif
+ return __LZTimerLap(tm);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Stops the Long Period Zen Timer counting.
+
+HEADER:
+ztimer.h
+
+PARAMETERS:
+tm - Timer object to stop timing with
+
+REMARKS:
+Stops the Long Period Zen Timer counting and latches the count. Once you
+have stopped the timer you can read the count with LZTimerCount. If you need
+highly accurate timing, you should use the on and off functions rather than
+the lap function since the lap function does not subtract the overhead of
+the function calls from the timed count.
+
+SEE ALSO:
+LZTimerOn, LZTimerLap, LZTimerCount
+****************************************************************************/
+void ZAPI LZTimerOffExt(
+ LZTimerObject *tm)
+{
+#ifdef __INTEL__
+ if (haveRDTSC) {
+ _CPU_readTimeStamp(&tm->end);
+ }
+ else
+#endif
+ __LZTimerOff(tm);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Returns the current count for the Long Period Zen Timer.
+
+HEADER:
+ztimer.h
+
+PARAMETERS:
+tm - Timer object to compute the elapsed time with.
+
+RETURNS:
+Count that has elapsed in microseconds.
+
+REMARKS:
+Returns the current count that has elapsed between calls to
+LZTimerOn and LZTimerOff in microseconds.
+
+SEE ALSO:
+LZTimerOn, LZTimerOff, LZTimerLap
+****************************************************************************/
+ulong ZAPI LZTimerCountExt(
+ LZTimerObject *tm)
+{
+#ifdef __INTEL__
+ CPU_largeInteger tmCount;
+
+ if (haveRDTSC) {
+ _CPU_diffTime64(&tm->start,&tm->end,&tmCount);
+ return _CPU_calcMicroSec(&tmCount,cpuSpeed);
+ }
+ else
+#endif
+ return __LZTimerCount(tm);
+}
+
+/****************************************************************************
+DESCRIPTION:
+Starts the Long Period Zen Timer counting.
+
+HEADER:
+ztimer.h
+
+REMARKS:
+Obsolete function. You should use the LZTimerOnExt function instead
+which allows for multiple timers running at the same time.
+****************************************************************************/
+void ZAPI LZTimerOn(void)
+{ LZTimerOnExt(&LZTimer); }
+
+/****************************************************************************
+DESCRIPTION:
+Returns the current count for the Long Period Zen Timer and keeps it
+running.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+Count that has elapsed in microseconds.
+
+REMARKS:
+Obsolete function. You should use the LZTimerLapExt function instead
+which allows for multiple timers running at the same time.
+****************************************************************************/
+ulong ZAPI LZTimerLap(void)
+{ return LZTimerLapExt(&LZTimer); }
+
+/****************************************************************************
+DESCRIPTION:
+Stops the Long Period Zen Timer counting.
+
+HEADER:
+ztimer.h
+
+REMARKS:
+Obsolete function. You should use the LZTimerOffExt function instead
+which allows for multiple timers running at the same time.
+****************************************************************************/
+void ZAPI LZTimerOff(void)
+{ LZTimerOffExt(&LZTimer); }
+
+/****************************************************************************
+DESCRIPTION:
+Returns the current count for the Long Period Zen Timer.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+Count that has elapsed in microseconds.
+
+REMARKS:
+Obsolete function. You should use the LZTimerCountExt function instead
+which allows for multiple timers running at the same time.
+****************************************************************************/
+ulong ZAPI LZTimerCount(void)
+{ return LZTimerCountExt(&LZTimer); }
+
+/****************************************************************************
+DESCRIPTION:
+Starts the Ultra Long Period Zen Timer counting.
+
+HEADER:
+ztimer.h
+
+REMARKS:
+Starts the Ultra Long Period Zen Timer counting. Once you have started the
+timer, you can stop it with ULZTimerOff or you can latch the current count
+with ULZTimerLap.
+
+The Ultra Long Period Zen Timer uses the available operating system services
+to obtain accurate timings results with as much precision as the operating
+system provides, but with enough granularity to time longer periods of
+time than the Long Period Zen Timer. Note that the resolution of the timer
+ticks is not constant between different platforms, and you should use the
+ULZTimerResolution function to determine the number of seconds in a single
+tick of the timer, and use this to convert the timer counts to seconds.
+
+Under 32-bit Windows, we use the timeGetTime function which provides a
+resolution of 1 millisecond (0.001 of a second). Given that the timer
+count is returned as an unsigned 32-bit integer, this we can time intervals
+that are a maximum of 2^32 milliseconds in length (or about 1,200 hours or
+50 days!).
+
+Under 32-bit DOS, we use the system timer tick which runs at 18.2 times per
+second. Given that the timer count is returned as an unsigned 32-bit integer,
+this we can time intervals that are a maximum of 2^32 * (1/18.2) in length
+(or about 65,550 hours or 2731 days!).
+
+SEE ALSO:
+ULZTimerOff, ULZTimerLap, ULZTimerCount, ULZElapsedTime, ULZReadTime
+****************************************************************************/
+void ZAPI ULZTimerOn(void)
+{ start = __ULZReadTime(); }
+
+/****************************************************************************
+DESCRIPTION:
+Returns the current count for the Ultra Long Period Zen Timer and keeps it
+running.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+Count that has elapsed in resolution counts.
+
+REMARKS:
+Returns the current count that has elapsed since the last call to
+ULZTimerOn in microseconds. The time continues to run after this function is
+called so you can call this function repeatedly.
+
+SEE ALSO:
+ULZTimerOn, ULZTimerOff, ULZTimerCount
+****************************************************************************/
+ulong ZAPI ULZTimerLap(void)
+{ return (__ULZReadTime() - start); }
+
+/****************************************************************************
+DESCRIPTION:
+Stops the Long Period Zen Timer counting.
+
+HEADER:
+ztimer.h
+
+REMARKS:
+Stops the Ultra Long Period Zen Timer counting and latches the count. Once
+you have stopped the timer you can read the count with ULZTimerCount.
+
+SEE ALSO:
+ULZTimerOn, ULZTimerLap, ULZTimerCount
+****************************************************************************/
+void ZAPI ULZTimerOff(void)
+{ finish = __ULZReadTime(); }
+
+/****************************************************************************
+DESCRIPTION:
+Returns the current count for the Ultra Long Period Zen Timer.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+Count that has elapsed in resolution counts.
+
+REMARKS:
+Returns the current count that has elapsed between calls to
+ULZTimerOn and ULZTimerOff in resolution counts.
+
+SEE ALSO:
+ULZTimerOn, ULZTimerOff, ULZTimerLap, ULZTimerResolution
+****************************************************************************/
+ulong ZAPI ULZTimerCount(void)
+{ return (finish - start); }
+
+/****************************************************************************
+DESCRIPTION:
+Reads the current time from the Ultra Long Period Zen Timer.
+
+HEADER:
+ztimer.h
+
+RETURNS:
+Current timer value in resolution counts.
+
+REMARKS:
+Reads the current Ultra Long Period Zen Timer and returns it’s current
+count. You can use the ULZElapsedTime function to find the elapsed time
+between two timer count readings.
+
+SEE ALSO:
+ULZElapsedTime, ULZTimerResolution
+****************************************************************************/
+ulong ZAPI ULZReadTime(void)
+{ return __ULZReadTime(); }
+
+/****************************************************************************
+DESCRIPTION:
+Compute the elapsed time between two timer counts.
+
+HEADER:
+ztimer.h
+
+PARAMETERS:
+start - Starting time for elapsed count
+finish - Ending time for elapsed count
+
+RETURNS:
+Elapsed timer in resolution counts.
+
+REMARKS:
+Returns the elapsed time for the Ultra Long Period Zen Timer in units of the
+timers resolution (1/18th of a second under DOS). This function correctly
+computes the difference even if a midnight boundary has been crossed
+during the timing period.
+
+SEE ALSO:
+ULZReadTime, ULZTimerResolution
+****************************************************************************/
+ulong ZAPI ULZElapsedTime(
+ ulong start,
+ ulong finish)
+{ return __ULZElapsedTime(start,finish); }
+
+/****************************************************************************
+DESCRIPTION:
+Returns the resolution of the Ultra Long Period Zen Timer.
+
+HEADER:
+ztimer.h
+
+PARAMETERS:
+resolution - Place to store the timer in microseconds per timer count.
+
+REMARKS:
+Returns the resolution of the Ultra Long Period Zen Timer as a 32-bit
+integer value measured in microseconds per timer count.
+
+SEE ALSO:
+ULZReadTime, ULZElapsedTime, ULZTimerCount
+****************************************************************************/
+void ZAPI ULZTimerResolution(
+ ulong *resolution)
+{ *resolution = ULZTIMER_RESOLUTION; }
+
OpenPOWER on IntegriCloud