home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / c / tsr_asm.arc / TSR.ASM < prev   
Assembly Source File  |  1988-08-05  |  50KB  |  1,483 lines

  1. page    60,132
  2. ; Copyright 1987 by Thomas Brandenborg. All Rights Reserved
  3. ; Written for uploading to Compuserve Forums by
  4. ;
  5. ;       Thomas Brandenborg
  6. ;       Lundbyesgade 11
  7. ;       DK-8000 Aarhus C
  8. ;       DENMARK
  9. ;
  10. ; Modified to work under Lattice-C S model version 2.14
  11. ; might work under newer versions as well
  12. ; H.F. van Rietschote
  13. ;
  14. ;    You write cpopup() in Lattice-C and you have a popup
  15. ;    go and become TSR after calling intdos() with ax=0x3100 and dx=_TSIZE
  16. ;    but after this no more MALLOC(), also not indirect ia fopen() etc.
  17. ;    allowed.
  18.  
  19. DGROUP    GROUP    DATA
  20. DATA    SEGMENT    WORD    PUBLIC    'DATA'
  21.     ASSUME    DS:DGROUP
  22. DATA    ENDS
  23.  
  24. ;==============================================================================
  25. ; DEFINE BIOS DATA SEGMENT OFFSETS
  26. ;==============================================================================
  27.  
  28. BiosData    segment at 40h
  29.         org     17h
  30. KbFlag        label   byte            ;current shift status bits
  31.         org     18h
  32.  
  33. KbFlag1         label   byte            ;current key status of toggle keys
  34. BiosData        ends
  35.  
  36. ;==============================================================================
  37. ; DEFINE OFFSETS WITHIN BIOS EXTRA DATA SEGMENT
  38. ;==============================================================================
  39.  
  40. BiosXX          segment at 50h
  41.         org     0
  42. StatusByte      label   byte            ;PrtSc status
  43. BiosXX          ends
  44.  
  45. ErrPrtSc        equ     -1              ;err during last PrtSc
  46. InPrtSc         equ     1               ;PrtSc in progress
  47.  
  48. ;==============================================================================
  49. ; DEFINE OFFSETS WITHIN OUR PSP
  50. ;==============================================================================
  51.  
  52. PGROUP        GROUP    PROG
  53. PROG        SEGMENT    BYTE PUBLIC 'PROG'
  54.         public    tsr,ErrBeep,Bleep
  55.         extrn    cpopup:near
  56.         assume    cs:PGROUP, ds:nothing, es:nothing, ss:nothing
  57.  
  58. ;==============================================================================
  59. ; IDENTIFICATION CODES FOR THIS TSR (MUST BE UNIQUE FOR EACH CO-EXISTING TSR)
  60. ; HIGH BYTE OF GetId MUST NOT MATCH ANY AH REQUEST CODES FOR INT16H.
  61. ;==============================================================================
  62.  
  63. GetId           equ     'tc'            ;INT16h AX val to get MyId
  64. MyId            equ     'TC'            ;ID of this TSR
  65. SetAlarm    equ    'al'            ; set alarm, BX= # of min. to wait
  66.  
  67. ;==============================================================================
  68. ; FLAGS AND PTRS FOR RESIDENT HANDLING
  69. ;==============================================================================
  70.  
  71. TsrMode         db      0               ;bits for various modes
  72. InInt08         equ     1 SHL 0         ;timer0 tick handler
  73. InInt09         equ     1 SHL 1         ;keyboard handler
  74. InInt13         equ     1 SHL 2         ;BIOS disk I/O
  75. InInt28         equ     1 SHL 3         ;INT28 handler
  76. In28Call        equ     1 SHL 4         ;we have issued INT28
  77. InPopup         equ     1 SHL 5         ;popup routine activated
  78. NewDos          equ     1 SHL 6         ;DOS 2.x in use
  79. InDosClr        equ     1 SHL 7         ;InDos=0 at popup time
  80.  
  81. KeyMode         db      0               ;bits for hotkey status
  82. HotIsShift      equ     1 SHL 0         ;hotkey is shift state
  83. InHotMatch      equ     1 SHL 1         ;so far keys match hotkey seq
  84. HotKeyOn        equ     1 SHL 2         ;full hotkey pressed
  85.  
  86. InDosPtr        label   dword           ;seg:off of InDos flag
  87. InDosOff        dw      0
  88. InDosSeg        dw      0
  89.  
  90. CritErrPtr      label   dword           ;seg:off of CritErr flag
  91. CritErrOff      dw      0
  92. CritErrSeg      dw      0
  93.  
  94. ;==============================================================================
  95. ; DATA FOR INT09H HANDLER TO CHECK FOR HOTKEY COMBINATION
  96. ;==============================================================================
  97.  
  98. ; ------------  EQU'S FOR BIT SHIFTS WITHIN KEYBOARD FLAGS
  99.  
  100. InsState        equ     80h
  101. CapsState       equ     40h
  102. NumState        equ     20h
  103. ScrollState     equ     10h
  104. AltShift        equ     08h
  105. CtlShift        equ     04h
  106. LeftShift       equ     02h
  107. RightShift      equ     01h
  108.  
  109. InsShift        equ     80h
  110. CapsShift       equ     40h
  111. NumShift        equ     20h
  112. ScrollShift     equ     10h
  113. HoldState       equ     08h
  114.  
  115. ; ------------  SCAN CODES FOR VARIOUS SHIFT KEYS
  116.  
  117. LeftDown        equ     42              ;scan code of left shift key
  118. LeftUp          equ     LeftDown OR 80h
  119. RightDown       equ     54              ;scan code of right shift key
  120. RightUp         equ     RightDown OR 80h
  121. AltDown         equ     56              ;scan code of alt key
  122. AltUp           equ     AltDown OR 80h
  123. CtlDown         equ     29              ;scan code of ctrl key
  124. CtlUp           equ     CtlDown OR 80h
  125.  
  126. ; ------------  MISC KEYBOARD DATA
  127.  
  128. KbData          equ     60h             ;keyboard data input
  129.  
  130. ;==============================================================================
  131. ; TO USE A SHIFT KEY COMBINATION AS HOT KEY:
  132. ;  -    SET THE FLAG HotIsShift IN KeyMode
  133. ;  -    DEFINE THE SHIFT STATUS BITS IN THE VARIABLE HotKeyShift
  134. ;
  135. ; TO USE A SERIES OF SCAN CODES AS HOT KEY:
  136. ;       CLEAR THE FLAG HotIsShift IN KeyMode
  137. ;  -    INSERT THE MAKE AND BREAK SCAN CODES IN THE HotKeySeq STRING
  138. ;       NOTE:   WITH THIS DEMO IMPLEMENTATION YOU SHOULD NOT USE A HOT KEY
  139. ;               SEQUENCE WHICH PRODUCES A KEY IN THE BIOS KEYBOARD QUEUE,
  140. ;               SINCE THE KEY IS NOT REMOVED BEFORE CALLING THE POPUP ROUTINE.
  141. ;
  142. ; NOTE: HOTKEY TYPE AND CONTENTS OF HOTKEY VARIABLES MAY BE CHANGED AT RUN TIME
  143. ;==============================================================================
  144.  
  145. HotKeyShift     db      LeftShift OR RightShift ;shift state IF HotIsShift=FF
  146.  
  147. ; HotKeySeq       db      LeftDown,LeftUp,LeftDown,LeftUp
  148. HotKeySeq       db      LeftDown,LeftUp,RightDown,RightUp
  149. HotKeyLen       equ     $-HotKeySeq
  150. HotIndex        db      0               ;# key in seq to compare next
  151. BetweenKeys     db      0               ;timeout count between keys
  152. KeyTimeOut      equ     10              ;more ticks means not a hotkey
  153.  
  154. ;==============================================================================
  155. ; DATA FOR INT08H HANDLER TO CHECK FOR POPUP
  156. ;==============================================================================
  157.  
  158. SafeWait        db      0               ;count-down for safe popup
  159. MaxWait         equ     8               ;wait no more 8/18 sec
  160. MinLeft        dw    0            ; minutes left until alarm
  161. TicksDone    dw    0            ; Ticks counted in this minute
  162. Bleeping    dw    0            ; 1 means we are bleeping
  163.  
  164. ;==============================================================================
  165. ; PROCESS & SYSTEM DATA
  166. ;==============================================================================
  167.  
  168. OurSS           dw      0               ;stack for popup routine
  169. OurSP           dw      0
  170. OurES        dw    0
  171. OurBP        dw    0
  172. OurDS        dw    0
  173. DSLattice    dw    0        ; DS as in Lattice-C
  174.  
  175. OldSS           dw      0               ;old stack seg
  176. OldSP           dw      0               ;old stack off
  177. OldES        dw    0
  178. OldBP        dw    0
  179. OldDS        dw    0
  180.  
  181. OurPSP          dw      0               ;our PSP seg
  182. OldPSP          dw      0               ;old PSP seg
  183.  
  184. OldDTA          label   dword           ;seg:off of old DTA area
  185. OldDTAOff       dw      0
  186. OldDTASeg       dw      0
  187.  
  188. OurDTA          label   dword           ;seg:off of our DTA
  189. OurDTAOff       dw      0
  190. OurDTASeg       dw      0
  191.  
  192. OldBreak        db      0               ;old ctrl-break state
  193. OldExtErr       dw      3 dup (0)               ;AX,BX,CX of ext err
  194.  
  195. ;==============================================================================
  196. ; LOCATIONS FOR SAVED INTERRUPT VECTORS
  197. ;==============================================================================
  198.  
  199. OldInt08        label   dword           ;Timer0 loaded before this
  200. OldInt08Off     dw      0
  201. OldInt08Seg     dw      0
  202.  
  203. OldInt09        label   dword           ;Kb handler loadde before this
  204. OldInt09Off     dw      0
  205. OldInt09Seg     dw      0
  206.  
  207. OldInt13        label   dword           ;BIOS diskette I/O
  208. OldInt13Off     dw      0
  209. OldInt13Seg     dw      0
  210.  
  211. OldInt16        label   dword           ;BIOS kb Q-handler
  212. OldInt16Off     dw      0
  213. OldInt16Seg     dw      0
  214.  
  215. OldInt1B        label   dword           ;^break of process we steal
  216. OldInt1BOff     dw      0
  217. OldInt1BSeg     dw      0
  218.  
  219. OldInt1C        label   dword           ;timer tick of process we steal
  220. OldInt1COff     dw      0
  221. OldInt1CSeg     dw      0
  222.  
  223. OldInt21        label   dword           ;DOS function dispatcher
  224. OldInt21Off     dw      0
  225. OldInt21Seg     dw      0
  226.  
  227. OldInt23        label   dword           ;^C of process we steal
  228. OldInt23Off     dw      0
  229. OldInt23Seg     dw      0
  230.  
  231. OldInt24        label   dword           ;crit err of process we steal
  232. OldInt24Off     dw      0
  233. OldInt24Seg     dw      0
  234.  
  235. OldInt28        label   dword           ;DOS idles loaded before this
  236. OldInt28Off     dw      0
  237. OldInt28Seg     dw      0
  238.  
  239. ;==============================================================================
  240. ; SPEAKER/TONE GENERATION DATA
  241. ;==============================================================================
  242.  
  243. PB0port         equ     61h             ;port for speaker bit
  244. ErrLen1         equ     10              ;# outer err beep cycles
  245. ErrLen2         equ     80              ;# inner err beep cycles
  246. ErrLow          equ     100             ;low tone wait in err beep
  247. ErrHi           equ     40              ;hi tone wait in err beep
  248.  
  249. ;==============================================================================
  250. ; ErrBeep - PRODUCE ERROR-INDICATING SOUND ON SPEAKER
  251. ;==============================================================================
  252.  
  253. ErrBeep         proc    near
  254.         assume  ds:nothing, es:nothing, ss:nothing
  255.  
  256.         push    bp
  257.         push    ax              ;save regs used
  258.         push    bx
  259.         push    cx
  260.         push    dx
  261.  
  262.         mov     cx,ErrLen1              ;# mix-cycles for beep
  263.  
  264. ErrBeep1:       mov     dx,ErrLow               ;wait time for half-cycle
  265.         mov     bx,ErrLen2              ;len of one tone
  266.         call    DoTone          ;output low err tone
  267.         mov     dx,ErrHi        ;wait time for half-cycle
  268.         mov     bx,ErrLen2              ;len of one tone
  269.         call    DoTone          ;output low err tone
  270.  
  271.         loop    ErrBeep1        ;loop for some time
  272.  
  273.         pop     dx
  274.         pop     cx              ;restore regs
  275.         pop     bx
  276.         pop     ax
  277.         pop    bp
  278.         ret
  279. ErrBeep         endp
  280.  
  281. ;==============================================================================
  282. ; DoTone - OUTPUT ONE TONE ON THE SPEAKER
  283. ;
  284. ; INPUT:        DX:     LOOP WAIT TIME FOR HALF CYCLE IN TONE
  285. ;               BX:     NUMBER OF CYCLES FOR TONE DURATION
  286. ; OUTPUT:       NONE
  287. ; REGS:         ALL PRESERVED
  288. ;==============================================================================
  289.  
  290. Bleep        proc    near            ; short bleep for in "C"
  291.         assume  ds:nothing, es:nothing, ss:nothing
  292.  
  293.         push    bp
  294.         push    dx
  295.         push    bx
  296.         mov     dx,ErrLow               ;wait time for half-cycle
  297.         mov     bx,ErrLen2              ;len of one tone
  298.         call    DoTone
  299.         pop    bx
  300.         pop    dx
  301.         pop    bp
  302.         ret
  303. Bleep        endp
  304.  
  305. DoTone          proc    near
  306.         assume  ds:nothing, es:nothing, ss:nothing
  307.  
  308.         push    ax              ;save regs used
  309.         push    bx
  310.         push    cx
  311.         in      al,PB0port              ;get PB0 reg pattern
  312.         mov     ah,al           ;save it
  313.  
  314. DoTone1:        and     al,0fch         ;mask off speaker bit
  315.         out     PB0port,al              ;pull!
  316.         mov     cx,dx           ;half cycle in counter
  317. DoTone2:        loop    DoTone2         ;leave there for half a cycle
  318.         or      al,2            ;turn on speaker bit
  319.         out     PB0port,al              ;push!
  320.         mov     cx,dx           ;half cycle in counter
  321. DoTone3:        loop    DoTone3         ;leave there for half a cycle
  322.  
  323.         dec     bx              ;count down tone duration
  324.         jnz     DoTone1         ;go through full tone
  325.  
  326.         mov     al,ah           ;AL=original PB0 reg value
  327.         out     PB0port,al              ;restore
  328.  
  329.         pop     cx              ;restore regs
  330.         pop     bx
  331.         pop     ax
  332.         ret
  333. DoTone          endp
  334.  
  335. ;==============================================================================
  336. ; TestSafe - CHECK IF THIS IS A SAFE TIME TO DO A POP UP
  337. ;
  338. ; RETURN CLC IF SAFE TO POP UP, CY IF NOT SAFE.
  339. ;
  340. ; CHECK IF ANY INTs ARE IN CRITICAL AREAS (InInt09 & InInt13)
  341. ; CHECK IF WE ARE IN AN OUR OWN INT28 CALL (In28Call)
  342. ; CHECK 8259A PIC ISR REGISTER FOR MISSING EOIs
  343. ; CHECK IF DOS IS STABLE FOR POP UP
  344. ; CHECK IF A PRINT SCREEN IS IN PROGRESS
  345. ;==============================================================================
  346.  
  347. TestSafe        proc    near
  348.         assume  ds:nothing, es:nothing
  349.  
  350.         push    ax              ;save regs used
  351.         push    bx
  352.         push    ds
  353.  
  354. ; ------------  CHECK INTs TO SEE IF THEY WERE INTERRUPTED AT BAD TIMES
  355.  
  356.         test    TsrMode,InInt09 OR InInt13 OR In28Call
  357.         jnz     NotSafe         ;jump if any INTs are chopped
  358.  
  359. ; ------------  CHECK THE 8259A PIC ISR REGISTER FOR NON-EOIed HW INTs
  360.  
  361.         mov     al,00001011b            ;tell 8259A we want the ISR
  362.         out     20h,al          ;8259A command reg
  363.         nop
  364.         nop
  365.         nop                     ;now, ISR should be ready
  366.         in      al,20h          ;AL=mask of active INTs
  367.         or      al,al           ;test all (IRQ0 *did* EOI)
  368.         jnz     NotSafe         ;jump if active INTs
  369.  
  370. ; ------------  NOW, ENSURE THAT DOS WAS NOT INTERRUPTED
  371.  
  372.         assume  ds:nothing
  373.  
  374.         lds     bx,InDosPtr             ;now, DS:BX=InDos
  375.         mov     al,byte ptr [bx]        ;get InDos to AL
  376.         lds     bx,CritErrPtr           ;now, DS:BX=CritErr
  377.         or      al,byte ptr [bx]        ;both flags zero?
  378.         jz      DosSafe         ;YES - DOS is really idle
  379.         test    TsrMode,InInt28         ;is this an INT28h
  380.         jz      NotSafe         ;NO - not safe, should be idle
  381.         cmp     al,1            ;YES - one InDos entry only?
  382.         ja      NotSafe         ;NO - jump if more than one
  383. DosSafe:
  384.  
  385. ; ------------  CHECK TO SEE IF A PRINT SCREEN IS IN PROGRESS
  386.  
  387.         mov     ax,BiosXX
  388.         mov     ds,ax           ;move DS to BIOS extra data seg
  389.         assume  ds:BiosXX
  390.  
  391.         cmp     StatusByte,InPrtSc      ;print screen in progress?
  392.         je      NotSafe         ;YES - jump if prtsc
  393.  
  394. ; ------------  SEEMS TO BE A SAFE TIME FOR POPUP
  395.  
  396. IsSafe:         clc                     ;CLC=safe to popup
  397.         jmp     short ExitSafe          ;end this then
  398.  
  399. ; ------------  APPARENTLY THIS IS JUST NOT THE TIME TO DO A POPUP
  400.  
  401. NotSafe:        stc                     ;CY=don't popup now
  402.  
  403. ; ------------  RETURN TO CALLER WITH CARRY SET/CLEAR
  404.  
  405. ExitSafe:       pop     ds              ;restore regs
  406.         pop     bx
  407.         pop     ax
  408.         ret
  409. TestSafe        endp
  410.  
  411. ;==============================================================================
  412. ; OurInt08 - TSR INT08H HANDLER TO WATCH FOR HOTKEY AND SAFE POPUP TIMES
  413. ;
  414. ; CALL OldInt08
  415. ; CHECK FOR RE-ENTRANCE INTO CRITICAL INT08 CODE
  416. ; SET InInt08 FLAG
  417. ; CHECK FOR TIMEOUT BETWEEN KEYS IN HOTKEY SEQUENCE
  418. ; CHECK IF HOTKEY WAS PRESSED
  419. ; CHECK IF ALREADY InPopup OR InInt28
  420. ; CHECK IF SAFE TIME FOR SYSTEM TO POPUP
  421. ; UPDATE FLAGS AND CALL POPUP IF SAFE
  422. ; GIVE ERROR BEEP IF POPUP WAS UNSAFE FOR A LONG TIME
  423. ; RESET InInt08 FLAG
  424. ; DO IRET
  425. ;==============================================================================
  426.  
  427. ; ------------  NEAR JUMP DESTINATION FOR FAST IRET'S
  428.  
  429. Exit08:         iret                    ;IRET (!)
  430.  
  431. ; ------------  ACTUAL INT08 ENTRY POINT
  432.  
  433. OurInt08        proc    far
  434.         assume  ds:nothing, es:nothing, ss:nothing
  435.  
  436.         pushf                   ;simulate INT08
  437.         cli                     ;in case others forgot it
  438.         call    OldInt08        ;call TSRs loaded before us
  439.  
  440. ; -- see if waiting for alarm
  441.  
  442.         cmp    MinLeft,0    ; see if we are waiting for alarm
  443.         je    NoAlarm
  444.         inc    TicksDone    ; one more tick done
  445.         cmp    TicksDone,1092
  446.         jne    NoMinute
  447.         dec    MinLeft        ; one less minute to wait
  448.         mov    TicksDone,0    ; reset count
  449. NoMinute:    cmp    MinLeft,1    ; is this last minute, if so bleep
  450.         jne    NoBleep
  451.         inc    Bleeping    ; we only bleep every 2 seconds
  452.         cmp    Bleeping,37    ; 37  is little more than 2 second
  453.         jne    NoBleep
  454.         call    ErrBeep
  455.         mov    Bleeping,0    ; wait 2 second until next bleep
  456. NoBleep:
  457.  
  458. ; ------------  ENSURE NO RECURSION INTO CRITICAL INT08 CODE
  459.  
  460. NoAlarm:    sti                     ;we'll manage INTs
  461.  
  462.         test    TsrMode,InInt08         ;already in here somewhere?
  463.         jnz     Exit08          ;YES - don't re-enter
  464.         or      TsrMode,InInt08         ;tell people we are here
  465.  
  466.         push    ax              ;need a few regs in this code
  467.  
  468. ; ------------  COUNT DOWN TIME-OUT BETWEEN KEYS IN HOTKEY SEQUENCE
  469.  
  470.         test    KeyMode,InHotMatch      ;are we in a key match?
  471.         jz      TestHot08               ;NO - don't care then
  472.         dec     BetweenKeys             ;count down timeout val
  473.         jnz     TestHot08               ;jump if no timeout yet
  474.         mov     HotIndex,0              ;start match from beginning
  475.         and     KeyMode,not InHotMatch  ;just so we know it next time
  476.  
  477. ; ------------  CHECK FOR POSSIBLE POPUP ACTIONS
  478.  
  479. TestHot08:      test    KeyMode,HotKeyOn        ;has hotkey been pressed?
  480.         jz      ExitInt08               ;NO - jump if no fun here
  481.  
  482.         test    TsrMode,InInt28 OR InPopup
  483.         jnz     ExitInt08               ;jmp if not alr in business
  484.  
  485. ; ------------  HOTKEY PRESSED, CHECK TO SEE IF IT IS SAFE TO POPUP
  486.  
  487.         cmp     SafeWait,0              ;first time we find hotkey?
  488.         ja      TestSafe08              ;NO - wait has alr been set
  489.         mov     SafeWait,MaxWait        ;# ticks to wait at most
  490.  
  491. TestSafe08:     call    TestSafe        ;now, CY clear if popup is safe
  492.         jc      NotSafe08               ;jump if popup is bad idea
  493.  
  494. ; ------------  SEEMS SAFE TO POPUP AT THIS TIME, SO DO!
  495.  
  496.         xor     al,al           ;fast zero
  497.         mov     SafeWait,al             ;don't count any more
  498.         and     KeyMode,not HotKeyOn    ;clear hotkey status
  499.         or      TsrMode,InPopup         ;tell'em we enter popup routine
  500.         and     TsrMode,not InInt08     ;OK to enter critical INT08
  501.         call    InitPopup               ;do actual popup
  502.         or      TsrMode,InInt08         ;back in INT08 code here
  503.         and     TsrMode,not InPopup     ;not in popup code any more
  504.         mov     SafeWait,al             ;in case of hotkey during popup
  505.         and     KeyMode,not HotKeyOn    ;clear hotkey status
  506.  
  507.         jmp     short ExitInt08         ;finally done
  508.  
  509. ; ------------  UNSAFE POPUP TIME, COUNT DOWN SafeWait
  510.  
  511. NotSafe08:      dec     SafeWait        ;count down waiter
  512.         jnz     ExitInt08               ;jump if still no timeout
  513.  
  514. ; ------------  NO SAFE TIMES FOUND FOR QUITE SOME TIME, ERROR
  515.  
  516.         and     KeyMode,not HotKeyOn    ;might as well clear hotkey
  517.         call    ErrBeep         ;do an error beep
  518.  
  519. ; ------------  NORMAL INT08H EXIT, RESET InInt08
  520.  
  521. ExitInt08:      pop     ax              ;restore regs used
  522.         and     TsrMode,not InInt08     ;clear that flag
  523.         iret                    ;straight back
  524. OurInt08        endp
  525.  
  526. ;==============================================================================
  527. ; OurInt09 - TSR INT09H HANDLER TO WATCH FOR HOTKEY
  528. ;
  529. ; SAVE SCAN CODE
  530. ; CALL OldInt09
  531. ; CHECK FOR RECURSION INTO CRITICAL INT09 CODE
  532. ; SET InInt09 FLAG
  533. ; CHECK IF HOTKEY ALREADY SET
  534. ; DETERMINE HOTKEY TYPE (SHIFT STATE OR KEY SEQENCE)
  535. ; CHECK SHIFT STATE IF HotIsShift
  536. ; COMPARE FOR KEY MATCH IF (NOT HotIsShift)
  537. ; SET HotKeyOn IF HOTKEY PRESSED
  538. ; RESET InInt09 FLAG
  539. ; DO IRET
  540. ;==============================================================================
  541.  
  542. ; ------------  NEAR JUMP DESTINATION FOR EARLY EXITS
  543.  
  544. Exit09:         pop     bx              ;restore regs
  545.         pop     ax
  546.         iret                    ;flags restored from stack
  547.  
  548. ; ------------  ACTUAL INT09 ENTRY POINT
  549.  
  550. OurInt09        proc    far
  551.         assume  ds:nothing, es:nothing, ss:nothing
  552.  
  553.         push    ax              ;save regs used
  554.         push    bx
  555.  
  556. ; ------------  READ SCAN CODE, IN CASE SEQUENCE MATCHING SELECTED
  557.  
  558.         in      al,KbData               ;Al=key, preserved by BIOS
  559.  
  560. ; ------------  CALL BIOS TO PERFORM IT'S DUTIES
  561.  
  562.         pushf                   ;simulate INT (CLI alr set)
  563.         cli                     ;in case others forgot it
  564.         call    OldInt09        ;call BIOS/earlier TSRs
  565.  
  566. ; ------------  ENSURE NO RECURSION INTO CRITICAL INT09 CODE
  567.  
  568.         sti                     ;we'll manage INTs
  569.  
  570.         test    TsrMode,InInt09         ;alr in business?
  571.         jnz     Exit09          ;YES - skip test till clear
  572.         or      TsrMode,InInt09         ;tell them we arrived here
  573.  
  574. ; ------------  DETERMINE HOT KEY TYPE SELECTED
  575.  
  576.         test    KeyMode,HotKeyOn        ;already hotkey there?
  577.         jnz     ExitInt09               ;YES - no double hotkeys here
  578.  
  579.         test    KeyMode,HotIsShift      ;shift state type hotkey?
  580.         jz      CompSeq09               ;NO - go compare sequence
  581.  
  582. ; ------------  COMPARE CURRENT SHIFT STATUS AGAINST HOTKEY
  583.  
  584.         push    ds              ;save current ds
  585.         mov     ax,BiosData             ;move DS to BIOS data seg
  586.         mov     ds,ax           ;DS can now access keyb vars
  587.         assume  ds:BiosData             ;tell MASM about our DS
  588.         mov     al,KbFlag               ;get BIOS shift state bits
  589.         pop     ds              ;restore
  590.         assume  ds:nothing              ;last thing we know about him
  591.  
  592.         and     al,HotKeyShift          ;isolate relevant bits
  593.         cmp     al,HotKeyShift          ;our shift state in effect?
  594.         jne     ExitInt09               ;NO - not that shift state
  595.         or      KeyMode,HotKeyOn        ;YES - flag hotkey
  596.         jmp     short ExitInt09         ;now we can be proud to leave
  597.  
  598. ; ------------  MATCH KEY IN SCAN CODE SEQUENCE
  599.  
  600. CompSeq09:      mov     bl,HotIndex             ;next scan code to match
  601.         xor     bh,bh           ;must be word
  602.         cmp     al,HotKeySeq[bx]        ;does key match?
  603.         je      HotMatch09              ;YES - jump if match
  604.         mov     HotIndex,bh             ;search from start next time
  605.         and     KeyMode,not InHotMatch  ;current no match
  606.         jmp     short ExitInt09         ;now end this
  607.  
  608. ; ------------  KEY MACTHED NEXT SCAN CODE IN HotKeySeq
  609.  
  610. HotMatch09:     inc     bl              ;new code at next pass
  611.         cmp     bl,HotKeyLen            ;did we match whole sequence?
  612.         jae     HotHit09        ;YES - jump if full sequence
  613.         mov     HotIndex,bl             ;NO - save new count
  614.         mov     BetweenKeys,KeyTimeOut  ;reset counter between keys
  615.         or      KeyMode,InHotMatch      ;we are in a match now
  616.         jmp     short ExitInt09         ;time to end this
  617.  
  618. ; ------------  KEY MATCHED ALL SCAN CODES IN HOTKEY SEQUENCE
  619.  
  620. HotHit09:       or      KeyMode,HotKeyOn        ;say hotkey was pressed
  621.         mov     HotIndex,bh             ;match 1st code next time
  622.         and     KeyMode,not InHotMatch  ;that's the end of a match
  623.  
  624. ; ------------  EXIT FROM INT09H, RESET InInt09 FLAG
  625.  
  626. ExitInt09:      and     TsrMode,not InInt09     ;tell'em we left this code
  627.         pop     bx              ;restore regs
  628.         pop     ax
  629.         iret                    ;flags restored from stack
  630. OurInt09        endp
  631.  
  632. ;==============================================================================
  633. ; OurInt13 - SET InInt13 FLAG TO SAY THAT WE ARE IN AN INT13H
  634. ;==============================================================================
  635.  
  636. OurInt13        proc    far
  637.         assume  ds:nothing, es:nothing, ss:nothing
  638.  
  639.         pushf                   ;save flags we use
  640.         or      TsrMode,InInt13         ;remember we are in BIOS now
  641.         popf                    ;restore flags
  642.  
  643.         pushf                   ;simulate INT13
  644.         cli                     ;just in case others forgot
  645.         call    OldInt13        ;let BIOS handle it all
  646.  
  647.         pushf                   ;BIOS uses flag return
  648.         and     TsrMode, not InInt13    ;tell people we left INT13h
  649.         popf
  650.  
  651.         ret     2               ;throw flags off stack
  652. OurInt13        endp
  653.  
  654. ;==============================================================================
  655. ; OurInt16 - TSR INT16H HANDLER, INT28 CHAIN INTERFACE
  656. ;
  657. ; INPUT:    AX = SetAlarm
  658. ;               BX = # of minutes to wait (0= no wait)
  659. ; OUTPUT:    nothing
  660. ;
  661. ; INPUT:        AX = GetId
  662. ; OUTPUT:       AX = MyId
  663. ; REGS:         AX LOST, ALL OTHERS PRESERVED
  664. ; DESCRIPTION:  DETERMINE IF TSR WITH THIS ID IS ALREADY IN MEMORY
  665. ;
  666. ; INPUT:        AH = 00
  667. ; OUTPUT:       AX = NEXT KEY FROM BUFFER
  668. ; REGS;         AX LOST, ALL OTHERS PRESERVED
  669. ; DESCRIPTION:  RETURN A KEY FROM KEYBOARD BUFFER, WAIT TILL KEY IS PRESSED
  670. ;
  671. ; INPUT:        AH = 02
  672. ; OUTPUT:       AX = KEY FROM BUFFER IN ANY
  673. ;               ZF = NO KEYS IN BUFFER (AX PRESERVED)
  674. ;               NZ = KEY IN BUFFER (RETURNED IN AX, KEY STILL IN BUFFER)
  675. ; DESCRIPTION:  CHECK BUFFER FOR ANY PENDING KEYS, RETURN KEY IF ANY
  676. ;
  677. ; NOTE: ALL OTHER AX REQUEST CODES ARE PASSED ON TO BIOS INT16H HANDLER.
  678. ;
  679. ; NOTE: DURING INT28 POPUP (InPopup AND NOT InDosClr) FUNCTIONS AH=0 AND
  680. ;       AH=1 WILL ISSUE INT28, UNLESS InDos HAS FROM VALUE AT POPUP OR
  681. ;       CritErr HAS BEEN SET.
  682. ;==============================================================================
  683.  
  684. OurInt16        proc    far
  685.         assume  ds:nothing, es:nothing, ss:nothing
  686.  
  687.         sti                     ;we'll manage INTs
  688.         pushf                   ;save callers flags
  689.         cmp    ax,SetAlarm    ; set alarm called ?
  690.         jne    NotAlarm
  691.         mov    MinLeft,bx    ; bx holds number of minutes to wait
  692.         xor    bx,bx
  693.         mov    TicksDone, bx    ; ticksdone = 0
  694.         mov    Bleeping, bx    ; bleeping = 0
  695.         popf
  696.         iret            ; return to caller
  697.  
  698. NotAlarm:    cmp     ax,GetId        ;return ID request?
  699.         jne     NotId16         ;NO - jump if not
  700.  
  701. ; ------------  TSR DIAGNOSTIC REQUEST, RETURN SPECIAL VALUE TO SAY WE ARE HERE
  702.  
  703.         mov     ax,MyId         ;ID val returned in AX
  704.         popf                    ;restore flags
  705.         iret                    ;return to caller
  706.  
  707. ; ------------  PASS CONTROL TO BIOS, FLAGS ON STACK
  708.  
  709. GoBios16:       popf                    ;restore flags at INT time
  710.         jmp     OldInt16        ;continue in the woods
  711.  
  712. ; ------------  REGULAR BIOS INT16 REQUEST, CHECK FOR ANY FANCY ACTIONS
  713.  
  714. NotId16:        test    TsrMode,InPopup         ;are we in a popup?
  715.         jz      GoBios16        ;NO - leave rest with BIOS
  716.         test    TsrMode,InDosClr        ;InDos clear at popup?
  717.         jnz     GoBios16        ;YES - no need to signal INT28
  718.  
  719.         popf                    ;restore original flags
  720.         push    bx              ;we need a few regs here
  721.         push    cx
  722.         push    si
  723.         push    ds
  724.         pushf                   ;original flags back on stack
  725.  
  726. ; ------------  GET REQUEST CODE TO BH ENHANCED BIT TO BL
  727.  
  728.         mov     bh,ah           ;BH=function request code
  729.         and     bh,not 10h              ;zap enhanced kybd bit
  730.         cmp     bh,1            ;any function above 1?
  731.         ja      ExitBios16              ;YES - leave rest with BIOS
  732.  
  733.         mov     bl,ah           ;BL used for enhanced bit
  734.         and     bl,10h          ;BL=value of enhanced bit
  735.  
  736. ; ------------  GET InDos To CL, CritErr to CH, SETUP REGS
  737.  
  738.         assume  ds:nothing
  739.  
  740.         lds     si,InDosPtr             ;DS:[SI]=InDos
  741.         mov     cl,byte ptr [si]        ;CL=InDos value
  742.         lds     si,CritErrPtr           ;ES:[SI]=CritErr
  743.         mov     ch,byte ptr [si]        ;CH=CritErr value
  744.  
  745.         mov     si,ax           ;save AX call value
  746.  
  747.         mov     ax,cs           ;move DS here, now we got it
  748.         mov     ds,ax
  749.         assume  ds:PGROUP         ;everybody should know
  750.  
  751. ; ------------  CHECK KEYBOARD BUFFER, ORIGINAL FLAGS ON STACK
  752.  
  753. Wait16:         mov     ah,1            ;AH=1=test buffer status
  754.         or      ah,bl           ;maintain enhanced bit value
  755.  
  756.         popf                    ;restore original flags
  757.         pushf                   ;simulate INT
  758.         cli                     ;in case others forgot
  759.         call    OldInt16        ;now, ZF set if no keys
  760.         pushf                   ;save result flags
  761.         jnz     TestSkip16              ;jump if a key was found
  762.  
  763. ; ------------  NO KEY FOUND, CALL INT28 IF DOS InDos ALLOWS
  764.  
  765.         cmp     cx,0001h        ;CritErr=0, InDos=1 ?
  766.         jne     NextKey16               ;NO - wait for next key
  767.         or      TsrMode,In28Call        ;tell people we called this INT
  768.         int     28h             ;now take your chance
  769.         and     TsrMode,not In28Call    ;end of that call
  770.  
  771. ; ------------  TEST BUFFER AGAIN IF INT16.00, IRET IF INT16.01
  772.  
  773. NextKey16:      or      bh,bh           ;is this a wait for key?
  774.         jz      Wait16          ;YES - then go wait for it!
  775.         mov     ax,si           ;restore original AX contents
  776.         jmp     short Exit16            ;NO - exit with status we got
  777.  
  778. ; ------------  KEY IN BUFFER, IF CTRL-C WE MAY HAVE TO SKIP IT, FLAGS ON STACK
  779.  
  780. TestSkip16:     cmp     al,3            ;is this Ctrl-C?
  781.         jne     TestExit16              ;NO - determine exit method
  782.         test    cx,not 0001h            ;anything but InDos=1?
  783.         jz      TestExit16              ;NO - determine exit method
  784.  
  785. ; ------------  SKIP CTRL-C IN KEYBOARD BUFFER
  786.  
  787.         mov     ah,bl           ;AH=0 + enhanced bit
  788.         popf                    ;restore original INTs
  789.         pushf                   ;save again
  790.         pushf                   ;simulate INT
  791.         cli                     ;simulate properly!
  792.         call    OldInt16        ;now, key should be gone
  793.         jmp     short Wait16            ;do as if nothing had happened
  794.  
  795. ; ------------  KEY IN AX, IRET IF INT16.01, LEAVE WITH BIOS IF INT16.00
  796.  
  797. TestExit16:     or      bh,bh           ;is this a wait for key?
  798.         jnz     Exit16          ;NO - do fast return
  799.         mov     ax,si           ;YES - restore AX code
  800.  
  801. ; ------------  PASS CONTROL TO BIOS, FLAGS & REGS ON STACK
  802.  
  803.         assume  ds:nothing
  804.  
  805. ExitBios16:     popf                    ;restore work flags
  806.         pop     ds              ;restore regs
  807.         pop     si
  808.         pop     cx
  809.         pop     bx
  810.         cli                     ;should look like an INT
  811.         jmp     OldInt16        ;leave rest with BIOS
  812.  
  813. ; ------------  RETURN FROM INT16, FLAGS & REGS ON STACK
  814.  
  815.         assume  ds:nothing
  816.  
  817. Exit16:         popf                    ;restore proper flags
  818.         pop     ds              ;restore regs
  819.         pop     si
  820.         pop     cx
  821.         pop     bx
  822.         ret     2               ;IRET, without flags restore
  823.  
  824. OurInt16        endp
  825.  
  826. ;==============================================================================
  827. ; OurInt21 - INT21 FILTER TO THROW DANGEROUS DOS CALLS ON CRITICAL STACK
  828. ;
  829. ; CHECK IF InPopup AND InDosClr
  830. ; CHECK FUNCTION USES CONSOLE STACK
  831. ; SET CritErr IN DOS IF CONSOLE STACK USED
  832. ; CALL OldInt21
  833. ; RESTORE CritErr IF CRITICAL STACK USED
  834. ;==============================================================================
  835.  
  836. OurInt21        proc    far
  837.         assume  ds:nothing, es:nothing
  838.  
  839.         pushf                   ;save calling flags
  840.         sti
  841.  
  842.         test    TsrMode,InPopup         ;are we in a popup?
  843.         jz      GoDos21         ;NO - don't worry then
  844.         test    TsrMode,InDosClr        ;console stack idle?
  845.         jnz     GoDos21         ;YES - nothing fancy then
  846.  
  847. ; ------------  THIS IS 2ND CALL INTO DOS, SEE IF USING CONSOLE STACK
  848.  
  849.         cmp     ah,0ch          ;any function 00-0C?
  850.         jbe     UseCrit21               ;YES - use critical stack
  851.         test    TsrMode,NewDos          ;NO - is this DOS 3.x?
  852.         jnz     GoDos21         ;YES - no other to worry about
  853.         cmp     ah,50h          ;set PSP function?
  854.         je      UseCrit21               ;YES - use critical stack
  855.         cmp     ah,51h          ;get PSP function?
  856.         jne     GoDos21         ;NO - leave it with DOS
  857.  
  858. ; ------------  FORCE USE OF CRITICAL STACK FOR THIS CALL
  859.  
  860. UseCrit21:      assume  ds:nothing              ;nothing to say about DS
  861.  
  862.         push    si              ;save regs
  863.         push    ds
  864.         lds     si,CritErrPtr           ;now, DS:[SI]=InDos
  865.         mov     byte ptr [si],-1        ;FF=use crit stack now
  866.         pop     ds              ;restore regs
  867.         pop     si
  868.  
  869.         popf                    ;retsore flags setting
  870.         pushf                   ;simulate INT
  871.         cli                     ;in case others forgot
  872.         call    OldInt21        ;flags already on stack
  873.  
  874.         push    si              ;save regs
  875.         push    ds
  876.         lds     si,CritErrPtr           ;now, DS:[SI]=InDos
  877.         mov     byte ptr [si],0         ;0=back to default stack
  878.         pop     ds              ;restore regs
  879.         pop     si
  880.  
  881.         ret     2               ;IRET throw old flags
  882.  
  883. ; ------------  PASS CONTROL TO DOS, FLAGS ON STACK
  884.  
  885. GoDos21:        popf                    ;restore original flags
  886.         cli                     ;just in case someone forgot
  887.         jmp     OldInt21        ;let DOS handle the rest
  888. OurInt21        endp
  889.  
  890. ;==============================================================================
  891. ; OurInt24 - SAFE DOS CRITICAL ERROR HANDLER
  892. ;
  893. ; IF DOS 3.X, FAIL THE SYSTEM CALL
  894. ; IF NOT DOS 3.X, IGNORE ERROR
  895. ;==============================================================================
  896.  
  897. OurInt24        proc    far
  898.         assume  ds:nothing, es:nothing, ss:nothing
  899.         mov     al,3            ;AL=3=fail system call
  900.         test    TsrMode,NewDos          ;are we using DOS 3.x?
  901.         jnz     Exit24          ;YES - OK to use AL=3
  902.         xor     al,al           ;NO - have to ignore err then
  903. Exit24:         iret                    ;return to DOS
  904. OurInt24        endp
  905.  
  906. ;==============================================================================
  907. ; OurInt28 - TSR INT28H HANDLER, ALLOWS POPUP DURING DOS IDLE CALLS
  908. ;
  909. ; CALL OldInt28
  910. ; CHECK FOR RECURSION INTO CRITICAL INT28 CODE (& OTHER INTs AS WELL)
  911. ; SET InInt28 FLAG
  912. ; CHECK FOR HOTKEY
  913. ; CHECK IF SAFE TO POPUP
  914. ; DO POPUP IF SAFE AT THIS TIME
  915. ; RESET InInt28 FLAG
  916. ; DO IRET
  917. ;==============================================================================
  918.  
  919. ; ------------  NEAR JUMP DESTINATION FOR FAST IRET'S
  920.  
  921. Exit28:         iret                    ;IRET (!)
  922.  
  923. ; ------------  ACTUAL INT28 ENTRY POINT
  924.  
  925. OurInt28        proc    far
  926.         assume  ds:nothing, es:nothing, ss:nothing
  927.  
  928.         pushf
  929.         cli                     ;in case others forgot it
  930.         call    OldInt28        ;call TSRs loaded before this
  931.  
  932. ; ------------  ENSURE NO RECURSION ON CRITICAL INT28 CODE
  933.  
  934.         sti                     ;we'll manage INT's after this
  935.         test    TsrMode,InInt08 OR InInt28 OR In28Call OR InPopup
  936.         jnz     Exit28          ;exit fast if already going
  937.         or      TsrMode,InInt28         ;tell'em we are here
  938.  
  939. ; ------------  CHECK FOR POSSIBLE POPUP ACTIONS
  940.  
  941.         test    KeyMode,HotKeyOn        ;any hotkeys pressed?
  942.         jz      ExitInt28               ;NO - don't check any more then
  943.  
  944. ; ------------  HOTKEY WAS PRESSED, ENSURE IT'S SAFE TO DO POPUP
  945.  
  946.         call    TestSafe        ;now, CY clear if popup is OK
  947.         jc      ExitInt28               ;jump if not to popup
  948.  
  949. ; ------------  SEEMS OK TO DO POPUP, SO DO!
  950.  
  951.         and     KeyMode,not HotKeyOn    ;clear hotkey status
  952.         or      TsrMode,InPopup         ;tell'em we enter popup routine
  953.         and     TsrMode,not InInt28     ;OK to enter critical INT28
  954.         call    InitPopup               ;then do popup
  955.         or      TsrMode,InInt28         ;back in INT28 code here
  956.         and     TsrMode,not InPopup     ;not in popup code any more
  957.         and     KeyMode,not HotKeyOn    ;clear hotkeys during popup
  958.  
  959. ; ------------  NORMAL INT28H EXIT, RESET InInt28 FLAG
  960.  
  961. ExitInt28:      and     TsrMode,not InInt28     ;tell'em we left this code
  962.         iret                    ;we have nothing more to say
  963. OurInt28        endp
  964.  
  965. ;==============================================================================
  966. ; NopInt - DUMMY IRET INSTRUCTION USED BY EMPTY INT HANDLERS
  967. ;==============================================================================
  968.  
  969. NopInt:         iret                    ;immediate return
  970.  
  971. ;==============================================================================
  972. ; InitPopup - PREPARES SYSTEM FOR POPUP, THEN CALLS Popup, THEN RESTORES
  973. ;
  974. ; ESTABLISH INTERNAL WORK STACK
  975. ; SAVE CPU REGS
  976. ; UPDATE InDosClr FLAG WITH CURRENT VALUE OF InDos
  977. ; SAVE PROCESS RELATED SYSTEM INFO
  978. ; SAVE USER INTERRUPT VECTORS
  979. ; INSERT SAFE USER INTERRUPT VECTORS
  980. ; CALL POPUP ROUTINE
  981. ; RESTORE USER INTERRUPT VECTORS
  982. ; RESTORE PROCESS AND SYSTEM INFO
  983. ; CLEAR InDosClr FLAG TO PREVENT UNSAFE INT28 CALLs
  984. ; RESTORE CPU REGS
  985. ;==============================================================================
  986.  
  987. InitPopup       proc    near
  988.         assume  ds:nothing, es:nothing, ss:nothing
  989.  
  990. ; ------------  SWITCH TO PSP INTERNAL STACK
  991.  
  992.         mov     OldSS,ss        ;save current stack frame
  993.         mov     OldSP,sp
  994.         mov    OldES,es
  995.         mov    OldBP,bp
  996.         mov    OldDS,ds
  997.  
  998.         cli                     ;always CLI for the old chips
  999.         mov     ss,OurSS        ;move SS here
  1000.         mov     sp,OurSP        ;move SP into position
  1001.         mov    es,OurES
  1002.         mov    bp,OurBP
  1003.         mov    ax,OurDS
  1004.         mov    ds,ax
  1005.         assume    ds:nothing, es:nothing, ss:nothing
  1006.         sti                     ;OK guys
  1007.  
  1008. ; ------------  SAVE ALL REGS
  1009.  
  1010.         push    ax
  1011.         push    bx
  1012.         push    cx
  1013.         push    dx
  1014.         push    bp
  1015.         push    si
  1016.         push    di
  1017.         push    ds
  1018.         push    es
  1019.  
  1020. ;               mov     ax,cs
  1021. ;               mov     ds,ax           ;mov DS here
  1022. ;               assume  ds:PGROUP         ;tell MASM that
  1023. ;
  1024. ; ------------  TAG VALUE OF InDos FLAG AT TIME OF POPUP
  1025.  
  1026.         or      TsrMode,InDosClr        ;assume InDos=0
  1027.         les     si,InDosPtr             ;now, ES:[SI]=InDos
  1028.         cmp     byte ptr es:[si],1      ;InDos set? (>2 impossible)
  1029.         jb      InDosSaved              ;NO - jump if all clear DOS
  1030.         and     TsrMode,not InDosClr    ;clear flag for popup InDos
  1031. InDosSaved:
  1032.  
  1033. ; ------------  SAVE DOS 3.X EXTENDED ERROR INFO
  1034.  
  1035.         test    TsrMode,NewDos          ;really DOS 3.x?
  1036.         jz      Dos3Saved               ;NO - jump if not 3.x
  1037.  
  1038.         mov     ah,59h          ;to get err info from DOS
  1039.         xor     bx,bx           ;BX must be zero
  1040.         push    ds              ;save DS (killed by DOS)
  1041.         int     21h             ;ext err info in AX,BX,CX
  1042.         pop     ds              ;restore
  1043.         mov     OldExtErr[0],ax         ;save
  1044.         mov     OldExtErr[2],bx
  1045.         mov     OldExtErr[4],cx
  1046.  
  1047. Dos3Saved:
  1048.  
  1049. ; ------------  SAVE CURRENT BREAK STATE, RELAX BREAK CHECKING
  1050.  
  1051.         mov     ax,3302h        ;to swap DL with BREAK value
  1052.         xor     dl,dl           ;DL=0=relax checking
  1053.         int     21h             ;current level in DL
  1054.         mov     OldBreak,dl             ;save current level
  1055.  
  1056. ; ------------  SAVE CURRENT USER INT VECTORS
  1057.  
  1058.         mov     ax,351bh        ;BIOS ctrl-break int
  1059.         int     21h             ;ES:BX=vector
  1060.         mov     OldInt1BOff,bx          ;save it
  1061.         mov     OldInt1BSeg,es
  1062.  
  1063.         mov     ax,351ch        ;BIOS timer tick
  1064.         int     21h             ;ES:BX=vector
  1065.         mov     OldInt1COff,bx          ;save it
  1066.         mov     OldInt1CSeg,es
  1067.  
  1068.         mov     ax,3523h        ;DOS ctrl-C
  1069.         int     21h             ;ES:BX=vector
  1070.         mov     OldInt23Off,bx          ;save it
  1071.         mov     OldInt23Seg,es
  1072.  
  1073.         mov     ax,3524h        ;DOS crit err handler
  1074.         int     21h             ;ES:BX=vector
  1075.         mov     OldInt24Off,bx          ;save it
  1076.         mov     OldInt24Seg,es
  1077.  
  1078. ; ------------  INSERT DUMMY IRET INTO DANGEROUS VECTORS
  1079.  
  1080.         mov     dx,offset NopInt        ;now, DS:DX=dunny iret
  1081.         mov     ax,251bh        ;BIOS ctrlk-break handler
  1082.         int     21h             ;set to IRET
  1083.         mov     ax,251ch        ;BIOS timer tick
  1084.         int     21h             ;set to IRET
  1085.         mov     ax,2523h        ;DOS ctrl-C handler
  1086.         int     21h             ;set to IRET
  1087.  
  1088. ; ------------  ESTABLISH SAFE CRITICAL ERROR HANDLER
  1089.  
  1090.         mov     dx,offset OurInt24      ;now, DS:DX=safe crit err
  1091.         mov     ax,2524h        ;to set crit err handler
  1092.         int     21h
  1093.  
  1094. ; ------------  SAVE CURRENT DTA AREA, SET OUR DEFAULT DTA
  1095.  
  1096.         mov     ah,2fh          ;to obtain current DTA from DOS
  1097.         int     21h             ;DTA addr now in ES:BX
  1098.         mov     OldDTAOff,bx            ;save it
  1099.         mov     OldDTASeg,es
  1100.  
  1101.         push    ds              ;save DS for a while
  1102.         lds     dx,OurDTA               ;DS:DX=our DTA addr
  1103.         mov     ah,1ah          ;to set DTA via DOS
  1104.         int     21h             ;set that addr
  1105.         pop     ds              ;restore DS
  1106.  
  1107. ; ------------  SAVE CURRENT PSP, ESTABLISH OURS INSTEAD
  1108.  
  1109.         mov     ax,5100h        ;to get PSP from DOS
  1110.         int     21h             ;current PSP now in BX
  1111.         mov     OldPSP,bx               ;save it
  1112.         mov     bx,OurPSP               ;het our PSP instead
  1113.         mov     ax,5000h        ;to set our PSP
  1114.         int     21h
  1115.  
  1116. ; ------------  CALL USER POPUP ROUTINE
  1117.  
  1118.         call    Popup           ;finally!
  1119.  
  1120. ; ------------  RESTORE TO SAVED CURRENT PROCESS
  1121.  
  1122.         mov     bx,OldPSP               ;new current process in BX
  1123.         mov     ax,5000h        ;to set PSP via DOS
  1124.         int     21h             ;restore original PSP
  1125.  
  1126. ; ------------  RESTORE SAVED DTA
  1127.  
  1128.         push    ds              ;save DS for a while
  1129.         lds     dx,OldDTA               ;DS:DX=our DTA addr
  1130.         mov     ah,1ah          ;to set DTA via DOS
  1131.         int     21h             ;set that addr
  1132.         pop     ds              ;restore DS
  1133.  
  1134. ; ------------  RESTORE SAVED INTERRUPT VECTORS
  1135.  
  1136.         push    ds              ;save for a while
  1137.         assume  ds:nothing              ;be careful about MASM
  1138.  
  1139.         lds     dx,OldInt1B             ;BIOS ctrl-break handler
  1140.         mov     ax,251bh
  1141.         int     21h
  1142.  
  1143.         lds     dx,OldInt1C             ;BIOS timer tick
  1144.         mov     ax,251ch
  1145.         int     21h
  1146.  
  1147.         lds     dx,OldInt23             ;DOS ctrl-C
  1148.         mov     ax,2523h
  1149.         int     21h
  1150.  
  1151.         lds     dx,OldInt24             ;DOS crit err handler
  1152.         mov     ax,2524h
  1153.         int     21h
  1154.  
  1155.         pop     ds              ;restore data seg DS
  1156.         assume  ds:PGROUP
  1157.  
  1158. ; ------------  RESTORE SAVED BREAK CHECKING LEVEL
  1159.  
  1160.         mov     ax,3301h        ;to set break check level
  1161.         mov     dl,OldBreak             ;get saved break state
  1162.         int     21h
  1163.  
  1164. ; ------------  RESTORE DOS 3.X SPECIFIC SYSTEM INFO
  1165.  
  1166.         test    TsrMode,NewDos          ;using DOS 3.x
  1167.         jz      Dos3Restored            ;NO - jump if old DOS 2
  1168.         mov     dx,offset OldExtErr     ;DS:DX=3 words of ext err
  1169.         mov     ax,5d0ah        ;to set ext err info
  1170.         int     21h
  1171. Dos3Restored:
  1172.  
  1173. ; ------------  RESET InDosSet FLAG VALUE TO PREVENT UNSAFE INT28
  1174.  
  1175.         or      TsrMode,InDosClr        ;now we only care that InDos=0
  1176.  
  1177. ; ------------  RESTORE USER REGS
  1178.  
  1179.         pop     es
  1180.         pop     ds
  1181.         pop     di
  1182.         pop     si
  1183.         pop     bp
  1184.         pop     dx
  1185.         pop     cx
  1186.         pop     bx
  1187.         pop     ax
  1188.         assume  ds:nothing
  1189.  
  1190. ; ------------  RETURN TO USER STACK
  1191.  
  1192.         cli                     ;always CLI for the old chips
  1193.         mov     ss,OldSS        ;restore SS
  1194.         mov     sp,OldSP        ;restore SP
  1195.         mov    es,OldES
  1196.         mov    bp,OldBP
  1197.         mov    ds,OldDS
  1198.         assume    ss:nothing, es:nothing, ds:nothing
  1199.         sti                     ;OK guys
  1200.  
  1201.         ret
  1202. InitPopup       endp
  1203.  
  1204. ;==============================================================================
  1205. ; Popup - POPUP USER ROUTINE
  1206. ;
  1207. ; ALL REGISTERS EXCEPT SS:SP AND DS MAY BE CHANGED.
  1208. ; DS IS PRESET TO THE TSR DATA SEGMENT.
  1209. ;
  1210. ; NOTE: UPON ENTRY TO THIS ROUTINE ALL DOS FUNCTIONS MAY BE CALLED.
  1211. ;       IF POPUP WAS DONE ON INT28, WITH CritErr==1, ALL DOS FUNCTIONS
  1212. ;       THAT WOULD NORMALLY USE THE CONSOLE STACK, WILL GO TO THE CRITICAL
  1213. ;       STACK, HENCE PREVENTING FURTHER POPUP DURING THE DOS CALL.
  1214. ;       (HOWEVER, MOST TSRs WOULD NOT POPUP ANYWAY, SINCE InDos==2).
  1215. ;
  1216. ;       ADDRESSES OF THE InDos AND CritErr ARE STORED IN THE DOUBLE WORDS
  1217. ;       InDosPtr AND CritErrPtr.
  1218. ;
  1219. ;       AT ENTRY CritErr FLAG IS 0 (ZERO), InDos NO GREATER THAN 1 (ONE).
  1220. ;==============================================================================
  1221.  
  1222. Popup           proc    near
  1223.         assume  ds:PGROUP, es:nothing, ss:nothing
  1224.  
  1225.         mov    MinLeft,0        ; turn off alarms
  1226.         push    ds
  1227.  
  1228.         cli                ; for old chips
  1229.         mov     ss,OurSS
  1230.         mov    es,OurES
  1231.         mov    bp,OurBP
  1232.         mov    ax,DSLattice
  1233.         mov    ds,ax
  1234.         assume    ds:nothing, ss:nothing, es:nothing
  1235.         sti                ; ok
  1236.  
  1237.         call    cpopup
  1238.  
  1239.         pop    ds
  1240.         assume    ds:PGROUP
  1241.         ret
  1242. Popup           endp
  1243.  
  1244. ;==============================================================================
  1245. ; NON-RESIDENT MESSAGES FOR INIT
  1246. ;==============================================================================
  1247.  
  1248. BannerMsg       label   byte
  1249. db      13,10
  1250. db      '<<<<<<  TSR INSTALLED  >>>>>>',13,10
  1251. db      '$'
  1252.  
  1253. SecondMsg       label   byte
  1254. db      'VA already loaded.',13,10
  1255. db      '$'
  1256.  
  1257. HotKeyMsg       label   byte
  1258. db      'Hit <Left Shift> <Right Shift> to pop up!',13,10,10
  1259. db      '$'
  1260.  
  1261. Dos1Msg label   byte
  1262. db      'OOPS!',7,13,10
  1263. db      'Must use DOS release 2.00 or later!',13,10,10
  1264. db      '$'
  1265.  
  1266. BadDosMsg       label   byte
  1267. db      'OOPS!',7,13,10
  1268. db      'Did not recognize DOS version!',13,10,10
  1269. db      '$'
  1270.  
  1271. ; ------------  DOS ERROR LEVEL EXIT CODES
  1272.  
  1273. xOk             equ     0               ;normal, OK exit
  1274. xSecond         equ     1               ;TSR already loaded
  1275. xBadDos         equ     2               ;CritErr flag not found
  1276.  
  1277. ;==============================================================================
  1278. ; Init - INITIALIZE TSR APPLICATION, ENTERED UPON DOS LOAD
  1279. ;
  1280. ; DISPLAY BANNER, INITIALIZE SYSTEM DATA, CHECK IF ALREADY LOADED,
  1281. ; HOOK INTO INTERRUPT CHAIN, TERMINATE, BUT STAY RESIDENT.
  1282. ;==============================================================================
  1283.  
  1284. ;Init            proc    near
  1285. tsr        proc    near
  1286.         assume  ds:nothing, es:nothing, ss:nothing
  1287.  
  1288. ; ------------  SAVE STUFF FOR RETURNING
  1289.  
  1290.         mov    OurSP,sp
  1291.         mov     OurSS,ss
  1292.         mov    OurES,es
  1293.         mov    OurBP,bp
  1294.  
  1295.         push    bp
  1296.         push    ds
  1297.         assume    ds:nothing
  1298.         mov    DSLattice,ds    ; save DS for later in popup()
  1299.  
  1300.         mov     ax,cs
  1301.         mov     ds,ax        ; mov DS here
  1302.         assume  ds:PGROUP    ; tell MASM that
  1303.         mov    OurDS,ds
  1304.  
  1305.         mov     dx,offset BannerMsg
  1306.         mov     ah,9
  1307.         int     21h             ;display programme banner
  1308.  
  1309. ; ------------  USE INT16H DIAGNOSTIC TO SEE IF TSR ALREADY INSTALLED
  1310.  
  1311.         mov     ax,GetId        ;INT16h diagnostic request
  1312.         int     16h             ;now, AX=MyId if installed
  1313.         cmp     ax,MyId         ;TSR already installed?
  1314.         jne     CheckDos        ;NO - jump if not installed
  1315.  
  1316. ; ------------  TSR ALREADY INSTALLED, DISPLAY MSG, EXIT
  1317.  
  1318.         mov     dx,offset SecondMsg
  1319.         mov     ah,9
  1320.         int     21h             ;display alr installed msg
  1321.         mov     dx,offset HotKeyMsg
  1322.         mov     ah,9
  1323.         int     21h             ;be kind & disp hot key
  1324.         mov     ax,4c00h + xSecond      ;error level in AL
  1325.         int     21h             ;abot now
  1326.  
  1327. ; ------------  IDIOT IS RUNNING DOS 1, LEAVE THE OLD FASHION WAY!
  1328.  
  1329. Dos1:           mov     dx,offset Dos1Msg
  1330.         mov     ah,9
  1331.         int     21h             ;display msg about DOS 1
  1332.         int     20h             ;no err level for DOS 1
  1333.  
  1334. ; ------------  ENSURE DOS VERSION IS NEWER THAN 2.00
  1335.  
  1336. CheckDos:       or      TsrMode,NewDos          ;assume using DOS 3.x
  1337.         mov     ah,30h          ;to get DOS version number
  1338.         int     21h             ;version is AL.AH
  1339.         cmp     al,2            ;release 2 or newer?
  1340.         jb      Dos1            ;NO - jump if DOS 1 in use
  1341.         ja      DosFlags        ;jump if DOS 3.x
  1342.         and     TsrMode,not NewDos      ;now, say we use DOS 2.x
  1343.  
  1344. ; ------------  INITIALIZE PTRS TO DOS FLAGS - 1ST InDos
  1345.  
  1346. DosFlags:       mov     ax,3400h        ;to get InDos ptr
  1347.         int     21h             ;ES:BX=seg:off of InDos
  1348.         mov     InDosOff,bx             ;save ptr
  1349.         mov     InDosSeg,es
  1350.  
  1351. ; ------------  WE NEED CritErr TO USE PSP FUNCTIONS IN DOS 2.X (CHIPs WAY)
  1352.  
  1353.         xor     dl,dl           ;DL=0=this is 1st scan
  1354.         mov     CritErrSeg,es           ;DOS seg still in ES
  1355. CritScan:       mov     di,bx           ;start search at InDos
  1356.         mov     cx,2000h        ;search max 1000h words
  1357.         mov     ax,3e80h        ;opcode CMP BYTE PTR [CritErr]
  1358.         cld                     ;better serach forward
  1359.  
  1360. CritScan2:      repne   scasw           ;search till found or end
  1361.         jne     NoCritFound             ;jump if CMP not found
  1362.                         ;ES:[DI-2] at:
  1363.                         ;       CMP BYTE PTR [CritErr]
  1364.                         ;       JNZ ...
  1365.                         ;       MOV SP,stack addr
  1366.         cmp     byte ptr es:[di][5],0bch ;really CMP SP there?
  1367.         jne     CritScan2               ;NO - scan again if not
  1368.         mov     ax,word ptr es:[di]     ;now, AX=CritErr offset
  1369.         mov     CritErrOff,ax           ;save it
  1370.         jmp     short InitData          ;OK to end this now
  1371.  
  1372. NoCritFound:    or      dl,dl           ;was this1 st scan?
  1373.         jnz     BadDos          ;NO - CritErr not founbd at all
  1374.         inc     dl              ;DL=1=this is 2nd scan
  1375.         inc     bx              ;try scan at odd/even offset
  1376.         jmp     CritScan        ;scan again
  1377.  
  1378. ; ------------  COULD NOT LOCATE DOS CritErr FLAG - THAT'S AN ERROR
  1379.  
  1380. BadDos:         mov     dx,offset BadDosMsg
  1381.         mov     ah,9
  1382.         int     21h             ;display msg about that
  1383.         mov     ax,4c00h + xBadDos      ;err level in AL
  1384.         int     21h             ;OK to use 4C (DOS >= 2)
  1385.  
  1386. ; ------------  INITIALIZE SYSTEM DATA VARIABLES
  1387.  
  1388. InitData:                       ;store position for stack
  1389.  
  1390.         mov     ax,5100h        ;to get current PSP from DOS
  1391.         int     21h             ;PSP now in BX
  1392.         mov     OurPSP,bx               ;save our PSP
  1393.  
  1394.         mov     ah,2fh          ;to get current DTA from DOS
  1395.         int     21h             ;now, ES:BX=current DTA
  1396.         mov     OurDTAOff,bx            ;save it
  1397.         mov     OurDTASeg,es
  1398.  
  1399.         and     KeyMode,not HotIsShift  ;hotkey is not shift state
  1400.         or      TsrMode,InDosClr        ;will prevent unsafe INT28s
  1401.  
  1402. ; ------------  SAVE VECTORS FOR OUR MONITOR INTERRUPTS
  1403.  
  1404.         mov     ax,3508h        ;BIOS timer0 tick handler
  1405.         int     21h             ;ES:BX=vector
  1406.         mov     OldInt08Off,bx
  1407.         mov     OldInt08Seg,es
  1408.  
  1409.         mov     ax,3509h        ;BIOS kb HW handler
  1410.         int     21h             ;ES:BX=vector
  1411.         mov     OldInt09Off,bx
  1412.         mov     OldInt09Seg,es
  1413.  
  1414.         mov     ax,3513h        ;BIOS disk I/O service
  1415.         int     21h             ;ES:BX=vector
  1416.         mov     OldInt13Off,bx
  1417.         mov     OldInt13Seg,es
  1418.  
  1419.         mov     ax,3516h        ;BIOS kb read
  1420.         int     21h             ;ES:BX=vector
  1421.         mov     OldInt16Off,bx
  1422.         mov     OldInt16Seg,es
  1423.  
  1424.         mov     ax,3521h        ;DOS functions dispatcher
  1425.         int     21h             ;ES:BX=vector
  1426.         mov     OldInt21Off,bx
  1427.         mov     OldInt21Seg,es
  1428.  
  1429.         mov     ax,3528h        ;DOS idle hook
  1430.         int     21h             ;ES:BX=vector
  1431.         mov     OldInt28Off,bx
  1432.         mov     OldInt28Seg,es
  1433.  
  1434. ; ------------  ESTABLISH IRET INT23 TO PREVENT BREAK DURING VECTOR FIX
  1435.  
  1436.         mov     dx,offset NopInt        ;DS:DX=dummy vector to set
  1437.         mov     ax,2523h        ;to set ^C handler through DOS
  1438.         int     21h             ;now, no break will occur
  1439.  
  1440. ; ------------  SAVE VECTORS FOR OUR MONITOR INTERRUPTS
  1441.  
  1442.         mov     ax,2508h        ;to set our INT08h handler
  1443.         mov     dx,offset OurInt08      ;DS:DX=new vector
  1444.         int     21h             ;let DOS set vector
  1445.  
  1446.         mov     ax,2509h        ;to set our INT09h handler
  1447.         mov     dx,offset OurInt09      ;DS:DX=new vector
  1448.         int     21h             ;let DOS set vector
  1449.  
  1450.         mov     ax,2513h        ;to set our INT13h handler
  1451.         mov     dx,offset OurInt13      ;DS:DX=new vector
  1452.         int     21h             ;let DOS set vector
  1453.  
  1454.         mov     ax,2516h        ;to set our INT16h handler
  1455.         mov     dx,offset OurInt16      ;DS:DX=new vector
  1456.         int     21h             ;let DOS set vector
  1457.  
  1458.         mov     ax,2521h        ;to set our INT21h handler
  1459.         mov     dx,offset OurInt21      ;DS:DX=new vector
  1460.         int     21h             ;let DOS set vector
  1461.  
  1462.         mov     ax,2528h        ;to set our INT28h handler
  1463.         mov     dx,offset OurInt28      ;DS:DX=new vector
  1464.         int     21h             ;let DOS set vector
  1465.  
  1466. ; ------------  DISLAY MSG ABOUT HOW WELL THIS IS ALL RUNNING
  1467.  
  1468.         mov     dx,offset HotKeyMsg
  1469.         mov     ah,9
  1470.         int     21h             ;disp hot key
  1471.  
  1472. ; ------------  RETURN TO LATTICE-C
  1473.  
  1474.         pop    ds
  1475.         assume    ds:nothing
  1476.         pop    bp
  1477.         ret
  1478.  
  1479. tsr        endp
  1480.  
  1481. PROG        ends
  1482.         end
  1483.