diff options
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/pm/os2')
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/os2/_pmos2.asm | 180 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/os2/cpuinfo.c | 66 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/os2/event.c | 566 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/os2/mon.h | 165 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/os2/oshdr.h | 42 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/os2/pm.c | 2008 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/os2/vflat.c | 49 | ||||
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/os2/ztimer.c | 110 |
8 files changed, 3186 insertions, 0 deletions
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 00000000000..761f0f42e1e --- /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 00000000000..7de400d0674 --- /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 00000000000..706e84d6f34 --- /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 00000000000..52f12f0d2dc --- /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 00000000000..ae1f97a06c0 --- /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 00000000000..50251028062 --- /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 00000000000..579ef2c95c4 --- /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 00000000000..30ffe4340b0 --- /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; } |