summaryrefslogtreecommitdiff
path: root/board/MAI/bios_emulator/scitech/src/pm/smx/pmsmx.c
blob: 98e31bc638f17dabe7e05746f691cbdba17ca86c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
/****************************************************************************
*
*                   SciTech OS Portability Manager Library
*
*  ========================================================================
*
*    The contents of this file are subject to the SciTech MGL Public
*    License Version 1.0 (the "License"); you may not use this file
*    except in compliance with the License. You may obtain a copy of
*    the License at http://www.scitechsoft.com/mgl-license.txt
*
*    Software distributed under the License is distributed on an
*    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
*    implied. See the License for the specific language governing
*    rights and limitations under the License.
*
*    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
*
*    The Initial Developer of the Original Code is SciTech Software, Inc.
*    All Rights Reserved.
*
*  ========================================================================
*
* Language:     ANSI C
* Environment:  32-bit SMX embedded systems development
*
* Description:  Implementation for the OS Portability Manager Library, which
*               contains functions to implement OS specific services in a
*               generic, cross platform API. Porting the OS Portability
*               Manager library is the first step to porting any SciTech
*               products to a new platform.
*
****************************************************************************/

#include "pmapi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include "smx/ps2mouse.h"

/*--------------------------- Global variables ----------------------------*/

static int  globalDataStart;

PM_criticalHandler  _VARAPI _PM_critHandler = NULL;
PM_breakHandler     _VARAPI _PM_breakHandler = NULL;
PM_intHandler       _VARAPI _PM_timerHandler = NULL;
PM_intHandler       _VARAPI _PM_rtcHandler = NULL;
PM_intHandler       _VARAPI _PM_keyHandler = NULL;
PM_key15Handler     _VARAPI _PM_key15Handler = NULL;
PM_mouseHandler     _VARAPI _PM_mouseHandler = NULL;
PM_intHandler       _VARAPI _PM_int10Handler = NULL;
int                 _VARAPI _PM_mouseMask;

uchar *     _VARAPI _PM_ctrlCPtr;               /* Location of Ctrl-C flag      */
uchar *     _VARAPI _PM_ctrlBPtr;               /* Location of Ctrl-Break flag  */
uchar *     _VARAPI _PM_critPtr;                /* Location of Critical error Bf*/
PMFARPTR    _VARAPI _PM_prevTimer = PMNULL;     /* Previous timer handler       */
PMFARPTR    _VARAPI _PM_prevRTC = PMNULL;       /* Previous RTC handler         */
PMFARPTR    _VARAPI _PM_prevKey = PMNULL;       /* Previous key handler         */
PMFARPTR    _VARAPI _PM_prevKey15 = PMNULL;     /* Previous key15 handler       */
PMFARPTR    _VARAPI _PM_prevBreak = PMNULL;     /* Previous break handler       */
PMFARPTR    _VARAPI _PM_prevCtrlC = PMNULL;     /* Previous CtrlC handler       */
PMFARPTR    _VARAPI _PM_prevCritical = PMNULL;  /* Previous critical handler    */
long        _VARAPI _PM_prevRealTimer;          /* Previous real mode timer     */
long        _VARAPI _PM_prevRealRTC;            /* Previous real mode RTC       */
long        _VARAPI _PM_prevRealKey;            /* Previous real mode key       */
long        _VARAPI _PM_prevRealKey15;          /* Previous real mode key15     */
long        _VARAPI _PM_prevRealInt10;          /* Previous real mode int 10h   */
static uchar        _PM_oldCMOSRegA;            /* CMOS register A contents     */
static uchar        _PM_oldCMOSRegB;            /* CMOS register B contents     */
static uchar        _PM_oldRTCPIC2;             /* Mask value for RTC IRQ8      */

/*----------------------------- Implementation ----------------------------*/

/* Globals for locking interrupt handlers in _pmsmx.asm */

extern int  _ASMAPI _PM_pmsmxDataStart;
extern int  _ASMAPI _PM_pmsmxDataEnd;
void _ASMAPI _PM_pmsmxCodeStart(void);
void _ASMAPI _PM_pmsmxCodeEnd(void);

/* Protected mode interrupt handlers, also called by PM callbacks below */

