home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / ASM / AMISL092.ZIP / AMIS.MAC < prev    next >
Encoding:
Text File  |  1993-02-21  |  36.7 KB  |  1,466 lines

  1. .XLIST
  2. ;-----------------------------------------------------------------------
  3. ; Alternate Multiplex Interrupt Specification Library
  4. ; AMIS.MAC    Public Domain 1992, 1993 Ralf Brown
  5. ;        You may do with this software whatever you want, but
  6. ;        common courtesy dictates that you not remove my name
  7. ;        from it.
  8. ;
  9. ; Version 0.92
  10. ; LastEdit: 2/21/93
  11. ;-----------------------------------------------------------------------
  12.  
  13. AMIS_VERSION equ 350    ;(version 3.5 of the Alternate Multiplex Interrupt Spec)
  14. AMISLIB_VERSION equ 092 ;(version 0.92 of this library)
  15.  
  16. ;-----------------------------------------------------------------------
  17. ; Return codes for various API calls
  18. ;
  19.  
  20. ; general, applies to all standard calls
  21. AMIS_NOTIMPLEMENTED      equ 0
  22. AMIS_SUCCESSFUL        equ 0FFh
  23.  
  24. ; additional return codes for Uninstall (function 02h)
  25. AMIS_UNINST_FAILED    equ 1
  26. AMIS_UNINST_WILL_DO    equ 2
  27. AMIS_UNINST_SAFE_ON    equ 3
  28. AMIS_UNINST_SAFE_OFF    equ 4
  29. AMIS_UNINST_TRYLATER     equ 5
  30.  
  31. ; additional return codes for Popup (function 03h)
  32. AMIS_POPUP_TRYLATER    equ 1
  33. AMIS_POPUP_WILLDO    equ 2
  34. AMIS_POPUP_BUSY        equ 3
  35. AMIS_POPUP_NEEDHELP    equ 4
  36.  
  37. ; additional return codes for Check Interrupt Chained (function 04h)
  38. AMIS_CHAIN_DONTKNOW    equ 1
  39. AMIS_CHAIN_HOOKED    equ 2
  40. AMIS_CHAIN_HOOKED_ADDR    equ 3
  41. AMIS_CHAIN_HOOKLIST    equ 4
  42. AMIS_CHAIN_NOTUSED    equ 0FFh
  43.  
  44. ; hotkey type bits returned by Get Hotkeys (function 05h)
  45. HK_INT09ENTRY        equ 1    ; TSR checks keys before calling orig INT 09h
  46. HK_INT09EXIT        equ 2    ; TSR checks keys after calling orig INT 09h
  47. HK_INT15ENTRY        equ 4    ; TSR checks keys before chaining INT 15h/AH=4Fh
  48. HK_INT15EXIT        equ 8    ; TSR checks keys after chaining INT 15h/AH=4Fh
  49. HK_INT16OLD        equ 10h ; TSR checks on INT 16/AH=00h-02h
  50. HK_INT16NEW        equ 20h ; TSR checks on INT 16/AH=10h-12h
  51.  
  52. ; hotkey shift bits returned by Get Hotkeys (function 05h)
  53. HK_NONE         equ 0000h  ; no shift keys
  54. HK_RSHIFT        equ 0001h  ; right shift key
  55. HK_LSHIFT        equ 0002h  ; left shift key
  56. HK_BOTHSHIFT        equ 0003h  ; both Shift keys must be pressed
  57. HK_ANYCTRL        equ 0004h  ; either Control key must be pressed
  58. HK_ANYALT        equ 0008h  ; either Alt key must be pressed
  59. HK_SCRLLOCK_ON        equ 0010h  ; ScrollLock must be on when hotkey pressed
  60. HK_NUMLOCK_ON        equ 0020h  ; NumLock must be on when hotkey pressed
  61. HK_CAPSLOCK_ON        equ 0040h  ; CapsLock must be on when hotkey pressed
  62. HK_ANYSHIFT        equ 0080h  ; either Shift key must be pressed
  63. HK_LCTRL        equ 0100h  ; left control key
  64. HK_LALT         equ 0200h  ; left Alt key
  65. HK_RCTRL        equ 0400h  ; right control key
  66. HK_RALT         equ 0800h  ; right Alt key
  67. HK_BOTHCTRL        equ 0500h  ; both Control keys must be pressed
  68. HK_BOTHALT        equ 0A00h  ; both Alt keys must be pressed
  69. HK_SCROLLOCK        equ 1000h  ; ScrollLock must be pressed with hotkey
  70. HK_NUMLOCK        equ 2000h  ; NumLock must be pressed with hotkey
  71. HK_CAPSLOCK        equ 4000h  ; CapsLock must be pressed with hotkey
  72. HK_SYSREQ        equ 8000h  ; SysRq must be pressed with hotkey
  73.  
  74. ; hotkey flag bits returned by Get Hotkeys (function 05h)
  75. HK_CHAINBEFORE        equ 1    ; TSR chains hotkey before processing it
  76. HK_CHAINAFTER        equ 2    ; TSR chains hotkey after processing it
  77. HK_MONITOR        equ 4    ; other TSRs should pass through this hotkey
  78.                 ; so that it can be monitored
  79. HK_NOPRESSRELEASE    equ 8    ; hotkey won't activate if other keys pressed
  80.                 ; and released before hotkey combination 
  81.                 ; completed
  82. HK_REMAPPED        equ 10h ; this key is remapped into some other key
  83.  
  84. HK_NOCHAIN        equ 0    ; TSR swallows hotkey
  85.  
  86. ; hotkey scan codes returned by Get Hotkeys (function 05h)
  87. SCAN_NONE    equ 0
  88. SCAN_ESC    equ 1
  89. SCAN_1        equ 2
  90. SCAN_2        equ 3
  91. SCAN_3        equ 4
  92. SCAN_4        equ 5
  93. SCAN_5        equ 6
  94. SCAN_6        equ 7
  95. SCAN_7        equ 8
  96. SCAN_8        equ 9
  97. SCAN_9        equ 10
  98. SCAN_0        equ 11
  99. SCAN_HYPHEN    equ 12
  100. SCAN_EQUAL    equ 13
  101. SCAN_BACKSP    equ 14
  102. SCAN_TAB    equ 15
  103. SCAN_Q        equ 16
  104. SCAN_W        equ 17
  105. SCAN_E        equ 18
  106. SCAN_R        equ 19
  107. SCAN_T        equ 20
  108. SCAN_Y        equ 21
  109. SCAN_U        equ 22
  110. SCAN_I        equ 23
  111. SCAN_O        equ 24
  112. SCAN_P        equ 25
  113. SCAN_LBRACKET    equ 26
  114. SCAN_RBRACKET    equ 27
  115. SCAN_ENTER    equ 28
  116. SCAN_CTRL    equ 29
  117. SCAN_A        equ 30
  118. SCAN_S        equ 31
  119. SCAN_D        equ 32
  120. SCAN_F        equ 33
  121. SCAN_G        equ 34
  122. SCAN_H        equ 35
  123. SCAN_J        equ 36
  124. SCAN_K        equ 37
  125. SCAN_L        equ 38
  126. SCAN_SEMICOLON    equ 39
  127. SCAN_SQUOTE    equ 40
  128. SCAN_BACKQUOTE    equ 41
  129. SCAN_LSHIFT    equ 42
  130. SCAN_BACKSLASH    equ 43
  131. SCAN_Z        equ 44
  132. SCAN_X        equ 45
  133. SCAN_C        equ 46
  134. SCAN_V        equ 47
  135. SCAN_B        equ 48
  136. SCAN_N        equ 49
  137. SCAN_M        equ 50
  138. SCAN_COMMA    equ 51
  139. SCAN_PERIOD    equ 52
  140. SCAN_SLASH    equ 53
  141. SCAN_RSHIFT    equ 54
  142. SCAN_GREYSTAR    equ 55
  143. SCAN_ALT    equ 56
  144. SCAN_SPACE    equ 57
  145. SCAN_CAPSLK    equ 58
  146. SCAN_F1        equ 59
  147. SCAN_F2        equ 60
  148. SCAN_F3        equ 61
  149. SCAN_F4        equ 62
  150. SCAN_F5        equ 63
  151. SCAN_F6        equ 64
  152. SCAN_F7        equ 65
  153. SCAN_F8        equ 66
  154. SCAN_F9        equ 67
  155. SCAN_F10    equ 68
  156. SCAN_NUMLK    equ 69
  157. SCAN_SCRLLK    equ 70
  158. SCAN_HOME    equ 71
  159. SCAN_UP        equ 72
  160. SCAN_PGUP    equ 73
  161. SCAN_GREYMINUS    equ 74
  162. SCAN_LEFT    equ 75
  163. SCAN_KP5    equ 76
  164. SCAN_RIGHT    equ 77
  165. SCAN_GREYPLUS    equ 78
  166. SCAN_END    equ 79
  167. SCAN_DOWN    equ 80
  168. SCAN_PGDN    equ 81
  169. SCAN_INS    equ 82
  170. SCAN_DEL    equ 83
  171. SCAN_SYSRQ    equ 84
  172. SCAN_F11    equ 87
  173. SCAN_F12    equ 88
  174. HK_ONRELEASE    equ 80h ; hotkey activates on key release (add to scan code)
  175.  
  176. ;-----------------------------------------------------------------------
  177. ; Return codes for AMISLIB functions
  178. ;
  179.  
  180. ; bit flags returned by CHECK_IF_HOTKEYS_USED
  181. HC_EXACT    equ 1        ; exact match found
  182. HC_SUPERSET    equ 2        ; some key whose shift states include ours used
  183. HC_SUBSET    equ 4        ; some key whose shift states included by one of ours used    
  184. HC_OVERLAP    equ 8        ; hotkey overlap found
  185. HC_MONITOR    equ 80h        ; other TSRs monitor one or more hotkeys, but no
  186.                 ;   actual conflict because caller chains them
  187.  
  188. HC_IS_CONFLICT  equ 7Fh        ; mask for testing whether conflict exists
  189.  
  190. ;-----------------------------------------------------------------------
  191. ;
  192. ; Set up a shorthand for the segment containing all the resident code and
  193. ; data.
  194. ; Note: the alignment 'align' must be blank to get the PARA alignment needed
  195. ; for the code to be properly relocatable in small-code memory models.
  196. ;
  197. TSRcode@ MACRO align
  198.     LOCAL alignment
  199. TGROUP GROUP RESIDENT_CODE
  200. IFB <align>
  201.  RESIDENT_CODE SEGMENT PUBLIC PARA 'TSRCODE'
  202. ELSE
  203.  RESIDENT_CODE SEGMENT PUBLIC BYTE 'TSRCODE'
  204. ENDIF
  205.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  206.     ASSUME    CS:TGROUP
  207.     ENDM
  208. TSRcodeEnd@ MACRO
  209. RESIDENT_CODE ENDS
  210.     ENDM
  211.  
  212. ;-----------------------------------------------------------------------
  213. ;
  214. ; Set up shorthands for the segments containing all the resident data,
  215. ; initialized and uninitialized.
  216. ;
  217. TSRdata@ MACRO
  218. RESIDENT_DATA SEGMENT PUBLIC BYTE 'TSRCODE'
  219.     ENDM
  220. TSRdataEnd@ MACRO
  221. RESIDENT_DATA ENDS
  222.     ENDM
  223.  
  224. TSRbss@ MACRO
  225. RESIDENT_BSS SEGMENT PUBLIC BYTE 'TSRCODE'
  226.     ENDM
  227. TSRbssEnd@ MACRO
  228. RESIDENT_BSS ENDS
  229.     ENDM
  230.  
  231. ;-----------------------------------------------------------------------
  232. ;
  233. ; dummy segment for determining the size of the resident code in the
  234. ; executable
  235. ;
  236. TSRlast@ MACRO
  237. RESIDENT_END SEGMENT PUBLIC BYTE 'TSRCODE'
  238.     ENDM
  239. TSRlastEnd@ MACRO
  240. RESIDENT_END ENDS
  241.     ENDM
  242.  
  243. ;-----------------------------------------------------------------------
  244. ;
  245. ; Set up a shorthand for declaring all three resident segments and a group
  246. ; TGROUP for those segments.
  247. ;
  248. TSRgroup@ MACRO align
  249. TSRcode@ align
  250. TSRcodeEnd@
  251. TSRdata@
  252. TSRdataEnd@
  253. TSRbss@
  254. TSRbssEnd@
  255. TSRlast@
  256. TSRlastEnd@
  257. TGROUP GROUP RESIDENT_CODE,RESIDENT_DATA,RESIDENT_BSS,RESIDENT_END
  258.     ENDM
  259.  
  260. ;-----------------------------------------------------------------------
  261. ;
  262. ; Some of the code in AMIS.ASM uses conditional assembly to handle
  263. ; segment registers differently in Tiny model than in other models, so
  264. ; we need to ensure that __TINY__ is defined in tiny model.
  265. ;
  266. IFDEF @Model        ; simplified memory models being used?
  267.   IF @Model eq 1    ; tiny model
  268.      IFNDEF __TINY__
  269.        __TINY__ equ 1
  270.      ENDIF ;NDEF
  271.   ENDIF
  272.   IF (@Model eq 1) or (@Model eq 2) or (@Model eq 3) ; Tiny, Small, or Compact?
  273.      DIST equ NEAR
  274.   ELSE
  275.      DIST equ FAR
  276.   ENDIF
  277. ELSE ;DEF @Model    ; else assume TCC/BCC memory-model #defines
  278.    IFDEF __TINY__
  279.       DIST equ NEAR
  280.    ELSEIFDEF __SMALL__
  281.       DIST equ NEAR
  282.    ELSEIFDEF __COMPACT__
  283.       DIST equ NEAR
  284.    ELSEIFDEF __MEDIUM__
  285.       DIST equ FAR
  286.    ELSEIFDEF __LARGE__
  287.       DIST equ FAR
  288.    ELSEIFDEF __HUGE__
  289.       DIST equ FAR
  290.    ENDIF
  291. ENDIF
  292.  
  293. NOWARN PDC    ; don't warn about pass-dependent constructions
  294. IF1
  295.    IFNDEF DIST
  296.       &__DEFAULT_MODEL__ equ 1
  297.       IFDEF __TINY__
  298.          DIST equ NEAR
  299.       ELSEIFDEF __SMALL__
  300.          DIST equ NEAR
  301.       ELSEIFDEF __COMPACT__
  302.          DIST equ NEAR
  303.       ELSEIFDEF __MEDIUM__
  304.          DIST equ FAR
  305.       ELSEIFDEF __LARGE__
  306.          DIST equ FAR
  307.       ELSEIFDEF __HUGE__
  308.          DIST equ FAR
  309.       ENDIF
  310.    ENDIF
  311. ENDIF
  312. WARN PDC
  313.  
  314. IFNDEF __TINY__
  315.    TGROUP@ equ TGROUP
  316. ENDIF
  317.  
  318. ;-----------------------------------------------------------------------
  319. ;
  320. ; first half of startup code (invoke right after INCLUDE AMIS.MAC in main module)
  321. ;
  322. ; arguments:    major,minor,stksize
  323. ;        [opt] major,minor   major/minor version of min supported DOS ver
  324. ;        [opt] stksize        size of initial stack for non-Tiny models
  325. ;
  326. @Startup MACRO major,minor,stksize
  327.   ;----------------------------------
  328.   ; Declare our segments in the order
  329.   ; we want them in the executable.
  330.   ;
  331.   _INIT    SEGMENT PUBLIC PARA 'INIT'
  332.   _INIT    ENDS
  333.   TSRgroup@
  334.   _TEXT    SEGMENT PUBLIC PARA 'CODE' ; must be aligned PARA to work properly
  335.   _TEXT    ENDS
  336. IFNDEF __TINY__
  337.   _STACK SEGMENT STACK 'STACK'
  338.   IFNB <stksize>
  339.       db <stksize> dup (?)
  340.   ELSE
  341.         db 100h dup (?)
  342.   ENDIF
  343.   _STACK ENDS
  344. ENDIF ;ndef __TINY__
  345.  
  346.   ;----------------------------------
  347.   ; set up labels for start and end of
  348.   ; resident code
  349.   ;
  350.   TSRcode@
  351.   $AMIS$start_TSRcode label byte    ; find address of beginning of segment
  352.   TSRcodeEnd@
  353.  
  354.   TSRlast@
  355.   $AMIS$end_TSRcode label byte    ; marker for end of resident code in executable
  356.   TSRlastEnd@
  357.  
  358. IFDEF __TINY__
  359. _INIT SEGMENT 'INIT'
  360.     ASSUME    CS:_INIT,DS:_INIT,ES:_INIT,SS:_INIT
  361.     ORG    100h
  362. ELSE
  363. _TEXT SEGMENT 'CODE'
  364.     ASSUME    CS:_TEXT,DS:NOTHING,ES:NOTHING,SS:NOTHING
  365. ENDIF ;def __TINY__
  366.  
  367. INIT    proc far
  368. IFNB <major>
  369.   IFNB <minor>
  370.       CHECK_DOS_VER major,minor
  371.   ENDIF
  372. ENDIF
  373. IFNDEF __TINY__
  374.     mov    dx,TGROUP
  375.     mov    es,dx
  376.     ASSUME    ES:TGROUP
  377.     jmp    $AMIS$PROGRAM_START
  378. ELSE
  379.     mov    ax,offset _INIT:$AMIS$start_TSRcode
  380.     mov    cl,4
  381.     shr    ax,cl
  382.     mov    dx,es
  383.     add    dx,ax
  384.     mov    es,dx
  385.     ASSUME    ES:TGROUP
  386.     ;
  387.     ; compute normalized address of actual program entry point
  388.     ;
  389.     mov    dx,offset _INIT:$AMIS$PROGRAM_START
  390.     mov    ax,offset _TEXT:$AMIS$PROGRAM_START
  391.     sub    dx,ax
  392.     shr    dx,cl            ; CL still 4
  393.     mov    cx,cs
  394.     add    dx,cx
  395.     push    dx            ; simulate far jump to computed address
  396.     push    ax
  397.     ret
  398. ENDIF ;ndef __TINY__
  399.  
  400. INIT    endp
  401.  
  402.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  403. IFDEF __TINY__
  404.  _INIT    ENDS
  405. ELSE
  406.  _TEXT    ENDS
  407. ENDIF ;def __TINY__
  408.  
  409.     ENDM
  410.  
  411. ;-----------------------------------------------------------------------
  412. ;
  413. ; additional startup code (invoke at start of main program)
  414. ;
  415. ; arguments: need_psp    non-blank to allocate __psp variable, blank if provided
  416. ;            by some other module (such as the C runtime library)
  417. ;
  418. @Startup2 MACRO need_psp
  419.  
  420. IFDEF __TINY__
  421.   public TGROUP@
  422.   TGROUP@    dw ?
  423. ENDIF ;__TINY__
  424. IFNB <need_psp>
  425.   public __psp
  426.   __psp        dw ?
  427. ENDIF ;need_psp
  428.  
  429. $AMIS$PROGRAM_START:
  430.     ASSUME    DS:NOTHING,ES:TGROUP
  431.     mov    __psp,ds
  432. IFDEF __TINY__
  433.     mov    TGROUP@,es
  434. ENDIF
  435.     ENDM
  436.  
  437. ;-----------------------------------------------------------------------
  438. ;
  439. ; installation flags (mainly internal use--see INSTALL_TSR below)
  440. ;
  441. BEST_FIT   equ 1    ; use best-fit rather than first-fit
  442. UMB_ONLY   equ 2    ; don't load into low memory, only into a UMB
  443. LOW_ONLY   equ 4    ; don't use UMB even if high memory available
  444.             ; (note: can't set both UMB_ONLY and LOW_ONLY)
  445. USE_TOPMEM equ 8    ; use the top of low memory if no high memory
  446.             ; (this is not always the best place to load)
  447. PATCH_RESIDENT equ 80h  ; patch resident code with actual memory block address
  448.  
  449. ;-----------------------------------------------------------------------
  450. ;
  451. ; DISPLAY_STRING    output a '$'-terminated string to standard output
  452. ; arguments:    string    the label of the string to be displayed
  453. ;        dataseg [opt] the segment of the string
  454. ;
  455. DISPLAY_STRING MACRO string,dataseg
  456. IFNB <dataseg>
  457.     push    ds
  458.     mov    ax,dataseg
  459.     mov    ds,ax
  460. ENDIF
  461.     mov    dx,offset string
  462.     mov    ah,9
  463.     int    21h
  464. IFNB <dataseg>
  465.     pop    ds
  466. ENDIF
  467.     ENDM
  468.  
  469. ;-----------------------------------------------------------------------
  470. ;
  471. ; CHECK_DOS_VER        ensure that the program is running under the proper
  472. ;            version of DOS, and terminate with an error message
  473. ;            specifying the minimum required version if not.
  474. ;
  475. CHECK_DOS_VER MACRO major,minor
  476.     LOCAL    bad_version_msg,version_OK
  477. IF major GE 5
  478.     mov    ax,3306h        ; get true DOS version
  479. ELSE
  480.     mov    ax,3000h
  481. ENDIF
  482.     int    21h
  483.     xchg    al,ah
  484.     cmp    ax,256*major + minor
  485.     jae    version_OK
  486. IFNDEF __TINY__
  487.     push    cs
  488.     pop    ds
  489. ENDIF
  490.     DISPLAY_STRING bad_version_msg
  491.     int    20h            ; terminate program
  492.  
  493. bad_version_msg label byte
  494.     db    "This program requires DOS "
  495.     db    major+'0',".",(minor/10)+'0',(minor mod 10)+'0'
  496.     db    " or higher.",13,10,"$"
  497.  
  498. version_OK:
  499.     ENDM
  500.  
  501. ;-----------------------------------------------------------------------
  502. ;
  503. ; IF_INSTALLED    conditionally branch somewhere if TSR is already installed
  504. ; arguments:
  505. ;    dest    label to branch to if already installed
  506. ; at exit:
  507. ;    CF set if installed
  508. ;        AH = multiplex number
  509. ;        CX = version number
  510. ;    CF clear if not installed
  511. ;
  512. IF_INSTALLED MACRO dest
  513.     LOCAL    not_installed
  514.     mov    dx,TGROUP@
  515.     mov    ax,offset RESIDENT_CODE:ALTMPX_SIGNATURE
  516.     extrn check_if_installed:DIST
  517.     call    check_if_installed
  518.     jnc    not_installed
  519.     jmp    dest
  520. not_installed:
  521.     ENDM
  522.  
  523. ;-----------------------------------------------------------------------
  524. ;
  525. ; IF_HOTKEY_USED conditionally branch somewhere if TSR's hotkeys already in use
  526. ; arguments:
  527. ;    dest    label to branch to if one or more hotkeys conflict
  528. ; at exit:
  529. ;    ZF clear if hotkeys conflict
  530. ;        AX = conflict types
  531. ;        bit 0: exact key already in use
  532. ;        bit 1: key with less-strict shift states in use
  533. ;        bit 2: key with stricter shift states in use
  534. ;    ZF set if no conflicts
  535. ;
  536. IF_HOTKEY_USED MACRO dest
  537.     LOCAL    no_conflicts
  538.     mov    dx,TGROUP@
  539.     mov    ax,offset TGROUP:$AMIS$HOTKEY_LIST
  540.     extrn check_if_hotkeys_used:DIST
  541.     call    check_if_hotkeys_used
  542.     jz    no_conflicts
  543.     jmp    dest
  544. no_conflicts:
  545.     ENDM
  546.  
  547. ;-----------------------------------------------------------------------
  548. ;
  549. ; INSTALL_TSR
  550. ; arguments:
  551. ;    extra    [opt] number of additional paragraphs needed in resident part
  552. ;    fit    [opt] FIRST (default) or BEST fit allocation
  553. ;    high    [opt] HIGHONLY to only use UMBs, TOPMEM to allocate block at
  554. ;            high end of conventional memory if no UMBs available,
  555. ;            LOWONLY to ignore UMBs, and TOPLOW to allocate at high
  556. ;            end of conventional memory whether or not UMBs are
  557. ;            available
  558. ;    init    [opt] function to call after installing TSR but before exiting
  559. ;    if_inst [opt] label to branch to if already installed
  560. ;    on_err    [opt] label to branch to if unable to install
  561. ;    more_flags [opt] label of byte containing additional flags to OR into
  562. ;           flags setup by <fit> and <high>
  563. ;
  564. ; if 'init' is specified, the indicated function will be called with
  565. ;    AX = segment at which TSR was loaded
  566. ; if 'if_inst' is specified, the indicated function will be jumped at with
  567. ;    AH = multiplex number
  568. ;    CX = version number
  569. ;
  570. INSTALL_TSR MACRO extra,fit,high,init,if_inst,on_err,more_flags
  571.     LOCAL not_installed,install_failed,iflags,install_error_msg
  572.     mov    bx,TGROUP@
  573.     push    bx            ; remember location of resident code
  574.     mov    dx,bx
  575.     mov    ax,offset RESIDENT_CODE:ALTMPX_SIGNATURE
  576.     extrn    check_if_installed:DIST
  577.     call    check_if_installed
  578.     pop    bx            ; retrieve location of resident code
  579.     jnc    not_installed
  580. install_failure:
  581. IFNB <if_inst>
  582.     jmp    if_inst
  583. ELSE
  584.     jmp short install_failed
  585. ENDIF
  586. not_installed:
  587.     cmp    al,1
  588.     je    install_failure
  589.     mov    dx,offset TGROUP:$AMIS$end_TSRcode+15
  590.     mov    cl,4            ; convert bytes to paragraphs
  591.     shr    dx,cl
  592.     mov    cx,dx
  593. IFNB <extra>
  594.     mov    dx,extra
  595. ELSE
  596.     xor    dx,dx            ; no extra memory required
  597. ENDIF
  598.     iflags = 0
  599. IFDIFI <fit>,<FIRST>
  600.     iflags = iflags OR BEST_FIT
  601. ENDIF
  602. IFIDNI <high>,<HIGHONLY>
  603.     iflags = iflags OR UMB_ONLY
  604. ENDIF
  605. IFIDNI <high>,<LOWONLY>
  606.     iflags = iflags OR LOW_ONLY
  607. ENDIF
  608. IFIDNI <high>,<TOPMEM>
  609.     iflags = iflags OR USE_TOPMEM
  610. ENDIF
  611. IFIDNI <high>,<TOPLOW>
  612.     iflags = iflags OR USE_TOPMEM OR LOW_ONLY
  613. ENDIF
  614. IFDEF ALTMPX$PSP
  615.     iflags = iflags OR PATCH_RESIDENT
  616. ENDIF
  617.     mov    al,iflags
  618. IFNB <more_flags>
  619.     or    al,more_flags
  620. ENDIF
  621.     extrn $install_TSR:DIST
  622.     call    $install_TSR
  623.     ; if success, returns CF clear, AX=segment at which TSR was installed
  624.     jc    install_failed
  625. IFNB <&init>
  626.     call    init
  627. ENDIF
  628.     extrn $go_TSR:DIST
  629.     call    $go_TSR            ; never returns
  630.  
  631. install_failed:
  632. IFNB <on_err>
  633.     jmp    on_err
  634. ELSE
  635.     push    cs
  636.     pop    ds
  637.     DISPLAY_STRING cs:install_error_msg
  638.     mov    ax,4CFFh        ; exit with ERRORLEVEL 255
  639.     int    21h
  640.  
  641. install_error_msg db "Unable to go resident.",13,10,"$"
  642. ENDIF
  643.     ENDM
  644.  
  645.  
  646. ;-----------------------------------------------------------------------
  647. ;
  648. ; UNINSTALL    remove the TSR from memory
  649. ; arguments:
  650. ;    on_err    [opt] label to branch to if unable to remove from memory
  651. ;
  652. ; If 'on_err' is omitted, check CF after this macro to determine whether
  653. ; the removal was successful (CF clear if successful, set on error)
  654. ;
  655. UNINSTALL MACRO on_err
  656.     LOCAL    success
  657.     mov    dx,TGROUP@
  658.     mov    ax,offset RESIDENT_CODE:ALTMPX_SIGNATURE
  659.     extrn $uninstall_TSR:DIST
  660.     call    $uninstall_TSR
  661. IFNB <on_err>
  662.     jnc    success
  663.     jmp    on_err
  664. ENDIF
  665. success:
  666.     ENDM
  667.  
  668. ;-----------------------------------------------------------------------
  669. ;
  670. ;             I M P O R T A N T ! ! !
  671. ; Note: in order to work properly with the code in AMIS.ASM, all of
  672. ; the following macros must be used inside TSRcode@
  673. ;
  674.  
  675. ;-----------------------------------------------------------------------
  676. ;
  677. ; ISP_HEADER    set up Interrupt Sharing Protocol header for an interrupt
  678. ; arguments:
  679. ;    intr    interrupt number
  680. ;    reset    [opt] name of routine to perform hardware reset
  681. ;    eoi    [opt] if nonzero, this is the primary handler for a hardware int
  682. ; exported labels: (for example "ISP_HEADER 00h,reset_func,0")
  683. ;    INT00h_handler (public), ORIG_INT00h (public), HWRESET_00h,
  684. ;    EOI_FLAG_00h
  685. ;    [in addition, hw_reset_00h would be present for ISP_HEADER 00h,,0]
  686. ;
  687. ISP_HEADER MACRO intr,reset,eoi
  688. public INT&intr&_handler,ORIG_INT&intr
  689.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  690. IFB <reset>
  691. hw_reset_&intr:
  692.     db    0CBh            ; RETF
  693. ENDIF ;reset
  694.  
  695. INT&intr&_handler:
  696.     db    0EBh,10h        ; short JMP to skip the header
  697. ORIG_INT&intr dd ?            ; previous handler in chain
  698.     dw   424Bh            ; ISP signature
  699. EOI_FLAG_&intr label byte
  700. IFB <eoi>
  701.     db   0                ; software int or secondary hardware int
  702. ELSE
  703. IF eoi eq 0
  704.     db   0                ; software int or secondary hardware int
  705. ELSE
  706.     db   80h            ; primary hardware int handler
  707. ENDIF ;eoi eq 0
  708. ENDIF ;B eoi
  709. IFB <reset>
  710. HWRESET_&intr: jmp short hw_reset_&intr
  711. ELSE
  712. HWRESET_&intr: jmp short reset
  713. ENDIF ;B reset
  714.     db   7 dup (0)
  715.     ENDM
  716.  
  717. ;-----------------------------------------------------------------------
  718. ;
  719. ; HOOKED_INTS        declare the interrupts this TSR hooks
  720. ; arguments:        up to 32 interrupt numbers
  721. ; exported labels:    $AMIS$HOOKED_INT_LIST (public)
  722. ;
  723. HOOKED_INTS MACRO a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa,ab,ac,ad,ae,af,over
  724. public $AMIS$HOOKED_INT_LIST
  725. $AMIS$HOOKED_INT_LIST label byte
  726. IFNB <over>
  727.     %out Too many interrupts hooked!
  728.     .err
  729. ENDIF ;NB over
  730.     IRP    intrpt,<a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa,ab,ac,ad,ae,af>
  731.         IFNB <intrpt>
  732.         IF intrpt ne 2Dh   ; ignore INT 2Dh if in the list
  733.             DB 0&&intrpt
  734.             DW INT&&intrpt&&_handler
  735.         ENDIF ;DIFI
  736.         ENDIF ;NB
  737.     ENDM
  738.     ;
  739.     ; the list terminator is INT 2Dh, since we know that one will always
  740.     ; be hooked; thus, all interrupts from 00h to FFh may be hooked
  741.     ;
  742.             DB 2Dh
  743.             DW INT2Dh_handler
  744.     ENDM
  745.  
  746. ;-----------------------------------------------------------------------
  747. ;
  748. ; HOTKEYS        declare the type of hotkeys this TSR uses
  749. ; arguments:
  750. ;    check    hotkey check type
  751. ;    flags    [opt] default flags for following hotkeys
  752. ; exported labels:    $AMIS$HOTKEY_LIST (public),
  753. ;            $amis$hotkey_list_start (internal use)
  754. ;
  755. ; To declare the TSR's hotkeys, you must use macros in the following order:
  756. ;            HOTKEYS    type
  757. ;            HOTKEY    scan1,req1,disall1
  758. ;            HOTKEY    scan2,req2,disall2,flags2
  759. ;            ...
  760. ;            HOTKEY    scanN,reqN,disallN
  761. ;            HOTKEYS_DONE
  762. ; these definitions must precede the use of the ALTMPX macro
  763. ;
  764. HOTKEYS MACRO check,flags
  765. public $AMIS$HOTKEY_LIST
  766. $AMIS$HOTKEY_LIST label byte
  767.     db    check            ; type of hotkey check
  768.     db    $amis$num_hotkeys    ; number of hotkeys following
  769. $amis$hotkey_list_start label byte
  770. IFNB <flags>
  771.    $amis$hotkey_def_flags equ flags
  772. ELSE
  773.    IF (check AND HK_INT15EXIT)
  774.       $amis$hotkey_def_flags equ HK_CHAINBEFORE
  775.    ELSEIF (check AND HK_INT09EXIT)
  776.       $amis$hotkey_def_flags equ HK_CHAINBEFORE
  777.    ELSE
  778.       $amis$hotkey_def_flags equ HK_NOCHAIN
  779.    ENDIF
  780. ENDIF ;flags
  781.     ENDM
  782.  
  783. ;-----------------------------------------------------------------------
  784. ;
  785. ; HOTKEY        declare one of the hotkeys this TSR uses
  786. ; arguments:
  787. ;    scan    scan code
  788. ;    req    required shift states
  789. ;    disall    disallowed shift states
  790. ;    flags    [opt] flags describing actions taken on hotkey
  791. ; exported labels: none
  792. ;
  793. ; To declare the TSR's hotkeys, you must use macros in the following order:
  794. ;            HOTKEYS    type
  795. ;            HOTKEY    scan1,req1,disall1
  796. ;            HOTKEY    scan2,req2,disall2,flags2
  797. ;            ...
  798. ;            HOTKEY    scanN,reqN,disallN
  799. ;            HOTKEYS_DONE
  800. ; these definitions must precede the use of the ALTMPX macro; the first HOTKEY
  801. ; line should define the TSR's primary hotkey
  802. ;
  803. HOTKEY    MACRO    scan,req,disall,flags
  804.     LOCAL    t
  805.     db    scan
  806. IFNB <req>
  807.     dw    req
  808. ELSE
  809.     dw    HK_NONE
  810. ENDIF ;req
  811. IFNB <disall>
  812.     t = disall
  813.    IF (((disall) AND HK_ANYSHIFT) eq HK_ANYSHIFT)
  814.        t = t OR HK_LSHIFT OR HK_RSHIFT
  815.    ENDIF
  816.    IF (((disall) AND HK_ANYCTRL) eq HK_ANYCTRL)
  817.        t = t OR HK_LCTRL OR HK_RCTRL
  818.    ENDIF
  819.    IF (((disall) AND HK_ANYALT) eq HK_ANYALT)
  820.        t = t OR HK_LALT OR HK_RALT
  821.    ENDIF
  822.     dw    t
  823. ELSE
  824.     dw    HK_NONE
  825. ENDIF ;disall
  826. IFNB <flags>
  827.     db    flags
  828. ELSE
  829.     db    $amis$hotkey_def_flags
  830. ENDIF ;flags
  831.     ENDM
  832.  
  833. ;-----------------------------------------------------------------------
  834. ;
  835. ; HOTKEYS_DONE        mark end of hotkey list
  836. ; arguments:    none
  837. ; exported labels:    $amis$num_hotkeys (equate)
  838. ;
  839. ; To declare the TSR's hotkeys, you must use macros in the following order:
  840. ;            HOTKEYS    type
  841. ;            HOTKEY    scan1,req1,disall1
  842. ;            HOTKEY    scan2,req2,disall2
  843. ;            ...
  844. ;            HOTKEY    scanN,reqN,disallN
  845. ;            HOTKEYS_DONE
  846. ; these definitions must precede the use of the ALTMPX macro
  847. ;
  848. HOTKEYS_DONE MACRO
  849. $amis$num_hotkeys equ ($-$amis$hotkey_list_start)/6
  850.     ENDM
  851.  
  852. ;-----------------------------------------------------------------------
  853. ;
  854. ; ALTMPX    define the alternate multiplex interrupt handler for the program
  855. ; arguments:
  856. ;    manuf       one- to eight-character manufacturer's name
  857. ;    prodname   one- to eight-character product name
  858. ;    version       four-digit hex version number (hi byte = major, lo = minor)
  859. ;    descrip       [opt] string (max 63 char) describing the product
  860. ;    priv_funcs [opt] name of routine to handle private INT 2Dh functions
  861. ;    api_entry  [opt] name of FAR routine giving non-INT 2Dh API entry point
  862. ;    popup       [opt] name of function to call to request a popup
  863. ;    remover       [opt] name of function to call to remove TSR from memory
  864. ;    psp       [opt] if nonblank, set up patch word for memblk segment to
  865. ;             be returned if <remover> omitted; returns CS if both
  866. ;             <remover> and <psp> blank
  867. ; limitations on routines:
  868. ;    all: must be located inside TSRcode@
  869. ;    <priv_funcs>
  870. ;        input:    AL = function number (10h-FFh)
  871. ;            AH = multiplex number (ignore)
  872. ;            others available for handler
  873. ;        return: via IRET, with regs as appropriate for requested func
  874. ;    <api_entry>
  875. ;        input:    registers as desired (no limitations)
  876. ;        return: registers as desired (no limitations)
  877. ;    <popup>
  878. ;        input:    nothing
  879. ;        return: AL = status
  880. ;                01h can not pop up now, try again later
  881. ;                02h can not pop up yet, will do so when able
  882. ;                03h already popped up
  883. ;                04h unable to popup, user intervention required
  884. ;                    BX = standard reason code
  885. ;                    0000h unknown failure
  886. ;                    0001h int chain passes through memory
  887. ;                        which must be swapped out
  888. ;                    0002h swap-in failed
  889. ;                    CX = application's reason code if nonzero
  890. ;                FFh TSR popped up and was exited by user
  891. ;                    BX = return value
  892. ;                    0000h no return value
  893. ;                    0001h TSR unloaded
  894. ;                    0002h-00FFh reserved
  895. ;                    0100h-FFFFh application-specific
  896. ;    <remover>
  897. ;        input:    DX:BX = return address if uninstall successful
  898. ;        return: AL = status
  899. ;                01h unable to remove from memory
  900. ;                02h can't remove now, will do so when able
  901. ;                03h safe to remove, but no resident uninstaller
  902. ;                    (TSR still enabled)
  903. ;                    BX = segment of memory block
  904. ;                04h safe to remove, but no resident uninstaller
  905. ;                    (TSR now disabled)
  906. ;                    BX = segment of memory block
  907. ;                05h not safe to remove now, try again later
  908. ;                FFh successful (DX:BX were ignored)
  909. ;        return at DX:BX with AX destroyed if successful and <remover>
  910. ;            honors specific return address
  911. ;        if <remover> omitted, ALTMPX returns AL=03h
  912. ; exported labels:
  913. ;    INT2Dh_handler (public), ORIG_INT2Dh (public), HWRESET_2Dh,
  914. ;    EOI_FLAG_2Dh, hw_reset_2Dh, $AMIS$MULTIPLEX_NUMBER (public),
  915. ;    ALTMPX_SIGNATURE (public), ALTMPX$PSP [patch word]
  916. ;
  917. ALTMPX MACRO manuf,prodname,version,descrip,priv_funcs,api_entry,popup,remover,psp
  918.     LOCAL our_int_2Dh,int2D_func_00,int2D_func_01,int2D_func_02
  919.     LOCAL int2D_func_03,int2D_func_04
  920.     LOCAL func_is_supported,func_not_supported,func_supported_segDX
  921.     PUBLIC $AMIS$MULTIPLEX_NUMBER,ALTMPX_SIGNATURE,ALTMPX$PSP
  922.  
  923. ALTMPX_SIGNATURE label byte
  924.     db    manuf
  925. IF ($-ALTMPX_SIGNATURE) gt 8
  926.     ERR "Manufacturer name >8 chars"
  927. ELSEIF ($-ALTMPX_SIGNATURE) lt 8
  928.     db    (ALTMPX_SIGNATURE+8-$) dup (' ')
  929. ENDIF
  930.     db    prodname
  931. IF ($-ALTMPX_SIGNATURE) gt 16
  932.     ERR "Product name >8 chars"
  933. ELSEIF ($-ALTMPX_SIGNATURE) lt 16
  934.     db    (ALTMPX_SIGNATURE+16-$) dup (' ')
  935. ENDIF
  936. IFNB <descrip>
  937.     db    descrip
  938. ENDIF
  939.     db    0
  940. IF ($-ALTMPX_SIGNATURE) gt 80
  941.     ERR "Description >63 chars"
  942. ENDIF
  943.  
  944. ; save an additional byte by overlaying the null hardware reset handler over
  945. ; other code, if possible
  946. IFNB <remover>
  947. hw_reset_2Dh:                ; <remover> not blank
  948.     db    0CBh            ; RETF
  949. IFNDEF ALTMPX$PSP
  950. ALTMPX$PSP equ word ptr ($+12)        ; point harmlessly into the ISP header
  951. ENDIF
  952. ELSE
  953.    IFB <psp>
  954.       ALTMPX$PSP equ word ptr ($+12)    ; point harmlessly into the ISP header
  955.    ENDIF
  956. ENDIF
  957. IFNB <psp>
  958.    IFB <remover>
  959. hw_reset_2Dh:                ; <remover> blank but <psp> not
  960.     db    0CBh            ; RETF
  961.    ENDIF
  962. ENDIF
  963.                     ; if both <remover> and <psp> blank,
  964.                     ;   hw_reset_2Dh is defined below
  965.                     ; if <remover> is blank and <psp> not,
  966.                     ;   ALTMPX$PSP is defined below
  967.  
  968.     ISP_HEADER 2Dh,hw_reset_2Dh
  969.     cmp    ah,0            ; will be patched with multiplex number
  970. $AMIS$MULTIPLEX_NUMBER equ byte ptr ($-1)
  971.     je    our_int_2Dh
  972.     jmp    ORIG_INT2Dh
  973. our_int_2Dh:
  974.     sti                ; OK to interrupt from now on
  975.     cmp    al,0
  976.     je    int2D_func_00
  977.     cmp    al,2
  978. IFNB <api_entry>
  979.     jb    int2D_func_01
  980. ELSE
  981.   IFNB <popup>
  982.     jb    func_not_supported
  983.   ENDIF
  984. ENDIF
  985.     je    int2D_func_02
  986.     cmp    al,4
  987. IFNB <popup>
  988.     jb    int2D_func_03
  989. ENDIF ;popup
  990.     je    int2D_func_04
  991. IFDEF $amis$num_hotkeys
  992.     cmp    al,5
  993.     jne    not_hotkey_check
  994.     mov    bx,offset TGROUP:$AMIS$HOTKEY_LIST
  995.     jmp short func_supported_segDX
  996. not_hotkey_check:
  997. ENDIF ;$amis$num_hotkeys
  998. IFNB <priv_funcs>
  999.     cmp    al,10h
  1000.     jb    func_not_supported
  1001.         jmp     priv_funcs
  1002. ENDIF ;priv_funcs
  1003. func_not_supported:
  1004.     mov    al,0
  1005.     iret
  1006.  
  1007. int2D_func_00:
  1008.     mov    cx,version
  1009.     mov    di,offset ALTMPX_SIGNATURE
  1010. func_supported_segDX:
  1011.     mov    dx,cs
  1012. func_is_supported:
  1013.     mov    al,0FFh
  1014.     iret
  1015.  
  1016. IFNB <api_entry>
  1017. int2D_func_01:
  1018.     mov    bx,offset api_entry
  1019.     jmp    func_supported_segDX
  1020. ENDIF ;api_entry
  1021.  
  1022. int2D_func_02:
  1023. IFNB <remover>
  1024.     call    remover
  1025. ELSE
  1026. ;    mov    al,3            ; safe to remove, no resident uninstaller
  1027.     inc    ax            ; AL was 02h, now 03h
  1028. IFNB <psp>
  1029.     mov    bx,0            ; will be patched at installation time
  1030. ALTMPX$PSP equ word ptr ($-2)
  1031. ELSE
  1032.     mov    bx,cs
  1033. hw_reset_2Dh equ near ptr ($-1) ; prev instruction happens to expand to 8Ch CBh
  1034. ENDIF ;psp
  1035. ENDIF ;remover
  1036.     iret
  1037.  
  1038. IFNB <popup>
  1039. int2D_func_03:
  1040.     call    popup
  1041.     iret
  1042. ENDIF ;popup
  1043.  
  1044. int2D_func_04:
  1045.     ;mov    al,4 ;not needed since AL=04h anyway
  1046.     mov    dx,cs
  1047.     mov    bx,offset cs:$AMIS$HOOKED_INT_LIST
  1048.     iret
  1049.  
  1050.     ENDM
  1051.  
  1052. ;-----------------------------------------------------------------------
  1053. ; generic hotkey dispatcher
  1054. ; args:
  1055. ;    chain    when to chain INT 15h: BEFORE or AFTER
  1056. ;        should match what HOTKEYS macro declares
  1057. ;    funcs    name of list of words containing offsets for the NEAR 
  1058. ;        functions to invoke for each hotkey (in the order they are
  1059. ;        listed via the HOTKEY macro)
  1060. ;    other    [opt] address to jump at if not INT 15/AH=4Fh
  1061. ;        the target code must chain via ORIG_INT15h
  1062. ;
  1063. HOTKEY_DISPATCHER MACRO chain,funcs,other
  1064.     LOCAL    int15_handler,not_anyshift
  1065.     LOCAL    int15_4F,int15_done,scan_hotkeys,try_next,not_hotkey
  1066.     LOCAL    got_hotkey,no_chainbefore,no_chainafter,chain_1
  1067.  
  1068. int15_handler proc far
  1069. ISP_HEADER 15h
  1070.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  1071. IFIDNI <chain>,<BEFORE>
  1072.     pushf
  1073.     call    ORIG_INT15h
  1074. ENDIF ;chain
  1075.     cmp    ah,4Fh
  1076.     je    int15_4F
  1077. IFNB <other>
  1078.     jmp    other
  1079. ELSE
  1080.    IFIDNI <chain>,<BEFORE>
  1081.        iret                ; we've already chained
  1082.    ELSE
  1083. chain_1:
  1084.     jmp    ORIG_INT15h
  1085.    ENDIF ;chain
  1086. ENDIF ;other
  1087.  
  1088. int15_4F:
  1089.     sti                ; OK to interrupt
  1090.     cld                ; string ops move up in memory
  1091.     push    bx
  1092.     push    ax
  1093.     mov    ah,12h            ; get shift states
  1094.     int    16h
  1095.     and    ax,not HK_ANYSHIFT
  1096.     test    ax,HK_RSHIFT or HK_LSHIFT
  1097.     jz    not_anyshift
  1098.     or    ax,HK_ANYSHIFT
  1099. not_anyshift:
  1100.     mov    bx,ax            ; BX <- current shift states
  1101.     pop    ax            ; restore scan code in AL
  1102.     push    ds
  1103.     push    si
  1104.     push    cx
  1105.     push    cs
  1106.     pop    ds
  1107.     ASSUME    DS:TGROUP
  1108.     mov    si,offset TGROUP:$AMIS$HOTKEY_LIST+1
  1109.     mov    cl,[si]
  1110.     mov    ch,0
  1111.     jcxz    not_hotkey        ; skip loop if no hotkeys active
  1112.     inc    si            ; skip hotkey list header
  1113. scan_hotkeys:
  1114.     cmp    al,[si]            ; is it our hotkey?
  1115.     jne    try_next        ; if scan code differs, it isn't
  1116.     test    bx,[si+3]        ; any disallowed shift states active?
  1117.     jnz    try_next        ; if yes, not our hotkey
  1118.     push    bx
  1119.     not    bx
  1120.     test    bx,[si+1]        ; any required shift states missing?
  1121.     pop    bx
  1122.     jz    got_hotkey
  1123. try_next:
  1124.     add    si,6            ; move to next hotkey record
  1125.     loop    scan_hotkeys
  1126. not_hotkey:
  1127.     stc                ; key not used by TSR
  1128.     pop    cx
  1129.     pop    si
  1130.     pop    ds
  1131.     ASSUME    DS:NOTHING
  1132.     pop    bx
  1133. IFDIFI <chain>,<BEFORE>
  1134.    IFNB <other>
  1135.        jmp    ORIG_INT15h
  1136.    ELSE
  1137.     jmp    chain_1
  1138.    ENDIF ;other
  1139. ELSE
  1140.     iret
  1141. ENDIF ;chain
  1142.  
  1143. got_hotkey:
  1144.     ASSUME    DS:TGROUP
  1145.     push    ax
  1146.     mov    ax,si
  1147.     sub    ax,offset TGROUP:$AMIS$HOTKEY_LIST+2
  1148.     mov    bl,3
  1149.     div    bl
  1150.     mov    bx,ax            ; BX <- offset of func in hk-func list
  1151.     pop    ax
  1152.     pop    cx
  1153. IFDIFI <chain>,<BEFORE>
  1154.     test    byte ptr [si+5],HK_CHAINBEFORE
  1155.     jz    no_chainbefore
  1156.     stc
  1157.     pushf
  1158.     call    ORIG_INT15h
  1159. no_chainbefore:
  1160.     test    byte ptr [si+5],HK_CHAINAFTER
  1161. ENDIF ;chain
  1162.     pop    si
  1163.     pop    ds
  1164.     ASSUME    DS:NOTHING
  1165. IFDIFI <chain>,<BEFORE>
  1166.     pushf
  1167. ENDIF ;chain
  1168.     call    word ptr RESIDENT_CODE:[bx+funcs]
  1169. IFDIFI <chain>,<BEFORE>
  1170.     popf
  1171.     pop    bx
  1172.   IFNB <other>
  1173.     jz    no_chainafter
  1174.     stc
  1175.     jmp    ORIG_INT15h
  1176.   ELSE
  1177.       stc
  1178.         jnz    chain_1
  1179.   ENDIF ;other
  1180. no_chainafter:
  1181. ELSE
  1182.     pop    bx
  1183. ENDIF ;chain
  1184.     clc                ; throw out scan code, all processing done
  1185.     ret    2
  1186. int15_handler endp
  1187.  
  1188.     ENDM
  1189.  
  1190. ;-----------------------------------------------------------------------
  1191. ;
  1192. DPL    STRUC
  1193.  dpl_ax dw ?
  1194.  dpl_bx dw ?
  1195.  dpl_cx dw ?
  1196.  dpl_dx dw ?
  1197.  dpl_si dw ?
  1198.  dpl_di dw ?
  1199.  dpl_ds dw ?
  1200.  dpl_es dw ?
  1201.  dpl_reserved dw ?
  1202.  dpl_machine  dw ?
  1203.  dpl_pid      dw ?
  1204. DPL    ENDS
  1205.  
  1206. ;-----------------------------------------------------------------------
  1207. ;
  1208. TSRstack@ MACRO size
  1209. TSRbss@
  1210. TSR_local_stack db size dup (?)
  1211. TSR_local_stack_end label byte
  1212. TSRbssEnd@
  1213.     ENDM
  1214.  
  1215. ;-----------------------------------------------------------------------
  1216. ; high-level language interrupt handler interface for AMISLIB
  1217. ; not yet ready to use
  1218. ;
  1219. ;    intnum    the number of the interrupt to hook
  1220. ;    chain    one of FIRST, BEFORE, DURING, AFTER, NONE
  1221. ;        FIRST chains before doing anything else, including testing the
  1222. ;            registers; if none of the register values matches, an
  1223. ;            IRET is executed
  1224. ;        BEFORE chains after testing the register but before calling the
  1225. ;            user handler; if none of the register values matches,
  1226. ;            a FAR JMP to the original interrupt handler is
  1227. ;            performed
  1228. ;        AFTER chains after the user handler returns; if none of the
  1229. ;            register values matches, a FAR JMP to the original
  1230. ;            interrupt handler is performed
  1231. ;        DURING permits the user handler to chain the interrupt at its
  1232. ;            discretion by calling _chain_INT<intnum>; if none of
  1233. ;            the register values matches, a FAR JMP to the original
  1234. ;            interrupt handler is performed
  1235. ;        NONE never chains the interrupt
  1236. ;    dseg    label (or segment name) to be loaded into DS
  1237. ;    localstk    [opt] label of DWORD containing address of local stack
  1238. ;    handler        the user function for handling the interrupt when triggered
  1239. ;    resetfunc   [opt] the function to call on a call to the ISP "reset"
  1240. ;             entry point
  1241. ;    reg    the name of the register to test
  1242. ;    valN    a list of up to eight values for the specfied register on which
  1243. ;        the user handler is to be invoked
  1244. ;            
  1245. ;
  1246. AMIS_INT MACRO intnum,chain,dseg,localstk,handler,resetfunc,reg,val1,val2,val3,val4,val5,val6,val7,val8,over
  1247.     LOCAL    TESTVALUES, our_func, not_ours, on_local_stack
  1248.     LOCAL    stackptr, old_SP, old_SS
  1249. TESTVALUES = 0
  1250.  
  1251. IFB <dseg>
  1252.     .err "Must specify DSEG"
  1253. ENDIF
  1254. IFB <handler>
  1255.     .err "Must specify an interrupt handler"
  1256. ENDIF
  1257. IFNB <over>
  1258.     .err "Too many values specified"
  1259. ENDIF
  1260.  
  1261. IFIDNI <chain>,<DURING>
  1262. stackptr dw ?
  1263. ENDIF ;chain during
  1264.  
  1265. IFNB <localstk>
  1266. old_SP    dw  ?
  1267. old_SS    dw  ?
  1268. ENDIF ;NB localstk
  1269.  
  1270. hw_reset_&intnum proc far
  1271.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  1272. IFNB <resetfunc>
  1273.     pushf
  1274.     push    es
  1275.     push    ds
  1276.     push    bp
  1277.     push    di
  1278.     push    si
  1279.     push    dx
  1280.     push    cx
  1281.     push    bx
  1282.     push    ax
  1283.     mov    ax,dseg
  1284.     mov    ds,ax
  1285.     call    resetfunc
  1286.     pop    ax
  1287.     pop    bx
  1288.     pop    cx
  1289.     pop    dx
  1290.     pop    si
  1291.     pop    di
  1292.     pop    bp
  1293.     pop    ds
  1294.     pop    es
  1295.     popf
  1296. ENDIF ;NB resetfunc
  1297.     ret
  1298. hw_reset_&intnum endp
  1299.  
  1300.     ISP_HEADER intnum,hw_reset_&intnum
  1301.     sti                ; OK to interrupt here
  1302. IFIDNI <chain>,<FIRST>
  1303.     pushf
  1304.     call    orig_INT&intnum        ; simulate interrupt
  1305. ENDIF ;chain
  1306. IFNB <reg>
  1307.     pushf
  1308.     IRP    val,<val1,val2,val3,val4,val5,val6,val7,val8>
  1309.         IFNB <val>
  1310.             cmp    reg,val
  1311.         je    our_func
  1312.         TESTVALUES = 1
  1313.         ENDIF ;NB val
  1314.     ENDM
  1315.     IF TESTVALUES
  1316.            popf
  1317.        IFIDNI <chain>,<FIRST>
  1318.            iret
  1319.        ELSE
  1320.         jmp    orig_INT&intnum
  1321.        ENDIF ;chain
  1322.     ENDIF ;TESTVALUES
  1323. our_func:
  1324. ENDIF
  1325.  
  1326. IFIDNI <chain>,<BEFORE>
  1327.   IFB <reg>
  1328.       pushf
  1329.   ENDIF ;reg
  1330.     call    orig_INT&intnum           ; chain, original flags already on stack
  1331. ELSE
  1332.   IFNB <reg>
  1333.     popf                ; clean up stack
  1334.   ENDIF ;reg
  1335. ENDIF ;chain before
  1336. IFNB <localstk>
  1337.     push    old_SS
  1338.     push    old_SP
  1339.     push    ax
  1340.     mov    ax,ss
  1341.     mov    old_SS,ax        ; remember current stack pointer
  1342.     mov    old_SP,sp
  1343.     cmp    ax,word ptr localstk+2    ; already on local stack?
  1344.     pop    ax
  1345.     je    on_local_stack        ; if yes, don't switch
  1346.     cli
  1347.     mov    ss,word ptr localstk+2    ; switch to local stack
  1348.     mov    sp,word ptr localstk
  1349.     sti
  1350. on_local_stack:
  1351. ENDIF ;NB localstk
  1352. IFIDNI <chain>,<DURING>
  1353.     push    cs:stackptr
  1354. ENDIF
  1355.     pushf
  1356.     push    es
  1357.     push    ds
  1358.     push    bp
  1359.     push    di
  1360.     push    si
  1361.     push    dx
  1362.     push    cx
  1363.     push    bx
  1364.     push    ax
  1365. IFIDNI <chain>,<DURING>
  1366.     mov    cs:stackptr,sp
  1367. ENDIF
  1368.     mov    ax,dseg
  1369.     mov    ds,ax
  1370.     call    handler
  1371.     pop    ax
  1372.     pop    bx
  1373.     pop    cx
  1374.     pop    dx
  1375.     pop    si
  1376.     pop    di
  1377.     pop    bp
  1378.     pop    ds
  1379.     pop    es
  1380.     popf
  1381. IFIDINI <chain>,<DURING>
  1382.     pop    cs:stackptr
  1383. ENDIF
  1384. IFNB <localstk>
  1385.     cli
  1386.     mov    ss,cs:old_SS
  1387.     mov    sp,cs:old_SP
  1388.     sti
  1389.     pop    old_SP
  1390.     pop    old_SS
  1391. ENDIF ;NB localstk
  1392. IFIDNI <chain>,<AFTER>
  1393.     jmp    orig_INT&intnum
  1394. ELSE
  1395.     iret
  1396. ENDIF
  1397.  
  1398. IFIDNI <chain>,<DURING>
  1399. public _chain_INT&intnum
  1400. _chain_INT&intnum proc DIST
  1401.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  1402.     push    bp
  1403.     mov    bp,stackptr
  1404.     mov    ax,[bp]            ; load registers from stack frame
  1405.     mov    bx,[bp+2]
  1406.     mov    cx,[bp+4]
  1407.     mov    dx,[bp+6]
  1408.     mov    si,[bp+8]
  1409.     mov    di,[bp+0Ah]
  1410.     mov    ds,[bp+0Eh]
  1411.     mov    es,[bp+10h]
  1412.     push    word ptr [bp+12h]    ; push flags
  1413.     popf                ; setup flags
  1414.     mov    bp,[bp+0Ch]
  1415.     pushf
  1416.     call    orig_INT&intnum        ; chain by simulating the interrupt
  1417.     push    bp
  1418.     mov    bp,stackptr
  1419.     pop    word ptr [bp+0Ch]    ; store returned BP
  1420.     pushf
  1421.     pop    word ptr [bp+12h]    ; store returned flags
  1422.     mov    [bp],ax            ; store returned registers back in
  1423.     mov    [bp+2],bx        ;   stack frame
  1424.     mov    [bp+4],cx
  1425.     mov    [bp+6],dx
  1426.     mov    [bp+8],si
  1427.     mov    [bp+0Ah],di
  1428.     mov    [bp+0Eh],ds
  1429.     mov    [bp+10h],es
  1430.     pop    bp
  1431.     ret
  1432. _chain_INT&intnum endp
  1433. ENDIF ;chain during
  1434.  
  1435.     ENDM
  1436.  
  1437. ;-----------------------------------------------------------------------
  1438. ;
  1439. GRAB_INTERRUPT MACRO intnum,handler
  1440.     TSRbss@
  1441.     TSR_old_INT&intnum dd ?
  1442.     TSRbssEnd@
  1443.  
  1444.     mov    ax,3500h+intnum
  1445.     int    21h
  1446.     mov    word ptr TSR_old_INT&intnum,bx
  1447.     mov    word ptr TSR_old_INT&intnum+2,es
  1448.     mov    dx,offset TGROUP:handler
  1449.     mov    ax,2500h+intnum
  1450.     int    21h
  1451.     ENDM
  1452.  
  1453. ;-----------------------------------------------------------------------
  1454. ;
  1455. RESTORE_INTERRUPT MACRO intnum
  1456.     push    ds
  1457.     lds    dx,TSR_old_INT&intnum
  1458.     mov    ax,2500h+intnum
  1459.     int    21h
  1460.     pop    ds
  1461.     ENDM
  1462.  
  1463. ;-----------------------------------------------------------------------
  1464.  
  1465. .LIST
  1466.