]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/pm/dos/pmdos.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / pm / dos / pmdos.c
1 /****************************************************************************
2 *
3 *                   SciTech OS Portability Manager Library
4 *
5 *  ========================================================================
6 *
7 *    The contents of this file are subject to the SciTech MGL Public
8 *    License Version 1.0 (the "License"); you may not use this file
9 *    except in compliance with the License. You may obtain a copy of
10 *    the License at http://www.scitechsoft.com/mgl-license.txt
11 *
12 *    Software distributed under the License is distributed on an
13 *    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 *    implied. See the License for the specific language governing
15 *    rights and limitations under the License.
16 *
17 *    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 *
19 *    The Initial Developer of the Original Code is SciTech Software, Inc.
20 *    All Rights Reserved.
21 *
22 *  ========================================================================
23 *
24 * Language:     ANSI C
25 * Environment:  16/32 bit DOS
26 *
27 * Description:  Implementation for the OS Portability Manager Library, which
28 *               contains functions to implement OS specific services in a
29 *               generic, cross platform API. Porting the OS Portability
30 *               Manager library is the first step to porting any SciTech
31 *               products to a new platform.
32 *
33 ****************************************************************************/
34
35 #include "pmapi.h"
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <dos.h>
40
41 /*--------------------------- Global variables ----------------------------*/
42
43 #ifndef REALMODE
44 static int  globalDataStart;
45 #endif
46
47 PM_criticalHandler  _VARAPI _PM_critHandler = NULL;
48 PM_breakHandler     _VARAPI _PM_breakHandler = NULL;
49 PM_intHandler       _VARAPI _PM_timerHandler = NULL;
50 PM_intHandler       _VARAPI _PM_rtcHandler = NULL;
51 PM_intHandler       _VARAPI _PM_keyHandler = NULL;
52 PM_key15Handler     _VARAPI _PM_key15Handler = NULL;
53 PM_mouseHandler     _VARAPI _PM_mouseHandler = NULL;
54 PM_intHandler       _VARAPI _PM_int10Handler = NULL;
55 int                 _VARAPI _PM_mouseMask;
56
57 uchar *     _VARAPI _PM_ctrlCPtr;               /* Location of Ctrl-C flag      */
58 uchar *     _VARAPI _PM_ctrlBPtr;               /* Location of Ctrl-Break flag  */
59 uchar *     _VARAPI _PM_critPtr;                /* Location of Critical error Bf*/
60 PMFARPTR    _VARAPI _PM_prevTimer = PMNULL;     /* Previous timer handler       */
61 PMFARPTR    _VARAPI _PM_prevRTC = PMNULL;       /* Previous RTC handler         */
62 PMFARPTR    _VARAPI _PM_prevKey = PMNULL;       /* Previous key handler         */
63 PMFARPTR    _VARAPI _PM_prevKey15 = PMNULL;     /* Previous key15 handler       */
64 PMFARPTR    _VARAPI _PM_prevBreak = PMNULL;     /* Previous break handler       */
65 PMFARPTR    _VARAPI _PM_prevCtrlC = PMNULL;     /* Previous CtrlC handler       */
66 PMFARPTR    _VARAPI _PM_prevCritical = PMNULL;  /* Previous critical handler    */
67 long        _VARAPI _PM_prevRealTimer;          /* Previous real mode timer     */
68 long        _VARAPI _PM_prevRealRTC;            /* Previous real mode RTC       */
69 long        _VARAPI _PM_prevRealKey;            /* Previous real mode key       */
70 long        _VARAPI _PM_prevRealKey15;          /* Previous real mode key15     */
71 long        _VARAPI _PM_prevRealInt10;          /* Previous real mode int 10h   */
72 static uchar        _PM_oldCMOSRegA;            /* CMOS register A contents     */
73 static uchar        _PM_oldCMOSRegB;            /* CMOS register B contents     */
74 static uchar        _PM_oldRTCPIC2;             /* Mask value for RTC IRQ8      */
75
76 /* Structure to maintain information about hardware interrupt handlers,
77  * include a copy of the hardware IRQ assembler thunk (one for each
78  * hooked interrupt handler).
79  */
80
81 typedef struct {
82     uchar       IRQ;
83     uchar       IRQVect;
84     uchar       prevPIC;
85     uchar       prevPIC2;
86     PMFARPTR    prevHandler;
87     long        prevRealhandler;
88     uchar       thunk[1];
89     /* IRQ assembler thunk follows ... */
90     } _PM_IRQHandle;
91
92 /*----------------------------- Implementation ----------------------------*/
93
94 /* Globals for locking interrupt handlers in _pmdos.asm */
95
96 #ifndef REALMODE
97 extern int  _VARAPI _PM_pmdosDataStart;
98 extern int  _VARAPI _PM_pmdosDataEnd;
99 extern int  _VARAPI _PM_DMADataStart;
100 extern int  _VARAPI _PM_DMADataEnd;
101 void _ASMAPI _PM_pmdosCodeStart(void);
102 void _ASMAPI _PM_pmdosCodeEnd(void);
103 void _ASMAPI _PM_DMACodeStart(void);
104 void _ASMAPI _PM_DMACodeEnd(void);
105 #endif
106
107 /* Protected mode interrupt handlers, also called by PM callbacks below */
108
109 void _ASMAPI _PM_timerISR(void);
110 void _ASMAPI _PM_rtcISR(void);
111 void _ASMAPI _PM_irqISRTemplate(void);
112 void _ASMAPI _PM_irqISRTemplateEnd(void);
113 void _ASMAPI _PM_keyISR(void);
114 void _ASMAPI _PM_key15ISR(void);
115 void _ASMAPI _PM_breakISR(void);
116 void _ASMAPI _PM_ctrlCISR(void);
117 void _ASMAPI _PM_criticalISR(void);
118 void _ASMAPI _PM_mouseISR(void);
119 void _ASMAPI _PM_int10PMCB(void);
120
121 /* Protected mode DPMI callback handlers */
122
123 void _ASMAPI _PM_mousePMCB(void);
124
125 /* Routine to install a mouse handler function */
126
127 void _ASMAPI _PM_setMouseHandler(int mask);
128
129 /* Routine to allocate DPMI real mode callback routines */
130
131 ibool _ASMAPI _DPMI_allocateCallback(void (_ASMAPI *pmcode)(),void *rmregs,long *RMCB);
132 void _ASMAPI _DPMI_freeCallback(long RMCB);
133
134 /* DPMI helper functions in PMLITE.C */
135
136 ulong   PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit);
137 int     PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr);
138 ulong   PMAPI DPMI_getSelectorBase(ushort sel);
139 int     PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit);
140 uint    PMAPI DPMI_createSelector(ulong base,ulong limit);
141 void    PMAPI DPMI_freeSelector(uint sel);
142 int     PMAPI DPMI_lockLinearPages(ulong linear,ulong len);
143 int     PMAPI DPMI_unlockLinearPages(ulong linear,ulong len);
144
145 /* Functions to read and write CMOS registers */
146
147 uchar   PMAPI _PM_readCMOS(int index);
148 void    PMAPI _PM_writeCMOS(int index,uchar value);
149
150 /*-------------------------------------------------------------------------*/
151 /* Generic routines common to all environments                             */
152 /*-------------------------------------------------------------------------*/
153
154 void PMAPI PM_resetMouseDriver(int hardReset)
155 {
156     RMREGS          regs;
157     PM_mouseHandler oldHandler = _PM_mouseHandler;
158
159     PM_restoreMouseHandler();
160     regs.x.ax = hardReset ? 0 : 33;
161     PM_int86(0x33, &regs, &regs);
162     if (oldHandler)
163         PM_setMouseHandler(_PM_mouseMask, oldHandler);
164 }
165
166 void PMAPI PM_setRealTimeClockFrequency(int frequency)
167 {
168     static short convert[] = {
169         8192,
170         4096,
171         2048,
172         1024,
173         512,
174         256,
175         128,
176         64,
177         32,
178         16,
179         8,
180         4,
181         2,
182         -1,
183         };
184     int i;
185
186     /* First clear any pending RTC timeout if not cleared */
187     _PM_readCMOS(0x0C);
188     if (frequency == 0) {
189         /* Disable RTC timout */
190         _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
191         _PM_writeCMOS(0x0B,_PM_oldCMOSRegB & 0x0F);
192         }
193     else {
194         /* Convert frequency value to RTC clock indexes */
195         for (i = 0; convert[i] != -1; i++) {
196             if (convert[i] == frequency)
197                 break;
198             }
199
200         /* Set RTC timout value and enable timeout */
201         _PM_writeCMOS(0x0A,0x20 | (i+3));
202         _PM_writeCMOS(0x0B,(_PM_oldCMOSRegB & 0x0F) | 0x40);
203         }
204 }
205
206 #ifndef REALMODE
207
208 static void PMAPI lockPMHandlers(void)
209 {
210     static int      locked = 0;
211     int             stat;
212     PM_lockHandle   lh; /* Unused in DOS */
213
214     /* Lock all of the code and data used by our protected mode interrupt
215      * handling routines, so that it will continue to work correctly
216      * under real mode.
217      */
218     if (!locked) {
219         PM_saveDS();
220         stat  = !PM_lockDataPages(&globalDataStart-2048,4096,&lh);
221         stat |= !PM_lockDataPages(&_PM_pmdosDataStart,(int)&_PM_pmdosDataEnd - (int)&_PM_pmdosDataStart,&lh);
222         stat |= !PM_lockCodePages((__codePtr)_PM_pmdosCodeStart,(int)_PM_pmdosCodeEnd-(int)_PM_pmdosCodeStart,&lh);
223         stat |= !PM_lockDataPages(&_PM_DMADataStart,(int)&_PM_DMADataEnd - (int)&_PM_DMADataStart,&lh);
224         stat |= !PM_lockCodePages((__codePtr)_PM_DMACodeStart,(int)_PM_DMACodeEnd-(int)_PM_DMACodeStart,&lh);
225         if (stat) {
226             printf("Page locking services failed - interrupt handling not safe!\n");
227             exit(1);
228             }
229         locked = 1;
230         }
231 }
232
233 #endif
234
235 /*-------------------------------------------------------------------------*/
236 /* DOS Real Mode support.                                                  */
237 /*-------------------------------------------------------------------------*/
238
239 #ifdef REALMODE
240
241 #ifndef MK_FP
242 #define MK_FP(s,o)  ( (void far *)( ((ulong)(s) << 16) + \
243                     (ulong)(o) ))
244 #endif
245
246 int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
247 {
248     PM_saveDS();
249     _PM_mouseHandler = mh;
250     _PM_setMouseHandler(_PM_mouseMask = mask);
251     return 1;
252 }
253
254 void PMAPI PM_restoreMouseHandler(void)
255 {
256     union REGS      regs;
257
258     if (_PM_mouseHandler) {
259         regs.x.ax = 33;
260         int86(0x33, &regs, &regs);
261         _PM_mouseHandler = NULL;
262         }
263 }
264
265 void PMAPI PM_setTimerHandler(PM_intHandler th)
266 {
267     _PM_getRMvect(0x8, (long*)&_PM_prevTimer);
268     _PM_timerHandler = th;
269     _PM_setRMvect(0x8, (long)_PM_timerISR);
270 }
271
272 void PMAPI PM_restoreTimerHandler(void)
273 {
274     if (_PM_timerHandler) {
275         _PM_setRMvect(0x8, (long)_PM_prevTimer);
276         _PM_timerHandler = NULL;
277         }
278 }
279
280 ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
281 {
282     /* Save the old CMOS real time clock values */
283     _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
284     _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
285
286     /* Set the real time clock interrupt handler */
287     _PM_getRMvect(0x70, (long*)&_PM_prevRTC);
288     _PM_rtcHandler = th;
289     _PM_setRMvect(0x70, (long)_PM_rtcISR);
290
291     /* Program the real time clock default frequency */
292     PM_setRealTimeClockFrequency(frequency);
293
294     /* Unmask IRQ8 in the PIC2 */
295     _PM_oldRTCPIC2 = PM_inpb(0xA1);
296     PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE);
297     return true;
298 }
299
300 void PMAPI PM_restoreRealTimeClockHandler(void)
301 {
302     if (_PM_rtcHandler) {
303         /* Restore CMOS registers and mask RTC clock */
304         _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
305         _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
306         PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE));
307
308         /* Restore the interrupt vector */
309         _PM_setRMvect(0x70, (long)_PM_prevRTC);
310         _PM_rtcHandler = NULL;
311         }
312 }
313
314 void PMAPI PM_setKeyHandler(PM_intHandler kh)
315 {
316     _PM_getRMvect(0x9, (long*)&_PM_prevKey);
317     _PM_keyHandler = kh;
318     _PM_setRMvect(0x9, (long)_PM_keyISR);
319 }
320
321 void PMAPI PM_restoreKeyHandler(void)
322 {
323     if (_PM_keyHandler) {
324         _PM_setRMvect(0x9, (long)_PM_prevKey);
325         _PM_keyHandler = NULL;
326         }
327 }
328
329 void PMAPI PM_setKey15Handler(PM_key15Handler kh)
330 {
331     _PM_getRMvect(0x15, (long*)&_PM_prevKey15);
332     _PM_key15Handler = kh;
333     _PM_setRMvect(0x15, (long)_PM_key15ISR);
334 }
335
336 void PMAPI PM_restoreKey15Handler(void)
337 {
338     if (_PM_key15Handler) {
339         _PM_setRMvect(0x15, (long)_PM_prevKey15);
340         _PM_key15Handler = NULL;
341         }
342 }
343
344 void PMAPI PM_installAltBreakHandler(PM_breakHandler bh)
345 {
346     static int  ctrlCFlag,ctrlBFlag;
347
348     _PM_ctrlCPtr = (uchar*)&ctrlCFlag;
349     _PM_ctrlBPtr = (uchar*)&ctrlBFlag;
350     _PM_getRMvect(0x1B, (long*)&_PM_prevBreak);
351     _PM_getRMvect(0x23, (long*)&_PM_prevCtrlC);
352     _PM_breakHandler = bh;
353     _PM_setRMvect(0x1B, (long)_PM_breakISR);
354     _PM_setRMvect(0x23, (long)_PM_ctrlCISR);
355 }
356
357 void PMAPI PM_installBreakHandler(void)
358 {
359     PM_installAltBreakHandler(NULL);
360 }
361
362 void PMAPI PM_restoreBreakHandler(void)
363 {
364     if (_PM_prevBreak) {
365         _PM_setRMvect(0x1B, (long)_PM_prevBreak);
366         _PM_setRMvect(0x23, (long)_PM_prevCtrlC);
367         _PM_prevBreak = NULL;
368         _PM_breakHandler = NULL;
369         }
370 }
371
372 void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch)
373 {
374     static  short critBuf[2];
375
376     _PM_critPtr = (uchar*)critBuf;
377     _PM_getRMvect(0x24, (long*)&_PM_prevCritical);
378     _PM_critHandler = ch;
379     _PM_setRMvect(0x24, (long)_PM_criticalISR);
380 }
381
382 void PMAPI PM_installCriticalHandler(void)
383 {
384     PM_installAltCriticalHandler(NULL);
385 }
386
387 void PMAPI PM_restoreCriticalHandler(void)
388 {
389     if (_PM_prevCritical) {
390         _PM_setRMvect(0x24, (long)_PM_prevCritical);
391         _PM_prevCritical = NULL;
392         _PM_critHandler = NULL;
393         }
394 }
395
396 int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
397 {
398     p = p;  len = len;      /* Do nothing for real mode */
399     return 1;
400 }
401
402 int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
403 {
404     p = p;  len = len;      /* Do nothing for real mode */
405     return 1;
406 }
407
408 int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
409 {
410     p = p;  len = len;      /* Do nothing for real mode */
411     return 1;
412 }
413
414 int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
415 {
416     p = p;  len = len;      /* Do nothing for real mode */
417     return 1;
418 }
419
420 void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
421 {
422     long t;
423     _PM_getRMvect(intno,&t);
424     *isr = (void*)t;
425 }
426
427 void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
428 {
429     PM_saveDS();
430     _PM_setRMvect(intno,(long)isr);
431 }
432
433 void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
434 {
435     _PM_setRMvect(intno,(long)isr);
436 }
437
438 #endif
439
440 /*-------------------------------------------------------------------------*/
441 /* Phar Lap TNT DOS Extender support.                                      */
442 /*-------------------------------------------------------------------------*/
443
444 #ifdef TNT
445
446 #include <pldos32.h>
447 #include <pharlap.h>
448 #include <hw386.h>
449
450 static long prevRealBreak;      /* Previous real mode break handler     */
451 static long prevRealCtrlC;      /* Previous real mode CtrlC handler     */
452 static long prevRealCritical;   /* Prev real mode critical handler      */
453 static uchar *mousePtr;
454
455 /* The following real mode routine is used to call a 32 bit protected
456  * mode FAR function from real mode. We use this for passing up control
457  * from the real mode mouse callback to our protected mode code.
458  */
459
460 static UCHAR realHandler[] = {      /* Real mode code generic handler   */
461     0x00,0x00,0x00,0x00,            /* __PM_callProtp                   */
462     0x00,0x00,                      /* __PM_protCS                      */
463     0x00,0x00,0x00,0x00,            /* __PM_protHandler                 */
464     0x66,0x60,                      /*  pushad                          */
465     0x1E,                           /*  push    ds                      */
466     0x6A,0x00,                      /*  push    0                       */
467     0x6A,0x00,                      /*  push    0                       */
468     0x2E,0xFF,0x36,0x04,0x00,       /*  push    [cs:__PM_protCS]        */
469     0x66,0x2E,0xFF,0x36,0x06,0x00,  /*  push    [cs:__PM_protHandler]   */
470     0x2E,0xFF,0x1E,0x00,0x00,       /*  call    [cs:__PM_callProtp]     */
471     0x83,0xC4,0x0A,                 /*  add     sp,10                   */
472     0x1F,                           /*  pop     ds                      */
473     0x66,0x61,                      /*  popad                           */
474     0xCB,                           /*  retf                            */
475     };
476
477 /* The following functions installs the above realmode callback mechanism
478  * in real mode memory for calling the protected mode routine.
479  */
480
481 uchar * installCallback(void (PMAPI *pmCB)(),uint *rseg, uint *roff)
482 {
483     CONFIG_INF  config;
484     REALPTR     realBufAdr,callProtp;
485     ULONG       bufSize;
486     FARPTR      protBufAdr;
487     uchar       *p;
488
489     /* Get address of real mode routine to call up to protected mode    */
490     _dx_rmlink_get(&callProtp, &realBufAdr, &bufSize, &protBufAdr);
491     _dx_config_inf(&config, (UCHAR*)&config);
492
493     /* Fill in the values in the real mode code segment so that it will
494      * call the correct routine.
495      */
496     *((REALPTR*)&realHandler[0]) = callProtp;
497     *((USHORT*)&realHandler[4]) = config.c_cs_sel;
498     *((ULONG*)&realHandler[6]) = (ULONG)pmCB;
499
500     /* Copy the real mode handler to real mode memory   */
501     if ((p = PM_allocRealSeg(sizeof(realHandler),rseg,roff)) == NULL)
502         return NULL;
503     memcpy(p,realHandler,sizeof(realHandler));
504
505     /* Skip past global variabls in real mode code segment */
506     *roff += 0x0A;
507     return p;
508 }
509
510 int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
511 {
512     RMREGS      regs;
513     RMSREGS     sregs;
514     uint        rseg,roff;
515
516     lockPMHandlers();           /* Ensure our handlers are locked   */
517
518     if ((mousePtr = installCallback(_PM_mouseISR, &rseg, &roff)) == NULL)
519         return 0;
520     _PM_mouseHandler = mh;
521
522     /* Install the real mode mouse handler  */
523     sregs.es = rseg;
524     regs.x.dx = roff;
525     regs.x.cx = _PM_mouseMask = mask;
526     regs.x.ax = 0xC;
527     PM_int86x(0x33, &regs, &regs, &sregs);
528     return 1;
529 }
530
531 void PMAPI PM_restoreMouseHandler(void)
532 {
533     RMREGS  regs;
534
535     if (_PM_mouseHandler) {
536         regs.x.ax = 33;
537         PM_int86(0x33, &regs, &regs);
538         PM_freeRealSeg(mousePtr);
539         _PM_mouseHandler = NULL;
540         }
541 }
542
543 void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
544 {
545     FARPTR  ph;
546
547     _dx_pmiv_get(intno, &ph);
548     isr->sel = FP_SEL(ph);
549     isr->off = FP_OFF(ph);
550 }
551
552 void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
553 {
554     CONFIG_INF  config;
555     FARPTR      ph;
556
557     PM_saveDS();
558     _dx_config_inf(&config, (UCHAR*)&config);
559     FP_SET(ph,(uint)isr,config.c_cs_sel);
560     _dx_pmiv_set(intno,ph);
561 }
562
563 void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
564 {
565     FARPTR  ph;
566
567     FP_SET(ph,isr.off,isr.sel);
568     _dx_pmiv_set(intno,ph);
569 }
570
571 static void getISR(int intno, PMFARPTR *pmisr, long *realisr)
572 {
573     PM_getPMvect(intno,pmisr);
574     _PM_getRMvect(intno, realisr);
575 }
576
577 static void restoreISR(int intno, PMFARPTR pmisr, long realisr)
578 {
579     _PM_setRMvect(intno,realisr);
580     PM_restorePMvect(intno,pmisr);
581 }
582
583 static void setISR(int intno, void (PMAPI *isr)())
584 {
585     CONFIG_INF  config;
586     FARPTR      ph;
587
588     lockPMHandlers();           /* Ensure our handlers are locked   */
589
590     _dx_config_inf(&config, (UCHAR*)&config);
591     FP_SET(ph,(uint)isr,config.c_cs_sel);
592     _dx_apmiv_set(intno,ph);
593 }
594
595 void PMAPI PM_setTimerHandler(PM_intHandler th)
596 {
597     getISR(0x8, &_PM_prevTimer, &_PM_prevRealTimer);
598     _PM_timerHandler = th;
599     setISR(0x8, _PM_timerISR);
600 }
601
602 void PMAPI PM_restoreTimerHandler(void)
603 {
604     if (_PM_timerHandler) {
605         restoreISR(0x8, _PM_prevTimer, _PM_prevRealTimer);
606         _PM_timerHandler = NULL;
607         }
608 }
609
610 ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
611 {
612     /* Save the old CMOS real time clock values */
613     _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
614     _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
615
616     /* Set the real time clock interrupt handler */
617     getISR(0x70, &_PM_prevRTC, &_PM_prevRealRTC);
618     _PM_rtcHandler = th;
619     setISR(0x70, _PM_rtcISR);
620
621     /* Program the real time clock default frequency */
622     PM_setRealTimeClockFrequency(frequency);
623
624     /* Unmask IRQ8 in the PIC2 */
625     _PM_oldRTCPIC2 = PM_inpb(0xA1);
626     PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE);
627     return true;
628 }
629
630 void PMAPI PM_restoreRealTimeClockHandler(void)
631 {
632     if (_PM_rtcHandler) {
633         /* Restore CMOS registers and mask RTC clock */
634         _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
635         _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
636         PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE));
637
638         /* Restore the interrupt vector */
639         restoreISR(0x70, _PM_prevRTC, _PM_prevRealRTC);
640         _PM_rtcHandler = NULL;
641         }
642 }
643
644 void PMAPI PM_setKeyHandler(PM_intHandler kh)
645 {
646     getISR(0x9, &_PM_prevKey, &_PM_prevRealKey);
647     _PM_keyHandler = kh;
648     setISR(0x9, _PM_keyISR);
649 }
650
651 void PMAPI PM_restoreKeyHandler(void)
652 {
653     if (_PM_keyHandler) {
654         restoreISR(0x9, _PM_prevKey, _PM_prevRealKey);
655         _PM_keyHandler = NULL;
656         }
657 }
658
659 void PMAPI PM_setKey15Handler(PM_key15Handler kh)
660 {
661     getISR(0x15, &_PM_prevKey15, &_PM_prevRealKey15);
662     _PM_key15Handler = kh;
663     setISR(0x15, _PM_key15ISR);
664 }
665
666 void PMAPI PM_restoreKey15Handler(void)
667 {
668     if (_PM_key15Handler) {
669         restoreISR(0x15, _PM_prevKey15, _PM_prevRealKey15);
670         _PM_key15Handler = NULL;
671         }
672 }
673
674 void PMAPI PM_installAltBreakHandler(PM_breakHandler bh)
675 {
676     static int  ctrlCFlag,ctrlBFlag;
677
678     _PM_ctrlCPtr = (uchar*)&ctrlCFlag;
679     _PM_ctrlBPtr = (uchar*)&ctrlBFlag;
680     getISR(0x1B, &_PM_prevBreak, &prevRealBreak);
681     getISR(0x23, &_PM_prevCtrlC, &prevRealCtrlC);
682     _PM_breakHandler = bh;
683     setISR(0x1B, _PM_breakISR);
684     setISR(0x23, _PM_ctrlCISR);
685 }
686
687 void PMAPI PM_installBreakHandler(void)
688 {
689     PM_installAltBreakHandler(NULL);
690 }
691
692 void PMAPI PM_restoreBreakHandler(void)
693 {
694     if (_PM_prevBreak.sel) {
695         restoreISR(0x1B, _PM_prevBreak, prevRealBreak);
696         restoreISR(0x23, _PM_prevCtrlC, prevRealCtrlC);
697         _PM_prevBreak.sel = 0;
698         _PM_breakHandler = NULL;
699         }
700 }
701
702 void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch)
703 {
704     static short    critBuf[2];
705
706     _PM_critPtr = (uchar*)critBuf;
707     getISR(0x24, &_PM_prevCritical, &prevRealCritical);
708     _PM_critHandler = ch;
709     setISR(0x24, _PM_criticalISR);
710 }
711
712 void PMAPI PM_installCriticalHandler(void)
713 {
714     PM_installAltCriticalHandler(NULL);
715 }
716
717 void PMAPI PM_restoreCriticalHandler(void)
718 {
719     if (_PM_prevCritical.sel) {
720         restoreISR(0x24, _PM_prevCritical, prevRealCritical);
721         _PM_prevCritical.sel = 0;
722         _PM_critHandler = NULL;
723         }
724 }
725
726 int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
727 {
728     return (_dx_lock_pgsn(p,len) == 0);
729 }
730
731 int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
732 {
733     return (_dx_ulock_pgsn(p,len) == 0);
734 }
735
736 int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
737 {
738     CONFIG_INF  config;
739     FARPTR      fp;
740
741     _dx_config_inf(&config, (UCHAR*)&config);
742     FP_SET(fp,p,config.c_cs_sel);
743     return (_dx_lock_pgs(fp,len) == 0);
744 }
745
746 int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
747 {
748     CONFIG_INF  config;
749     FARPTR      fp;
750
751     _dx_config_inf(&config, (UCHAR*)&config);
752     FP_SET(fp,p,config.c_cs_sel);
753     return (_dx_ulock_pgs(fp,len) == 0);
754 }
755
756 #endif
757
758 /*-------------------------------------------------------------------------*/
759 /* Symantec C++ DOSX and FlashTek X-32/X-32VM support                      */
760 /*-------------------------------------------------------------------------*/
761
762 #if defined(DOSX) || defined(X32VM)
763
764 #ifdef  X32VM
765 #include <x32.h>
766 #endif
767
768 static long prevRealBreak;      /* Previous real mode break handler     */
769 static long prevRealCtrlC;      /* Previous real mode CtrlC handler     */
770 static long prevRealCritical;   /* Prev real mode critical handler      */
771
772 static uint mouseSel = 0,mouseOff;
773
774 /* The following real mode routine is used to call a 32 bit protected
775  * mode FAR function from real mode. We use this for passing up control
776  * from the real mode mouse callback to our protected mode code.
777  */
778
779 static char realHandler[] = {       /* Real mode code generic handler   */
780     0x00,0x00,0x00,0x00,            /* __PM_callProtp                   */
781     0x00,0x00,                      /* __PM_protCS                      */
782     0x00,0x00,0x00,0x00,            /* __PM_protHandler                 */
783     0x1E,                           /*  push    ds                      */
784     0x6A,0x00,                      /*  push    0                       */
785     0x6A,0x00,                      /*  push    0                       */
786     0x2E,0xFF,0x36,0x04,0x00,       /*  push    [cs:__PM_protCS]        */
787     0x66,0x2E,0xFF,0x36,0x06,0x00,  /*  push    [cs:__PM_protHandler]   */
788     0x2E,0xFF,0x1E,0x00,0x00,       /*  call    [cs:__PM_callProtp]     */
789     0x83,0xC4,0x0A,                 /*  add     sp,10                   */
790     0x1F,                           /*  pop     ds                      */
791     0xCB,                           /*  retf                            */
792     };
793
794 /* The following functions installs the above realmode callback mechanism
795  * in real mode memory for calling the protected mode routine.
796  */
797
798 int installCallback(void (PMAPI *pmCB)(),uint *psel, uint *poff,
799     uint *rseg, uint *roff)
800 {
801     PMREGS          regs;
802     PMSREGS         sregs;
803
804     regs.x.ax = 0x250D;
805     PM_segread(&sregs);
806     PM_int386x(0x21,&regs,&regs,&sregs);    /* Get RM callback address  */
807
808     /* Fill in the values in the real mode code segment so that it will
809      * call the correct routine.
810      */
811     *((ulong*)&realHandler[0]) = regs.e.eax;
812     *((ushort*)&realHandler[4]) = sregs.cs;
813     *((ulong*)&realHandler[6]) = (ulong)pmCB;
814
815     /* Copy the real mode handler to real mode memory (only allocate the
816      * buffer once since we cant dealloate it with X32).
817      */
818     if (*psel == 0) {
819         if (!PM_allocRealSeg(sizeof(realHandler),psel,poff,rseg,roff))
820             return 0;
821         }
822     PM_memcpyfn(*psel,*poff,realHandler,sizeof(realHandler));
823
824     /* Skip past global variables in real mode code segment */
825     *roff += 0x0A;
826     return 1;
827 }
828
829 int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
830 {
831     RMREGS      regs;
832     RMSREGS     sregs;
833     uint    rseg,roff;
834
835     lockPMHandlers();           /* Ensure our handlers are locked   */
836
837     if (!installCallback(_PM_mouseISR, &mouseSel, &mouseOff, &rseg, &roff))
838         return 0;
839     _PM_mouseHandler = mh;
840
841     /* Install the real mode mouse handler  */
842     sregs.es = rseg;
843     regs.x.dx = roff;
844     regs.x.cx = _PM_mouseMask = mask;
845     regs.x.ax = 0xC;
846     PM_int86x(0x33, &regs, &regs, &sregs);
847     return 1;
848 }
849
850 void PMAPI PM_restoreMouseHandler(void)
851 {
852     RMREGS  regs;
853
854     if (_PM_mouseHandler) {
855         regs.x.ax = 33;
856         PM_int86(0x33, &regs, &regs);
857         _PM_mouseHandler = NULL;
858         }
859 }
860
861 void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
862 {
863     PMREGS  regs;
864     PMSREGS sregs;
865
866     PM_segread(&sregs);
867     regs.x.ax = 0x2502;         /* Get PM interrupt vector              */
868     regs.x.cx = intno;
869     PM_int386x(0x21, &regs, &regs, &sregs);
870     isr->sel = sregs.es;
871     isr->off = regs.e.ebx;
872 }
873
874 void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
875 {
876     PMFARPTR    pmisr;
877     PMSREGS     sregs;
878
879     PM_saveDS();
880     PM_segread(&sregs);
881     pmisr.sel = sregs.cs;
882     pmisr.off = (uint)isr;
883     PM_restorePMvect(intno, pmisr);
884 }
885
886 void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
887 {
888     PMREGS  regs;
889     PMSREGS sregs;
890
891     PM_segread(&sregs);
892     regs.x.ax = 0x2505;         /* Set PM interrupt vector              */
893     regs.x.cx = intno;
894     sregs.ds = isr.sel;
895     regs.e.edx = isr.off;
896     PM_int386x(0x21, &regs, &regs, &sregs);
897 }
898
899 static void getISR(int intno, PMFARPTR *pmisr, long *realisr)
900 {
901     PM_getPMvect(intno,pmisr);
902     _PM_getRMvect(intno,realisr);
903 }
904
905 static void restoreISR(int intno, PMFARPTR pmisr, long realisr)
906 {
907     PMREGS  regs;
908     PMSREGS sregs;
909
910     PM_segread(&sregs);
911     regs.x.ax = 0x2507;         /* Set real and PM vectors              */
912     regs.x.cx = intno;
913     sregs.ds = pmisr.sel;
914     regs.e.edx = pmisr.off;
915     regs.e.ebx = realisr;
916     PM_int386x(0x21, &regs, &regs, &sregs);
917 }
918
919 static void setISR(int intno, void *isr)
920 {
921     PMREGS  regs;
922     PMSREGS sregs;
923
924     lockPMHandlers();           /* Ensure our handlers are locked       */
925
926     PM_segread(&sregs);
927     regs.x.ax = 0x2506;         /* Hook real and protected vectors      */
928     regs.x.cx = intno;
929     sregs.ds = sregs.cs;
930     regs.e.edx = (uint)isr;
931     PM_int386x(0x21, &regs, &regs, &sregs);
932 }
933
934 void PMAPI PM_setTimerHandler(PM_intHandler th)
935 {
936     getISR(0x8, &_PM_prevTimer, &_PM_prevRealTimer);
937     _PM_timerHandler = th;
938     setISR(0x8, _PM_timerISR);
939 }
940
941 void PMAPI PM_restoreTimerHandler(void)
942 {
943     if (_PM_timerHandler) {
944         restoreISR(0x8, _PM_prevTimer, _PM_prevRealTimer);
945         _PM_timerHandler = NULL;
946         }
947 }
948
949 ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
950 {
951     /* Save the old CMOS real time clock values */
952     _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
953     _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
954
955     /* Set the real time clock interrupt handler */
956     getISR(0x70, &_PM_prevRTC, &_PM_prevRealRTC);
957     _PM_rtcHandler = th;
958     setISR(0x70, _PM_rtcISR);
959
960     /* Program the real time clock default frequency */
961     PM_setRealTimeClockFrequency(frequency);
962
963     /* Unmask IRQ8 in the PIC2 */
964     _PM_oldRTCPIC2 = PM_inpb(0xA1);
965     PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE);
966     return true;
967 }
968
969 void PMAPI PM_restoreRealTimeClockHandler(void)
970 {
971     if (_PM_rtcHandler) {
972         /* Restore CMOS registers and mask RTC clock */
973         _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
974         _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
975         PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE));
976
977         /* Restore the interrupt vector */
978         restoreISR(0x70, _PM_prevRTC, _PM_prevRealRTC);
979         _PM_rtcHandler = NULL;
980         }
981 }
982
983 void PMAPI PM_setKeyHandler(PM_intHandler kh)
984 {
985     getISR(0x9, &_PM_prevKey, &_PM_prevRealKey);
986     _PM_keyHandler = kh;
987     setISR(0x9, _PM_keyISR);
988 }
989
990 void PMAPI PM_restoreKeyHandler(void)
991 {
992     if (_PM_keyHandler) {
993         restoreISR(0x9, _PM_prevKey, _PM_prevRealKey);
994         _PM_keyHandler = NULL;
995         }
996 }
997
998 void PMAPI PM_setKey15Handler(PM_key15Handler kh)
999 {
1000     getISR(0x15, &_PM_prevKey15, &_PM_prevRealKey15);
1001     _PM_key15Handler = kh;
1002     setISR(0x15, _PM_key15ISR);
1003 }
1004
1005 void PMAPI PM_restoreKey15Handler(void)
1006 {
1007     if (_PM_key15Handler) {
1008         restoreISR(0x15, _PM_prevKey15, _PM_prevRealKey15);
1009         _PM_key15Handler = NULL;
1010         }
1011 }
1012
1013 void PMAPI PM_installAltBreakHandler(PM_breakHandler bh)
1014 {
1015     static int  ctrlCFlag,ctrlBFlag;
1016
1017     _PM_ctrlCPtr = (uchar*)&ctrlCFlag;
1018     _PM_ctrlBPtr = (uchar*)&ctrlBFlag;
1019     getISR(0x1B, &_PM_prevBreak, &prevRealBreak);
1020     getISR(0x23, &_PM_prevCtrlC, &prevRealCtrlC);
1021     _PM_breakHandler = bh;
1022     setISR(0x1B, _PM_breakISR);
1023     setISR(0x23, _PM_ctrlCISR);
1024 }
1025
1026 void PMAPI PM_installBreakHandler(void)
1027 {
1028     PM_installAltBreakHandler(NULL);
1029 }
1030
1031 void PMAPI PM_restoreBreakHandler(void)
1032 {
1033     if (_PM_prevBreak.sel) {
1034         restoreISR(0x1B, _PM_prevBreak, prevRealBreak);
1035         restoreISR(0x23, _PM_prevCtrlC, prevRealCtrlC);
1036         _PM_prevBreak.sel = 0;
1037         _PM_breakHandler = NULL;
1038         }
1039 }
1040
1041 void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch)
1042 {
1043     static short    critBuf[2];
1044
1045     _PM_critPtr = (uchar*)critBuf;
1046     getISR(0x24, &_PM_prevCritical, &prevRealCritical);
1047     _PM_critHandler = ch;
1048     setISR(0x24, _PM_criticalISR);
1049 }
1050
1051 void PMAPI PM_installCriticalHandler(void)
1052 {
1053     PM_installAltCriticalHandler(NULL);
1054 }
1055
1056 void PMAPI PM_restoreCriticalHandler(void)
1057 {
1058     if (_PM_prevCritical.sel) {
1059         restoreISR(0x24, _PM_prevCritical, prevRealCritical);
1060         _PM_prevCritical.sel = 0;
1061         _PM_critHandler = NULL;
1062         }
1063 }
1064
1065 int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
1066 {
1067     return (_x386_memlock(p,len) == 0);
1068 }
1069
1070 int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
1071 {
1072     return (_x386_memunlock(p,len) == 0);
1073 }
1074
1075 int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
1076 {
1077     return (_x386_memlock(p,len) == 0);
1078 }
1079
1080 int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
1081 {
1082     return (_x386_memunlock(p,len) == 0);
1083 }
1084
1085 #endif
1086
1087 /*-------------------------------------------------------------------------*/
1088 /* Borland's DPMI32 DOS Power Pack Extender support.                       */
1089 /*-------------------------------------------------------------------------*/
1090
1091 #ifdef  DPMI32
1092 #define GENERIC_DPMI32          /* Use generic 32 bit DPMI routines */
1093
1094 void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
1095 {
1096     PMREGS  regs;
1097
1098     regs.x.ax = 0x204;
1099     regs.h.bl = intno;
1100     PM_int386(0x31,&regs,&regs);
1101     isr->sel = regs.x.cx;
1102     isr->off = regs.e.edx;
1103 }
1104
1105 void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
1106 {
1107     PMSREGS sregs;
1108     PMREGS  regs;
1109
1110     PM_saveDS();
1111     regs.x.ax = 0x205;          /* Set protected mode vector        */
1112     regs.h.bl = intno;
1113     PM_segread(&sregs);
1114     regs.x.cx = sregs.cs;
1115     regs.e.edx = (uint)isr;
1116     PM_int386(0x31,&regs,&regs);
1117 }
1118
1119 void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
1120 {
1121     PMREGS  regs;
1122
1123     regs.x.ax = 0x205;
1124     regs.h.bl = intno;
1125     regs.x.cx = isr.sel;
1126     regs.e.edx = isr.off;
1127     PM_int386(0x31,&regs,&regs);
1128 }
1129 #endif
1130
1131 /*-------------------------------------------------------------------------*/
1132 /* Watcom C/C++ with Rational DOS/4GW support.                             */
1133 /*-------------------------------------------------------------------------*/
1134
1135 #ifdef  DOS4GW
1136 #define GENERIC_DPMI32          /* Use generic 32 bit DPMI routines */
1137
1138 #define MOUSE_SUPPORTED         /* DOS4GW directly supports mouse   */
1139
1140 /* We use the normal DOS services to save and restore interrupts handlers
1141  * for Watcom C++, because using the direct DPMI functions does not
1142  * appear to work properly. At least if we use the DPMI functions, we
1143  * dont get the auto-passup feature that we need to correctly trap
1144  * real and protected mode interrupts without installing Bi-model
1145  * interrupt handlers.
1146  */
1147
1148 void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
1149 {
1150     PMREGS  regs;
1151     PMSREGS sregs;
1152
1153     PM_segread(&sregs);
1154     regs.h.ah = 0x35;
1155     regs.h.al = intno;
1156     PM_int386x(0x21,&regs,&regs,&sregs);
1157     isr->sel = sregs.es;
1158     isr->off = regs.e.ebx;
1159 }
1160
1161 void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
1162 {
1163     PMREGS  regs;
1164     PMSREGS sregs;
1165
1166     PM_saveDS();
1167     PM_segread(&sregs);
1168     regs.h.ah = 0x25;
1169     regs.h.al = intno;
1170     sregs.ds = sregs.cs;
1171     regs.e.edx = (uint)isr;
1172     PM_int386x(0x21,&regs,&regs,&sregs);
1173 }
1174
1175 void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
1176 {
1177     PMREGS  regs;
1178     PMSREGS sregs;
1179
1180     PM_segread(&sregs);
1181     regs.h.ah = 0x25;
1182     regs.h.al = intno;
1183     sregs.ds = isr.sel;
1184     regs.e.edx = isr.off;
1185     PM_int386x(0x21,&regs,&regs,&sregs);
1186 }
1187
1188 int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
1189 {
1190     lockPMHandlers();           /* Ensure our handlers are locked   */
1191
1192     _PM_mouseHandler = mh;
1193     _PM_setMouseHandler(_PM_mouseMask = mask);
1194     return 1;
1195 }
1196
1197 void PMAPI PM_restoreMouseHandler(void)
1198 {
1199     PMREGS  regs;
1200
1201     if (_PM_mouseHandler) {
1202         regs.x.ax = 33;
1203         PM_int386(0x33, &regs, &regs);
1204         _PM_mouseHandler = NULL;
1205         }
1206 }
1207
1208 #endif
1209
1210 /*-------------------------------------------------------------------------*/
1211 /* DJGPP port of GNU C++ support.                                          */
1212 /*-------------------------------------------------------------------------*/
1213
1214 #ifdef DJGPP
1215 #define GENERIC_DPMI32          /* Use generic 32 bit DPMI routines */
1216
1217 void PMAPI PM_getPMvect(int intno, PMFARPTR *isr)
1218 {
1219     PMREGS  regs;
1220
1221     regs.x.ax = 0x204;
1222     regs.h.bl = intno;
1223     PM_int386(0x31,&regs,&regs);
1224     isr->sel = regs.x.cx;
1225     isr->off = regs.e.edx;
1226 }
1227
1228 void PMAPI PM_setPMvect(int intno, PM_intHandler isr)
1229 {
1230     PMSREGS sregs;
1231     PMREGS  regs;
1232
1233     PM_saveDS();
1234     regs.x.ax = 0x205;          /* Set protected mode vector        */
1235     regs.h.bl = intno;
1236     PM_segread(&sregs);
1237     regs.x.cx = sregs.cs;
1238     regs.e.edx = (uint)isr;
1239     PM_int386(0x31,&regs,&regs);
1240 }
1241
1242 void PMAPI PM_restorePMvect(int intno, PMFARPTR isr)
1243 {
1244     PMREGS  regs;
1245
1246     regs.x.ax = 0x205;
1247     regs.h.bl = intno;
1248     regs.x.cx = isr.sel;
1249     regs.e.edx = isr.off;
1250     PM_int386(0x31,&regs,&regs);
1251 }
1252
1253 #endif
1254
1255 /*-------------------------------------------------------------------------*/
1256 /* Generic 32 bit DPMI routines                                            */
1257 /*-------------------------------------------------------------------------*/
1258
1259 #if defined(GENERIC_DPMI32)
1260
1261 static long prevRealBreak;      /* Previous real mode break handler     */
1262 static long prevRealCtrlC;      /* Previous real mode CtrlC handler     */
1263 static long prevRealCritical;   /* Prev real mode critical handler      */
1264
1265 #ifndef MOUSE_SUPPORTED
1266
1267 /* The following real mode routine is used to call a 32 bit protected
1268  * mode FAR function from real mode. We use this for passing up control
1269  * from the real mode mouse callback to our protected mode code.
1270  */
1271
1272 static long mouseRMCB;          /* Mouse real mode callback address     */
1273 static uchar *mousePtr;
1274 static char mouseRegs[0x32];    /* Real mode regs for mouse callback    */
1275 static uchar mouseHandler[] = {
1276     0x00,0x00,0x00,0x00,        /* _realRMCB                            */
1277     0x2E,0xFF,0x1E,0x00,0x00,   /*  call    [cs:_realRMCB]              */
1278     0xCB,                       /*  retf                                */
1279     };
1280
1281 int PMAPI PM_setMouseHandler(int mask, PM_mouseHandler mh)
1282 {
1283     RMREGS      regs;
1284     RMSREGS     sregs;
1285     uint        rseg,roff;
1286
1287     lockPMHandlers();           /* Ensure our handlers are locked   */
1288
1289     /* Copy the real mode handler to real mode memory   */
1290     if ((mousePtr = PM_allocRealSeg(sizeof(mouseHandler),&rseg,&roff)) == NULL)
1291         return 0;
1292     memcpy(mousePtr,mouseHandler,sizeof(mouseHandler));
1293     if (!_DPMI_allocateCallback(_PM_mousePMCB, mouseRegs, &mouseRMCB))
1294         PM_fatalError("Unable to allocate real mode callback!\n");
1295     PM_setLong(mousePtr,mouseRMCB);
1296
1297     /* Install the real mode mouse handler  */
1298     _PM_mouseHandler = mh;
1299     sregs.es = rseg;
1300     regs.x.dx = roff+4;
1301     regs.x.cx = _PM_mouseMask = mask;
1302     regs.x.ax = 0xC;
1303     PM_int86x(0x33, &regs, &regs, &sregs);
1304     return 1;
1305 }
1306
1307 void PMAPI PM_restoreMouseHandler(void)
1308 {
1309     RMREGS  regs;
1310
1311     if (_PM_mouseHandler) {
1312         regs.x.ax = 33;
1313         PM_int86(0x33, &regs, &regs);
1314         PM_freeRealSeg(mousePtr);
1315         _DPMI_freeCallback(mouseRMCB);
1316         _PM_mouseHandler = NULL;
1317         }
1318 }
1319
1320 #endif
1321
1322 static void getISR(int intno, PMFARPTR *pmisr, long *realisr)
1323 {
1324     PM_getPMvect(intno,pmisr);
1325     _PM_getRMvect(intno,realisr);
1326 }
1327
1328 static void restoreISR(int intno, PMFARPTR pmisr, long realisr)
1329 {
1330     _PM_setRMvect(intno,realisr);
1331     PM_restorePMvect(intno,pmisr);
1332 }
1333
1334 static void setISR(int intno, void (* PMAPI pmisr)())
1335 {
1336     lockPMHandlers();           /* Ensure our handlers are locked   */
1337     PM_setPMvect(intno,pmisr);
1338 }
1339
1340 void PMAPI PM_setTimerHandler(PM_intHandler th)
1341 {
1342     getISR(0x8, &_PM_prevTimer, &_PM_prevRealTimer);
1343     _PM_timerHandler = th;
1344     setISR(0x8, _PM_timerISR);
1345 }
1346
1347 void PMAPI PM_restoreTimerHandler(void)
1348 {
1349     if (_PM_timerHandler) {
1350         restoreISR(0x8, _PM_prevTimer, _PM_prevRealTimer);
1351         _PM_timerHandler = NULL;
1352         }
1353 }
1354
1355 ibool PMAPI PM_setRealTimeClockHandler(PM_intHandler th,int frequency)
1356 {
1357     /* Save the old CMOS real time clock values */
1358     _PM_oldCMOSRegA = _PM_readCMOS(0x0A);
1359     _PM_oldCMOSRegB = _PM_readCMOS(0x0B);
1360
1361     /* Set the real time clock interrupt handler */
1362     getISR(0x70, &_PM_prevRTC, &_PM_prevRealRTC);
1363     _PM_rtcHandler = th;
1364     setISR(0x70, _PM_rtcISR);
1365
1366     /* Program the real time clock default frequency */
1367     PM_setRealTimeClockFrequency(frequency);
1368
1369     /* Unmask IRQ8 in the PIC2 */
1370     _PM_oldRTCPIC2 = PM_inpb(0xA1);
1371     PM_outpb(0xA1,_PM_oldRTCPIC2 & 0xFE);
1372     return true;
1373 }
1374
1375 void PMAPI PM_restoreRealTimeClockHandler(void)
1376 {
1377     if (_PM_rtcHandler) {
1378         /* Restore CMOS registers and mask RTC clock */
1379         _PM_writeCMOS(0x0A,_PM_oldCMOSRegA);
1380         _PM_writeCMOS(0x0B,_PM_oldCMOSRegB);
1381         PM_outpb(0xA1,(PM_inpb(0xA1) & 0xFE) | (_PM_oldRTCPIC2 & ~0xFE));
1382
1383         /* Restore the interrupt vector */
1384         restoreISR(0x70, _PM_prevRTC, _PM_prevRealRTC);
1385         _PM_rtcHandler = NULL;
1386         }
1387 }
1388
1389 PM_IRQHandle PMAPI PM_setIRQHandler(
1390     int IRQ,
1391     PM_irqHandler ih)
1392 {
1393     int             thunkSize,PICmask,chainPrevious;
1394     ulong           offsetAdjust;
1395     _PM_IRQHandle   *handle;
1396
1397     thunkSize = (ulong)_PM_irqISRTemplateEnd - (ulong)_PM_irqISRTemplate;
1398     if ((handle = PM_malloc(sizeof(_PM_IRQHandle) + thunkSize)) == NULL)
1399         return NULL;
1400     handle->IRQ = IRQ;
1401     handle->prevPIC = PM_inpb(0x21);
1402     handle->prevPIC2 = PM_inpb(0xA1);
1403     if (IRQ < 8) {
1404         handle->IRQVect = (IRQ + 8);
1405         PICmask = (1 << IRQ);
1406         chainPrevious = ((handle->prevPIC & PICmask) == 0);
1407         }
1408     else {
1409         handle->IRQVect = (0x60 + IRQ + 8);
1410         PICmask = ((1 << IRQ) | 0x4);
1411         chainPrevious = ((handle->prevPIC2 & (PICmask >> 8)) == 0);
1412         }
1413
1414     /* Copy and setup the assembler thunk */
1415     offsetAdjust = (ulong)handle->thunk - (ulong)_PM_irqISRTemplate;
1416     memcpy(handle->thunk,_PM_irqISRTemplate,thunkSize);
1417     *((ulong*)&handle->thunk[2]) = offsetAdjust;
1418     *((ulong*)&handle->thunk[11+0]) = (ulong)ih;
1419     if (chainPrevious) {
1420         *((ulong*)&handle->thunk[11+4]) = handle->prevHandler.off;
1421         *((ulong*)&handle->thunk[11+8]) = handle->prevHandler.sel;
1422         }
1423     else {
1424         *((ulong*)&handle->thunk[11+4]) = 0;
1425         *((ulong*)&handle->thunk[11+8]) = 0;
1426         }
1427     *((ulong*)&handle->thunk[11+12]) = IRQ;
1428
1429     /* Set the real time clock interrupt handler */
1430     getISR(handle->IRQVect, &handle->prevHandler, &handle->prevRealhandler);
1431     setISR(handle->IRQVect, (PM_intHandler)handle->thunk);
1432
1433     /* Unmask the IRQ in the PIC */
1434     PM_outpb(0xA1,handle->prevPIC2 & ~(PICmask >> 8));
1435     PM_outpb(0x21,handle->prevPIC & ~PICmask);
1436     return handle;
1437 }
1438
1439 void PMAPI PM_restoreIRQHandler(
1440     PM_IRQHandle irqHandle)
1441 {
1442     int             PICmask;
1443     _PM_IRQHandle   *handle = irqHandle;
1444
1445     /* Restore PIC mask for the interrupt */
1446     if (handle->IRQ < 8)
1447         PICmask = (1 << handle->IRQ);
1448     else
1449         PICmask = ((1 << handle->IRQ) | 0x4);
1450     PM_outpb(0xA1,(PM_inpb(0xA1) & ~(PICmask >> 8)) | (handle->prevPIC2 & (PICmask >> 8)));
1451     PM_outpb(0x21,(PM_inpb(0x21) & ~PICmask) | (handle->prevPIC & PICmask));
1452
1453     /* Restore the interrupt vector */
1454     restoreISR(handle->IRQVect, handle->prevHandler, handle->prevRealhandler);
1455
1456     /* Finally free the thunk */
1457     PM_free(handle);
1458 }
1459
1460 void PMAPI PM_setKeyHandler(PM_intHandler kh)
1461 {
1462     getISR(0x9, &_PM_prevKey, &_PM_prevRealKey);
1463     _PM_keyHandler = kh;
1464     setISR(0x9, _PM_keyISR);
1465 }
1466
1467 void PMAPI PM_restoreKeyHandler(void)
1468 {
1469     if (_PM_keyHandler) {
1470         restoreISR(0x9, _PM_prevKey, _PM_prevRealKey);
1471         _PM_keyHandler = NULL;
1472         }
1473 }
1474
1475 void PMAPI PM_setKey15Handler(PM_key15Handler kh)
1476 {
1477     getISR(0x15, &_PM_prevKey15, &_PM_prevRealKey15);
1478     _PM_key15Handler = kh;
1479     setISR(0x15, _PM_key15ISR);
1480 }
1481
1482 void PMAPI PM_restoreKey15Handler(void)
1483 {
1484     if (_PM_key15Handler) {
1485         restoreISR(0x15, _PM_prevKey15, _PM_prevRealKey15);
1486         _PM_key15Handler = NULL;
1487         }
1488 }
1489
1490 /* Real mode Ctrl-C and Ctrl-Break handler. This handler simply sets a
1491  * flag in the real mode code segment and exit. We save the location
1492  * of this flag in real mode memory so that both the real mode and
1493  * protected mode code will be modifying the same flags.
1494  */
1495
1496 #ifndef DOS4GW
1497 static uchar ctrlHandler[] = {
1498     0x00,0x00,0x00,0x00,            /*  ctrlBFlag                       */
1499     0x66,0x2E,0xC7,0x06,0x00,0x00,
1500     0x01,0x00,0x00,0x00,            /*  mov     [cs:ctrlBFlag],1        */
1501     0xCF,                           /*  iretf                           */
1502     };
1503 #endif
1504
1505 void PMAPI PM_installAltBreakHandler(PM_breakHandler bh)
1506 {
1507 #ifndef DOS4GW
1508     uint    rseg,roff;
1509 #else
1510     static int  ctrlCFlag,ctrlBFlag;
1511
1512     _PM_ctrlCPtr = (uchar*)&ctrlCFlag;
1513     _PM_ctrlBPtr = (uchar*)&ctrlBFlag;
1514 #endif
1515
1516     getISR(0x1B, &_PM_prevBreak, &prevRealBreak);
1517     getISR(0x23, &_PM_prevCtrlC, &prevRealCtrlC);
1518     _PM_breakHandler = bh;
1519     setISR(0x1B, _PM_breakISR);
1520     setISR(0x23, _PM_ctrlCISR);
1521
1522 #ifndef DOS4GW
1523     /* Hook the real mode vectors for these handlers, as these are not
1524      * normally reflected by the DPMI server up to protected mode
1525      */
1526     _PM_ctrlBPtr = PM_allocRealSeg(sizeof(ctrlHandler)*2, &rseg, &roff);
1527     memcpy(_PM_ctrlBPtr,ctrlHandler,sizeof(ctrlHandler));
1528     memcpy(_PM_ctrlBPtr+sizeof(ctrlHandler),ctrlHandler,sizeof(ctrlHandler));
1529     _PM_ctrlCPtr = _PM_ctrlBPtr + sizeof(ctrlHandler);
1530     _PM_setRMvect(0x1B,((long)rseg << 16) | (roff+4));
1531     _PM_setRMvect(0x23,((long)rseg << 16) | (roff+sizeof(ctrlHandler)+4));
1532 #endif
1533 }
1534
1535 void PMAPI PM_installBreakHandler(void)
1536 {
1537     PM_installAltBreakHandler(NULL);
1538 }
1539
1540 void PMAPI PM_restoreBreakHandler(void)
1541 {
1542     if (_PM_prevBreak.sel) {
1543         restoreISR(0x1B, _PM_prevBreak, prevRealBreak);
1544         restoreISR(0x23, _PM_prevCtrlC, prevRealCtrlC);
1545         _PM_prevBreak.sel = 0;
1546         _PM_breakHandler = NULL;
1547 #ifndef DOS4GW
1548         PM_freeRealSeg(_PM_ctrlBPtr);
1549 #endif
1550         }
1551 }
1552
1553 /* Real mode Critical Error handler. This handler simply saves the AX and
1554  * DI values in the real mode code segment and exits. We save the location
1555  * of this flag in real mode memory so that both the real mode and
1556  * protected mode code will be modifying the same flags.
1557  */
1558
1559 #ifndef DOS4GW
1560 static uchar criticalHandler[] = {
1561     0x00,0x00,                      /*  axCode                          */
1562     0x00,0x00,                      /*  diCode                          */
1563     0x2E,0xA3,0x00,0x00,            /*  mov     [cs:axCode],ax          */
1564     0x2E,0x89,0x3E,0x02,0x00,       /*  mov     [cs:diCode],di          */
1565     0xB8,0x03,0x00,                 /*  mov     ax,3                    */
1566     0xCF,                           /*  iretf                           */
1567     };
1568 #endif
1569
1570 void PMAPI PM_installAltCriticalHandler(PM_criticalHandler ch)
1571 {
1572 #ifndef DOS4GW
1573     uint    rseg,roff;
1574 #else
1575     static  short   critBuf[2];
1576
1577     _PM_critPtr = (uchar*)critBuf;
1578 #endif
1579
1580     getISR(0x24, &_PM_prevCritical, &prevRealCritical);
1581     _PM_critHandler = ch;
1582     setISR(0x24, _PM_criticalISR);
1583
1584 #ifndef DOS4GW
1585     /* Hook the real mode vector, as this is not normally reflected by the
1586      * DPMI server up to protected mode.
1587      */
1588     _PM_critPtr = PM_allocRealSeg(sizeof(criticalHandler)*2, &rseg, &roff);
1589     memcpy(_PM_critPtr,criticalHandler,sizeof(criticalHandler));
1590     _PM_setRMvect(0x24,((long)rseg << 16) | (roff+4));
1591 #endif
1592 }
1593
1594 void PMAPI PM_installCriticalHandler(void)
1595 {
1596     PM_installAltCriticalHandler(NULL);
1597 }
1598
1599 void PMAPI PM_restoreCriticalHandler(void)
1600 {
1601     if (_PM_prevCritical.sel) {
1602         restoreISR(0x24, _PM_prevCritical, prevRealCritical);
1603         PM_freeRealSeg(_PM_critPtr);
1604         _PM_prevCritical.sel = 0;
1605         _PM_critHandler = NULL;
1606         }
1607 }
1608
1609 int PMAPI PM_lockDataPages(void *p,uint len,PM_lockHandle *lh)
1610 {
1611     PMSREGS sregs;
1612     PM_segread(&sregs);
1613     return DPMI_lockLinearPages((uint)p + DPMI_getSelectorBase(sregs.ds),len);
1614 }
1615
1616 int PMAPI PM_unlockDataPages(void *p,uint len,PM_lockHandle *lh)
1617 {
1618     PMSREGS sregs;
1619     PM_segread(&sregs);
1620     return DPMI_unlockLinearPages((uint)p + DPMI_getSelectorBase(sregs.ds),len);
1621 }
1622
1623 int PMAPI PM_lockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
1624 {
1625     PMSREGS sregs;
1626     PM_segread(&sregs);
1627     return DPMI_lockLinearPages((uint)p + DPMI_getSelectorBase(sregs.cs),len);
1628 }
1629
1630 int PMAPI PM_unlockCodePages(void (*p)(),uint len,PM_lockHandle *lh)
1631 {
1632     PMSREGS sregs;
1633     PM_segread(&sregs);
1634     return DPMI_unlockLinearPages((uint)p + DPMI_getSelectorBase(sregs.cs),len);
1635 }
1636
1637 #endif