void _ASMAPI _PM_timerISR(void);
void _ASMAPI _PM_rtcISR(void);
void _ASMAPI _PM_keyISR(void);
void _ASMAPI _PM_key15ISR(void);
void _ASMAPI _PM_breakISR(void);
void _ASMAPI _PM_ctrlCISR(void);
void _ASMAPI _PM_criticalISR(void);
void _ASMAPI _PM_mouseISR(void);
void _ASMAPI _PM_int10PMCB(void);

/* Protected mode DPMI callback handlers */

void _ASMAPI _PM_mousePMCB(void);

/* Routine to install a mouse handler function */

void _ASMAPI _PM_setMouseHandler(int mask);

/* Routine to allocate DPMI real mode callback routines */

void _ASMAPI _DPMI_allocateCallback(void (_ASMAPI *pmcode)(),void *rmregs,long *RMCB);
void _ASMAPI _DPMI_freeCallback(long RMCB);

/* DPMI helper functions in PMLITE.C */

ulong   PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit);
int     PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr);
ulong   PMAPI DPMI_getSelectorBase(ushort sel);
int     PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit);
uint    PMAPI DPMI_createSelector(ulong base,ulong limit);
void    PMAPI DPMI_freeSelector(uint sel);
int     PMAPI DPMI_lockLinearPages(ulong linear,ulong len);
int     PMAPI DPMI_unlockLinearPages(ulong linear,ulong len);

/* Functions to read and write CMOS registers */

uchar   PMAPI _PM_readCMOS(int index);
void    PMAPI _PM_writeCMOS(int index,uchar value);

/*-------------------------------------------------------------------------*/
/* Generic routines common to all environments                             */
/*-------------------------------------------------------------------------*/

void PMAPI PM_resetMouseDriver(int hardReset)
{
    ps2MouseReset();
}

void PMAPI PM_setRealTimeClockFrequency(int frequency)
{
    static short convert[] = {
	8192,
	4096,
	2048,
	1024,
	512,
	256,
	128,
	64,
	32,
	16,
	8,
	4,
	2,
	-1,
	};
    int i;

    /* First clear any pending RTC timeout if not cleared */
    _PM_readCMOS(0x0C);
    if (frequency == 0) {
	/* Disable RTC timout */
	_PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
	_PM_writeCMOS(0x0B,_PM_oldCMOSRegB & 0x0F);
	}
    else {
	/* Convert frequency value to RTC clock indexes */
	for (i = 0; convert[i] != -1; i++) {
	    if (convert[i] == frequency)
		break;
	    }

	/* Set RTC timout value and enable timeout */
	_PM_writeCMOS(0x0A,(_PM_oldCMOSRegA & 0xF0) | (i+3));
	_PM_writeCMOS(0x0B,(_PM_oldCMOSRegB & 0x0F) | 0x40);
	}
}

static void PMAPI lockPMHandlers(void)
{
    static int      locked = 0;
    int             stat = 0;
    PM_lockHandle   lh;

    /* Lock all of the code and data used by our protected mode interrupt
     * handling routines, so that it will continue to work correctly
     * under real mode.
     */
    if (!locked) {
	PM_saveDS();
	stat  = !PM_lockDataPages(&globalDataStart-2048,4096,&lh);
	stat |= !PM_lockDataPages(&_PM_pmsmxDataStart,(int)&_PM_pmsmxDataEnd - (int)&_PM_pmsmxDataStart,&lh);
	stat |= !PM_lockCodePages((__codePtr)_PM_pmsmxCodeStart,(int)_PM_pmsmxCodeEnd-(int)_PM_pmsmxCodeStart,&lh);
	if (stat) {
	    printf("Page locking services failed - interrupt handling not safe!\n");
	    exit(1);
	    }
	locked = 1;
	}
}

void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
{
    PMREGS  regs;

    regs.x.ax = 0x204;
    regs.h.bl = intno;
    PM_int386(0x31,&regs,&regs);
    isr->sel = regs.x.cx;
    isr->off = regs.e.edx;
}

void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
{
    PMSREGS sregs;
    PMREGS  regs;

    PM_saveDS();
    regs.x.ax = 0x205;          /* Set protected mode vector        */
    regs.h.bl = intno;
    PM_segread(&sregs);
    regs.x.cx = sregs.cs;
    regs.e.edx = (uint)isr;
    PM_int386(0x31,&regs,&regs);
}

