diff options
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/pm/dos/event.c')
-rw-r--r-- | board/MAI/bios_emulator/scitech/src/pm/dos/event.c | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/event.c b/board/MAI/bios_emulator/scitech/src/pm/dos/event.c new file mode 100644 index 0000000..12ecb29 --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/pm/dos/event.c @@ -0,0 +1,494 @@ +/**************************************************************************** +* +* SciTech OS Portability Manager Library +* +* ======================================================================== +* +* The contents of this file are subject to the SciTech MGL Public +* License Version 1.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.scitechsoft.com/mgl-license.txt +* +* Software distributed under the License is distributed on an +* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc. +* +* The Initial Developer of the Original Code is SciTech Software, Inc. +* All Rights Reserved. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: 32-bit DOS +* +* Description: 32-bit DOS implementation for the SciTech cross platform +* event library. +* +****************************************************************************/ + +/*--------------------------- Global variables ----------------------------*/ + +ibool _VARAPI _EVT_useEvents = true; /* True to use event handling */ +ibool _VARAPI _EVT_installed = 0; /* Event handers installed? */ +uchar _VARAPI *_EVT_biosPtr = NULL; /* Pointer to the BIOS data area */ +static ibool haveMouse = false; /* True if we have a mouse */ + +/*---------------------------- Implementation -----------------------------*/ + +/* External assembler functions */ + +void EVTAPI _EVT_pollJoystick(void); +uint EVTAPI _EVT_disableInt(void); +uint EVTAPI _EVT_restoreInt(uint flags); +void EVTAPI _EVT_codeStart(void); +void EVTAPI _EVT_codeEnd(void); +void EVTAPI _EVT_cCodeStart(void); +void EVTAPI _EVT_cCodeEnd(void); +int EVTAPI _EVT_getKeyCode(void); +void EVTAPI _EVT_pumpMessages(void); +int EVTAPI EVT_rdinx(int port,int index); +void EVTAPI EVT_wrinx(int port,int index,int value); + +#ifdef NO_KEYBOARD_INTERRUPT +/**************************************************************************** +REMARKS: +This function is used to pump all keyboard messages from the BIOS keyboard +handler into our event queue. This can be used to avoid using the +installable keyboard handler if this is causing problems. +****************************************************************************/ +static void EVTAPI _EVT_pumpMessages(void) +{ + RMREGS regs; + uint key,ps; + + /* Since the keyboard ISR has not been installed if NO_IDE_BUG has + * been defined, we first check for any pending keyboard events + * here, and if there are some insert them into the event queue to + * be picked up later - what a kludge. + */ + while ((key = _EVT_getKeyCode()) != 0) { + ps = _EVT_disableInt(); + addKeyEvent(EVT_KEYDOWN, key); + _EVT_restoreInt(ps); + } + + regs.x.ax = 0x0B; // Reset Move Mouse + PM_int86(0x33,®s,®s); +} +#endif + +/**************************************************************************** +REMARKS: +This function is used to return the number of ticks since system +startup in milliseconds. This should be the same value that is placed into +the time stamp fields of events, and is used to implement auto mouse down +events. +****************************************************************************/ +ulong _EVT_getTicks(void) +{ + return (ulong)PM_getLong(_EVT_biosPtr+0x6C) * 55UL; +} + +/**************************************************************************** +REMARKS: +Reboots the machine from DOS (warm boot) +****************************************************************************/ +static void Reboot(void) +{ + PMREGS regs; + PMSREGS sregs; + + ushort *rebootType = PM_mapRealPointer(0x40,0x72); + *rebootType = 0x1234; + PM_callRealMode(0xFFFF,0x0000,®s,&sregs); +} + +/**************************************************************************** +REMARKS: +Include generic raw scancode keyboard module. +****************************************************************************/ +#define SUPPORT_CTRL_ALT_DEL +#include "common/keyboard.c" + +/**************************************************************************** +REMARKS: +This function fools the DOS mouse driver into thinking that it is running +in graphics mode, rather than text mode so we always get virtual coordinates +correctly rather than character coordinates. +****************************************************************************/ +int _EVT_foolMouse(void) +{ + int oldmode = PM_getByte(_EVT_biosPtr+0x49); + PM_setByte(_EVT_biosPtr+0x49,0x10); + oldmode |= (EVT_rdinx(0x3C4,0x2) << 8); + return oldmode; +} + +/**************************************************************************** +REMARKS: +This function unfools the DOS mouse driver after we have finished calling it. +****************************************************************************/ +void _EVT_unfoolMouse( + int oldmode) +{ + PM_setByte(_EVT_biosPtr+0x49,oldmode); + + /* Some mouse drivers reset the plane mask register for VGA plane 4 + * modes, which screws up the display on some VGA compatible controllers + * in SuperVGA modes. We reset the value back again in here to solve + * the problem. + */ + EVT_wrinx(0x3C4,0x2,oldmode >> 8); +} + +/**************************************************************************** +REMARKS: +Determines if we have a mouse attached and functioning. +****************************************************************************/ +static ibool detectMouse(void) +{ + RMREGS regs; + RMSREGS sregs; + uchar *p; + ibool retval; + + regs.x.ax = 0x3533; /* Get interrupt vector 0x33 */ + PM_int86x(0x21,®s,®s,&sregs); + + /* Check that interrupt vector 0x33 is not a zero, and that the first + * instruction in the interrupt vector is not an IRET instruction + */ + p = PM_mapRealPointer(sregs.es, regs.x.bx); + retval = ((sregs.es != 0) || (regs.x.bx != 0)) && (PM_getByte(p) != 207); + return retval; +} + +/**************************************************************************** +PARAMETERS: +what - Event code +message - Event message +x,y - Mouse position at time of event +but_stat - Mouse button status at time of event + +REMARKS: +Adds a new mouse event to the event queue. This routine is called from within +the mouse interrupt subroutine, so it must be efficient. + +NOTE: Interrupts MUST be OFF while this routine is called to ensure we have + mutually exclusive access to our internal data structures for + interrupt driven systems (like under DOS). +****************************************************************************/ +static void addMouseEvent( + uint what, + uint message, + int x, + int y, + int mickeyX, + int mickeyY, + uint but_stat) +{ + event_t evt; + + if (EVT.count < EVENTQSIZE) { + /* Save information in event record. */ + evt.when = _EVT_getTicks(); + evt.what = what; + evt.message = message; + evt.modifiers = but_stat; + evt.where_x = x; /* Save mouse event position */ + evt.where_y = y; + evt.relative_x = mickeyX; + evt.relative_y = mickeyY; + evt.modifiers |= EVT.keyModifiers; + addEvent(&evt); /* Add to tail of event queue */ + } +} + +/**************************************************************************** +PARAMETERS: +mask - Event mask +butstate - Button state +x - Mouse x coordinate +y - Mouse y coordinate + +REMARKS: +Mouse event handling routine. This gets called when a mouse event occurs, +and we call the addMouseEvent() routine to add the appropriate mouse event +to the event queue. + +Note: Interrupts are ON when this routine is called by the mouse driver code. +****************************************************************************/ +static void EVTAPI mouseISR( + uint mask, + uint butstate, + int x, + int y, + int mickeyX, + int mickeyY) +{ + uint ps; + uint buttonMask; + + if (mask & 1) { + /* Save the current mouse coordinates */ + EVT.mx = x; EVT.my = y; + + /* If the last event was a movement event, then modify the last + * event rather than post a new one, so that the queue will not + * become saturated. Before we modify the data structures, we + * MUST ensure that interrupts are off. + */ + ps = _EVT_disableInt(); + if (EVT.oldMove != -1) { + EVT.evtq[EVT.oldMove].where_x = x; /* Modify existing one */ + EVT.evtq[EVT.oldMove].where_y = y; + EVT.evtq[EVT.oldMove].relative_x += mickeyX; + EVT.evtq[EVT.oldMove].relative_y += mickeyY; + } + else { + EVT.oldMove = EVT.freeHead; /* Save id of this move event */ + addMouseEvent(EVT_MOUSEMOVE,0,x,y,mickeyX,mickeyY,butstate); + } + _EVT_restoreInt(ps); + } + if (mask & 0x2A) { + ps = _EVT_disableInt(); + buttonMask = 0; + if (mask & 2) buttonMask |= EVT_LEFTBMASK; + if (mask & 8) buttonMask |= EVT_RIGHTBMASK; + if (mask & 32) buttonMask |= EVT_MIDDLEBMASK; + addMouseEvent(EVT_MOUSEDOWN,buttonMask,x,y,0,0,butstate); + EVT.oldMove = -1; + _EVT_restoreInt(ps); + } + if (mask & 0x54) { + ps = _EVT_disableInt(); + buttonMask = 0; + if (mask & 2) buttonMask |= EVT_LEFTBMASK; + if (mask & 8) buttonMask |= EVT_RIGHTBMASK; + if (mask & 32) buttonMask |= EVT_MIDDLEBMASK; + addMouseEvent(EVT_MOUSEUP,buttonMask,x,y,0,0,butstate); + EVT.oldMove = -1; + _EVT_restoreInt(ps); + } + EVT.oldKey = -1; +} + +/**************************************************************************** +REMARKS: +Keyboard interrupt handler function. + +NOTE: Interrupts are OFF when this routine is called by the keyboard ISR, + and we leave them OFF the entire time. +****************************************************************************/ +static void EVTAPI keyboardISR(void) +{ + processRawScanCode(PM_inpb(0x60)); + PM_outpb(0x20,0x20); +} + +/**************************************************************************** +REMARKS: +Safely abort the event module upon catching a fatal error. +****************************************************************************/ +void _EVT_abort() +{ + EVT_exit(); + PM_fatalError("Unhandled exception!"); +} + +/**************************************************************************** +PARAMETERS: +mouseMove - Callback function to call wheneve the mouse needs to be moved + +REMARKS: +Initiliase the event handling module. Here we install our mouse handling ISR +to be called whenever any button's are pressed or released. We also build +the free list of events in the event queue. + +We use handler number 2 of the mouse libraries interrupt handlers for our +event handling routines. +****************************************************************************/ +void EVTAPI EVT_init( + _EVT_mouseMoveHandler mouseMove) +{ + int i; + + PM_init(); + EVT.mouseMove = mouseMove; + _EVT_biosPtr = PM_getBIOSPointer(); + EVT_resume(); + + /* Grab all characters pending in the keyboard buffer and stuff + * them into our event buffer. This allows us to pick up any keypresses + * while the program is initialising. + */ + while ((i = _EVT_getKeyCode()) != 0) + addKeyEvent(EVT_KEYDOWN,i); +} + +/**************************************************************************** +REMARKS: +Initiailises the internal event handling modules. The EVT_suspend function +can be called to suspend event handling (such as when shelling out to DOS), +and this function can be used to resume it again later. +****************************************************************************/ +void EVTAPI EVT_resume(void) +{ + static int locked = 0; + int stat; + uchar mods; + PM_lockHandle lh; /* Unused in DOS */ + + if (_EVT_useEvents) { + /* Initialise the event queue and enable our interrupt handlers */ + initEventQueue(); +#ifndef NO_KEYBOARD_INTERRUPT + PM_setKeyHandler(keyboardISR); +#endif +#ifndef NO_MOUSE_INTERRUPT + if ((haveMouse = detectMouse()) != 0) { + int oldmode = _EVT_foolMouse(); + PM_setMouseHandler(0xFFFF,mouseISR); + _EVT_unfoolMouse(oldmode); + } +#endif + + /* Read the keyboard modifier flags from the BIOS to get the + * correct initialisation state. The only state we care about is + * the correct toggle state flags such as SCROLLLOCK, NUMLOCK and + * CAPSLOCK. + */ + EVT.keyModifiers = 0; + mods = PM_getByte(_EVT_biosPtr+0x17); + if (mods & 0x10) + EVT.keyModifiers |= EVT_SCROLLLOCK; + if (mods & 0x20) + EVT.keyModifiers |= EVT_NUMLOCK; + if (mods & 0x40) + EVT.keyModifiers |= EVT_CAPSLOCK; + + /* Lock all of the code and data used by our protected mode interrupt + * handling routines, so that it will continue to work correctly + * under real mode. + */ + if (!locked) { + /* It is difficult to ensure that we lock our global data, so we + * do this by taking the address of a variable locking all data + * 2Kb on either side. This should properly cover the global data + * used by the module (the other alternative is to declare the + * variables in assembler, in which case we know it will be + * correct). + */ + stat = !PM_lockDataPages(&EVT,sizeof(EVT),&lh); + stat |= !PM_lockDataPages(&_EVT_biosPtr,sizeof(_EVT_biosPtr),&lh); + stat |= !PM_lockCodePages((__codePtr)_EVT_cCodeStart,(int)_EVT_cCodeEnd-(int)_EVT_cCodeStart,&lh); + stat |= !PM_lockCodePages((__codePtr)_EVT_codeStart,(int)_EVT_codeEnd-(int)_EVT_codeStart,&lh); + if (stat) { + PM_fatalError("Page locking services failed - interrupt handling not safe!"); + exit(1); + } + locked = 1; + } + + /* Catch program termination signals so we can clean up properly */ + signal(SIGABRT, _EVT_abort); + signal(SIGFPE, _EVT_abort); + signal(SIGINT, _EVT_abort); + _EVT_installed = true; + } +} + +/**************************************************************************** +REMARKS +Changes the range of coordinates returned by the mouse functions to the +specified range of values. This is used when changing between graphics +modes set the range of mouse coordinates for the new display mode. +****************************************************************************/ +void EVTAPI EVT_setMouseRange( + int xRes, + int yRes) +{ + RMREGS regs; + + if (haveMouse) { + int oldmode = _EVT_foolMouse(); + PM_resetMouseDriver(1); + regs.x.ax = 7; /* Mouse function 7 - Set horizontal min and max */ + regs.x.cx = 0; + regs.x.dx = xRes; + PM_int86(0x33,®s,®s); + regs.x.ax = 8; /* Mouse function 8 - Set vertical min and max */ + regs.x.cx = 0; + regs.x.dx = yRes; + PM_int86(0x33,®s,®s); + _EVT_unfoolMouse(oldmode); + } +} + +/**************************************************************************** +REMARKS +Modifes the mouse coordinates as necessary if scaling to OS coordinates, +and sets the OS mouse cursor position. +****************************************************************************/ +void _EVT_setMousePos( + int *x, + int *y) +{ + RMREGS regs; + + if (haveMouse) { + int oldmode = _EVT_foolMouse(); + regs.x.ax = 4; /* Mouse function 4 - Set mouse position */ + regs.x.cx = *x; /* New horizontal coordinate */ + regs.x.dx = *y; /* New vertical coordinate */ + PM_int86(0x33,®s,®s); + _EVT_unfoolMouse(oldmode); + } +} + +/**************************************************************************** +REMARKS +Suspends all of our event handling operations. This is also used to +de-install the event handling code. +****************************************************************************/ +void EVTAPI EVT_suspend(void) +{ + uchar mods; + + if (_EVT_installed) { + /* Restore the interrupt handlers */ + PM_restoreKeyHandler(); + if (haveMouse) + PM_restoreMouseHandler(); + signal(SIGABRT, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGINT, SIG_DFL); + + /* Set the keyboard modifier flags in the BIOS to our values */ + EVT_allowLEDS(true); + mods = PM_getByte(_EVT_biosPtr+0x17) & ~0x70; + if (EVT.keyModifiers & EVT_SCROLLLOCK) + mods |= 0x10; + if (EVT.keyModifiers & EVT_NUMLOCK) + mods |= 0x20; + if (EVT.keyModifiers & EVT_CAPSLOCK) + mods |= 0x40; + PM_setByte(_EVT_biosPtr+0x17,mods); + + /* Flag that we are no longer installed */ + _EVT_installed = false; + } +} + +/**************************************************************************** +REMARKS +Exits the event module for program terminatation. +****************************************************************************/ +void EVTAPI EVT_exit(void) +{ + EVT_suspend(); +} |