home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0000 - 0009 / ibm0000-0009 / ibm0003.tar / ibm0003 / TPOWER53.ZIP / TPASM.ARC / TPTSR.ASM < prev   
Encoding:
Assembly Source File  |  1989-07-10  |  44.0 KB  |  1,554 lines

  1. ;******************************************************
  2. ;           TPTSR.ASM 5.07
  3. ;           TSR Management routines
  4. ;     Copyright (c) TurboPower Software 1987.
  5. ; Portions copyright (c) Sunny Hill Software 1985, 1986
  6. ;     and used under license to    TurboPower Software
  7. ;         All rights reserved.
  8. ;******************************************************
  9.  
  10.     INCLUDE    TPCOMMON.ASM
  11.  
  12. ;******************************************************    Equates
  13.  
  14. MaxScanCode    =    86h        ;Do not    change    !!.07
  15. IfcSignature    =    0F0F0h        ;Do not    change
  16. IfcSignature2    =    0E0E0h        ;Do not    change
  17. NextIfc        =    14        ;Offset    of NextIfc field in IFC    record
  18.  
  19. ;******************************************************    Data
  20.  
  21.  
  22. DATA    SEGMENT    BYTE PUBLIC
  23.  
  24.     ;Pascal    variables
  25.  
  26.     EXTRN    PopupAddrs : BYTE        ;Addresses of popup routines
  27.     EXTRN    PopupStacks : BYTE        ;Stacks    for popup routines
  28.     EXTRN    PopupInUse : BYTE        ;Flags for popups in use
  29.     EXTRN    PopupKeys : BYTE        ;Trigger keys for popups
  30.     EXTRN    ShiftKeys : BYTE        ;Shift keys for    popups
  31.     EXTRN    DosWaitFlags : BYTE        ;Flags popups that need    DOS
  32.     EXTRN    PopTickerPtr : DWORD        ;Points    to PopTicker
  33.     EXTRN    PopupsEnabledPtr : DWORD    ;Points    to PopupsEnabled
  34.     EXTRN    PopupToCallPtr : DWORD        ;Points    to PopupToCall
  35.     EXTRN    PrefixSeg : WORD        ;Our PSP segment
  36.     EXTRN    DosVersion : WORD        ;Version of DOS
  37.     EXTRN    ThisIfc    : BYTE            ;Standard interface record
  38.     EXTRN    IfcInstalled : BYTE        ;True if we're in charge of IFC
  39.  
  40.     ;internal variables
  41.  
  42.     DosTrapsSet    DB    ?        ;True if special trapping of DOS
  43.                         ;INT vectors, etc. has been done
  44.     LastEntrySS    DW    ?        ;Data needed for EmergencyExit
  45.     LastEntrySP    DW    ?
  46.     LastEntryIP    DW    ?
  47.  
  48. DATA    ENDS
  49.  
  50. ;******************************************************    Code
  51.  
  52. CODE    SEGMENT    BYTE PUBLIC
  53.  
  54.     ASSUME    CS:CODE,DS:DATA
  55.  
  56.     PUBLIC    Int5, Int8, Int9, Int10, Int13,    Int14, Int16, Int17, Int25,
  57.     PUBLIC    Int26, Int28, Int33, InitTsrPtrs, Int24Result, EmergencyExit
  58.     PUBLIC    Save3Fvector, DosBusyFlag, DosCriticalFlag
  59.  
  60.     ;Pascal    routines
  61.  
  62.     EXTRN    IoResultPrim:NEAR    ;Pascal    routine
  63.  
  64. ;Note that these variables are all in the code segment
  65.  
  66. ;When both of these variables point to zero, DOS may be    called
  67. DosInUsePtr    Pointer    <>        ;Non-0 if DOS is in use
  68. DosCriticalPtr    Pointer    <>        ;Non-0 if DOS is critical
  69. HaveDosCritical    DB    0        ;Set to    1 if DosCriticalPtr is reliable
  70.  
  71. ;Old interrupt vectors
  72. OldInt05    Pointer    <>        ;Old INT $05 handler (PrtSc)
  73. OldInt08    Pointer    <>        ;Old INT $08 handler (clock)
  74. OldInt09    Pointer    <>        ;Old INT $09 handler (keyboard)
  75. OldInt10    Pointer    <>        ;Old INT $10 handler (video)
  76. OldInt13    Pointer    <>        ;Old INT $13 handler (disk)
  77. OldInt14    Pointer    <>        ;Old INT $14 handler (comm.)
  78. OldInt16    Pointer    <>        ;Old INT $16 handler (keyboard)
  79. OldInt17    Pointer    <>        ;Old INT $17 handler (printer)
  80. OldInt25    Pointer    <>        ;Old INT $25 handler (abs. disk    read)
  81. OldInt26    Pointer    <>        ;Old INT $26 handler (abs. disk    write)
  82. OldInt28    Pointer    <>        ;Old INT $28 handler (DOS multitasking)
  83. OldInt33    Pointer    <>        ;Old INT $33 handler (mouse driver)
  84.  
  85. ;Following needed for TSR's written with TP 5.0
  86. NewInt34    Pointer    <>        ;for emulation
  87. NewInt35    Pointer    <>
  88. NewInt36    Pointer    <>
  89. NewInt37    Pointer    <>
  90. NewInt38    Pointer    <>
  91. NewInt39    Pointer    <>
  92. NewInt3A    Pointer    <>
  93. NewInt3B    Pointer    <>
  94. NewInt3C    Pointer    <>
  95. NewInt3D    Pointer    <>
  96. NewInt3E    Pointer    <>
  97. NewInt3F    Pointer    <>        ;for overlays
  98.  
  99. ;Following needed for TSR's that use the 8087
  100. NewInt02    Pointer    <>        ;NMI interrupt
  101. NewInt75    Pointer    <>        ;8087 exceptions
  102.  
  103. Int24Err    DB    0        ;Boolean -- 1 means critical error
  104. Int24ErrCode    DB    0        ;Byte -- the DOS error code
  105.  
  106. PopupToCall    DB    0        ;Index number of a pending popup
  107. PopupsEnabled    DB    0        ;Boolean, determines if    we react to pop    keys
  108. PopTimeOut    DW    36        ;Default timeout number    of clock ticks
  109.                     ;(2 seconds on PC)
  110. PopTicker    DW    0        ;Decremented as    the clock ticker
  111. OurDS        DW    DATA        ;Value of DS --    init'd by EXE loader
  112. OurDTA        Pointer    <>        ;Our DTA
  113. OurPSP        DW    0        ;Our PSP
  114. TempTrapFlag    DB    0        ;Flag to indicate if traps need    setting
  115. IsEnhanced    DB    0        ;1 if it's an enhanced keyboard
  116.  
  117. Dos3Plus    DB    True        ;Boolean - True    if running DOS 3.x or
  118.                     ; higher
  119.  
  120. SystemState    DW    0        ;see comment below
  121. StateFlags    EQU    WP CS:SystemState ;for convenience
  122.  
  123. COMMENT    @
  124.  When SystemState is zero, popping up is OK.  Each interrupt handler has its
  125.  own bit which is set on entry and reset on exit from the interrupt.  One
  126.  bit used is set when we are setting/removing the DOS traps.
  127.  
  128.  The bit flags are as follows:
  129.  
  130.    F E D C B A 9 8 7 6 5 4 3 2 1 0  Flag indicates we're inside this INT:
  131.    -------------------------------- -------------------------------------
  132.    | | | | | | | | | | | | | | | +- $05     PrtSc
  133.    | | | | | | | | | | | | | | +--- $08     Clock tick (hardware)
  134.    | | | | | | | | | | | | | +----- $09     Keyboard (hardware)
  135.    | | | | | | | | | | | | +------- $10     BIOS video interrupt
  136.    | | | | | | | | | | | +--------- $13     BIOS disk read/write
  137.    | | | | | | | | | | +----------- $14     BIOS communications
  138.    | | | | | | | | | +------------- $16     BIOS keyboard
  139.    | | | | | | | | +--------------- $17     BIOS printer
  140.    | | | | | | | +----------------- $25     DOS absolute disk read
  141.    | | | | | | +------------------- $26     DOS absolute disk write
  142.    | | | | | +--------------------- $28     DOS multitasking
  143.    | | | | +----------------------- $33     Mouse driver
  144.    | | | +-------------------------  --     Setting DOS traps
  145.    +-+-+--------------------------- xxx     Bits $D-$F are    reserved
  146. @
  147.  
  148. ;******************************************************    Bit masks
  149.  
  150. InInt05        =    0000000000000001b    ;Set when in INT $05
  151. InInt08        =    0000000000000010b    ;Set when in INT $08
  152. InInt09        =    0000000000000100b    ;Set when in INT $09
  153. InInt10        =    0000000000001000b    ;Set when in INT $10
  154. InInt13        =    0000000000010000b    ;Set when in INT $13
  155. InInt14        =    0000000000100000b    ;Set when in INT $14
  156. InInt16        =    0000000001000000b    ;Set when in INT $16
  157. InInt17        =    0000000010000000b    ;Set when in INT $17
  158. InInt25        =    0000000100000000b    ;Set when in INT $25
  159. InInt26        =    0000001000000000b    ;Set when in INT $26
  160. InInt28        =    0000010000000000b    ;Set when in INT $28
  161. InInt33        =    0000100000000000b    ;Set when in INT $33
  162. InSetTR        =    0001000000000000b    ;Set when we set traps
  163.  
  164. NotIn05        =    1111111111111110b    ;Clears    INT $05    flag
  165. NotIn08        =    1111111111111101b    ;Clears    INT $08    flag
  166. NotIn09        =    1111111111111011b    ;Clears    INT $09    flag
  167. NotIn10        =    1111111111110111b    ;Clears    INT $10    flag
  168. NotIn13        =    1111111111101111b    ;Clears    INT $13    flag
  169. NotIn14        =    1111111111011111b    ;Clears    INT $14    flag
  170. NotIn16        =    1111111110111111b    ;Clears    INT $16    flag
  171. NotIn17        =    1111111101111111b    ;Clears    INT $17    flag
  172. NotIn25        =    1111111011111111b    ;Clears    INT $25    flag
  173. NotIn26        =    1111110111111111b    ;Clears    INT $26    flag
  174. NotIn28        =    1111101111111111b    ;Clears    INT $28    flag
  175. NotIn33        =    1111011111111111b    ;Clears    INT $33    flag
  176. NotSetTR    =    1110111111111111b    ;Clears    setting    traps flag
  177.  
  178. ;******************************************************    TryPop
  179.  
  180. COMMENT    |
  181.   This procedure checks    to see if the system is    OK and,    if so, calls the
  182.   current popup.  It preserves all registers except the    flags.
  183.  
  184.   On entry, the    stack should look exactly as it    did after the interrupt
  185.   occurred, with no other data PUSHed, and the interrupt flag should be
  186.   disabled.
  187.  
  188.   TryPop must not be CALLed; it    must be    jumped to. When    finished, TryPop
  189.   executes an IRET instruction.
  190.  
  191.   TryPop also contains the label DosOkToPop, which the interrupt $28 filter
  192.   jumps    to when    it needs to pop    up.
  193. |
  194.  
  195. TryPop    PROC NEAR
  196.  
  197.     CLI                ;No interrupts between chk and zero
  198.     CMP    CS:PopupsEnabled,0    ;make sure popups are enabled
  199.     JZ    SysNotOK
  200.     CMP    CS:PopTicker,0        ;check this so we can be called    without
  201.                     ;knowing
  202.     JZ    SysNotOK        ;if not    waiting, just return
  203.     CMP    StateFlags,0        ;Check system state
  204.     JE    SysOkTryPop        ;if not    OK, pass on
  205.  
  206. SysNotOK:
  207.     IRET                ;return    with non-zero flags
  208.  
  209. SysOkTryPop:
  210.     MOV    CS:PopupsEnabled,0    ;no popups now
  211.     STI                ;Interrupts on
  212.     PUSH    DS            ;Save DS
  213.     PUSH    BX            ;Save BX
  214.     PUSH    AX            ;Save AX
  215.  
  216.     MOV    DS,CS:OurDS        ;get data seg
  217.     SetZero    AX            ;zero AX
  218.     MOV    AL,CS:PopupToCall    ;Popup index in    AL
  219.     DEC    AX            ;less 1    for base of 1
  220.     MOV    BX,Offset DosWaitFlags    ;offset    of DosWaitFlags    array
  221.     XLAT                ;Get value. If not 0, check DOS
  222.     MOV    BX,AX            ;Store state of    the flag in BX
  223.     SUB    BL,DosTrapsSet        ;BL = (1-0), (1-1), (0-0), or (0-1)
  224.     MOV    CS:TempTrapFlag,BL    ;Save the result
  225.     OR    AX,AX            ;check for 0
  226.     JNZ    CheckDosOkToPop        ;if not    0, check DOS
  227.  
  228.     POP    AX            ;restore used regs
  229.     POP    BX
  230.     POP    DS
  231.     JMP    SHORT DosOkToPop    ;not using DOS,    all's well
  232.  
  233. CheckDosOkToPop:
  234.     LDS    BX,CS:DosInUsePtr    ;DOS in    use pointer in DS:BX
  235.     MOV    AL,[BX]            ;DOS byte in AL
  236.     LDS    BX,CS:DosCriticalPtr    ;Check DOS critical flag
  237.     OR    AL,[BX]            ;they must both    be zero
  238.     POP    AX            ;restore used regs
  239.     POP    BX
  240.     POP    DS
  241.     JZ     DosOkToPop
  242.  
  243. ExitEnabled:
  244.     MOV    CS:PopupsEnabled,1    ;reenable popups
  245.     IRET
  246.  
  247. ;If we get here    then the DISK and DOS are fine.
  248. DosOkToPop:
  249.     MOV    CS:PopTicker,0        ;stop checking period
  250.     STI                ;interrupts on
  251.     SaveAllRegs            ;Save all registers
  252.     MOV    DS,CS:OurDS        ;Get data segment
  253.  
  254.     SetZero    BX            ;Zero BX
  255.     MOV    BL,CS:PopupToCall    ;Get index of popup
  256.     DEC    BX            ;PopupAddrs is 1-based
  257.     MOV    SI,BX            ;save index in SI for now
  258.     SHL    BX,1            ;PopupAddrs is array of    pointers
  259.     SHL    BX,1
  260.  
  261.     PUSH    WP PopupAddrs[BX].Segm    ;Push segment of popup
  262.     PUSH    WP PopupAddrs[BX].Ofst    ;Push offset of    popup
  263.  
  264.     ;switch    stacks
  265.  
  266.     MOV    AX,SS            ;save current SS in AX
  267.     MOV    ES,AX            ;ES = current SS
  268.     MOV    DX,WP PopupStacks[BX].Segm ;DX = new SS
  269.     MOV    BX,WP PopupStacks[BX].Ofst ;BX = new SP
  270.     CLI                ;interrupts off
  271.     MOV    SS,DX            ;new SS    in SS
  272.     XCHG    BX,SP            ;swap new & old    SP, old    in ES:BX
  273.     STI                ;interrupts on
  274.  
  275.     ADD    BX,4            ;ES:BX points to Regs,
  276.                     ;ES:[BX-4] has pointer to popup
  277.     PUSH    ES            ;save top of regs segment
  278.     PUSH    BX            ;and offset
  279.     PUSH    SI            ;save index of popup
  280.  
  281.     PUSH    LastEntrySS        ;Save any previous routine's SS
  282.     PUSH    LastEntrySP        ;SP
  283.     PUSH    LastEntryIP        ;and reentry offset
  284.  
  285.     PUSH    ES            ;pass top of regs segment
  286.     PUSH    BX            ;and offset as VAR parameter
  287.  
  288.     CMP    CS:TempTrapFlag,True    ;see if    traps need to be set
  289.     JE    SetTrapsToPop        ;If so,    use alternate routine
  290.  
  291.     ;Else, save info for emergency exit and    call popup
  292.     MOV    LastEntrySS,SS        ;Save SS
  293.     MOV    LastEntrySP,SP        ;Save SP
  294.     MOV    LastEntryIP,Offset BackInTryPop    ;Save reentry offset
  295.  
  296.     MOV    CS:PopupsEnabled,1    ;reenable popups
  297.     CallFar    ES:[BX-4]        ;CALL popup, which will    get rid
  298.                     ;of the    last two PUSH's
  299.     JMP    SHORT BackInTryPop    ;We're back, clean up
  300.  
  301. SetTrapsToPop:
  302.     CALL    SetDosTraps        ;Set the traps and call    pop-up
  303.  
  304. BackInTryPop:
  305.     POP    LastEntryIP        ;restore previous reentry offset
  306.     POP    LastEntrySP        ;SP
  307.     POP    LastEntrySS        ;and previous routine's SS
  308.     POP    BX            ;index value in    BX
  309.  
  310.     MOV    PopupInUse[BX],False    ;Popup is not in use
  311.     POP    BX            ;old SP    in BX
  312.     POP    AX            ;old SS    in AX
  313.     CLI                ;interrupts off
  314.     MOV    SS,AX            ;restore SS
  315.     MOV    SP,BX            ;restore SP
  316.     STI                ;interrupts on
  317.     RestoreAllRegs            ;restore all registers
  318.     IRET                ;return    to caller
  319.  
  320. TryPop    ENDP
  321.  
  322. ;******************************************************    DecPopTicker
  323.  
  324. ;Check to see if we've timed out while waiting to pop up
  325.  
  326. DecPopTicker    PROC NEAR
  327.  
  328.     DEC    CS:PopTicker        ;Decrement ticker
  329.     JNZ    DecDone
  330.  
  331.     PUSH    DS            ;Timed out, use    these regs
  332.     PUSH    BX
  333.     MOV    DS,CS:OurDS        ;get data segment
  334.     SetZero    BH            ;zero BH
  335.     MOV    BL,CS:PopupToCall    ;get number of popup
  336.     DEC    BX            ;array has base    of 1, convert to 0 base
  337.     MOV    PopupInUse[BX],False    ;Popup is not in use
  338.     POP    BX            ;restore registers
  339.     POP    DS
  340.  
  341. DecDone:
  342.     STI                ;interrupts on
  343.     RET
  344.  
  345. DecPopTicker    ENDP
  346.  
  347. ;******************************************************    Int8
  348.  
  349. COMMENT    |
  350.   Clock    interrupt handler.
  351.   ------------------------
  352.   Traps    the clock tick to see if it should activate a routine. If it can, it
  353.   clears the clock tick, then calls the    appropriate popup. If it can't, it
  354.   chains to the    previous INT $8    handler.
  355. |
  356.  
  357. TempInt08    Pointer    <>        ;Temporary address
  358.  
  359. Int8    PROC NEAR
  360.  
  361.     CMP    CS:PopTicker,0        ;Check to see if we're waiting to pop up
  362.     JE    Int8Pass        ;if not, pass on interrupt
  363.  
  364. CheckPopClk:
  365.     TEST    StateFlags,InInt08    ;check if we're in use
  366.     JZ    Int8Try            ;if not, try to    pop up
  367.     CALL    DecPopTicker        ;else, see if we timed out
  368.  
  369. Int8Pass:
  370.     CLI                ;interrupts off
  371.     JmpFar    CS:OldInt08        ;pass on interrupt
  372.  
  373. Int8Try:
  374.     OR    StateFlags,InInt08    ;now we    are in use
  375.     STI                ;interrupts on
  376.     POP    CS:TempInt08.Ofst    ;caller's offset
  377.     POP    CS:TempInt08.Segm    ;caller's segment
  378.     CLI                ;interrupts off
  379.     CALL    CS:OldInt08        ;Call original routine
  380.  
  381.     ;Push flags and    address    on the stack so    we can use IRET    to return
  382.     STI                ;interrupts on
  383.     PUSHF                ;caller's flags on stack
  384.     PUSH    CS:TempInt08.Segm    ;caller's segment
  385.     PUSH    CS:TempInt08.Ofst    ;caller's offset on stack
  386.  
  387.     CLI                ;interrupts off
  388.     CMP    CS:PopTicker,0        ;check again in    case it    expired
  389.     JZ    NoTimeOut        ;return
  390.  
  391.     AND    StateFlags,NotIn08    ;clear clock-in-use bit
  392.     JNZ    CheckTimeOut        ;not OK, pass on
  393.     JMP    TryPop            ;try to    pop-up
  394.  
  395. CheckTimeOut:
  396.     CALL    DecPopTicker        ;see if    we've timed out
  397.  
  398. NoTimeOut:
  399.     AND    StateFlags,NotIn08    ;clear clock-in-use bit
  400.     IRET                ;return    to caller
  401.  
  402. Int8    ENDP
  403.  
  404. ;******************************************************    Int9
  405.  
  406. COMMENT    |
  407.   Keyboard interrupt handler.
  408.   ---------------------------
  409.   Intercepts the keyboard hardware interrupt (INT 9) to    determine when we should
  410.   pop up. If the proper    mask is    active and one of the defined keys is struck,
  411.   then this routine does the following:
  412.  
  413.   - sets PopupToCall to    the array index    of the key that    was struck
  414.   - sets PopTicker to the timeout value
  415.   - resets the keyboard    and returns
  416.  
  417.   Int8,    Int16, and Int28 take over from    there.
  418. |
  419.  
  420. TempInt09    Pointer    <>
  421. RoutineNum    DB    0
  422. BiosDataSeg    DW    40h
  423.  
  424. KbdData        =    60h
  425. BiosShiftFlags    =    17h
  426.  
  427. Int9    PROC NEAR
  428.  
  429.     STI                ;interrupts on
  430.     PUSH    DS            ;Save DS
  431.     PUSH    AX            ;Save AX
  432.     PUSH    BX            ;Save BX
  433.     MOV    DS,CS:BiosDataSeg    ;Check BIOS data area
  434.     MOV    AH,DS:[BiosShiftFlags]    ;BIOS status byte into AH
  435.     AND    AH,00001111b        ;If none of these flags    is set,    can't
  436.                     ;be a hot key...
  437.     JZ    PassKbdInt        ;So exit
  438.  
  439.     IN    AL,KbdData        ;Get key struck
  440.     CMP    AL,MaxScanCode        ;see if    it's in our range
  441.     JA    PassKbdInt        ;no, pass on
  442.  
  443.     MOV    DS,CS:OurDS        ;Reset DS
  444.     SetZero    BH            ;BH = 0
  445.     MOV    BL,AL            ;BX has    index into arrays of bytes
  446.                     ;based on scan codes
  447.     MOV    AL,PopupKeys[BX]    ;get popup handle in AL
  448.     OR    AL,AL            ;check for 0
  449.     JZ    PassKbdInt        ;if 0, not a hot key
  450.     CMP    AH,ShiftKeys[BX]    ;Shift keys match?
  451.     JE    AttemptPop        ;if so,    try to POP up
  452.  
  453. PassKbdInt:
  454.     POP    BX            ;Restore BX
  455.     POP    AX            ;Restore AX
  456.     POP    DS            ;Restore DS
  457.     TEST    StateFlags,InInt09    ;Check if we're in use
  458.     JZ    TrackKbd        ;if no,    set variable
  459.     CLI                ;interrupts off
  460.     JmpFar    CS:OldInt09        ;else, just pass this on
  461.  
  462. TrackKbd:
  463.     OR    StateFlags,InInt09    ;Set our bit
  464.     POP    CS:TempInt09.Ofst    ;Offset    of caller
  465.     POP    CS:TempInt09.Segm    ;Segment of caller
  466.     CLI                ;interrupts off
  467.     CallFar    CS:OldInt09        ;Call original routine
  468.  
  469.     ;Push flags and    address    on the stack so    we can use IRET    to return
  470.     PUSHF                ;Save flags
  471.     CLI                ;Ints off
  472.     PUSH    CS:TempInt09.Segm    ;Segment of caller
  473.     PUSH    CS:TempInt09.Ofst    ;Offset    of caller
  474.  
  475.     AND    StateFlags,NotIn09    ;Reset our bit
  476.     IRET                ;return    to caller
  477.  
  478. AttemptPop:
  479.     SetZero    AH            ;zero in AH
  480.     MOV    BX,AX            ;get routine handle IN BX
  481.     DEC    BX            ;array has base    of 1
  482.  
  483.     ;make sure it's all right to try to pop up
  484.  
  485.     CLI                ;Ints off
  486.     CMP    CS:PopupsEnabled,True    ;Are popups enabled?
  487.     JNE    DontPop            ;No? Eat the hotkey
  488.     CMP    PopupInUse[BX],AH    ;Popup already in use?
  489.     JNE    DontPop            ;Yes? Eat the hotkey
  490.     CMP    CS:PopTicker,0        ;Something else    waiting    to pop up?
  491.     JNE    DontPop            ;Yes? Eat the hotkey
  492.  
  493.     ;checks    went OK, we can    set the    pop ticker
  494.  
  495.     MOV    PopupInUse[BX],True    ;This popup is in use now
  496.     INC    BX            ;Popup to call in BX
  497.     MOV    CS:PopupToCall,BL    ;In PopupToCall
  498.     MOV    AX,CS:PopTimeOut    ;timeout value in AX
  499.     MOV    CS:PopTicker,AX        ;set PopTicker
  500. DontPop:
  501.     STI                ;interrupts on
  502.     ResetKbd            ;reset keyboard    (trashes AX)
  503.     NullJump            ;delay
  504.     ResetPIC            ;reset PIC port    (trashes AX)
  505.     POP    BX            ;Restore BX
  506.     POP    AX            ;Restore AX
  507.     POP    DS            ;Restore DS
  508.     IRET
  509.  
  510. Int9    ENDP
  511.  
  512. ;******************************************************    Int16
  513.  
  514. COMMENT    |
  515.   BIOS keyboard    interrupt handler.
  516.   --------------------------------
  517.   Intercepts the BIOS keyboard interrupt (INT 16) to allow popups to be
  518.   activated while waiting for keyboard input.
  519.  
  520.   Also used to communicate data    between    TSR's written with Turbo Professional.
  521. |
  522.  
  523. TempInt16    Pointer    <>        ;local
  524. IntraApp    =    00F0h        ;offset    of intraapplication comm area
  525.  
  526. Int16    PROC NEAR
  527.  
  528.     STI                ;Interrupts on
  529.     CMP    AX,IfcSignature        ;See if    this is    a request for info
  530.     JNE    NotIfcCheck1        ;If not, continue
  531.     PUSH    DS            ;Save DS
  532.     MOV    DS,CS:OurDs        ;DS = OurDS
  533.     CMP    IfcInstalled,True    ;Are we    in charge of the interface?
  534.     POP    DS            ;Restore DS
  535.     JNE    JumpOld16        ;If not, chain to old ISR
  536.     NOT    AX            ;Flip the bits in AX
  537.     MOV    ES,CS:OurDs        ;ES = DS
  538.     MOV    DI,Offset ThisIfc    ;ES:DI points to ThisIfc
  539.     MOV    WP ES:[DI].NextIfc,0    ;If we're answering this, we're    the end
  540.     MOV    WP ES:[DI].NextIfc+2,0    ; of the line, so NextIfc is nil
  541.     IRET
  542.  
  543. NotIfcCheck1:
  544.     CMP    AX,IfcSignature2    ;Is this a secondary request?
  545.     JNE    NotIfcCheck
  546.     PUSH    DS            ;Save DS
  547.     MOV    DS,CS:OurDs        ;DS = OurDS
  548.     CMP    IfcInstalled,True    ;Are we    in charge of the interface?
  549.     POP    DS            ;Restore DS
  550.     JNE    JumpOld16        ;If not, chain to old ISR
  551.     NOT    AX            ;Flip the bits in AX
  552.     PUSH    ES            ;save registers
  553.     PUSH    DI
  554.     PUSH    BX
  555.     PUSH    CX
  556.     MOV    CX,BiosDataSeg        ;ES:DI => intra-app comm area
  557.     MOV    ES,CX
  558.     MOV    DI,IntraApp
  559.     MOV    CX,CS:OurDs        ;CX:BX => ThisIfc
  560.     MOV    BX,Offset ThisIfc
  561.     MOV    ES:[DI].Ofst,BX        ;store @ThisIfc    at Ptr(ES,DI)^
  562.     MOV    ES:[DI].Segm,CX
  563.     MOV    ES,CX            ;ES:BX points to ThisIfc
  564.     MOV    WP ES:[BX].NextIfc,0    ;If we're answering this, we're    the end
  565.     MOV    WP ES:[BX].NextIfc+2,0    ; of the line, so NextIfc is nil
  566.     POP    CX
  567.     POP    BX
  568.     POP    DI
  569.     POP    ES
  570.     IRET
  571.  
  572. NotIfcCheck:
  573.     TEST    StateFlags,InInt16    ;Check if we're in use
  574.     JZ    TrackInt16        ;if not, set variable
  575.  
  576. JumpOld16:
  577.     CLI                ;Interrupts off
  578.     JmpFar    CS:OldInt16        ;else, pass this on
  579.  
  580. TrackInt16:
  581.     CMP    AH,10h            ;Is it function    10h?
  582.     JE    ChkEnhKbd        ;If so,    use enhanced keyboard code
  583.     OR    AH,AH            ;check for function 0 (read next char)
  584.     JNZ    TrackRaw16        ;if AH <> 0, track INT 16 raw
  585.  
  586. ChkKbdLoop:
  587.     ;loop until a key is pressed, alternately checking for keyboard
  588.     ;input and trying to pop up
  589.  
  590.     MOV    AH,1            ;execute check for keypress function
  591.     OR    StateFlags,InInt16    ;Set our bit
  592.  
  593.     POP    CS:TempInt16.Ofst    ;Offset    of caller
  594.     POP    CS:TempInt16.Segm    ;Segment of caller
  595.  
  596.     CLI                ;interrupts off    to emulate interrupt
  597.     CallFar    CS:OldInt16        ;Call original routine
  598.  
  599.     PUSHF                ;save flags
  600.     STI                ;interrupts on
  601.     PUSH    CS:TempInt16.Segm    ;Segment of caller
  602.     PUSH    CS:TempInt16.Ofst    ;Offset    of caller
  603.  
  604.     LAHF                ;save return flags
  605.     AND    StateFlags,NotIn16    ;Reset our bit
  606.     JNZ    ChkKbdLoopNext        ;if state isn't clear, don't try
  607.  
  608.     PUSHF                ;get set for IRET
  609.     PUSH    CS            ;push CS (next call is near)
  610.     CALL    ChkKbdTryPop        ;push return offset too
  611.  
  612.     ;IRET in TryPop    returns    to here
  613.     JMP    SHORT ChkKbdLoopNext    ;check again
  614.  
  615. ChkKbdTryPop:
  616.     JMP    TryPop            ;try to    pop up
  617.  
  618. ChkKbdLoopNext:
  619.     SAHF                ;restore flags
  620.     JZ    ChkKbdLoop        ;if no key waiting, loop
  621.     SetZero    AH            ;switch    back to    function 0, get    key
  622.  
  623. TrackRaw16:
  624.     OR    StateFlags,InInt16    ;Set our bit
  625.     POP    CS:TempInt16.Ofst    ;Offset    of caller
  626.     POP    CS:TempInt16.Segm    ;Segment of caller
  627.     CLI                ;interrupts off    to emulate interrupt
  628.     CallFar    CS:OldInt16        ;Call original routine
  629.  
  630.     ;Push flags and    address    on the stack so    we can use IRET    to return
  631.     PUSHF                ;save flags
  632.     STI                ;interrupts on
  633.     PUSH    CS:TempInt16.Segm    ;Segment of caller
  634.     PUSH    CS:TempInt16.Ofst    ;Offset    of caller
  635.  
  636.     ;reset our in-interrupt    flag and return
  637.     AND    StateFlags,NotIn16    ;Reset our bit
  638.     JNZ    RetFromI16        ;if that didn't make state 0, return
  639.  
  640.     JMP    TryPop            ;try to    pop up
  641.  
  642. RetFromI16:
  643.     IRET
  644.  
  645.     ;the remainder of the ISR allows us to pop up during function $10
  646.     ;calls (the enhanced keyboard version of function 0, read next char)
  647.  
  648. ChkEnhKbd:
  649.     CMP    CS:IsEnhanced,1        ;Is it an enhanced keyboard?
  650.     JNE    TrackRaw16        ;If not, don't use the following code!
  651.  
  652. ChkEnhKbdLoop:
  653.     ;loop until a key is pressed, alternately checking for keyboard
  654.     ;input and trying to pop up
  655.  
  656.     MOV    AH,11h            ;execute check for keypress function
  657.     OR    StateFlags,InInt16    ;Set our bit
  658.  
  659.     POP    CS:TempInt16.Ofst    ;Offset    of caller
  660.     POP    CS:TempInt16.Segm    ;Segment of caller
  661.  
  662.     CLI                ;interrupts off    to emulate interrupt
  663.     CallFar    CS:OldInt16        ;Call original routine
  664.  
  665.     PUSHF                ;save flags
  666.     STI                ;interrupts on
  667.     PUSH    CS:TempInt16.Segm    ;Segment of caller
  668.     PUSH    CS:TempInt16.Ofst    ;Offset    of caller
  669.  
  670.     LAHF                ;save return flags
  671.     AND    StateFlags,NotIn16    ;Reset our bit
  672.     JNZ    ChkEnhKbdLoopNext    ;if state isn't clear, don't try
  673.  
  674.     PUSHF                ;get set for IRET
  675.     PUSH    CS            ;push CS (next call is near)
  676.     CALL    ChkEnhKbdTryPop        ;push return offset too
  677.  
  678.     ;IRET in TryPop    returns    to here
  679.     JMP    SHORT ChkEnhKbdLoopNext    ;check again
  680.  
  681. ChkEnhKbdTryPop:
  682.     JMP    TryPop            ;try to    pop up
  683.  
  684. ChkEnhKbdLoopNext:
  685.     SAHF                ;restore flags
  686.     JZ    ChkEnhKbdLoop        ;if no key waiting, loop
  687.     MOV    AH,10h            ;switch    back to    function 10h, get key
  688.     JMP    SHORT TrackRaw16    ;and track it
  689.  
  690. Int16    ENDP
  691.  
  692. ;******************************************************    Int28
  693.  
  694. COMMENT    |
  695.   DOS multitasking interrupt handler.
  696.   -----------------------------------
  697.   Handles the DOS multitasking interrupt, which    is called continuously at
  698.   the DOS prompt. If PopTicker > 0, this interrupt will    call the appropriate
  699.   popup    before chaining    to the previous    INT $28    handler.
  700. |
  701.  
  702. TempInt28    Pointer    <>        ;Temporary address
  703.  
  704. Int28    PROC NEAR
  705.  
  706.     CLI                ;ints off to make sure
  707.     CMP    CS:PopTicker,0        ;check pop ticker before doing anything
  708.     JZ    I28Pass            ;pass if not set
  709.  
  710.     TEST    StateFlags,InInt28    ;check if we're in use
  711.     JNZ    I28Pass            ;if so,    pass
  712.  
  713.     ;following needed for Compaq DOS 3.25--calls itself to check for ^Break
  714.     ;during    file operations
  715.  
  716.     STI                ;interrupts on
  717.     PUSH    DS            ;Save DS
  718.     PUSH    BX            ;Save BX
  719.     LDS    BX,CS:DosInUsePtr    ;DS:BX => DosInUse flag
  720.     CMP    BYTE PTR [BX],2        ;BX <= 2?
  721.     JAE    Passing            ;pass if DosInUse >= 2
  722.     CMP    CS:HaveDosCritical,1    ;Do we know where DOS critical flag is?
  723.     JNE    NotPassing        ;If not, don't check it here
  724.     LDS    BX,CS:DosCriticalPtr    ;Check DOS critical flag
  725.     CMP    BYTE PTR [BX],0        ;is it 0?
  726.     JE    NotPassing        ;continue if it's 0
  727. Passing:
  728.     POP    BX            ;Restore DS
  729.     POP    DS            ;Restore BX
  730.     JMP    SHORT I28Pass
  731.  
  732. NotPassing:
  733.     POP    BX            ;Restore DS
  734.     POP    DS            ;Restore BX
  735.  
  736.     OR    StateFlags,InInt28    ;now we're in use
  737.     POP    CS:TempInt28.Ofst    ;caller's offset
  738.     POP    CS:TempInt28.Segm    ;caller's segment
  739.     CLI                ;interrupts off
  740.     CallFar    CS:OldInt28        ;call original routine
  741.  
  742.     PUSHF                ;caller's flags on stack
  743.     STI                ;interrupts on
  744.     PUSH    CS:TempInt28.Segm    ;caller's segment
  745.     PUSH    CS:TempInt28.Ofst    ;caller's offset on stack
  746.  
  747.     CMP    CS:PopTicker,0        ;check if we're waiting to pop up
  748.     JNE    Go28            ;if so,    do it
  749.     AND    StateFlags,NotIn28    ;now we're not in use
  750.     IRET
  751.  
  752. I28Pass:
  753.     CLI                ;interrupts off
  754.     JmpFar    CS:OldInt28        ;pass to old int 28 handler
  755.  
  756. Go28:
  757.     PUSH    DS            ;Save DS
  758.     PUSH    BX            ;Save BX
  759.     PUSH    AX            ;Save AX
  760.  
  761.     MOV    PopupsEnabled,0        ;disable popups
  762.     MOV    DS,CS:OurDS        ;get data seg
  763.     SetZero    AX            ;zero AX
  764.     MOV    AL,CS:PopupToCall    ;Popup index in    AL
  765.     DEC    AX            ;less 1    for base of 1
  766.     MOV    BX,Offset DosWaitFlags    ;offset    of DosWaitFlags    array
  767.     XLAT                ;Get value. If not 0, check DOS
  768.     SUB    AL,DosTrapsSet        ;AL = (1-0), (1-1), (0-0), or (0-1)
  769.     MOV    CS:TempTrapFlag,AL    ;Save the result
  770.  
  771.     POP    AX            ;restore used regs
  772.     POP    BX
  773.     POP    DS
  774.     AND    StateFlags,NotIn28    ;now we're not in use
  775.     JMP    DosOkToPop        ;call routine which won't return
  776.     IRET                ;put this here anyhow
  777.  
  778. Int28    ENDP
  779.  
  780. COMMENT    |
  781.   The remainder    of these interrupt handlers are    simple filters that prevent
  782.   us from popping up when any one of these interrupts is in progress by    setting
  783.   a bit    in the system state flag. Their    overhead is minimal.
  784. |
  785.  
  786. ;******************************************************    Int5
  787.  
  788. COMMENT    |
  789.   PrtSc    interrupt handler.
  790.   ------------------------
  791.   Intercepts the PrtSc interrupt to contend with programs that generate    the
  792.   interrupt themselves to do screen dumps.
  793. |
  794.  
  795. TempInt05      Pointer <>           ;local
  796.  
  797. Int5    PROC NEAR
  798.  
  799.     CLI                ;Just in case it wasn't called properly
  800.     TEST    StateFlags,InInt05    ;Check if we're in use
  801.     JZ    TrackInt5        ;if not, set variable
  802.     JmpFar    CS:OldInt05        ;yes, pass this    on
  803.  
  804. TrackInt5:
  805.     OR    StateFlags,InInt05    ;Set our bit
  806.     POP    CS:TempInt05.Ofst    ;Offset    of caller
  807.     POP    CS:TempInt05.Segm    ;Segment of caller
  808.     CallFar    CS:OldInt05        ;Call original routine
  809.  
  810.     ;Push flags and    address    on the stack so    we can use IRET    to return
  811.     PUSHF                ;save flags
  812.     CLI                ;interrupts off
  813.     PUSH    CS:TempInt05.Segm    ;Segment of caller
  814.     PUSH    CS:TempInt05.Ofst    ;Offset    of caller
  815.  
  816.     ;reset our in-interrupt    flag and return
  817.     AND    StateFlags,NotIn05    ;Reset our bit
  818.     IRET
  819.  
  820. Int5    ENDP
  821.  
  822. ;******************************************************    Int10
  823.  
  824. COMMENT    |
  825.   BIOS video interrupt handler.
  826.   -----------------------------
  827.   Intercepts the BIOS video interrupt to prevent problems when running in
  828.   the OS/2 compatibility box. Not captured if running under DOS    2.x or 3.x.
  829. |
  830.  
  831. TempInt10    Pointer    <>        ;local
  832.  
  833. Int10    PROC NEAR
  834.  
  835.     CLI                ;Just in case it wasn't called properly
  836.     TEST    StateFlags,InInt10    ;Check if we're in use
  837.     JZ    TrackInt10        ;if not, set variable
  838.     JmpFar    CS:OldInt10        ;yes, pass this    on
  839.  
  840. TrackInt10:
  841.     OR    StateFlags,InInt10    ;Set our bit
  842.     POP    CS:TempInt10.Ofst    ;Offset    of caller
  843.     POP    CS:TempInt10.Segm    ;Segment of caller
  844.     CallFar    CS:OldInt10        ;Call original routine
  845.  
  846.     ;Push flags and    address    on the stack so    we can use IRET    to return
  847.     PUSHF                ;save flags
  848.     CLI                ;interrupts off
  849.     PUSH    CS:TempInt10.Segm    ;Segment of caller
  850.     PUSH    CS:TempInt10.Ofst    ;Offset    of caller
  851.  
  852.     AND    StateFlags,NotIn10    ;reset our in-interrupt    flag and return
  853.     IRET
  854.  
  855. Int10    ENDP
  856.  
  857. ;******************************************************    Int13
  858.  
  859. COMMENT    |
  860.   BIOS disk interrupt handler.
  861.   ----------------------------
  862.   Intercepts the BIOS disk interrupt to    contend    with programs that bypass DOS
  863.   and access the disk directly.
  864. |
  865.  
  866. TempInt13    Pointer    <>        ;local
  867.  
  868. Int13    PROC NEAR
  869.  
  870.     CLI                ;Just in case it wasn't called properly
  871.     TEST    StateFlags,InInt13    ;Check if we're in use
  872.     JZ    TrackInt13        ;if not, set variable
  873.     JmpFar    CS:OldInt13        ;yes, pass this    on
  874.  
  875. TrackInt13:
  876.     OR    StateFlags,InInt13    ;Set our bit
  877.     POP    CS:TempInt13.Ofst    ;Offset    of caller
  878.     POP    CS:TempInt13.Segm    ;Segment of caller
  879.     CallFar    CS:OldInt13        ;Call original routine
  880.  
  881.     ;Push flags and    address    on the stack so    we can use IRET    to return
  882.     PUSHF                ;save flags
  883.     CLI                ;interrupts off
  884.     PUSH    CS:TempInt13.Segm    ;Segment of caller
  885.     PUSH    CS:TempInt13.Ofst    ;Offset    of caller
  886.  
  887.     AND    StateFlags,NotIn13    ;reset our in-interrupt    flag and return
  888.     IRET
  889.  
  890. Int13    ENDP
  891.  
  892. ;******************************************************    Int14
  893.  
  894. COMMENT    |
  895.   BIOS communications interrupt    handler.
  896.   --------------------------------------
  897.   Intercepts the BIOS communications interrupt to prevent problems when    running
  898.   in the OS/2 compatibility box. Not captured if running under DOS 2.x or 3.x.
  899. |
  900.  
  901. TempInt14    Pointer    <>        ;local
  902.  
  903. Int14    PROC NEAR
  904.  
  905.     CLI                ;Just in case it wasn't called properly
  906.     TEST    StateFlags,InInt14    ;Check if we're in use
  907.     JZ    TrackInt14        ;if not, set variable
  908.     JmpFar    CS:OldInt14        ;yes, pass this    on
  909.  
  910. TrackInt14:
  911.     OR    StateFlags,InInt14    ;Set our bit
  912.     POP    CS:TempInt14.Ofst    ;Offset    of caller
  913.     POP    CS:TempInt14.Segm    ;Segment of caller
  914.     CallFar    CS:OldInt14        ;Call original routine
  915.  
  916.     ;Push flags and    address    on the stack so    we can use IRET    to return
  917.     PUSHF                ;save flags
  918.     CLI                ;interrupts off
  919.     PUSH    CS:TempInt14.Segm    ;Segment of caller
  920.     PUSH    CS:TempInt14.Ofst    ;Offset    of caller
  921.  
  922.     AND    StateFlags,NotIn14    ;reset our in-interrupt    flag and return
  923.     IRET
  924.  
  925. Int14    ENDP
  926.  
  927. ;******************************************************    Int17
  928.  
  929. COMMENT    |
  930.   BIOS printer interrupt handler.
  931.   ------------------------------
  932.   Intercepts the BIOS printer interrupt    to prevent problems when running in the
  933.   OS/2 compatibility box. Not captured if running under    DOS 2.x    or 3.x.
  934. |
  935.  
  936. TempInt17    Pointer    <>        ;local
  937.  
  938. Int17    PROC NEAR
  939.  
  940.     CLI                ;Just in case it wasn't called properly
  941.     TEST    StateFlags,InInt17    ;Check if we're in use
  942.     JZ    TrackInt17        ;if not, set variable
  943.     JmpFar    CS:OldInt17        ;yes, pass this    on
  944.  
  945. TrackInt17:
  946.     OR    StateFlags,InInt17    ;Set our bit
  947.     POP    CS:TempInt17.Ofst    ;Offset    of caller
  948.     POP    CS:TempInt17.Segm    ;Segment of caller
  949.     CallFar    CS:OldInt17        ;Call original routine
  950.  
  951.     ;Push flags and    address    on the stack so    we can use IRET    to return
  952.     PUSHF                ;save flags
  953.     CLI                ;interrupts off
  954.     PUSH    CS:TempInt17.Segm    ;Segment of caller
  955.     PUSH    CS:TempInt17.Ofst    ;Offset    of caller
  956.  
  957.     AND    StateFlags,NotIn17    ;reset our in-interrupt    flag and return
  958.     IRET
  959.  
  960. Int17    ENDP
  961.  
  962. ;******************************************************    Int25
  963.  
  964. COMMENT    |
  965.   DOS absolute disk read interrupt handler.
  966.   -----------------------------------------
  967.   Intercepts the absolute disk read interrupt to contend with programs
  968.   that use this    interrupt.
  969. |
  970.  
  971. TempInt25    Pointer    <>        ;local
  972.  
  973. Int25    PROC NEAR
  974.  
  975.     CLI                ;Just in case it wasn't called properly
  976.     TEST    StateFlags,InInt25    ;Check if we're in use
  977.     JZ    TrackInt25        ;if not, set variable
  978.     JmpFar    CS:OldInt25        ;yes, pass this    on
  979.  
  980. TrackInt25:
  981.     OR    StateFlags,InInt25    ;Set our bit
  982.     POP    CS:TempInt25.Ofst    ;Offset    of caller
  983.     POP    CS:TempInt25.Segm    ;Segment of caller
  984.     CallFar    CS:OldInt25        ;Call original routine
  985.  
  986.     ;Push flags and    address    on the stack so    we can use IRET    to return
  987.     PUSHF                ;save flags
  988.     CLI                ;interrupts off
  989.     PUSH    CS:TempInt25.Segm    ;Segment of caller
  990.     PUSH    CS:TempInt25.Ofst    ;Offset    of caller
  991.  
  992.     AND    StateFlags,NotIn25    ;reset our in-interrupt    flag and return
  993.     IRET
  994.  
  995. Int25    ENDP
  996.  
  997. ;******************************************************    Int26
  998.  
  999. COMMENT    |
  1000.   DOS absolute disk write interrupt handler.
  1001.   -----------------------------------------
  1002.   Intercepts the absolute disk write interrupt to contend with programs
  1003.   that use this    interrupt.
  1004. |
  1005.  
  1006. TempInt26    Pointer    <>        ;local
  1007.  
  1008. Int26    PROC NEAR
  1009.  
  1010.     CLI                ;Just in case it wasn't called properly
  1011.     TEST    StateFlags,InInt26    ;Check if we're in use
  1012.     JZ    TrackInt26        ;if not, set variable
  1013.     JmpFar    CS:OldInt26        ;yes, pass this    on
  1014.  
  1015. TrackInt26:
  1016.     OR    StateFlags,InInt26    ;Set our bit
  1017.     POP    CS:TempInt26.Ofst    ;Offset    of caller
  1018.     POP    CS:TempInt26.Segm    ;Segment of caller
  1019.     CallFar    CS:OldInt26        ;Call original routine
  1020.  
  1021.     ;Push flags and    address    on the stack so    we can use IRET    to return
  1022.     PUSHF                ;save flags
  1023.     CLI                ;interrupts off
  1024.     PUSH    CS:TempInt26.Segm    ;Segment of caller
  1025.     PUSH    CS:TempInt26.Ofst    ;Offset    of caller
  1026.  
  1027.     AND    StateFlags,NotIn26    ;reset our in-interrupt    flag and return
  1028.     IRET
  1029.  
  1030. Int26    ENDP
  1031.  
  1032. ;******************************************************    Int33
  1033.  
  1034. COMMENT    |
  1035.   Mouse    driver interrupt
  1036.   ----------------------
  1037.   Intercepts mouse driver calls    to contend with    programs that use this
  1038.   interrupt.
  1039. |
  1040.  
  1041. TempInt33    Pointer    <>        ;local
  1042.  
  1043. Int33    PROC NEAR
  1044.  
  1045.     CLI                ;Just in case it wasn't called properly
  1046.     TEST    StateFlags,InInt33    ;Check if we're in use
  1047.     JZ    TrackInt33        ;if not, set variable
  1048.     JmpFar    CS:OldInt33        ;yes, pass this    on
  1049.  
  1050. TrackInt33:
  1051.     OR    StateFlags,InInt33    ;Set our bit
  1052.     POP    CS:TempInt33.Ofst    ;Offset    of caller
  1053.     POP    CS:TempInt33.Segm    ;Segment of caller
  1054.     CallFar    CS:OldInt33        ;Call original routine
  1055.  
  1056.     ;Push flags and    address    on the stack so    we can use IRET    to return
  1057.     PUSHF                ;save flags
  1058.     CLI                ;interrupts off
  1059.     PUSH    CS:TempInt33.Segm    ;Segment of caller
  1060.     PUSH    CS:TempInt33.Ofst    ;Offset    of caller
  1061.  
  1062.     AND    StateFlags,NotIn33    ;reset our in-interrupt    flag and return
  1063.     IRET
  1064.  
  1065. Int33    ENDP
  1066.  
  1067. ;******************************************************    Save3Fvector
  1068.  
  1069. Save3Fvector    PROC NEAR
  1070.  
  1071.     GetVector    3Fh, CS:NewInt3F    ;for overlays
  1072.     RET
  1073.  
  1074. Save3Fvector    ENDP
  1075.  
  1076. ;******************************************************    InitTsrPtrs
  1077.  
  1078. ;procedure InitTsrPtrs;
  1079.  
  1080. ;Initializes pointers to hidden    variables and pointers that indicate when
  1081. ;DOS is    active.
  1082.  
  1083. InitTsrPtrs    PROC NEAR
  1084.  
  1085.     ;initialization
  1086.     MOV    DosTrapsSet,False    ;DOS traps not set
  1087.     DosCall    2Fh            ;Get current DTA
  1088.     SetPtr    CS:OurDTA, ES, BX    ;Save our DTA (in ES:BX)
  1089.     MOV    AX,PrefixSeg        ;AX = our PSP
  1090.     MOV    CS:OurPSP,AX        ;Save in CS-relative storage
  1091.  
  1092.     ;check to see if it's an enhanced keyboard
  1093.     MOV    AX,40h            ;check bit 4 of    byte at    $40:$96
  1094.     MOV    ES,AX
  1095.     MOV    DI,96h
  1096.     TEST    BYTE PTR ES:[DI],00010000b
  1097.     JZ    EnhDone            ;if bit    is set,    it's enhanced
  1098.     MOV    CS:IsEnhanced,True    ;Store CS-relative variable
  1099. EnhDone:
  1100.  
  1101.     ;allow Pascal routines access to CS-relative data
  1102.     SetPtrByOfst    PopTickerPtr, CS, PopTicker
  1103.     SetPtrByOfst    PopupsEnabledPtr, CS, PopupsEnabled
  1104.     SetPtrByOfst    PopupToCallPtr,    CS, PopupToCall
  1105.  
  1106.     ;Get current interrupt vectors
  1107.  
  1108.     GetVector    02h, CS:NewInt02    ;NMI interrupt
  1109.     GetVector    05h, CS:OldInt05    ;PrtSc interrupt
  1110.     GetVector    08h, CS:OldInt08    ;Clock tick interrupt
  1111.     GetVector    09h, CS:OldInt09    ;Keyboard interrupt
  1112.     GetVector    10h, CS:OldInt10    ;Video interrupt
  1113.     GetVector    13h, CS:OldInt13    ;Disk interrupt
  1114.     GetVector    14h, CS:OldInt14    ;Comm. interrupt
  1115.     GetVector    16h, CS:OldInt16    ;Keyboard interrupt
  1116.     GetVector    17h, CS:OldInt17    ;Printer interrupt
  1117.     GetVector    25h, CS:OldInt25    ;Disk read interrupt
  1118.     GetVector    26h, CS:OldInt26    ;Disk write interrupt
  1119.     GetVector    28h, CS:OldInt28    ;DOS multitasking interrupt
  1120.     GetVector    33h, CS:OldInt33    ;Mouse driver interrupt
  1121.     GetVector    34h, CS:NewInt34    ;for emulation
  1122.     GetVector    35h, CS:NewInt35
  1123.     GetVector    36h, CS:NewInt36
  1124.     GetVector    37h, CS:NewInt37
  1125.     GetVector    38h, CS:NewInt38
  1126.     GetVector    39h, CS:NewInt39
  1127.     GetVector    3Ah, CS:NewInt3A
  1128.     GetVector    3Bh, CS:NewInt3B
  1129.     GetVector    3Ch, CS:NewInt3C
  1130.     GetVector    3Dh, CS:NewInt3D
  1131.     GetVector    3Eh, CS:NewInt3E
  1132.     GetVector    75h, CS:NewInt75    ;8087 exception    ???
  1133.  
  1134.     ;Get the DOS version
  1135.  
  1136.     DosCall    30h            ;Get DOS version
  1137.     XCHG    AL,AH            ;Major version # in AH,    minor in AL
  1138.     MOV    DosVersion,AX        ;Save for the Pascal code
  1139.  
  1140.     ;Get address of    the In-DOS flag
  1141.  
  1142.     PUSH    DS            ;Save DS
  1143.     DosCall    34h            ;Undocumented call to get pointer to
  1144.                     ;In-DOS    flag --    returned in ES:BX
  1145.     POP    DS            ;Restore DS
  1146.     SetPtr    CS:DosInUsePtr,    ES, BX    ;Set DOS-in-use    pointer
  1147.  
  1148.     ;Determine the address of the DOS critical pointer based on DOS    version
  1149.  
  1150.     SetZero    CX            ;Assume    failure
  1151.     MOV    AX,DosVersion        ;Get DosVersion    back into AX
  1152.     CMP    AX,0200h        ;Check for range 2.00 -    2.$FF
  1153.     JB    InitDosExit        ;Exit with error if < 2.00
  1154.     CMP    AX,0300h        ;Check for 3.00
  1155.     JA    Dos3x            ;If higher, need extra checks
  1156.     JB    Dos2            ;If less, it's DOS 2.x
  1157.  
  1158.     CMP    BX,019Ch        ;Is this Compaq    DOS 3.0?
  1159.     JE    DecOffset        ;If so,    critical flag below InDos
  1160.     SUB    BX,01AAh        ;Else, this is MS/PC-DOS 3.0
  1161.     JMP    SHORT SetCriticalPtr    ;Ready
  1162.  
  1163. Dos2:
  1164.     MOV    CS:Dos3Plus,False    ;Not running DOS 3.x or    above
  1165.     INC    BX            ;Critical pointer after    in-use pointer
  1166.     JMP    SHORT SetCriticalPtr    ;Ready
  1167.  
  1168. Dos3x:
  1169.     CMP    AX,030Ah        ;Check for 3.10    or higher
  1170.     JB    SetCriticalPtr        ;This shouldn't happen
  1171.     CMP    AX,0363h        ;If <=,    DOS version is 3.10-3.99
  1172.     JA    SetCriticalPtr        ;Higher    version    -- presumably OS/2
  1173.                     ;set DosCriticalPtr = DosInUsePtr
  1174.  
  1175. DecOffset:
  1176.     DEC    BX            ;Critical pointer before in-use    pointer
  1177.  
  1178. SetCriticalPtr:
  1179.     INC    CX            ;Set success flag
  1180.     SetPtr    CS:DosCriticalPtr, ES, BX    ;Set DOS critical pointer
  1181.  
  1182. InitDosExit:
  1183.     MOV    AX,CX            ;Result    into AX
  1184.     RET
  1185.  
  1186. InitTsrPtrs    ENDP
  1187.  
  1188. ;******************************************************    Int24
  1189.  
  1190. ;procedure Int24
  1191. ;Interrupt handler for DOS critical errors
  1192.  
  1193. FailCode    = 3
  1194. IgnoreCode    = 0
  1195.  
  1196. Int24        PROC NEAR
  1197.  
  1198.     MOV    CS:Int24Err,True    ;Set error flag
  1199.     XCHG    AX,DI            ;DI has    error code on entry
  1200.     MOV    CS:Int24ErrCode,AL    ;Store error code for later
  1201.     XCHG    AX,DI            ;Restore AX
  1202.     MOV    AL,FailCode        ;Fail the DOS call
  1203.     CMP    CS:Dos3Plus,True    ;DOS 3.x or higher?
  1204.     JE    Int24Exit        ;If so,    done
  1205.     MOV    AL,IgnoreCode        ;else, tell DOS    to I)gnore error instead
  1206. Int24Exit:
  1207.     IRET
  1208.  
  1209. Int24        ENDP
  1210.  
  1211. ;******************************************************    Int24Result
  1212.  
  1213. ;function Int24Result :    Word;
  1214. ;Returns word in AX. AH    has Int24ErrCode, AL has IoResult.
  1215.  
  1216. Int24Result    PROC FAR
  1217.  
  1218.     CALL    IoResultPrim        ;Get IoResult into AL
  1219.     SetZero    AH            ;Clear AH
  1220.     CMP    CS:Int24Err,True    ;Critical error    flag set?
  1221.     JNE    Int24ResultExit        ;No? Done
  1222.  
  1223.     ;Merge critical    error code into    result
  1224.  
  1225.     MOV    AH,CS:Int24ErrCode    ;Int24ErrCode into AH
  1226.     OR    AH,AH            ;Is AH 0?
  1227.     JNZ    IrAHnot0        ;If not, continue
  1228.     MOV    AH,0Dh            ;Else, attempt to write    to
  1229.                     ;write protected disk. Map to $0D.
  1230. IrAHnot0:
  1231.     MOV    CS:Int24ErrCode,0    ;Reset Int24ErrCode to 0
  1232.     MOV    CS:Int24Err,False    ;Clear error flag
  1233.  
  1234. Int24ResultExit:
  1235.     RET
  1236.  
  1237. Int24Result    ENDP
  1238.  
  1239. ;******************************************************    NopISR
  1240.  
  1241. NopISR    PROC NEAR
  1242.  
  1243.     IRET                ;For dummy ISR's
  1244.  
  1245. NopISR    ENDP
  1246.  
  1247. ;******************************************************    UseCritical
  1248.  
  1249. ;Force DOS 2.x to use DOS critical stack when getting/setting PSP
  1250.  
  1251. UseCritical    PROC NEAR
  1252.  
  1253.     CMP    CS:Dos3Plus,True    ;Is this DOS 3.x?
  1254.     JE    UCexit            ;if so,    do nothing
  1255.     LES    DI,CS:DosCriticalPtr    ;ES:DI => DosCriticalPtr
  1256.     MOV    BYTE PTR ES:[DI],-1    ;Tell DOS to use critical stack
  1257. UCexit:
  1258.     RET
  1259.  
  1260. UseCritical    ENDP
  1261.  
  1262. ;******************************************************    NotCritical
  1263.  
  1264. ;Reset DOS 2.x for non-critical    stack
  1265.  
  1266. NotCritical    PROC NEAR
  1267.  
  1268.     CMP    CS:Dos3Plus,True    ;Is this DOS 3.x?
  1269.     JE    NCexit            ;if so,    do nothing
  1270.     LES    DI,CS:DosCriticalPtr    ;ES:DI => DosCriticalPtr
  1271.     MOV    BYTE PTR ES:[DI],0    ;Tell DOS to use non-critical stack
  1272. NCexit:
  1273.     RET
  1274.  
  1275. NotCritical    ENDP
  1276.  
  1277. ;******************************************************    SetDosTraps
  1278.  
  1279. COMMENT    |
  1280.  
  1281.   SetDosTraps
  1282.   -----------
  1283.   Makes    preparations to    insure that DOS    is safe    to use during a    popup:
  1284.  
  1285.   -- Saves and restores    current    DTA and    PSP, switching to ours in between
  1286.   -- Prevents ^Break/^C    problems by taking over    dangerous interrupts
  1287.      and changing the DOS BREAK    level, restoring them after the    call
  1288.   -- Sets up DOS critical error    handler    for the    popup
  1289.  
  1290.   After    these preparations have    been made, the popup is    called.    Reentrancy
  1291.   problems are avoided by means    of the DosTrapsSet flag, which prohibits
  1292.   this code from being executed    twice before the first session is over.
  1293. |
  1294.  
  1295. SaveBreak    DB    0        ;Saved ^Break state
  1296. SavePSP        DW    0        ;Saved PSP segment
  1297. SaveInt02    Pointer    <>        ;Saved vectors
  1298. SaveInt1B    Pointer    <>
  1299. SaveInt23    Pointer    <>
  1300. SaveInt24    Pointer    <>
  1301. SaveInt34    Pointer    <>
  1302. SaveInt35    Pointer    <>
  1303. SaveInt36    Pointer    <>
  1304. SaveInt37    Pointer    <>
  1305. SaveInt38    Pointer    <>
  1306. SaveInt39    Pointer    <>
  1307. SaveInt3A    Pointer    <>
  1308. SaveInt3B    Pointer    <>
  1309. SaveInt3C    Pointer    <>
  1310. SaveInt3D    Pointer    <>
  1311. SaveInt3E    Pointer    <>
  1312. SaveInt3F    Pointer    <>
  1313. SaveInt75    Pointer    <>
  1314. SaveDTA        Pointer    <>        ;Saved DTA
  1315. OurReturn    DW    0        ;Our return address
  1316. OurCall        Pointer    <>        ;The address we're supposed to call
  1317.  
  1318. SetDosTraps    PROC NEAR
  1319.  
  1320.     OR    StateFlags,InSetTR    ;setting DOS traps
  1321.     MOV    DosTrapsSet,True    ;next time sys ok, DOS traps are set
  1322.     MOV    CS:PopupsEnabled,1    ;reenable popups
  1323.  
  1324.     MOV    AX,CS            ;AX = CS
  1325.     MOV    DS,AX            ;DS = CS
  1326.  
  1327.     assume    DS:CODE            ;Tell MASM that    DS = CS
  1328.  
  1329.     POP    OurReturn        ;POP our return    address    off the    stack
  1330.  
  1331.     ;save the address we're supposed to call (at ES:[BX-4])
  1332.     LES    BX,ES:[BX-4]        ;Get the address
  1333.     SetPtr    OurCall, ES, BX        ;And save it
  1334.  
  1335.     DosCallAX    3300h        ;Get current BREAK level
  1336.     MOV    SaveBreak,DL        ;Save current level, returned in DL
  1337.     SetZero    DL            ;0 means relax break checking
  1338.     DosCallAX    3301h        ;Set BREAK value in DL
  1339.  
  1340.     ;save interrupt    vectors    we're taking over
  1341.     GetVector 02h, SaveInt02
  1342.     GetVector 1Bh, SaveInt1B
  1343.     GetVector 23h, SaveInt23
  1344.     GetVector 24h, SaveInt24
  1345.     GetVector 34h, SaveInt34
  1346.     GetVector 35h, SaveInt35
  1347.     GetVector 36h, SaveInt36
  1348.     GetVector 37h, SaveInt37
  1349.     GetVector 38h, SaveInt38
  1350.     GetVector 39h, SaveInt39
  1351.     GetVector 3Ah, SaveInt3A
  1352.     GetVector 3Bh, SaveInt3B
  1353.     GetVector 3Ch, SaveInt3C
  1354.     GetVector 3Dh, SaveInt3D
  1355.     GetVector 3Eh, SaveInt3E
  1356.     GetVector 3Fh, SaveInt3F
  1357.     GetVector 75h, SaveInt75
  1358.  
  1359.     ;grab control of potentially dangerous interrupts
  1360.     MOV    DX,Offset NopIsr    ;DS:DX to points to IRET
  1361.     DosCallAX    251Bh        ;BIOS ^Break handler
  1362.     DosCallAX    2523h        ;DOS ^C    handler
  1363.  
  1364.     ;set up    our Int24 handler
  1365.     MOV    DX,Offset Int24        ;DS:DX points to Int24
  1366.     DosCallAX    2524h        ;Set critical error handler
  1367.  
  1368.     ;Restore Turbo's interrupt handlers
  1369.     LDS    DX,CS:NewInt02
  1370.     DosCallAX    2502h
  1371.     LDS    DX,CS:NewInt34
  1372.     DosCallAX    2534h
  1373.     LDS    DX,CS:NewInt35
  1374.     DosCallAX    2535h
  1375.     LDS    DX,CS:NewInt36
  1376.     DosCallAX    2536h
  1377.     LDS    DX,CS:NewInt37
  1378.     DosCallAX    2537h
  1379.     LDS    DX,CS:NewInt38
  1380.     DosCallAX    2538h
  1381.     LDS    DX,CS:NewInt39
  1382.     DosCallAX    2539h
  1383.     LDS    DX,CS:NewInt3A
  1384.     DosCallAX    253Ah
  1385.     LDS    DX,CS:NewInt3B
  1386.     DosCallAX    253Bh
  1387.     LDS    DX,CS:NewInt3C
  1388.     DosCallAX    253Ch
  1389.     LDS    DX,CS:NewInt3D
  1390.     DosCallAX    253Dh
  1391.     LDS    DX,CS:NewInt3E
  1392.     DosCallAX    253Eh
  1393.     LDS    DX,CS:NewInt3F
  1394.     DosCallAX    253Fh
  1395.     LDS    DX,CS:NewInt75
  1396.     DosCallAX    2575h
  1397.     MOV    AX,CS            ;Reset DS to CS
  1398.     MOV    DS,AX
  1399.  
  1400.     ;save current DTA and switch to    ours
  1401.     DosCall    2Fh            ;Get current DTA
  1402.     SetPtr    SaveDTA, ES, BX        ;Save current DTA (in ES:BX)
  1403.     LDS    DX,OurDTA        ;DS:DX points to our DTA
  1404.     DosCall    1Ah            ;Set DTA
  1405.  
  1406.     assume    DS:NOTHING        ;we don't know what ds is
  1407.  
  1408.     ;save current PSP and switch to    ours
  1409.     CALL    UseCritical        ;Switch    to critical stack in DOS 2.x
  1410.     DosCallAX    5100h        ;Get current PSP
  1411.     MOV    CS:SavePSP,BX        ;Save PSP returned in BX
  1412.     MOV    BX,CS:OurPSP        ;Get our PSP
  1413.     DosCallAX    5000h        ;Switch    to our PSP
  1414.     CALL    NotCritical        ;Critical stack    no longer needed
  1415.  
  1416.     ;reset DS to DATA
  1417.     MOV    DS,CS:OurDS        ;Restore our DS
  1418.     assume    DS:DATA            ;Tell MASM that    DS = DATA
  1419.  
  1420.     ;Save info for emergency exit and call the popup
  1421.     MOV    LastEntrySS,SS        ;Save SS
  1422.     MOV    LastEntrySP,SP        ;Save SP
  1423.     MOV    LastEntryIP,Offset SDTReentry    ;Save reentry offset
  1424.  
  1425.     ;make popup look like main block to the    overlay    manager
  1426.     XOR    BP,BP            ;BP = 0
  1427.  
  1428.     AND    StateFlags,NotSetTR    ;done setting DOS traps
  1429.     CallFar    OurCall            ;Call the popup
  1430.     OR    StateFlags,InSetTR    ;resetting DOS traps
  1431.  
  1432. SDTReentry:
  1433.     ;reset DS to CS    and PUSH our return address back on the    stack
  1434.     MOV    AX,CS            ;Set DS    to CS
  1435.     MOV    DS,AX
  1436.     assume    DS:CODE            ;Tell MASM that    DS = CS
  1437.  
  1438.     PUSH    OurReturn        ;PUSH the return address back up
  1439.  
  1440.     ;restore saved PSP
  1441.     CALL    UseCritical        ;Switch    to critical stack in DOS 2.x
  1442.     MOV    BX,SavePSP        ;BX = saved PSP
  1443.     DosCallAX    5000h        ;Set PSP function
  1444.     CALL    NotCritical        ;Critical stack    no longer needed
  1445.  
  1446.     ;restore saved DTA
  1447.     LDS    DX,SaveDTA        ;DS:DX points to saved DTA
  1448.     DosCall    1Ah            ;Set DTA function
  1449.  
  1450.     assume    DS:NOTHING        ;Tell MASM that    DS = ?
  1451.  
  1452.     ;restore saved interrupt vectors
  1453.     LDS    DX,CS:SaveInt02
  1454.     DosCallAX    2502h
  1455.     LDS    DX,CS:SaveInt1B
  1456.     DosCallAX    251Bh
  1457.     LDS    DX,CS:SaveInt23
  1458.     DosCallAX    2523h
  1459.     LDS    DX,CS:SaveInt24
  1460.     DosCallAX    2524h
  1461.     LDS    DX,CS:SaveInt34
  1462.     DosCallAX    2534h
  1463.     LDS    DX,CS:SaveInt35
  1464.     DosCallAX    2535h
  1465.     LDS    DX,CS:SaveInt36
  1466.     DosCallAX    2536h
  1467.     LDS    DX,CS:SaveInt37
  1468.     DosCallAX    2537h
  1469.     LDS    DX,CS:SaveInt38
  1470.     DosCallAX    2538h
  1471.     LDS    DX,CS:SaveInt39
  1472.     DosCallAX    2539h
  1473.     LDS    DX,CS:SaveInt3A
  1474.     DosCallAX    253Ah
  1475.     LDS    DX,CS:SaveInt3B
  1476.     DosCallAX    253Bh
  1477.     LDS    DX,CS:SaveInt3C
  1478.     DosCallAX    253Ch
  1479.     LDS    DX,CS:SaveInt3D
  1480.     DosCallAX    253Dh
  1481.     LDS    DX,CS:SaveInt3E
  1482.     DosCallAX    253Eh
  1483.     LDS    DX,CS:SaveInt3F
  1484.     DosCallAX    253Fh
  1485.     LDS    DX,CS:SaveInt75
  1486.     DosCallAX    2575h
  1487.  
  1488.     ;restore DOS BREAK level
  1489.     MOV    AX,CS            ;Reset DS to CS
  1490.     MOV    DS,AX
  1491.     assume    DS:CODE            ;Tell MASM that    DS = CS
  1492.  
  1493.     MOV    DL,SaveBreak        ;Restore saved break state
  1494.     DosCallAX    3301h        ;Set break check level
  1495.  
  1496.     MOV    Int24Err,False        ;Don't leave error flag set
  1497.  
  1498. SetTrapExit:
  1499.     MOV    DS,CS:OurDS        ;Restore our DS
  1500.     assume    DS:DATA            ;Tell MASM that    DS = DATA
  1501.  
  1502.     MOV    DosTrapsSet,False    ;DOS traps are not set now
  1503.     AND    StateFlags,NotSetTR    ;not setting DOS traps now
  1504.  
  1505.     RET
  1506.  
  1507. SetDosTraps    ENDP
  1508.  
  1509. ;******************************************************    EmergencyExit
  1510.  
  1511. ;Called    by exit/error handler in case of runtime error while popped up
  1512.  
  1513. EmergencyExit    PROC NEAR
  1514.  
  1515.     CLI                ;Interrupts off
  1516.     MOV    SS,LastEntrySS        ;Switch    stacks
  1517.     MOV    SP,LastEntrySP
  1518.     STI                ;Interrupts on
  1519.     ADD    SP,4            ;Get rid of the    parameter to the popup
  1520.     MOV    BX,LastEntryIP        ;Jump to re-entry point
  1521.     JMP    BX
  1522.  
  1523. EmergencyExit    ENDP
  1524.  
  1525. ;******************************************************    DosBusyFlag
  1526.  
  1527. ;function DosBusyFlag :    Byte;
  1528. ;Returns current value of DOS busy flag
  1529.  
  1530. DosBusyFlag    PROC FAR
  1531.  
  1532.     GetPtr    CS:DosInUsePtr        ;ES:DI => DosInUsePtr
  1533.     MOV    AL,ES:[DI]        ;value into AL
  1534.     RET
  1535.  
  1536. DosBusyFlag    ENDP
  1537.  
  1538. ;******************************************************    DosCriticalFlag
  1539.  
  1540. ;function DosCriticalFlag : Byte;
  1541. ;Returns current value of DOS critical flag
  1542.  
  1543. DosCriticalFlag    PROC FAR
  1544.  
  1545.     GetPtr    CS:DosCriticalPtr    ;ES:DI => DosCriticalPtr
  1546.     MOV    AL,ES:[DI]        ;value into AL
  1547.     RET
  1548.  
  1549. DosCriticalFlag    ENDP
  1550.  
  1551. CODE    ENDS
  1552.  
  1553.     END
  1554.