void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
{
    PMREGS  regs;

    regs.x.ax = 0x205;
    regs.h.bl = intno;
    regs.x.cx = isr.sel;
    regs.e.edx = isr.off;
    PM_int386(0x31,&regs,&regs);
}

static long prevRealBreak;      /* Previous real mode break handler     */
static long prevRealCtrlC;      /* Previous real mode CtrlC handler     */
static long prevRealCritical;   /* Prev real mode critical handler      */

int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
{
    lockPMHandlers();           /* Ensure our handlers are locked   */

    _PM_mouseHandler = mh;
    return 0;
}

void PMAPI PM_restoreMouseHandler(void)
{
    if (_PM_mouseHandler)
	_PM_mouseHandler = NULL;
}

static void getISR(int intno, PMFARPTR *pmisr, long *realisr)
{
    PM_getPMvect(intno,pmisr);
}

static void restoreISR(int intno, PMFARPTR pmisr, long realisr)
{
    PM_restorePMvect(intno,pmisr);
}

static void setISR(int intno, void (* PMAPI pmisr)())
{
    lockPMHandlers();           /* Ensure our handlers are locked   */
    PM_setPMvect(intno,pmisr);
}

void PMAPI PM_setTimerHandler(PM_intHandler th)
{
    getISR(PM_IRQ0, &_PM_prevTimer, &_PM_prevRealTimer);
    _PM_timerHandler = th;
    setISR(PM_IRQ0, _PM_timerISR);
}

void PMAPI PM_restoreTimerHandler(void)
{
    if (_PM_timerHandler) {
	restoreISR(PM_IRQ0, _PM_prevTimer, _PM_prevRealTimer);
	_PM_timerHandler = NULL;
	}
}

ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
{
    /* Save the old CMOS real time clock values */
    _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
    _PM_oldCMOSRegB = _PM_readCMOS(0x0B);

    /* Set the real time clock interrupt handler */
    getISR(0x70, &_PM_prevRTC, &_PM_prevRealRTC);
    _PM_rtcHandler = th;
    setISR(0x70, _PM_rtcISR);

    /* Program the real time clock default frequency */
    PM_setRealTimeClockFrequency(frequency);

    /* Unmask IRQ8 in the PIC2 */
    _PM_oldRTCPIC2 = PM_inpb(0xA1);
    PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE);
    return true;
}

void PMAPI PM_restoreRealTimeClockHandler(void)
{
    if (_PM_rtcHandler) {
	/* Restore CMOS registers and mask RTC clock */
	_PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
	_PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
	PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE));

	/* Restore the interrupt vector */
	restoreISR(0x70, _PM_prevRTC, _PM_prevRealRTC);
	_PM_rtcHandler = NULL;
	}
}

void PMAPI PM_setKeyHandler(PM_intHandler kh)
{
    getISR(PM_IRQ1, &_PM_prevKey, &_PM_prevRealKey);
    _PM_keyHandler = kh;
    setISR(PM_IRQ1, _PM_keyISR);
}

void PMAPI PM_restoreKeyHandler(void)
{
    if (_PM_keyHandler) {
	restoreISR(PM_IRQ1, _PM_prevKey, _PM_prevRealKey);
	_PM_keyHandler = NULL;
	}
}

void PMAPI PM_setKey15Handler(PM_key15Handler kh)
{
    getISR(0x15, &_PM_prevKey15, &_PM_prevRealKey15);
    _PM_key15Handler = kh;
    setISR(0x15, _PM_key15ISR);
}

void PMAPI PM_restoreKey15Handler(void)
{
    if (_PM_key15Handler) {
	restoreISR(0x15, _PM_prevKey15, _PM_prevRealKey15);
	_PM_key15Handler = NULL;
	}
}

/* Real mode Ctrl-C and Ctrl-Break handler. This handler simply sets a
 * flag in the real mode code segment and exit. We save the location
 * of this flag in real mode memory so that both the real mode and
 * protected mode code will be modifying the same flags.
 */

static uchar ctrlHandler[] = {
    0x00,0x00,0x00,0x00,            /*  ctrlBFlag                       */
    0x66,0x2E,0xC7,0x06,0x00,0x00,
    0x01,0x00,0x00,0x00,            /*  mov     [cs:ctrlBFlag],1        */
    0xCF,                           /*  iretf                           */
    };

