home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / asmutil / tbones07.zip / TSRBONES.ASM < prev    next >
Assembly Source File  |  1991-01-20  |  38KB  |  794 lines

  1. ;************************
  2. PAGE 55,132             ;Format .LST listing at 55 lines by 132 columns.
  3. TITLE TSRBONES Version 0.1 Jan 20 91 Robert Curtis Davis
  4. SUBTTL Introduction
  5. ;**************************************************************************
  6. ;
  7. ;       TSRBONES.ASM     Version 0.1     Jan 20 91
  8. ;       A part of the TBONES software package.
  9. ;
  10. ;       Copyright (C) 1990, 1991 by Robert Curtis Davis,
  11. ;    All Rights Reserved.
  12. ;
  13. ;    DESCRIPTION:
  14. ;    ASM Program template for Terminate-and-Stay-Resident (TSR) programs
  15. ;        that are activated by a specified HotKey WHEN DOS IS NOT
  16. ;               BUSY (the InDOS Flag AND the DOS Critical Error Flag are zero)
  17. ;               flag), OR WHEN DOS IS AT "BUSY IDLE" (when INT28h is called),
  18. ;               AND WHEN NO HARDWARE INTERRUPT IRQ0-IRQ7 IS BEING HANDLED.
  19. ;               This avoids problems of interfering with hardware interrupt
  20. ;               handling and with DOS non-reentrancy; and allows DOS function
  21. ;               calls above 0Ch to be used in the TSR routine. The TSR's code
  22. ;               prevents multiple installations. Also checks DOS version and
  23. ;               requires DOS Version 2 or later before installation is
  24. ;               permitted.
  25. ;
  26. ;    PURPOSE:
  27. ;    Provides a skeletal framework program as a starting point in the 
  28. ;       design of your own HotKey TSRs which use DOS function calls, and
  29. ;       for which a single installation is desired.
  30. ;
  31. ;                   E-mail address:
  32. ;              Internet: sonny@trantor.harris-atd.com
  33. ;
  34. ;                  US Mail address:
  35. ;                                   430 Bahama Drive
  36. ;                                   Indialantic, FL 32903
  37. ;
  38. ;**************************************************************************
  39. ;
  40. ; Special thanks to Roy Silvernail, whose persistent hacking (in the best
  41. ; sense of that word) and E-mail exchanges over the holiday season in
  42. ; December 1990, rooted out TBONES incompatibilities with Borland's TASM v.1.0.
  43. ;
  44. ;**************************************************************************
  45. ;
  46. ; Special thanks to Anto Prijosoesilo and Richard Brittain for E-mail
  47. ; exchanges which helped solve detailed problems with the implementation of
  48. ; the "Pseudo-Environment" idea.
  49. ;
  50. ;**************************************************************************
  51. ;
  52. ; Special thanks to David Kirschbaum, whose Toad Hall Tweaks significantly
  53. ; improved an early version of the TBONES Assembly Language code:
  54. ;
  55. ;v0.01    Toad Hall Tweak, 25 Nov 90
  56. ;**************************************************************************
  57. SUBTTL Code Segment
  58. PAGE
  59. ;**************************************************************************
  60. ;
  61. CodeSeg        segment
  62.         assume cs:CodeSeg,ds:CodeSeg
  63. BeginDump    EQU    $        ;Roy Silvernail - Keep TASM 1.0 happy
  64.                     ;when computing # resident paragraphs.
  65. ;
  66.         org    2CH        ;v0.01 ORG in PSP to pick up the
  67. envseg        label    word        ;v0.01 Environment Segment.
  68. ;
  69.         org    100h        ;ORG for all COM programs.
  70. ;
  71. Entry        PROC    NEAR        ;v0.01
  72.         jmp    TSRinit        ;Jump over resident portion and
  73.                     ;initialize things and make code
  74.                     ;between Entry: and TSRinit: resident.
  75. ;
  76. ; Old Interrupt Vectors are stored here during TSR initialization:
  77. oldint09        dd      ?               ;Keyboard Hardware Interrupt.
  78. oldint13        dd      ?               ;Disk BIOS Interrupt.
  79. oldint16        dd      ?               ;Keyboard BIOS Interrupt.
  80. oldint28        dd      ?               ;DOS Idle Interrupt.
  81. ;
  82. ; For this HotKey TSR Template, specify Keyboard Interrupt 09h as the Hook:
  83. HOOK09        equ    09h            ;Hooked Interrupt 09h.
  84. ; Int 13h is used to set a flag to prevent TSR trigger while disk active:
  85. HOOK13          equ     13h                     ;Hooked Interrupt 13h.
  86. ; Int 16h is hooked solely to provide way to check for prior TSR installation.
  87. HOOK16        equ    16h            ;Hooked Interrupt 16h.
  88. ; We also have to hook Interrupt 28h to check for "DOS idle":
  89. HOOK28        equ    28h            ;Hooked Interrupt 28h.
  90. ;
  91. bellgate    db    0    ;Gate closed (=1) when in Bell routine.
  92.                 ;Gate open (=0) when not in Bell routine.
  93. ; Below:
  94. ; EQUates related to the Intel 8259A Programmable Interrupt Controller (PIC)
  95. ;    chip. Hardware Interrupts IRQ0 through IRQ7 are controlled by the PIC.
  96. ;
  97. ;    To really understand the nitty-gritty details of this stuff, 
  98. ;    you have to study the Intel Specification data for the 8259A PIC chip.
  99. ;    These EQUates are used in this TSR to examine the PIC chip's In Service
  100. ;    Register (ISR) to be sure that the TSR is not interrupting one of
  101. ;    the hardware interrupt service routines. The reason for not wanting to 
  102. ;    interrupt these hardware interrupt service routines is that they are
  103. ;    often time-critical and can be compromised by intruding on them with
  104. ;    our TSR (for example, a hardware COM port interrupt-driven comm 
  105. ;    program might lose bytes on a modem transfer if we bull our way in and
  106. ;    steal the CPU away from the comm program's service routine):
  107. PICPORT        EQU    20h        ;I/O Port for the 8259A PIC chip.
  108. ISRREQ        EQU    00001011B    ;This is a byte defining the
  109.                     ;Operation Control Word 3 (OCW3) to
  110.                     ;output on port 20h to make the PIC
  111.                     ;chip's In Service Register available 
  112.                     ;for reading by the CPU on the
  113.                     ;next IN 20h command.
  114. ;
  115. ; EQUs defining Key Flag weights in the Key Flag Byte:
  116. RSHIFT        equ    00000001B        ;Right Shift Key Flag weight.
  117. LSHIFT        equ    00000010B        ;Left Shift  Key Flag weight.
  118. CTRL        equ    00000100B        ;Ctrl        Key Flag weight.
  119. ALT        equ    00001000B        ;Alt         Key Flag weight.
  120. ;SCROLL          equ     00010000B               ;Scroll Lock Key Flag weight.
  121. ;NUM             equ     00100000B               ;Num Lock    Key Flag weight.
  122. ;CAPS            equ     01000000B               ;Caps Lock   Key Flag weight.
  123. INSRT        equ    10000000B        ;Ins         Key Flag weight.
  124. ;
  125. LockKeyMask     equ     10001111B               ;For masking out Scroll, Caps,
  126.                                                 ;and Num Lock bits in KeyFlags.
  127. ;
  128. ; Pointer to "DOS busy" (InDOS) flag (loaded during TSR initialization):
  129. indosptr    dd    ?
  130. ;
  131. ; Pointer to "Critical Error" (CritErr) flag (loaded at TSR initialization):
  132. criterrptr    dd    ?
  133. ;
  134. ; Pointer to "Print Screen" busy (PrtScrn) flag
  135. prtscrn         dd      00500000h
  136. ;
  137. ; hotkeyflag used to signal HotKey pressed to "DOS idle" Interrupt 28h:
  138. hotkeyflag      db      0       ;hotkeyflag initially zero.
  139. ;
  140. ; diskflag used to prevent TSR trigger during time-critical Disk operations:
  141. diskflag        db      0       ;diskflag initially zero.
  142. ;*************************************************************************
  143. ;    Your HotKey is specified here:
  144. ;       (This sample HotKey is set for Ctrl-Alt-B)
  145. ;
  146. ; Specify TSR's HotKey Shift Keys:
  147. KEYFLAGBYTE     equ     CTRL+ALT                ;HotKey Flags
  148. ;
  149. ; Specify TSR's HotKey Scan Code:
  150. HOTKEY          equ     30h                     ;'B' (for Bones) key
  151. ;
  152. ;*************************************************************************
  153. ; Specify TSR's signature words:
  154. TSRsigA         equ     'TS'            ;'TSRBONES' Signature
  155. TSRsigB         equ     'RB'
  156. TSRsigC         equ     'ON'
  157. TSRsigD         equ     'ES'
  158. ;*************************************************************************
  159. Entry    ENDP        ;v0.01
  160. ;
  161. ;*************************************************************************
  162. SUBTTL User-supplied TSR Routine
  163. PAGE
  164. ;*************************************************************************
  165. ROUTINE         PROC    NEAR
  166. ;*************************************************************************
  167. ;    Code for your HotKey-triggered TSR routine  GOES HERE:
  168. ;    ( Here, a dummy routine has been placed which simply rings the
  169. ;      terminal Bell whenever the TSR is triggered. )
  170. ;
  171. ;    Announce this dummy TSR's trigger by a Bell signal:
  172. ;
  173. Enter:
  174.                 mov     al,07h          ;al = ASCII Bell.
  175.                 mov     bh,0            ;Video page.
  176.                 mov     cx,1            ;No. of bytes to write.
  177.                 mov     ah,0Eh          ;BIOS Int10,OEh=TTY Screen.
  178.                 Int     10h             ;Write ASCII Bell to screen.
  179. ;
  180. Exit:
  181.                 ret                     ;Return from TSR routine.
  182. ;
  183. ROUTINE         endp
  184. ;
  185. ;    End of your HotKeyed TSR routine.
  186. ;***************************************************************************
  187. SUBTTL Hooked Interrupts
  188. PAGE
  189. ;***************************************************************************
  190. ;
  191. NewInt09    PROC    FAR        ;v0.01
  192. ;
  193. ; The following three instructions often are said to "simulate an interrupt"
  194. ; that calls the PRIOR interrupt handler routine and then the prior interrupt
  195. ; handler's IRET instruction pops the flags and returns here to the point
  196. ; after the following CALL instruction.
  197. ;    The reason for "simulating the interrupt" here is to give prior (and
  198. ; presumably more time-critical) handlers a shot at processing this interrupt
  199. ; before we process with this TSR's code.
  200. ;
  201.         pushf            ;Push flags as a true interrupt would.
  202.                 cli                     ;Be sure interrupts are disabled.
  203.         call    CS:oldint09    ;Call FAR PTR address of old interrupt
  204. ;                    ;     handler routine.
  205. ;
  206. ;
  207.                 push    ax      ;Prepare to check for Hotkey.
  208.                 push    bx      ;Save all registers (DS is already pushed).
  209.                 push    cx
  210.                 push    dx
  211.                 push    si
  212.                 push    di
  213.                 push    bp
  214.                 push    ds
  215.                 push    es
  216. ;
  217.                 push    CS              ;Set up data segment
  218.                 pop     DS              ;register to point to code segment.
  219. ;
  220.                 ASSUME  DS:CodeSeg      ;v0.01
  221. ;
  222. ;       Determine if the current Keyboard Interrupt (Int09h) occurred
  223. ;       because this TSR's HotKey was pressed:
  224.                 in      al,60h          ;Get current Key Scan Code.
  225.                 cmp     al,HOTKEY       ;Is it HotKey's Scan Code?
  226.                 jne     Exit09          ;Exit if not.
  227.                 mov     ah,02h          ;Int16h,Fcn02h:GetKEYFLAGBYTE.
  228.                 Int     16h             ;Return Key Flag Byte in al.
  229.                 and     al,LockKeyMask  ;Mask out Num, Caps, Scroll Lock bits.
  230.                 cmp     al,KEYFLAGBYTE  ;Are the HotKey Flags active ?
  231.                 jne     Exit09          ;Exit if not.
  232. ;
  233. ;       At this point, Hotkey is known to have been pressed. First, purge
  234. ;       the DOS Keyboard type-ahead buffer of the hot key(s) so they won't
  235. ;       be passed on to DOS:
  236. ;
  237. ClrKbdBuf:      ;Clear Keyboard buffer:
  238.                 mov     ah,01h          ;Get Keyboard buffer status
  239.                 int     16h             ;via BIOS Interrupt 16h.
  240.                 jz      BufClr          ;Jump if buffer empty.
  241.                 mov     ah,00h          ;Get key from buffer (to purge it)
  242.                 int     16h             ;via BIOS Interrupt 16h.
  243.                 jmp     ClrKbdBuf       ;Loop back to purge another key.
  244. BufClr:
  245. ;
  246. ; We shall allow other interrupts to occur during our TSR ROUTINE.
  247. ; If we didn't allow other interrupts (through the STI instruction),
  248. ; we could lock out time-critical interrupts from access to the CPU during
  249. ; our TSR routine. However, by allowing interrupts during our routine, we 
  250. ; have an increased responsibility to make sure critical portions of our
  251. ; own code is not re-entered. (The "bellgate" stuff below is an example
  252. ; of a measure necessary to keep us from re-entering our own TSR's code).
  253. ; What we really want to do by allowing interrupts is to make the CPU avail-
  254. ; able to OTHER critical interrupt service routines WITHOUT swarming all over 
  255. ; ourselves through multiple detections of our own HotKey.
  256. ;               This "gate" technique is a good one to keep in
  257. ;               mind whenever you have a code region in an interrupt handler
  258. ;               that needs to be protected from re-entry:
  259. ;
  260.                 cmp     bellgate,0      ;Is it clear to re-enter Hotkey code?
  261.                 jne     BusyExit09      ;Exit if not,
  262.                 mov     bellgate,1      ;Else, close gate and proceed.
  263. ;
  264.                 CLI                     ;DISABLE INTERRUPTS
  265. ;       Now we will check to be sure that no time-critical hardware interrupt
  266. ;       handling is underway. We do this by querying the Intel 8259A Program-
  267. ;       mable Interrupt Controller (PIC) chip's In Service Register (ISR) and
  268. ;    testing it to see that it is zero (i.e., nothing being serviced).
  269. ;
  270. HotKeyPressed:
  271.                 mov     al,ISRREQ       ;al=PIC's OCW3 to ask for ISR Register.
  272.         out    PICPORT,al    ;Tell PIC to get ISR ready for reading.
  273.         jmp    Dally        ;Give PIC time to make ISR available.
  274. Dally:        in    al,PICPORT    ;Fetch the ISR Register from PIC.
  275.                 or      al,al           ;Activate processor flags.
  276.                 jnz     SetFlag         ;If al not zero, go set flag.
  277. ;
  278. ;       At this point, HotKey is known to be pressed AND NO hardware interrupt
  279. ;    is being serviced. BUT is InDOS flag zero, indicating that DOS is
  280. ;    not busy and therefore can safely be entered? This will now be
  281. ;    checked:
  282. ;
  283. HotKeyNoHWI:
  284.         les    bx,indosptr    ;es:bx = pointer to InDOS flag
  285.         mov    al,es:[bx]    ;al = InDOS flag.
  286.                 or      al,al           ;Activate processor flags.
  287.                 jnz     SetFlag         ;Jump if InDOS not zero.
  288. ;
  289. ;       Include a check on Critical Error flag. Don't trigger the TSR if
  290. ;       DOS is in the middle of handling a Critical Error:
  291. ;
  292.                 les     bx,criterrptr   ;es:bx = pointer to CritErr flag.
  293.                 mov     al,es:[bx]      ;al = CritErr flag.
  294. ;
  295. ;       Also, don't trigger the TSR if time-critical Disk access is underway:
  296. ;               Normally, this Disk check would not be necessary since the
  297. ;               InDOS flag would not be clear during Disk accesses, BUT some
  298. ;               software will bypass DOS and go directly to the BIOS Int13
  299. ;               Interrupt for Disk access. Therefore, to be safe, we HAVE to
  300. ;               be sure Int13 has not been entered and is not in the process
  301. ;               of performing time-critical Disk stuff when we hit the TSR
  302. ;               HotKey. Many TSRs don't even check this. They just depend
  303. ;               upon users not to hit the HotKey during Disk access. That seems
  304. ;               terribly risky to me:
  305. ;
  306.                 or      al,diskflag     ;al = CritErr | diskflag
  307.                                         ; (| => Logical OR).
  308.                 jnz     Exit09          ;If al not zero, try again later.
  309. ;
  310. ;       Also, don't trigger the TSR if a PrtScrn is in progress:
  311. ;       (Is this really necessary? I don't think TSR will trigger during PrtSc)
  312.                 les     bx,prtscrn      ;ES:bx = pointer to PrtScrn busy flag.
  313.                 cmp     BYTE PTR es:[bx],1      ;Is PrtScrn in progress?
  314.                 je      Exit09          ;If so, try again later.
  315. ;
  316.                 STI                     ;Allow other interrupts in our TSR.
  317. ;
  318.                 call    ROUTINE         ;All is clear!, so call routine.
  319.                 mov     hotkeyflag,0    ;Be sure HotKey flag is reset.
  320.                 jmp     SHORT Exit09    ;Exit after TSR routine.
  321. ;
  322. SetFlag:
  323.                 mov     hotkeyflag,1    ;Set HotKey Flag for use by Int28h.
  324. ;
  325. Exit09:
  326.                 mov     CS:bellgate,0   ;Open gate allowing new HotKey detect.
  327. BusyExit09:
  328.                 pop     es              ;Restore all registers
  329.                 pop     ds
  330.                 ASSUME  DS:NOTHING      ;v0.01
  331.                 pop     bp
  332.         pop    di
  333.         pop    si
  334.         pop    dx
  335.         pop    cx
  336.         pop    bx
  337.         pop    ax
  338. ;
  339. ;
  340. ;    Return from this TSR's Keyboard Interrupt 09h handler routine:
  341.         iret
  342. ;
  343. NewInt09    ENDP            ;v0.01
  344. ;
  345. ;*************************************************************************
  346. PAGE
  347. ;*************************************************************************
  348. NewInt13        PROC    FAR             ;We hook Int13h only for purpose
  349.                                         ;of setting a flag to prevent our
  350.                                         ;TSR from triggering during time-
  351.                                         ;critical Disk accesses.
  352.                 mov     CS:diskflag,1   ;Set flag to show Disk access.
  353. ;
  354.                 pushf                   ;Invoke prior Int13 handler
  355.                 cli                     ;(be sure interrupts disabled)
  356.                 call    CS:oldint13     ;by simulating an interrupt.
  357. ;
  358.                 mov     CS:diskflag,0   ;Clear flag to show Disk finished.
  359. ;
  360. ; The following RET 2 bumps the SP register up by 2 bytes to effectively
  361. ;        take the flags off the stack (where they were put by the invoking
  362. ;        INT 13h) WITHOUT popping them off and ruining the meaningful flags
  363. ;        left in the Flags register by the original DOS INT13 handler (the
  364. ;        DOS INT13 handler also returns via a RET 2 to keep from ruining the
  365. ;        Flags that the handler has painstakingly prepared for communicating
  366. ;        back to the calling program). The effect on the stack pointer, SP, is
  367. ;        exactly the same as with the more usual IRET. It is just that the Flags
  368. ;        in the Flag register are preserved at the values the handler placed
  369. ;        and wanted there.
  370. ;
  371.                 RET     2               ;Return from interrupt while
  372.                                         ;preserving flags.
  373. ;
  374. NewInt13        ENDP
  375. ;*************************************************************************
  376. PAGE
  377. ;*************************************************************************
  378. NewInt16    PROC    FAR        ;v0.01
  379. ;
  380.                 push    ds              ;Entry for New Int. Handler.
  381. ;                                       ;Save required registers.
  382. ;
  383.                 push    CS              ;Set data seg   v0.01
  384.                 pop     DS              ;to our CodeSeg v0.01
  385.         ASSUME    DS:CodeSeg    ;v0.01
  386. ;
  387. ; This next portion of code provides back to the non-resident
  388. ; TSR installation code a check on whether the TSR has already been installed.
  389. ; It does this through the following technique:
  390. ;        Check to see if the ax, bx, cx, dx registers are loaded with this
  391. ;    TSR's signature words. Since all TSR ax signature words are chosen 
  392. ;    so as NOT to match any allowed DOS Int16h Function in ah, ALL
  393. ;    standard DOS Int16h calls will exit from this sequence of compares
  394. ;    at the first JNE instruction below and will ultimately be processed
  395. ;    by the standard DOS Int16h handler.
  396. ;     The ONLY place where all the registers are loaded with THIS TSR's
  397. ;    signature words and then Int16h called is IN THE INITIALIZATION CODE 
  398. ;    AT THE END OF THIS TSR. Given that all the signature words are matched
  399. ;    in the four comparisons below, we need to signal back to the
  400. ;    invoking TSR initialization code by setting the data registers to
  401. ;    values that NEVER would be returned by the standard DOS Int16h handler,
  402. ;    and that therefore could ONLY have come from this previously-installed
  403. ;    TSR's Int16h handler code. The TSR installation code will then take
  404. ;    the return of these unique register values as the indication that
  405. ;    this TSR has already been installed.
  406. ;
  407.         cmp    ax,TSRsigA    ;Is ax = TSR signature word A?
  408.         jne    Exit16        ;No, let regular Int16 handle this.
  409.         cmp    bx,TSRsigB    ;Is bx = TSR signature word B?
  410.         jne    Exit16        ;No, let regular Int16 handle this.
  411.         cmp    cx,TSRsigC    ;Is cx = TSR signature word C?
  412.         jne    Exit16        ;No, let regular Int16 handle this.
  413.         cmp    dx,TSRsigD    ;Is dx = TSR signature word D?
  414.         jne    Exit16        ;No, let regular Int16 handle this.
  415. ;
  416. ;       The ONLY way you ever get to here is by having called Int16h with the
  417. ;    ax, bx, cx, dx registers loaded with this TSR's signature words. This
  418. ;    only occurs in the TSR initialization routine. Therefore, set the
  419. ;       registers to return values that a DOS Int16h never would, and then
  420. ;       return from this interrupt back to the TSR initialization routine.
  421. ;
  422.                 xchg    bx,cx   ;Exchange regs. (DOS Int16h wouldn't do this)
  423.         xchg    ax,dx    ;   "         "        "
  424. ;
  425.                 pop     ds      ;Restore regs.
  426.                 iret            ;Return from Int to TSR Initialize routine.
  427. ;
  428. Exit16:
  429.                 pop     ds                      ;Restore all registers
  430.         ASSUME    DS:NOTHING    ;v0.01
  431. ;
  432. ;       Chain to prior Interrupt 16h handler routine:
  433.                 jmp     CS:oldint16
  434. ;
  435. NewInt16        ENDP            ;v0.01
  436.  
  437. ;*************************************************************************
  438. PAGE
  439. ;*************************************************************************
  440. NewInt28    PROC    FAR        ;v0.01
  441. ;
  442.                 pushf                   ;Call prior handler.
  443.                 cli
  444.                 call    CS:oldint28
  445. ;
  446. ;    Determine if this TSR's HotKey has been flagged as pressed:
  447.                 cmp     CS:hotkeyflag,1 ;Has HotKey been pressed?
  448.                 jne     QuickExit       ;Exit if not.
  449. ;
  450.                 cmp     CS:bellgate,1   ;Is gate closed?
  451.                 je      QuickExit       ;If so, exit.
  452.                 mov     CS:bellgate,1   ;Else close gate and proceed.
  453. ;
  454.                 CLI                     ;DISABLE INTERRUPTS
  455. ;       If you are here, then HotKey has been pressed.
  456.                 push    ax              ;Entry for New Int. Handler.
  457.                 push    bx              ;Save all registers.
  458.                 push    cx
  459.                 push    dx
  460.                 push    si
  461.                 push    di
  462.                 push    bp
  463.                 push    ds
  464.                 push    es
  465. ;
  466.                 push    CS
  467.                 pop     DS
  468.                 ASSUME  DS:CodeSeg      ;v0.01
  469. ;
  470. ;
  471. ;       Make sure InDOS flag is no greater than 1. The InDOS flag equals
  472. ;       the number of DOS calls currently active. If we want to be sure
  473. ;       that we do not disrupt DOS by reentry in our TSR user routine,
  474. ;       we have to be sure that the present Int28 has occurred while
  475. ;       only 1-deep into DOS calls (as it is when DOS is TRULY idling):
  476.                 les     bx,indosptr             ;ES:bx points to InDOS flag.
  477.                 cmp     BYTE PTR ES:[bx],1      ;Is InDOS flag above 1?
  478.                 ja      Exit28                  ;Exit if InDOS > 1.
  479. ;
  480. ;       DOS is known to be idling at this point.
  481. ;    At this point, HotKey is known to have been pressed. Now we will
  482. ;    check to be sure that no time-critical hardware interrupt handling
  483. ;    is underway. We do this by querying the Intel 8259A Programmable
  484. ;    Interrupt Controller (PIC) chip's In Service Register (ISR) and
  485. ;    testing it to see that it is zero (i.e., nothing being serviced
  486. ;    except Int09 (PIC's IRQ1) ):
  487. HotKeyPressed2:
  488.                 mov     al,ISRREQ       ;al=PIC's OCW3 to ask for ISR Register.
  489.         out    PICPORT,al    ;Tell PIC to get ISR ready for reading.
  490.         jmp    Dally2        ;Give PIC time to make ISR available.
  491. Dally2:        in    al,PICPORT    ;Fetch the ISR Register from PIC.
  492. ;
  493. ;       Also, don't trigger the TSR if time-critical Disk access is underway:
  494.                 or      al,diskflag     ;al = ISR | diskflag. (| => Logical OR).
  495.                 jnz     Exit28          ;If al not zero, try again later.
  496. ;
  497. ;       Also, don't trigger the TSR if a PrtScrn is in progress:
  498. ;       (Is this really necessary? I don't think TSR will trigger during PrtSc)
  499.                 les     bx,prtscrn      ;ES:bx = pointer to PrtScrn busy flag.
  500.                 cmp     BYTE PTR es:[bx],1      ;Is PrtScrn in progress?
  501.                 je      Exit28                  ;If so, Exit w/o triggering TSR.
  502. ;
  503.                 STI                     ;ENABLE OTHER INTERRUPTS.
  504. ;
  505. HotKeyFlagSet:
  506. ;    Here, HotKey is flagged as pressed and DOS is idling (since we are
  507. ;       servicing Int28h) and no hardware interrupts are being handled.
  508. ;       Also, no Print Screen or Disk access is underway.
  509. ;    DOS Int21h Functions above 0Ch can be accessed if required in your 
  510. ;    TSR routine:
  511. ;
  512.                 call    ROUTINE         ;Call TSR routine; DOSOK & No Hardware
  513.                     ;interrupts being serviced.
  514.                 mov     CS:hotkeyflag,0    ;Clear HotKey Flag.
  515. ;
  516. Exit28:
  517.                 pop     es                      ;Restore all registers
  518.                 pop     ds
  519.                 ASSUME  ds:NOTHING
  520.                 pop     bp
  521.         pop    di
  522.         pop    si
  523.         pop    dx
  524.         pop    cx
  525.         pop    bx
  526.         pop    ax
  527.                 mov     CS:bellgate,0
  528. ;
  529. QuickExit:
  530. ;       Return from this Keyboard Interrupt 28h handler routine:
  531.                 iret
  532. ;
  533. NewInt28        ENDP            ;v0.01
  534. ;*************************************************************************
  535. ;    -END OF TSR's RESIDENT CODE-
  536. ;    Only the code above will remain locked in memory
  537. ;        after the initialization performed below.
  538. ;*************************************************************************
  539. SUBTTL TSR BOOSTER (Initialization)
  540. PAGE
  541. ;*************************************************************************
  542. ;       BEGINNING OF TSR's INITIALIZATION CODE (THE "BOOSTER"):
  543. ;    The following code is protected in RAM *ONLY* during initialization
  544. ;               of the TSR that occurs when the TSR name is first invoked
  545. ;        at the DOS command level. All the following code is abandonned
  546. ;               unprotected in RAM after the Terminate-and-Stay-Resident (TSR)
  547. ;        call to Function 31h of DOS Interrupt 21h below. This
  548. ;        is allowed to happen because the code's work is complete at
  549. ;        that point. The code will be overwritten as the memory which
  550. ;        it temporarily occupied is needed by DOS for other purposes.
  551. ;
  552. ;               I have seen this following section of code colorfully called
  553. ;               the TSR "Booster". This is quite appropriate since the code
  554. ;               sits here, strapped to the very end of the TSR, and it is of
  555. ;               use only during the "blastoff" (initialization) of the TSR, when
  556. ;               it is used to put the TSR into "orbit" (residency), and after
  557. ;               which it is "jettisoned" (abandonned unprotected in memory) by
  558. ;               the DOS TSR call, Int 21h, Fcn 31h.
  559. ;
  560. TSRinit        PROC    NEAR                ;v0.01
  561. EndDump        EQU    $    ;Roy Silvernail - Keep TASM 1.0 happy
  562.                 ;when computing # resident paragraphs.
  563. ;
  564. ;       Get DOS Version Number:
  565.                 mov     ah,30h                  ;Fcn 30h = Get DOS Version
  566.                 int     21h                     ;DOS Version = al.ah
  567. ;
  568. ;       If this is DOS v.1.x, this TSR cannot work, so go print message
  569. ;       and exit without installing:
  570.                 cmp     al,1         ;Is this DOS Version 1.x?
  571.                 ja      DOSverOK     ;If not, DOS version is OK.
  572.                 push    bx           ;A "push" for the "pop" at DOSver1 label.
  573.                 jmp     DOSver1      ;If so, TSR won't work so exit.
  574. ;
  575. DOSverOK:
  576. ;       If here, DOS version is 2.0 or later. TSR can work, so proceed.
  577. ;
  578. ;       Check for prior installation of this TSR:
  579. ;
  580.                 mov     ax,TSRsigA              ;Prime registers for our
  581.                 mov     bx,TSRsigB              ;Int16h handler's check
  582.                 mov     cx,TSRsigC              ;for prior installation
  583.                 mov     dx,TSRsigD              ;thru TSR signature words.
  584. ;
  585.                 Int     16h                     ;Check prior installation.
  586. ;
  587.                 cmp     ax,TSRsigD              ;Was TSR signature detected?
  588.                 jne     Install                 ;If not, Install it.
  589.                 cmp     bx,TSRsigC
  590.                 jne     Install         
  591.                 cmp     cx,TSRsigB
  592.                 jne     Install         
  593.                 cmp     dx,TSRsigA
  594.                 jne     Install
  595. ;
  596. ; If you are here, all four TSR signature words were detected and signalled,
  597. ; so the TSR is already installed.
  598. ;       Announce the TSR's PRIOR Installation and exit:
  599.                 mov     dx,Offset PriorInstMsg  ;DX points to message.
  600.                 mov     ah,09h                  ;DOS Fcn. 09h=Display String.
  601.                 Int     21h                     ;Display String via DOS.
  602. ;
  603.                 mov     ax,4C00h                ;Fcn 4C = DOS Terminate call
  604.                 Int     21h                     ;Do it.
  605. ;
  606. Install:
  607. ;       If you are here, then DOS version is 2.+ and the TSR has not
  608. ;       previously been installed.
  609. ;
  610. ;       To conserve RAM usage, release from memory the copy of the DOS 
  611. ;    Environment passed to this TSR (this assumes, of course, that
  612. ;    your Interrupt handler routine will not need to reference this
  613. ;    de-allocated Environment) So, if you are going to write your
  614. ;    TSR routine to reference the Environment, DON'T DEALLOCATE IT
  615. ;    HERE.
  616. ;
  617.                 ;Get segment of Environment
  618.         ;from 02Ch in the Program
  619.         ;Segment Prefix (PSP).
  620. ;
  621.                 mov     ES,envseg       ;ES=PSP's environ seg   v0.01
  622.                 mov     ah,49h          ;DOS Fcn 49h = Release Memory
  623.                 int     21h             ;Release it via DOS interrupt.
  624. ;
  625. ; In order to make the TSR's command name show under the "owner" column in 
  626. ;    the "MAPMEM" command of Kim Kokkonen's excellent TSR Mark/Release 
  627. ;       package, allocate a tiny 1-paragraph "Pseudo-Environment" here which
  628. ;       contains nothing but the TSR name.
  629. ;
  630. ; Allocate the memory needed by the tiny 'Pseudo-Environment":
  631.                 mov     bx,1            ;Allocate one parag. (16bytes)
  632.                 mov     ah,48h          ;and return allocation
  633.                 int     21h             ;segment in ax via DOS call.
  634. ;
  635.                 mov     ES,ax           ;Pseudo-Env. Segment to ES.
  636.         mov    si,OFFSET PseudoEnv    ;si=source string OFFSET.
  637.                 mov     di,0            ;di=destination string OFFSET.
  638.                 mov     cx,ENVLNGTH     ;cx=Bytes in Pseudo-Env.string.
  639.                 cld                     ;Forward string move direction.
  640.         rep    movsb    ;Move Pseudo-Env. string @ DS:si to ES:di
  641. ;
  642. ; Set PSP's Environment segment pointer to point to tiny Pseudo-Environment.
  643.         mov    envseg,ES    
  644. ;
  645. ;*****************************************************************************
  646. ; NOW, capture all the required Interrupts:
  647. ;
  648. ;       **** INT 09 ****
  649. ;       Get Old Interrupt 09h Vector:
  650.                 mov     ax,3500H+HOOK09 ;Get old Int 9 vector   v0.01
  651.                 int     21h             ;Int.Vector in ES:BX via DOS.
  652. ;
  653. ;    Save Old Interrupt 09h Vector:
  654.         mov    Word Ptr oldint09,bx    ;Save Offset of Old Interrupt.
  655.         mov    word ptr oldint09+2,ES    ;save seg        v0.01
  656. ;
  657. ;    Install New Interrupt Vector to this TSR's "NewInt09:" Label:
  658.                 mov     ax,2500H+HOOK09         ;Set new Int 9 vector   v0.01
  659.         mov    dx,Offset NewInt09    ;dx=Offset of New Int Handler.
  660.                 int     21h                     ;Set New Int via DOS.
  661. ;
  662. ;       **** INT 13 ****
  663. ;       Get Old Interrupt 13h Vector:
  664.                 mov     ax,3500H+HOOK13         ;Get old Int 13 vector
  665.                 int     21h                     ;Int.Vector in ES:BX via DOS.
  666. ;
  667. ;       Save Old Interrupt 13h Vector:
  668.                 mov     Word Ptr oldint13,bx    ;Save Offset of Old Interrupt.
  669.                 mov     word ptr oldint13+2,ES  ;save Segment.
  670. ;
  671. ;       Install New Interrupt Vector to this TSR's "NewInt13:" Label:
  672.                 mov     ax,2500H+HOOK13         ;Set new Int 13 vector.
  673.                 mov     dx,Offset NewInt13      ;dx=Offset of New Int Handler.
  674.                 int     21h                     ;Set New Int via DOS.
  675. ;
  676. ;       **** INT 16 ****
  677. ;       Get Old Interrupt 16h Vector:
  678.                 mov     ax,3500H+HOOK16         ;get old Int 16H vector v0.01
  679.                 int     21h                     ;Int.Vector in ES:BX via DOS.
  680. ;
  681. ;    Save Old Interrupt 16h Vector:
  682.                 mov     Word Ptr oldint16,bx    ;Save Offset of Old Interrupt.
  683.                 mov     word ptr oldint16+2,ES  ;save segment           v0.01
  684. ;
  685. ;    Install New Interrupt Vector to this TSR's "NewInt16:" Label:
  686.                 mov     ax,2500H+HOOK16         ;set new Int 16H vector v0.01
  687.                 mov     dx,Offset NewInt16      ;dx=Offset of New Int Handler.
  688.                 int     21h                     ;Set New Int via DOS.
  689. ;
  690. ;       **** INT 28 ****
  691. ;    Get Old Interrupt 28h Vector:
  692.                 mov     ax,3500H+HOOK28         ;Get old Int 28H vector v0.01
  693.                 int     21h                     ;Int.Vector in ES:BX via DOS.
  694. ;
  695. ;    Save Old Interrupt 28h Vector:
  696.                 mov     Word Ptr oldint28,bx    ;Save Offset of Old Interrupt.
  697.                 mov     word ptr oldint28+2,ES  ;save segment           v0.01
  698. ;
  699. ;    Install New Interrupt Vector to this TSR's "NewInt28:" Label:
  700.                 mov     ax,2500H+HOOK28         ;set new Int 28H vector v0.01
  701.                 mov     dx,Offset NewInt28      ;dx=Offset of New Int Handler.
  702.                 int     21h                     ;Set New Int via DOS.
  703. ;
  704. ;*****************************************************************************
  705. ;       Get Pointer to InDOS flag ("DOS Busy" flag) and save it:
  706.                 mov     ah,34h                  ;DOS FCN=34h:Get InDOS Pointer.
  707.                 int     21h                     ;Pointer in ES:BX
  708.                 mov     Word Ptr indosptr,bx    ;Save Offset of InDOS flag.
  709.                 mov     Word Ptr indosptr+2,ES  ;Save Segment of InDOS flag.
  710. ;
  711.                 mov     Word Ptr criterrptr+2,ES ;Also, Seg of CritErr flag.
  712.                 push    bx      ;Save indosptr on stack for use below.
  713. ;
  714. ;       Get DOS Version Number:
  715.                 mov     ah,30h          ;Fcn 30h = Get DOS Version
  716.                 int     21h             ;DOS Version = al.ah
  717. ;
  718. ;       If DOS version is 2.x, then DOS Critical Error flag is @ indosptr + 1.
  719. ;       If DOS version is 3.x+, then DOS Critical Error flag is @ indosptr - 1.
  720. ;    Determine DOS Version:
  721.                 cmp     al,2            ;Is it DOS Version 2.x?
  722.                 je      DOSver2         ;If yes, jump;
  723.                 ja      DOSver3         ;or, if later version, jump;
  724.                                         ;else, it's DOS Version 1.x:
  725. ;
  726. DOSver1:        ;If here, DOS Version 1.x is being run:
  727.                 mov     dx,OFFSET BailOutMsg    ;TBONES needs DOS 2.x or later.
  728.                 mov     ah,09h                  ;Say we're sorry, but NO GO
  729.                 int     21h                     ;via DOS.
  730.                 pop     bx                      ;Clear stack.
  731.                 int     20h                     ;Terminate without installing
  732.                                                 ;in only way DOS 1.x knows.
  733. ;
  734. DOSver2:        ;If here, DOS Version 2.x is being run:
  735.                 pop     bx                      ;Get indosptr from stack.
  736.                 inc     bx                      ;CritErr flag is @ indosptr+1.
  737.                 mov     Word Ptr criterrptr,bx  ;Save CritErr Pointer.
  738.                 jmp     Announce                ;Go announce TSR installed.
  739. ;
  740. DOSver3:        ;If here, DOS Version 3.+ is being run:
  741.                 pop     bx                      ;Get indosptr from stack.
  742.                 dec     bx                      ;CritErr flag is @ indosptr-1.
  743.                 mov     Word Ptr criterrptr,bx  ;Save CritErr Pointer.
  744. ;
  745. ;    Announce the TSR's Installation:
  746. Announce:
  747.                 mov     dx,Offset InstallMsg    ;DX points to message.
  748.                 mov     ah,09h                  ;DOS Fcn. 09h=Display String.
  749.                 int     21h                     ;Display String via DOS.
  750. ;
  751. ; Lock resident code in memory via Terminate-and-Stay-Resident (TSR) DOS call:
  752. ;
  753. ;v0.11    DX requires size of resident code (in 16-byte paragraphs)
  754. ;    This awkward construct is required to keep
  755. ;    DOS Function 31h happy.  Notice how we first compute
  756. ;    the length of the TSR code in bytes [i.e., end of
  757. ;    the TSR code (EndDump) minus start of the TSR code
  758. ;    (0, our BeginDump)], round it up to the next whole paragraph ( + 0Fh),
  759. ;    and then divide by 16 (SHR 4) to get the number of resident paragraphs:
  760. ;
  761.                 mov     dx,(EndDump-BeginDump+0Fh)/16
  762. ;Roy Silvernail discovered that the BeginDump and EndDump symbols
  763. ;were necessary to keep TASM 1.0 happy when computing # resident paragraphs
  764. ;in the above statement.
  765. ;
  766.                 mov     ah,31h                  ;DOS FCN 31h=TSR Call.
  767.                 int     21h                     ;Go Resident via DOS TSR call.
  768. ;
  769. PseudoEnv:      DB      ' ',0,0,1,0,'TSRBONES',0
  770. ENVLNGTH    EQU    $-PseudoEnv
  771. ;
  772. BailOutMsg:
  773.                 db      0Dh,0Ah
  774.                 db      'Sorry. TSRBONES needs DOS v.2+. You have v.1.x'
  775.                 db      0Dh,0Ah,'$'
  776. PriorInstMsg:
  777.                 db      0Dh,0Ah
  778.                 db      'TSRBONES IS *ALREADY* INSTALLED.'
  779. InstallMsg:
  780.                 db      0Dh,0Ah
  781.                 db      'HotKey => Ctrl-Alt-B'
  782.                 db      0Dh,0Ah
  783.                 db      0Dh,0Ah
  784.                 db      'TSRBONES Version 0.1'
  785.                 db      0Dh,0Ah
  786.                 db      'Copyright (C) 1990 by Robert Curtis Davis'
  787.                 db      0Dh,0Ah,'$'
  788. ;
  789. TSRinit         ENDP    ;v0.01
  790.  
  791. CodeSeg         ends
  792.                 end     Entry
  793. ;***********************************************************************
  794.