home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / asmutl / tsrdemo.arc / TSRDEMO2.ASM
Assembly Source File  |  1980-04-10  |  45KB  |  1,494 lines

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