void PMAPI PM_installAltBreakHandler(PM_breakHandler bh)
{
    uint    rseg,roff;

    getISR(0x1B, &_PM_prevBreak, &prevRealBreak);
    getISR(0x23, &_PM_prevCtrlC, &prevRealCtrlC);
    _PM_breakHandler = bh;
    setISR(0x1B, _PM_breakISR);
    setISR(0x23, _PM_ctrlCISR);

    /* Hook the real mode vectors for these handlers, as these are not
     * normally reflected by the DPMI server up to protected mode
     */
    _PM_ctrlBPtr = PM_allocRealSeg(sizeof(ctrlHandler)*2, &rseg, &roff);
    memcpy(_PM_ctrlBPtr,ctrlHandler,sizeof(ctrlHandler));
    memcpy(_PM_ctrlBPtr+sizeof(ctrlHandler),ctrlHandler,sizeof(ctrlHandler));
    _PM_ctrlCPtr = _PM_ctrlBPtr + sizeof(ctrlHandler);
    _PM_setRMvect(0x1B,((long)rseg << 16) | (roff+4));
    _PM_setRMvect(0x23,((long)rseg << 16) | (roff+sizeof(ctrlHandler)+4));
}

void PMAPI PM_installBreakHandler(void)
{
    PM_installAltBreakHandler(NULL);
}

void PMAPI PM_restoreBreakHandler(void)
{
    if (_PM_prevBreak.sel) {
	restoreISR(0x1B, _PM_prevBreak, prevRealBreak);
	restoreISR(0x23, _PM_prevCtrlC, prevRealCtrlC);
	_PM_prevBreak.sel = 0;
	_PM_breakHandler = NULL;
	PM_freeRealSeg(_PM_ctrlBPtr);
	}
}

/* Real mode Critical Error handler. This handler simply saves the AX and
 * DI values in the real mode code segment and exits. We save the location
 * of this flag in real mode memory so that both the real mode and
 * protected mode code will be modifying the same flags.
 */

static uchar criticalHandler[] = {
    0x00,0x00,                      /*  axCode                          */
    0x00,0x00,                      /*  diCode                          */
    0x2E,0xA3,0x00,0x00,            /*  mov     [cs:axCode],ax          */
    0x2E,0x89,0x3E,0x02,0x00,       /*  mov     [cs:diCode],di          */
    0xB8,0x03,0x00,                 /*  mov     ax,3                    */
    0xCF,                           /*  iretf                           */
    };

void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch)
{
    uint    rseg,roff;

    getISR(0x24, &_PM_prevCritical, &prevRealCritical);
    _PM_critHandler = ch;
    setISR(0x24, _PM_criticalISR);

    /* Hook the real mode vector, as this is not normally reflected by the
     * DPMI server up to protected mode.
     */
    _PM_critPtr = PM_allocRealSeg(sizeof(criticalHandler)*2, &rseg, &roff);
    memcpy(_PM_critPtr,criticalHandler,sizeof(criticalHandler));
    _PM_setRMvect(0x24,((long)rseg << 16) | (roff+4));
}

void PMAPI PM_installCriticalHandler(void)
{
    PM_installAltCriticalHandler(NULL);
}

void PMAPI PM_restoreCriticalHandler(void)
{
    if (_PM_prevCritical.sel) {
	restoreISR(0x24, _PM_prevCritical, prevRealCritical);
	PM_freeRealSeg(_PM_critPtr);
	_PM_prevCritical.sel = 0;
	_PM_critHandler = NULL;
	}
}

int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
{
    PMSREGS sregs;
    PM_segread(&sregs);
    return DPMI_lockLinearPages((uint)p + DPMI_getSelectorBase(sregs.ds),len);
}

int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
{
    PMSREGS sregs;
    PM_segread(&sregs);
    return DPMI_unlockLinearPages((uint)p + DPMI_getSelectorBase(sregs.ds),len);
}

int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
{
    PMSREGS sregs;
    PM_segread(&sregs);
/*AM: causes minor glitch with */
/*AM: older versions pmEasy which don't allow DPMI 06 on */
/*AM: Code selector 0x0C -- assume base is 0 which it should be. */
    return DPMI_lockLinearPages((uint)p,len);
}

int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
{
    PMSREGS sregs;
    PM_segread(&sregs);
    return DPMI_unlockLinearPages((uint)p,len);
}