]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/pm/smx/_pmsmx.asm
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / pm / smx / _pmsmx.asm
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:    80386 Assembler, TASM 4.0 or NASM
25 ;* Environment: 32-bit SMX embedded systems development
26 ;*
27 ;* Description: Low level assembly support for the PM library specific to
28 ;*              SMX interrupt handling.
29 ;*
30 ;****************************************************************************
31
32         IDEAL
33
34 include "scitech.mac"           ; Memory model macros
35
36 header      _pmsmx              ; Set up memory model
37
38 ; Define the size of our local stacks. For real mode code they cant be
39 ; that big, but for 32 bit protected mode code we can make them nice and
40 ; large so that complex C functions can be used.
41
42 MOUSE_STACK EQU 4096
43 TIMER_STACK EQU 4096
44 KEY_STACK   EQU 1024
45 INT10_STACK EQU 1024
46
47 ifdef   USE_NASM
48
49 ; Macro to load DS and ES registers with correct value.
50
51 %imacro   LOAD_DS 0
52         mov     ds,[cs:_PM_savedDS]
53         mov     es,[cs:_PM_savedDS]
54 %endmacro
55
56 ; Note that interrupts we disable interrupts during the following stack
57 ; %imacro for correct operation, but we do not enable them again. Normally
58 ; these %imacros are used within interrupt handlers so interrupts should
59 ; already be off. We turn them back on explicitly later if the user code
60 ; needs them to be back on.
61
62 ; Macro to switch to a new local stack.
63
64 %imacro NEWSTK  1
65         cli
66         mov     [seg_%1],ss
67         mov     [ptr_%1],_sp
68         mov     [TempSeg],ds
69         mov     ss,[TempSeg]
70         mov     _sp,offset %1
71 %endmacro
72
73 ; %imacro to switch back to the old stack.
74
75 %imacro   RESTSTK   1
76         cli
77         mov     ss,[seg_%1]
78         mov     _sp,[ptr_%1]
79 %endmacro
80
81 ; %imacro to swap the current stack with the one saved away.
82
83 %imacro SWAPSTK 1
84         cli
85         mov     ax,ss
86         xchg    ax,[seg_%1]
87         mov     ss,ax
88         xchg    _sp,[ptr_%1]
89 %endmacro
90
91 else
92
93 ; Macro to load DS and ES registers with correct value.
94
95 MACRO   LOAD_DS
96         mov     ds,[cs:_PM_savedDS]
97         mov     es,[cs:_PM_savedDS]
98 ENDM
99
100 ; Note that interrupts we disable interrupts during the following stack
101 ; macro for correct operation, but we do not enable them again. Normally
102 ; these macros are used within interrupt handlers so interrupts should
103 ; already be off. We turn them back on explicitly later if the user code
104 ; needs them to be back on.
105
106 ; Macro to switch to a new local stack.
107
108 MACRO   NEWSTK  stkname
109         cli
110         mov     [seg_&stkname&],ss
111         mov     [ptr_&stkname&],_sp
112         mov     [TempSeg],ds
113         mov     ss,[TempSeg]
114         mov     _sp,offset stkname
115 ENDM
116
117 ; Macro to switch back to the old stack.
118
119 MACRO   RESTSTK stkname
120         cli
121         mov     ss,[seg_&stkname&]
122         mov     _sp,[ptr_&stkname&]
123 ENDM
124
125 ; Macro to swap the current stack with the one saved away.
126
127 MACRO   SWAPSTK stkname
128         cli
129         mov     ax,ss
130         xchg    ax,[seg_&stkname&]
131         mov     ss,ax
132         xchg    _sp,[ptr_&stkname&]
133 ENDM
134
135 endif
136
137 begdataseg  _pmsmx
138
139     cextern _PM_savedDS,USHORT
140     cextern _PM_critHandler,CPTR
141     cextern _PM_breakHandler,CPTR
142     cextern _PM_timerHandler,CPTR
143     cextern _PM_rtcHandler,CPTR
144     cextern _PM_keyHandler,CPTR
145     cextern _PM_key15Handler,CPTR
146     cextern _PM_mouseHandler,CPTR
147     cextern _PM_int10Handler,CPTR
148
149     cextern _PM_ctrlCPtr,DPTR
150     cextern _PM_ctrlBPtr,DPTR
151     cextern _PM_critPtr,DPTR
152
153     cextern _PM_prevTimer,FCPTR
154     cextern _PM_prevRTC,FCPTR
155     cextern _PM_prevKey,FCPTR
156     cextern _PM_prevKey15,FCPTR
157     cextern _PM_prevBreak,FCPTR
158     cextern _PM_prevCtrlC,FCPTR
159     cextern _PM_prevCritical,FCPTR
160     cextern _PM_prevRealTimer,ULONG
161     cextern _PM_prevRealRTC,ULONG
162     cextern _PM_prevRealKey,ULONG
163     cextern _PM_prevRealKey15,ULONG
164     cextern _PM_prevRealInt10,ULONG
165
166 cpublic _PM_pmsmxDataStart
167
168 ; Allocate space for all of the local stacks that we need. These stacks
169 ; are not very large, but should be large enough for most purposes
170 ; (generally you want to handle these interrupts quickly, simply storing
171 ; the information for later and then returning). If you need bigger
172 ; stacks then change the appropriate value in here.
173
174             ALIGN   4
175             dclb MOUSE_STACK    ; Space for local stack (small)
176 MsStack:                        ; Stack starts at end!
177 ptr_MsStack DUINT   0           ; Place to store old stack offset
178 seg_MsStack dw      0           ; Place to store old stack segment
179
180             ALIGN   4
181             dclb INT10_STACK    ; Space for local stack (small)
182 Int10Stack:                     ; Stack starts at end!
183 ptr_Int10Stack  DUINT   0       ; Place to store old stack offset
184 seg_Int10Stack  dw      0       ; Place to store old stack segment
185
186             ALIGN   4
187             dclb TIMER_STACK    ; Space for local stack (small)
188 TmStack:                        ; Stack starts at end!
189 ptr_TmStack DUINT   0           ; Place to store old stack offset
190 seg_TmStack dw      0           ; Place to store old stack segment
191
192             ALIGN   4
193             dclb TIMER_STACK    ; Space for local stack (small)
194 RtcStack:                       ; Stack starts at end!
195 ptr_RtcStack DUINT  0           ; Place to store old stack offset
196 seg_RtcStack dw     0           ; Place to store old stack segment
197 RtcInside   dw      0           ; Are we still handling current interrupt
198
199             ALIGN   4
200             dclb KEY_STACK      ; Space for local stack (small)
201 KyStack:                        ; Stack starts at end!
202 ptr_KyStack DUINT   0           ; Place to store old stack offset
203 seg_KyStack dw      0           ; Place to store old stack segment
204 KyInside    dw      0           ; Are we still handling current interrupt
205
206             ALIGN   4
207             dclb KEY_STACK      ; Space for local stack (small)
208 Ky15Stack:                      ; Stack starts at end!
209 ptr_Ky15Stack   DUINT   0       ; Place to store old stack offset
210 seg_Ky15Stack   dw      0       ; Place to store old stack segment
211
212 TempSeg     dw      0           ; Place to store stack segment
213
214 cpublic _PM_pmsmxDataEnd
215
216 enddataseg  _pmsmx
217
218 begcodeseg  _pmsmx              ; Start of code segment
219
220 cpublic _PM_pmsmxCodeStart
221
222 ;----------------------------------------------------------------------------
223 ; PM_mouseISR - Mouse interrupt subroutine dispatcher
224 ;----------------------------------------------------------------------------
225 ; Interrupt subroutine called by the mouse driver upon interrupts, to
226 ; dispatch control to high level C based subroutines. Interrupts are on
227 ; when we call the user code.
228 ;
229 ; It is _extremely_ important to save the state of the extended registers
230 ; as these may well be trashed by the routines called from here and not
231 ; restored correctly by the mouse interface module.
232 ;
233 ; NOTE: This routine switches to a local stack before calling any C code,
234 ;       and hence is _not_ re-entrant. For mouse handlers this is not a
235 ;       problem, as the mouse driver arbitrates calls to the user mouse
236 ;       handler for us.
237 ;
238 ; Entry:    AX  - Condition mask giving reason for call
239 ;           BX  - Mouse button state
240 ;           CX  - Horizontal cursor coordinate
241 ;           DX  - Vertical cursor coordinate
242 ;           SI  - Horizontal mickey value
243 ;           DI  - Vertical mickey value
244 ;
245 ;----------------------------------------------------------------------------
246 cprocfar    _PM_mouseISR
247
248         push    ds              ; Save value of DS
249         push    es
250         pushad                  ; Save _all_ extended registers
251         cld                     ; Clear direction flag
252
253         LOAD_DS                 ; Load DS register
254         NEWSTK  MsStack         ; Switch to local stack
255
256 ; Call the installed high level C code routine
257
258         clrhi   dx              ; Clear out high order values
259         clrhi   cx
260         clrhi   bx
261         clrhi   ax
262         sgnhi   si
263         sgnhi   di
264
265         push    _di
266         push    _si
267         push    _dx
268         push    _cx
269         push    _bx
270         push    _ax
271         sti                     ; Enable interrupts
272         call    [CPTR _PM_mouseHandler]
273         _add    sp,12,24
274
275         RESTSTK MsStack         ; Restore previous stack
276
277         popad                   ; Restore all extended registers
278         pop     es
279         pop     ds
280         ret                     ; We are done!!
281
282 cprocend
283
284 ;----------------------------------------------------------------------------
285 ; PM_timerISR - Timer interrupt subroutine dispatcher
286 ;----------------------------------------------------------------------------
287 ; Hardware interrupt handler for the timer interrupt, to dispatch control
288 ; to high level C based subroutines. We save the state of all registers
289 ; in this routine, and switch to a local stack. Interrupts are *off*
290 ; when we call the user code.
291 ;
292 ; NOTE: This routine switches to a local stack before calling any C code,
293 ;       and hence is _not_ re-entrant. Make sure your C code executes as
294 ;       quickly as possible, since a timer overrun will simply hang the
295 ;       system.
296 ;----------------------------------------------------------------------------
297 cprocfar    _PM_timerISR
298
299         push    ds              ; Save value of DS
300         push    es
301         pushad                  ; Save _all_ extended registers
302         cld                     ; Clear direction flag
303
304         LOAD_DS                 ; Load DS register
305
306         NEWSTK  TmStack         ; Switch to local stack
307         call    [CPTR _PM_timerHandler]
308         RESTSTK TmStack         ; Restore previous stack
309
310         popad                   ; Restore all extended registers
311         pop     es
312         pop     ds
313         iret                    ; Return from interrupt
314
315 cprocend
316
317 ;----------------------------------------------------------------------------
318 ; PM_chainPrevTimer - Chain to previous timer interrupt and return
319 ;----------------------------------------------------------------------------
320 ; Chains to the previous timer interrupt routine and returns control
321 ; back to the high level interrupt handler.
322 ;----------------------------------------------------------------------------
323 cprocstart  PM_chainPrevTimer
324
325 ifdef   TNT
326         push    eax
327         push    ebx
328         push    ecx
329         pushfd                  ; Push flags on stack to simulate interrupt
330         mov     ax,250Eh        ; Call real mode procedure function
331         mov     ebx,[_PM_prevRealTimer]
332         mov     ecx,1           ; Copy real mode flags to real mode stack
333         int     21h             ; Call the real mode code
334         popfd
335         pop     ecx
336         pop     ebx
337         pop     eax
338         ret
339 else
340         SWAPSTK TmStack         ; Swap back to previous stack
341         pushf                   ; Save state of interrupt flag
342         pushf                   ; Push flags on stack to simulate interrupt
343 ifdef   USE_NASM
344         call far dword [_PM_prevTimer]
345 else
346         call    [_PM_prevTimer]
347 endif
348         popf                    ; Restore state of interrupt flag
349         SWAPSTK TmStack         ; Swap back to C stack again
350         ret
351 endif
352
353 cprocend
354
355 ; Macro to delay briefly to ensure that enough time has elapsed between
356 ; successive I/O accesses so that the device being accessed can respond
357 ; to both accesses even on a very fast PC.
358
359 ifdef   USE_NASM
360 %macro  DELAY 0
361         jmp     short $+2
362         jmp     short $+2
363         jmp     short $+2
364 %endmacro
365 %macro  IODELAYN 1
366 %rep    %1
367         DELAY
368 %endrep
369 %endmacro
370 else
371 macro   DELAY
372         jmp     short $+2
373         jmp     short $+2
374         jmp     short $+2
375 endm
376 macro   IODELAYN    N
377     rept    N
378         DELAY
379     endm
380 endm
381 endif
382
383 ;----------------------------------------------------------------------------
384 ; PM_rtcISR - Real time clock interrupt subroutine dispatcher
385 ;----------------------------------------------------------------------------
386 ; Hardware interrupt handler for the timer interrupt, to dispatch control
387 ; to high level C based subroutines. We save the state of all registers
388 ; in this routine, and switch to a local stack. Interrupts are *off*
389 ; when we call the user code.
390 ;
391 ; NOTE: This routine switches to a local stack before calling any C code,
392 ;       and hence is _not_ re-entrant. Make sure your C code executes as
393 ;       quickly as possible, since a timer overrun will simply hang the
394 ;       system.
395 ;----------------------------------------------------------------------------
396 cprocfar    _PM_rtcISR
397
398         push    ds                  ; Save value of DS
399         push    es
400         pushad                      ; Save _all_ extended registers
401         cld                         ; Clear direction flag
402
403 ; Clear priority interrupt controller and re-enable interrupts so we
404 ; dont lock things up for long.
405
406         mov     al,20h
407         out     0A0h,al
408         out     020h,al
409
410 ; Clear real-time clock timeout
411
412         in      al,70h              ; Read CMOS index register
413         push    _ax                 ;  and save for later
414         IODELAYN 3
415         mov     al,0Ch
416         out     70h,al
417         IODELAYN 5
418         in      al,71h
419
420 ; Call the C interrupt handler function
421
422         LOAD_DS                     ; Load DS register
423         cmp     [BYTE RtcInside],1  ; Check for mutual exclusion
424         je      @@Exit
425         mov     [BYTE RtcInside],1
426         sti                         ; Re-enable interrupts
427         NEWSTK  RtcStack            ; Switch to local stack
428         call    [CPTR _PM_rtcHandler]
429         RESTSTK RtcStack            ; Restore previous stack
430         mov     [BYTE RtcInside],0
431
432 @@Exit: pop     _ax
433         out     70h,al              ; Restore CMOS index register
434         popad                       ; Restore all extended registers
435         pop     es
436         pop     ds
437         iret                        ; Return from interrupt
438
439 cprocend
440
441 ;----------------------------------------------------------------------------
442 ; PM_keyISR - keyboard interrupt subroutine dispatcher
443 ;----------------------------------------------------------------------------
444 ; Hardware interrupt handler for the keyboard interrupt, to dispatch control
445 ; to high level C based subroutines. We save the state of all registers
446 ; in this routine, and switch to a local stack. Interrupts are *off*
447 ; when we call the user code.
448 ;
449 ; NOTE: This routine switches to a local stack before calling any C code,
450 ;       and hence is _not_ re-entrant. However we ensure within this routine
451 ;       mutual exclusion to the keyboard handling routine.
452 ;----------------------------------------------------------------------------
453 cprocfar    _PM_keyISR
454
455         push    ds              ; Save value of DS
456         push    es
457         pushad                  ; Save _all_ extended registers
458         cld                     ; Clear direction flag
459
460         LOAD_DS                 ; Load DS register
461
462         cmp     [BYTE KyInside],1   ; Check for mutual exclusion
463         je      @@Reissued
464
465         mov     [BYTE KyInside],1
466         NEWSTK  KyStack         ; Switch to local stack
467         call    [CPTR _PM_keyHandler]   ; Call C code
468         RESTSTK KyStack         ; Restore previous stack
469         mov     [BYTE KyInside],0
470
471 @@Exit: popad                   ; Restore all extended registers
472         pop     es
473         pop     ds
474         iret                    ; Return from interrupt
475
476 ; When the BIOS keyboard handler needs to change the SHIFT status lights
477 ; on the keyboard, in the process of doing this the keyboard controller
478 ; re-issues another interrupt, while the current handler is still executing.
479 ; If we recieve another interrupt while still handling the current one,
480 ; then simply chain directly to the previous handler.
481 ;
482 ; Note that for most DOS extenders, the real mode interrupt handler that we
483 ; install takes care of this for us.
484
485 @@Reissued:
486 ifdef   TNT
487         push    eax
488         push    ebx
489         push    ecx
490         pushfd                  ; Push flags on stack to simulate interrupt
491         mov     ax,250Eh        ; Call real mode procedure function
492         mov     ebx,[_PM_prevRealKey]
493         mov     ecx,1           ; Copy real mode flags to real mode stack
494         int     21h             ; Call the real mode code
495         popfd
496         pop     ecx
497         pop     ebx
498         pop     eax
499 else
500         pushf
501 ifdef   USE_NASM
502         call far dword [_PM_prevKey]
503 else
504         call    [_PM_prevKey]
505 endif
506 endif
507         jmp     @@Exit
508
509 cprocend
510
511 ;----------------------------------------------------------------------------
512 ; PM_chainPrevkey - Chain to previous key interrupt and return
513 ;----------------------------------------------------------------------------
514 ; Chains to the previous key interrupt routine and returns control
515 ; back to the high level interrupt handler.
516 ;----------------------------------------------------------------------------
517 cprocstart  PM_chainPrevKey
518
519 ifdef   TNT
520         push    eax
521         push    ebx
522         push    ecx
523         pushfd                  ; Push flags on stack to simulate interrupt
524         mov     ax,250Eh        ; Call real mode procedure function
525         mov     ebx,[_PM_prevRealKey]
526         mov     ecx,1           ; Copy real mode flags to real mode stack
527         int     21h             ; Call the real mode code
528         popfd
529         pop     ecx
530         pop     ebx
531         pop     eax
532         ret
533 else
534
535 ; YIKES! For some strange reason, when execution returns from the
536 ; previous keyboard handler, interrupts are re-enabled!! Since we expect
537 ; interrupts to remain off during the duration of our handler, this can
538 ; cause havoc. However our stack macros always turn off interrupts, so they
539 ; will be off when we exit this routine. Obviously there is a tiny weeny
540 ; window when interrupts will be enabled, but there is nothing we can
541 ; do about this.
542
543         SWAPSTK KyStack         ; Swap back to previous stack
544         pushf                   ; Push flags on stack to simulate interrupt
545 ifdef   USE_NASM
546         call far dword [_PM_prevKey]
547 else
548         call    [_PM_prevKey]
549 endif
550         SWAPSTK KyStack         ; Swap back to C stack again
551         ret
552 endif
553
554 cprocend
555
556 ;----------------------------------------------------------------------------
557 ; PM_key15ISR - Int 15h keyboard interrupt subroutine dispatcher
558 ;----------------------------------------------------------------------------
559 ; This routine gets called if we have been called to handle the Int 15h
560 ; keyboard interrupt callout from real mode.
561 ;
562 ;   Entry:  AX  - Hardware scan code to process
563 ;   Exit:   AX  - Hardware scan code to process (0 to ignore)
564 ;----------------------------------------------------------------------------
565 cprocfar    _PM_key15ISR
566
567         push    ds
568         push    es
569         LOAD_DS
570         cmp     ah,4Fh
571         jnz     @@NotOurs       ; Quit if not keyboard callout
572
573         pushad
574         cld                     ; Clear direction flag
575         xor     ah,ah           ; AX := scan code
576         NEWSTK  Ky15Stack       ; Switch to local stack
577         push    _ax
578         call    [CPTR _PM_key15Handler] ; Call C code
579         _add    sp,2,4
580         RESTSTK Ky15Stack       ; Restore previous stack
581         test    ax,ax
582         jz      @@1
583         stc                     ; Set carry to process as normal
584         jmp     @@2
585 @@1:    clc                     ; Clear carry to ignore scan code
586 @@2:    popad
587         jmp     @@Exit          ; We are done
588
589 @@NotOurs:
590 ifdef   TNT
591         push    eax
592         push    ebx
593         push    ecx
594         pushfd                  ; Push flags on stack to simulate interrupt
595         mov     ax,250Eh        ; Call real mode procedure function
596         mov     ebx,[_PM_prevRealKey15]
597         mov     ecx,1           ; Copy real mode flags to real mode stack
598         int     21h             ; Call the real mode code
599         popfd
600         pop     ecx
601         pop     ebx
602         pop     eax
603 else
604         pushf
605 ifdef   USE_NASM
606         call far dword [_PM_prevKey15]
607 else
608         call    [_PM_prevKey15]
609 endif
610 endif
611 @@Exit: pop     es
612         pop     ds
613         retf    4
614
615 cprocend
616
617 ;----------------------------------------------------------------------------
618 ; PM_breakISR - Control Break interrupt subroutine dispatcher
619 ;----------------------------------------------------------------------------
620 ; Hardware interrupt handler for the Ctrl-Break interrupt. We simply set
621 ; the Ctrl-Break flag to a 1 and leave (note that this is accessed through
622 ; a far pointer, as it may well be located in conventional memory).
623 ;----------------------------------------------------------------------------
624 cprocfar    _PM_breakISR
625
626         sti
627         push    ds              ; Save value of DS
628         push    es
629         push    _bx
630
631         LOAD_DS                 ; Load DS register
632         mov     ebx,[_PM_ctrlBPtr]
633         mov     [UINT _ES _bx],1
634
635 ; Run alternate break handler code if installed
636
637         cmp     [CPTR _PM_breakHandler],0
638         je      @@Exit
639
640         pushad
641         mov     _ax,1
642         push    _ax
643         call    [CPTR _PM_breakHandler] ; Call C code
644         pop     _ax
645         popad
646
647 @@Exit: pop     _bx
648         pop     es
649         pop     ds
650         iret                    ; Return from interrupt
651
652 cprocend
653
654 ;----------------------------------------------------------------------------
655 ; int PM_ctrlBreakHit(int clearFlag)
656 ;----------------------------------------------------------------------------
657 ; Returns the current state of the Ctrl-Break flag and possibly clears it.
658 ;----------------------------------------------------------------------------
659 cprocstart  PM_ctrlBreakHit
660
661         ARG     clearFlag:UINT
662
663         enter_c
664         pushf                   ; Save interrupt status
665         push    es
666         mov     ebx,[_PM_ctrlBPtr]
667         cli                     ; No interrupts thanks!
668         mov     _ax,[_ES _bx]
669         test    [BYTE clearFlag],1
670         jz      @@Done
671         mov     [UINT _ES _bx],0
672
673 @@Done: pop     es
674         popf                    ; Restore interrupt status
675         leave_c
676         ret
677
678 cprocend
679
680 ;----------------------------------------------------------------------------
681 ; PM_ctrlCISR - Control Break interrupt subroutine dispatcher
682 ;----------------------------------------------------------------------------
683 ; Hardware interrupt handler for the Ctrl-C interrupt. We simply set
684 ; the Ctrl-C flag to a 1 and leave (note that this is accessed through
685 ; a far pointer, as it may well be located in conventional memory).
686 ;----------------------------------------------------------------------------
687 cprocfar    _PM_ctrlCISR
688
689         sti
690         push    ds              ; Save value of DS
691         push    es
692         push    _bx
693
694         LOAD_DS                 ; Load DS register
695         mov     ebx,[_PM_ctrlCPtr]
696         mov     [UINT _ES _bx],1
697
698 ; Run alternate break handler code if installed
699
700         cmp     [CPTR _PM_breakHandler],0
701         je      @@Exit
702
703         pushad
704         mov     _ax,0
705         push    _ax
706         call    [CPTR _PM_breakHandler] ; Call C code
707         pop     _ax
708         popad
709
710 @@Exit: pop     _bx
711         pop     es
712         pop     ds
713         iret                    ; Return from interrupt
714         iretd
715
716 cprocend
717
718 ;----------------------------------------------------------------------------
719 ; int PM_ctrlCHit(int clearFlag)
720 ;----------------------------------------------------------------------------
721 ; Returns the current state of the Ctrl-C flag and possibly clears it.
722 ;----------------------------------------------------------------------------
723 cprocstart  PM_ctrlCHit
724
725         ARG     clearFlag:UINT
726
727         enter_c
728         pushf                   ; Save interrupt status
729         push    es
730         mov     ebx,[_PM_ctrlCPtr]
731         cli                     ; No interrupts thanks!
732         mov     _ax,[_ES _bx]
733         test    [BYTE clearFlag],1
734         jz      @@Done
735         mov     [UINT _ES _bx],0
736
737 @@Done:
738         pop     es
739         popf                    ; Restore interrupt status
740         leave_c
741         ret
742
743 cprocend
744
745 ;----------------------------------------------------------------------------
746 ; PM_criticalISR - Control Error handler interrupt subroutine dispatcher
747 ;----------------------------------------------------------------------------
748 ; Interrupt handler for the MSDOS Critical Error interrupt, to dispatch
749 ; control to high level C based subroutines. We save the state of all
750 ; registers in this routine, and switch to a local stack. We also pass
751 ; the values of the AX and DI registers to the as pointers, so that the
752 ; values can be modified before returning to MSDOS.
753 ;----------------------------------------------------------------------------
754 cprocfar    _PM_criticalISR
755
756         sti
757         push    ds              ; Save value of DS
758         push    es
759         push    _bx             ; Save register values changed
760         cld                     ; Clear direction flag
761
762         LOAD_DS                 ; Load DS register
763         mov     ebx,[_PM_critPtr]
764         mov     [_ES _bx],ax
765         mov     [_ES _bx+2],di
766
767 ; Run alternate critical handler code if installed
768
769         cmp     [CPTR _PM_critHandler],0
770         je      @@NoAltHandler
771
772         pushad
773         push    _di
774         push    _ax
775         call    [CPTR _PM_critHandler]  ; Call C code
776         _add    sp,4,8
777         popad
778
779         pop     _bx
780         pop     es
781         pop     ds
782         iret                    ; Return from interrupt
783
784 @@NoAltHandler:
785         mov     ax,3            ; Tell MSDOS to fail the operation
786         pop     _bx
787         pop     es
788         pop     ds
789         iret                    ; Return from interrupt
790
791 cprocend
792
793 ;----------------------------------------------------------------------------
794 ; int PM_criticalError(int *axVal,int *diVal,int clearFlag)
795 ;----------------------------------------------------------------------------
796 ; Returns the current state of the critical error flags, and the values that
797 ; MSDOS passed in the AX and DI registers to our handler.
798 ;----------------------------------------------------------------------------
799 cprocstart  PM_criticalError
800
801         ARG     axVal:DPTR, diVal:DPTR, clearFlag:UINT
802
803         enter_c
804         pushf                   ; Save interrupt status
805         push    es
806         mov     ebx,[_PM_critPtr]
807         cli                     ; No interrupts thanks!
808         xor     _ax,_ax
809         xor     _di,_di
810         mov     ax,[_ES _bx]
811         mov     di,[_ES _bx+2]
812         test    [BYTE clearFlag],1
813         jz      @@NoClear
814         mov     [ULONG _ES _bx],0
815 @@NoClear:
816         _les    _bx,[axVal]
817         mov     [_ES _bx],_ax
818         _les    _bx,[diVal]
819         mov     [_ES _bx],_di
820         pop     es
821         popf                    ; Restore interrupt status
822         leave_c
823         ret
824
825 cprocend
826
827 ;----------------------------------------------------------------------------
828 ; void PM_setMouseHandler(int mask, PM_mouseHandler mh)
829 ;----------------------------------------------------------------------------
830 cprocstart  _PM_setMouseHandler
831
832         ARG     mouseMask:UINT
833
834         enter_c
835         push    es
836
837         mov     ax,0Ch          ; AX := Function 12 - install interrupt sub
838         mov     _cx,[mouseMask] ; CX := mouse mask
839         mov     _dx,offset _PM_mouseISR
840         push    cs
841         pop     es              ; ES:_DX -> mouse handler
842         int     33h             ; Call mouse driver
843
844         pop     es
845         leave_c
846         ret
847
848 cprocend
849
850 ;----------------------------------------------------------------------------
851 ; void PM_mousePMCB(void)
852 ;----------------------------------------------------------------------------
853 ; Mouse realmode callback routine. Upon entry to this routine, we recieve
854 ; the following from the DPMI server:
855 ;
856 ;   Entry:  DS:_SI  -> Real mode stack at time of call
857 ;           ES:_DI  -> Real mode register data structure
858 ;           SS:_SP  -> Locked protected mode stack to use
859 ;----------------------------------------------------------------------------
860 cprocfar    _PM_mousePMCB
861
862         pushad
863         mov     eax,[es:_di+1Ch]    ; Load register values from real mode
864         mov     ebx,[es:_di+10h]
865         mov     ecx,[es:_di+18h]
866         mov     edx,[es:_di+14h]
867         mov     esi,[es:_di+04h]
868         mov     edi,[es:_di]
869         call    _PM_mouseISR        ; Call the mouse handler
870         popad
871
872         mov     ax,[ds:_si]
873         mov     [es:_di+2Ah],ax     ; Plug in return IP address
874         mov     ax,[ds:_si+2]
875         mov     [es:_di+2Ch],ax     ; Plug in return CS value
876         add     [WORD es:_di+2Eh],4 ; Remove return address from stack
877         iret                        ; Go back to real mode!
878
879 cprocend
880
881 ;----------------------------------------------------------------------------
882 ; void PM_int10PMCB(void)
883 ;----------------------------------------------------------------------------
884 ; int10 realmode callback routine. Upon entry to this routine, we recieve
885 ; the following from the DPMI server:
886 ;
887 ;   Entry:  DS:ESI  -> Real mode stack at time of call
888 ;           ES:EDI  -> Real mode register data structure
889 ;           SS:ESP  -> Locked protected mode stack to use
890 ;----------------------------------------------------------------------------
891 cprocfar        _PM_int10PMCB
892
893         pushad
894         push    ds
895         push    es
896         push    fs
897
898         pushfd
899         pop     eax
900         mov     [es:edi+20h],ax     ; Save return flag status
901         mov     ax,[ds:esi]
902         mov     [es:edi+2Ah],ax     ; Plug in return IP address
903         mov     ax,[ds:esi+2]
904         mov     [es:edi+2Ch],ax     ; Plug in return CS value
905         add     [WORD es:edi+2Eh],4 ; Remove return address from stack
906
907 ; Call the install int10 handler in protected mode. This function gets called
908 ; with DS set to the current data selector, and ES:EDI pointing the the
909 ; real mode DPMI register structure at the time of the interrupt. The
910 ; handle must be written in assembler to be able to extract the real mode
911 ; register values from the structure
912
913         push    es
914         pop     fs                  ; FS:EDI -> real mode registers
915         LOAD_DS
916         NEWSTK  Int10Stack          ; Switch to local stack
917
918         call    [_PM_int10Handler]
919
920         RESTSTK Int10Stack          ; Restore previous stack
921         pop     fs
922         pop     es
923         pop     ds
924         popad
925         iret                        ; Go back to real mode!
926
927 cprocend
928
929 cpublic _PM_pmsmxCodeEnd
930
931 endcodeseg  _pmsmx
932
933         END                     ; End of module