home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / memory / amisl081.arj / AMIS.MAC < prev    next >
Text File  |  1992-04-19  |  19KB  |  683 lines

  1. .XLIST
  2. ;-----------------------------------------------------------------------
  3. ; Alternate Multiplex Interrupt Specification Library
  4. ; AMIS.MAC    Public Domain 1992 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.80
  10. ; LastEdit: 4/19/92
  11. ;-----------------------------------------------------------------------
  12.  
  13. AMIS_VERSION equ 340    ;(version 3.4 of the Alternate Multiplex Interrupt Spec)
  14. AMISLIB_VERSION equ 080 ;(version 0.80 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. ;-----------------------------------------------------------------------
  45. ;
  46. ; Set up a shorthand for the segment containing all the resident code and
  47. ; data.
  48. ; Note: the alignment must be PARA for the code to be properly relocatable
  49. ; in small-code memory models.
  50. ;
  51. TSRcode@ MACRO
  52. TGROUP GROUP RESIDENT_CODE
  53. RESIDENT_CODE SEGMENT PUBLIC PARA 'TSRCODE'
  54.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  55.     ASSUME    CS:TGROUP
  56.     ENDM
  57. TSRcodeEnd@ MACRO
  58. RESIDENT_CODE ENDS
  59.     ENDM
  60.  
  61. ;-----------------------------------------------------------------------
  62. ;
  63. ; Set up shorthands for the segments containing all the resident data,
  64. ; initialized and uninitialized.
  65. ;
  66. TSRdata@ MACRO
  67. RESIDENT_DATA SEGMENT PUBLIC BYTE 'TSRCODE'
  68.     ENDM
  69. TSRdataEnd@ MACRO
  70. RESIDENT_DATA ENDS
  71.     ENDM
  72.  
  73. TSRbss@ MACRO
  74. RESIDENT_BSS SEGMENT PUBLIC BYTE 'TSRCODE'
  75.     ENDM
  76. TSRbssEnd@ MACRO
  77. RESIDENT_BSS ENDS
  78.     ENDM
  79.  
  80. ;-----------------------------------------------------------------------
  81. ;
  82. ; Set up a shorthand for declaring all three resident segments and a group
  83. ; TGROUP for those segments.
  84. ;
  85. TSRgroup@ MACRO
  86. TSRcode@
  87. TSRcodeEnd@
  88. TSRdata@
  89. TSRdataEnd@
  90. TSRbss@
  91. TSRbssEnd@
  92. TGROUP GROUP RESIDENT_CODE,RESIDENT_DATA,RESIDENT_BSS
  93.     ENDM
  94.  
  95. ;-----------------------------------------------------------------------
  96. ;
  97. ; Some of the code in ALTMPX.ASM uses conditional assembly to handle
  98. ; segment registers differently in Tiny model than in other models, so
  99. ; we need to ensure that __TINY__ is defined in tiny model.
  100. ;
  101. IFDEF @Model        ; simplified memory models being used?
  102.   IF @Model eq 1    ; tiny model
  103.      IFNDEF __TINY__
  104.        __TINY__ equ 1
  105.      ENDIF ;NDEF
  106.   ENDIF
  107.   IF (@Model eq 1) or (@Model eq 2) or (@Model eq 3) ; Tiny, Small, or Compact?
  108.      DIST equ NEAR
  109.   ELSE
  110.      DIST equ FAR
  111.   ENDIF
  112. ELSE ;DEF @Model    ; else assume TCC/BCC memory-model #defines
  113.    IFDEF __TINY__
  114.       DIST equ NEAR
  115.    ELSEIFDEF __SMALL__
  116.       DIST equ NEAR
  117.    ELSEIFDEF __COMPACT__
  118.       DIST equ NEAR
  119.    ELSE
  120.       DIST equ FAR
  121.    ENDIF
  122. ENDIF
  123.  
  124. ;-----------------------------------------------------------------------
  125. ;
  126. ; installation flags (mainly internal use--see INSTALL_TSR below)
  127. ;
  128. BEST_FIT   equ 1    ; use best-fit rather than first-fit
  129. UMB_ONLY   equ 2    ; don't load into low memory, only into a UMB
  130. LOW_ONLY   equ 4    ; don't use UMB even if high memory available
  131.             ; (note: can't set both UMB_ONLY and LOW_ONLY)
  132. USE_TOPMEM equ 8    ; use the top of low memory if no high memory
  133.             ; (this is not always the best place to load)
  134. PATCH_RESIDENT equ 80h  ; patch resident code with actual memory block address
  135.  
  136. ;-----------------------------------------------------------------------
  137. ;
  138. ; DISPLAY_STRING    output a '$'-terminated string to standard output
  139. ; arguments:    string    the label of the string to be displayed
  140. ;        dataseg [opt] the segment of the string
  141. ;
  142. DISPLAY_STRING MACRO string,dataseg
  143. IFNB <dataseg>
  144.     push    ds
  145.     mov    ax,dataseg
  146.     mov    ds,ax
  147. ENDIF
  148.     mov    dx,offset string
  149.     mov    ah,9
  150.     int    21h
  151. IFNB <dataseg>
  152.     pop    ds
  153. ENDIF
  154.     ENDM
  155.  
  156. ;-----------------------------------------------------------------------
  157. ;
  158. ; CHECK_DOS_VER        ensure that the program is running under the proper
  159. ;            version of DOS, and terminate with an error message
  160. ;            specifying the minimum required version if not.
  161. ;
  162. CHECK_DOS_VER MACRO major,minor
  163.     LOCAL    bad_version_msg,version_OK
  164. IF major GE 5
  165.     mov    ax,3306h        ; get true DOS version
  166. ELSE
  167.     mov    ax,3000h
  168. ENDIF
  169.     int    21h
  170.     xchg    al,ah
  171.     cmp    ax,256*major + minor
  172.     jae    version_OK
  173. IFNDEF __TINY__
  174.     push    cs
  175.     pop    ds
  176. ENDIF
  177.     DISPLAY_STRING bad_version_msg
  178.     int    20h            ; terminate program
  179.  
  180. bad_version_msg label byte
  181.     db    "This program requires DOS "
  182.     db    major+'0',".",(minor/10)+'0',(minor mod 10)+'0'
  183.     db    " or higher.",13,10,"$"
  184.  
  185. version_OK:
  186.     ENDM
  187.  
  188. ;-----------------------------------------------------------------------
  189. ;
  190. ; IF_INSTALLED    conditionally branch somewhere if TSR is already installed
  191. ; arguments:
  192. ;    rescode segment of TSR code within executable (to get signature and
  193. ;            hook list)
  194. ;    rtype    type of segment reference: REL = paras offset from CS
  195. ;                       ABS = absolute segment number
  196. ;    dest    label to branch to if already installed
  197. ; at exit:
  198. ;    CF set if installed
  199. ;        AH = multiplex number
  200. ;    CF clear if not installed
  201. ;
  202. IF_INSTALLED MACRO rescode,rtype,dest
  203.     LOCAL    not_installed
  204. IFIDNI <rtype>,<REL>
  205.     mov    ax,cs
  206.     add    ax,rescode
  207. ELSE
  208. IFIDNI <rtype>,<RELBYTE>
  209.     mov    bx,rescode
  210.     ; note: loc must always be paragraph-aligned; TSRcode@ ensures this
  211.     mov    cl,4
  212.     shr    bx,cl
  213.     mov    ax,cs
  214.     add    ax,bx
  215. ELSE
  216.     mov    ax,rescode
  217. ENDIF
  218. ENDIF
  219.     extrn check_if_installed:DIST
  220.     call    check_if_installed
  221.     jnc    not_installed
  222.     jmp    dest
  223. not_installed:
  224.     ENDM
  225.  
  226. ;-----------------------------------------------------------------------
  227. ;
  228. ; INSTALL_TSR
  229. ; arguments:
  230. ;    loc    location of resident code
  231. ;    ltype    type of above location: REL = para offset from CS
  232. ;                    ABS = absolute paragraph number
  233. ;    siz    size of resident code
  234. ;    stype    type of above size: BYTE or PARA
  235. ;    extra    [opt] number of additional paragraphs needed in resident part
  236. ;    fit    [opt] FIRST (default) or BEST fit allocation
  237. ;    high    [opt] HIGHONLY to only use UMBs, TOPMEM to allocate block at
  238. ;            high end of conventional memory if no UMBs available,
  239. ;            LOWONLY to ignore UMBs, and TOPLOW to allocate at high
  240. ;            end of conventional memory whether or not UMBs are
  241. ;            available
  242. ;    init    [opt] function to call after installing TSR but before exiting
  243. ;    if_inst [opt] label to branch to if already installed
  244. ;    on_err    [opt] label to branch to if unable to install
  245. ;    more_flags [opt] label of byte containing additional flags to OR into
  246. ;           flags setup by <fit> and <high>
  247. ;
  248. ; if 'init' is specified, the indicated function will be called with
  249. ;    AX = segment at which TSR was loaded
  250. ;
  251. INSTALL_TSR MACRO loc,ltype,siz,stype,extra,fit,high,init,if_inst,on_err,more_flags
  252.     LOCAL not_installed,install_failed,iflags
  253.     mov    bx,loc
  254. IFIDNI <ltype>,<REL>
  255.     mov    ax,cs
  256.     add    bx,ax
  257. ELSE
  258. IFIDNI <ltype>,<RELBYTE>
  259.     ; note: loc must always be paragraph-aligned; TSRcode@ ensures this
  260.     mov    cl,4
  261.     shr    bx,cl
  262.     mov    ax,cs
  263.     add    bx,ax
  264. ENDIF
  265. ENDIF    
  266.     push    bx
  267.     mov    ax,bx
  268.     extrn    check_if_installed:DIST
  269.     call    check_if_installed
  270.     pop    bx
  271.     jnc    not_installed
  272. install_failure:
  273. IFNB <if_inst>
  274.     jmp    if_inst
  275. ELSE
  276.     jmp short install_failed
  277. ENDIF
  278. not_installed:
  279.     cmp    al,1
  280.     je    install_failure
  281.     push    ax            ; remember multiplex number
  282. IFIDNI <stype>,<PARA>
  283.     mov    cx,siz
  284. ELSE
  285.     mov    ax,siz
  286.     add    ax,15            ; convert bytes to paragraphs
  287.     mov    cl,4
  288.     shr    ax,cl
  289.     mov    cx,ax
  290. ENDIF
  291. IFNB <extra>
  292.     mov    dx,extra
  293. ELSE
  294.     xor    dx,dx            ; no extra memory required
  295. ENDIF
  296.     pop    ax            ; get back multiplex number
  297.     iflags = 0
  298. IFDIFI <fit>,<FIRST>
  299.     iflags = iflags OR BEST_FIT
  300. ENDIF
  301. IFIDNI <high>,<HIGHONLY>
  302.     iflags = iflags OR UMB_ONLY
  303. ENDIF
  304. IFIDNI <high>,<LOWONLY>
  305.     iflags = iflags OR LOW_ONLY
  306. ENDIF
  307. IFIDNI <high>,<TOPMEM>
  308.     iflags = iflags OR USE_TOPMEM
  309. ENDIF
  310. IFIDNI <high>,<TOPLOW>
  311.     iflags = iflags OR USE_TOPMEM OR LOW_ONLY
  312. ENDIF
  313. IFDEF ALTMPX$PSP
  314.     iflags = iflags OR PATCH_RESIDENT
  315. ENDIF
  316.     mov    al,iflags
  317. IFNB <more_flags>
  318.     or    al,more_flags
  319. ENDIF
  320.     extrn $install_TSR:DIST
  321.     call    $install_TSR
  322.     ; if success, returns CF clear, AX=segment at which TSR was installed
  323.     jc    install_failed
  324. IFNB <&init>
  325.     call    init
  326. ENDIF
  327.     extrn $go_TSR:DIST
  328.     call    $go_TSR            ; never returns
  329.  
  330. install_failed:
  331. IFNB <on_err>
  332.     jmp    on_err
  333. ELSE
  334.     push    cs
  335.     pop    ds
  336.     DISPLAY_STRING cs:install_error_msg
  337.     mov    ax,4CFFh        ; exit with ERRORLEVEL 255
  338.     int    21h
  339.  
  340. install_error_msg db "Unable to go resident.",13,10,"$"
  341. ENDIF
  342.     ENDM
  343.  
  344.  
  345. ;-----------------------------------------------------------------------
  346. ;
  347. ; UNINSTALL    remove the TSR from memory
  348. ; arguments:
  349. ;    rescode segment of TSR code within executable (to get signature and
  350. ;            hook list)
  351. ;    rtype    type of segment reference: REL = paras offset from CS
  352. ;                       ABS = absolute segment number
  353. ;    on_err    [opt] label to branch to if unable to remove from memory
  354. ;
  355. ; If 'on_err' is omitted, check CF after this macro to determine whether
  356. ; the removal was successful (CF clear if successful, set on error)
  357. ;
  358. UNINSTALL MACRO rescode,rtype,on_err
  359.     LOCAL    success
  360. IFIDNI <rtype>,<REL>
  361.     mov    ax,cs
  362.     add    ax,rescode
  363. ELSE
  364. IFIDNI <rtype>,<RELBYTE>
  365.     mov    bx,rescode
  366.     ; note: loc must always be paragraph-aligned; TSRcode@ ensures this
  367.     mov    cl,4
  368.     shr    bx,cl
  369.     mov    ax,cs
  370.     add    ax,bx
  371. ELSE
  372.     mov    ax,rescode
  373. ENDIF
  374. ENDIF
  375.     extrn $uninstall_TSR:DIST
  376.     call    $uninstall_TSR
  377. IFNB <on_err>
  378.     jnc    success
  379.     jmp    on_err
  380. ENDIF
  381. success:
  382.     ENDM
  383.  
  384. ;-----------------------------------------------------------------------
  385. ;
  386. ;             I M P O R T A N T ! ! !
  387. ; Note: in order to work properly with the code in ALTMPX.ASM, all of
  388. ; the following macros must be used inside TSRcode@
  389. ;
  390.  
  391. ;-----------------------------------------------------------------------
  392. ;
  393. ; ISP_HEADER    set up Interrupt Sharing Protocol header for an interrupt
  394. ; arguments:
  395. ;    intr    interrupt number
  396. ;    reset    [opt] name of routine to perform hardware reset
  397. ;    eoi    [opt] if nonzero, this is the primary handler for a hardware int
  398. ; exported labels: (for example "ISP_HEADER 00h,reset_func,0")
  399. ;    INT00h_handler (public), ORIG_INT00h (public), HWRESET_00h,
  400. ;    EOI_FLAG_00h
  401. ;    [in addition, hw_reset_00h would be present for ISP_HEADER 00h,,0]
  402. ;
  403. ISP_HEADER MACRO intr,reset,eoi
  404. public INT&intr&_handler,ORIG_INT&intr
  405.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  406. IFB <reset>
  407. hw_reset_&intr:
  408.     db    0CBh            ; RETF
  409. ENDIF ;reset
  410.  
  411. INT&intr&_handler:
  412.     db    0EBh,10h        ; short JMP to skip the header
  413. ORIG_INT&intr dd ?            ; previous handler in chain
  414.     dw   424Bh            ; ISP signature
  415. EOI_FLAG_&intr label byte
  416. IFB <eoi>
  417.     db   0                ; software int or secondary hardware int
  418. ELSE
  419. IF eoi eq 0
  420.     db   0                ; software int or secondary hardware int
  421. ELSE
  422.     db   80h            ; primary hardware int handler
  423. ENDIF ;eoi eq 0
  424. ENDIF ;B eoi
  425. IFB <reset>
  426. HWRESET_&intr: jmp short hw_reset_&intr
  427. ELSE
  428. HWRESET_&intr: jmp short reset
  429. ENDIF ;B reset
  430.     db   7 dup (0)
  431.     ENDM
  432.  
  433. ;-----------------------------------------------------------------------
  434. ;
  435. ; HOOKED_INTS        declare the interrupts this TSR hooks
  436. ; arguments:        up to 32 interrupt numbers
  437. ; exported labels:    HOOKED_INT_LIST (public)
  438. ;
  439. 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
  440. public HOOKED_INT_LIST
  441. HOOKED_INT_LIST label byte
  442. IFNB <over>
  443.     %out Too many interrupts hooked!
  444.     .err
  445. ENDIF ;NB over
  446.     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>
  447.         IFNB <intrpt>
  448.         IF intrpt ne 2Dh   ; ignore INT 2Dh if in the list
  449.             DB 0&&intrpt
  450.             DW INT&&intrpt&&_handler
  451.         ENDIF ;DIFI
  452.         ENDIF ;NB
  453.     ENDM
  454.     ;
  455.     ; the list terminator is INT 2Dh, since we know that one will always
  456.     ; be hooked; thus, all interrupts from 00h to FFh may be hooked
  457.     ;
  458.             DB 2Dh
  459.             DW INT2Dh_handler
  460.     ENDM
  461.  
  462. ;-----------------------------------------------------------------------
  463. ;
  464. ; ALTMPX    define the alternate multiplex interrupt handler for the program
  465. ; arguments:
  466. ;    manuf       one- to eight-character manufacturer's name
  467. ;    prodname   one- to eight-character product name
  468. ;    version       four-digit hex version number (hi byte = major, lo = minor)
  469. ;    descrip       [opt] string (max 63 char) describing the product
  470. ;    priv_funcs [opt] name of routine to handle private INT 2Dh functions
  471. ;    api_entry  [opt] name of FAR routine giving non-INT 2Dh API entry point
  472. ;    popup       [opt] name of function to call to request a popup
  473. ;    remover       [opt] name of function to call to remove TSR from memory
  474. ;    psp       [opt] if nonblank, set up patch word for memblk segment to
  475. ;             be returned if <remover> omitted; returns CS if both
  476. ;             <remover> and <psp> blank
  477. ; limitations on routines:
  478. ;    all: must be located inside TSRcode@
  479. ;    <priv_funcs>
  480. ;        input:    AL = function number (10h-FFh)
  481. ;            AH = multiplex number (ignore)
  482. ;            others available for handler
  483. ;        return: via IRET, with regs as appropriate for requested func
  484. ;    <api_entry>
  485. ;        input:    registers as desired (no limitations)
  486. ;        return: registers as desired (no limitations)
  487. ;    <popup>
  488. ;        input:    nothing
  489. ;        return: AL = status
  490. ;                01h can not pop up now, try again later
  491. ;                02h can not pop up yet, will do so when able
  492. ;                03h already popped up
  493. ;                04h unable to popup, user intervention required
  494. ;                    BX = standard reason code
  495. ;                    0000h unknown failure
  496. ;                    0001h int chain passes through memory
  497. ;                        which must be swapped out
  498. ;                    0002h swap-in failed
  499. ;                    CX = application's reason code if nonzero
  500. ;                FFh TSR popped up and was exited by user
  501. ;                    BX = return value
  502. ;                    0000h no return value
  503. ;                    0001h TSR unloaded
  504. ;                    0002h-00FFh reserved
  505. ;                    0100h-FFFFh application-specific
  506. ;    <remover>
  507. ;        input:    DX:BX = return address if uninstall successful
  508. ;        return: AL = status
  509. ;                01h unable to remove from memory
  510. ;                02h can't remove now, will do so when able
  511. ;                03h safe to remove, but no resident uninstaller
  512. ;                    (TSR still enabled)
  513. ;                    BX = segment of memory block
  514. ;                04h safe to remove, but no resident uninstaller
  515. ;                    (TSR now disabled)
  516. ;                    BX = segment of memory block
  517. ;                05h not safe to remove now, try again later
  518. ;                FFh successful (DX:BX were ignored)
  519. ;        return at DX:BX with AX destroyed if successful and <remover>
  520. ;            honors specific return address
  521. ;        if <remover> omitted, ALTMPX returns AL=03h
  522. ; exported labels:
  523. ;    INT2Dh_handler (public), ORIG_INT2Dh (public), HWRESET_2Dh,
  524. ;    EOI_FLAG_2Dh, hw_reset_00h, MULTIPLEX_NUMBER (public),
  525. ;    ALTMPX_SIGNATURE (public), ALTMPX$PSP [patch word]
  526. ;
  527. ALTMPX MACRO manuf,prodname,version,descrip,priv_funcs,api_entry,popup,remover,psp
  528.     LOCAL our_int_2Dh,int2D_func_00,int2D_func_01,int2D_func_02
  529.     LOCAL int2D_func_03,int2D_func_04,private_functions
  530.     LOCAL func_is_supported,func_not_supported,func_supported_segDX
  531.     PUBLIC MULTIPLEX_NUMBER,ALTMPX_SIGNATURE,ALTMPX$PSP
  532.  
  533. ALTMPX_SIGNATURE label byte
  534.     db    manuf
  535. IF ($-ALTMPX_SIGNATURE) gt 8
  536.     ERR "Manufacturer name >8 chars"
  537. ELSEIF ($-ALTMPX_SIGNATURE) lt 8
  538.     db    (ALTMPX_SIGNATURE+8-$) dup (' ')
  539. ENDIF
  540.     db    prodname
  541. IF ($-ALTMPX_SIGNATURE) gt 16
  542.     ERR "Product name >8 chars"
  543. ELSEIF ($-ALTMPX_SIGNATURE) lt 16
  544.     db    (ALTMPX_SIGNATURE+16-$) dup (' ')
  545. ENDIF
  546. IFNB <descrip>
  547.     db    descrip
  548. ENDIF
  549.     db    0
  550. IF ($-ALTMPX_SIGNATURE) gt 80
  551.     ERR "Description >63 chars"
  552. ENDIF
  553.  
  554. ; save an additional byte by overlaying the null hardware reset handler over
  555. ; other code, if possible
  556. IFNB <remover>
  557. hw_reset_2Dh:                ; <remover> not blank
  558.     db    0CBh            ; RETF
  559. IFNDEF ALTMPX$PSP
  560. ALTMPX$PSP equ word ptr ($+12)        ; point harmlessly into the ISP header
  561. ENDIF
  562. ELSE
  563.    IFB <psp>
  564.       ALTMPX$PSP equ word ptr ($+12)    ; point harmlessly into the ISP header
  565.    ENDIF
  566. ENDIF
  567. IFNB <psp>
  568.    IFB <remover>
  569. hw_reset_2Dh:                ; <remover> blank but <psp> not
  570.     db    0CBh            ; RETF
  571.    ENDIF
  572. ENDIF
  573.                     ; if both <remover> and <psp> blank,
  574.                     ;   hw_reset_2Dh is defined below
  575.                     ; if <remover> is blank and <psp> not,
  576.                     ;   ALTMPX$PSP is defined below
  577.  
  578.     ISP_HEADER 2Dh,hw_reset_2Dh
  579.     cmp    ah,0            ; will be patched with multiplex number
  580. MULTIPLEX_NUMBER equ byte ptr ($-1)
  581.     je    our_int_2Dh
  582.     jmp    ORIG_INT2Dh
  583. our_int_2Dh:
  584.     sti                ; OK to interrupt from now on
  585.     cmp    al,0
  586.     je    int2D_func_00
  587.     cmp    al,2
  588. IFNB <api_entry>
  589.     jb    int2D_func_01
  590. ENDIF
  591.     je    int2D_func_02
  592.     cmp    al,4
  593. IFNB <popup>
  594.     jb    int2D_func_03
  595. ENDIF ;popup
  596.     je    int2D_func_04
  597. IFNB <priv_funcs>
  598.     cmp    al,10h
  599.     jae    private_functions
  600. ENDIF ;priv_funcs
  601. func_not_supported:
  602.     mov    al,0
  603.     iret
  604.  
  605. int2D_func_00:
  606.     mov    cx,version
  607.     mov    di,offset ALTMPX_SIGNATURE
  608. func_supported_segDX:
  609.     mov    dx,cs
  610. func_is_supported:
  611.     mov    al,0FFh
  612.     iret
  613.  
  614. IFNB <api_entry>
  615. int2D_func_01:
  616.     mov    bx,offset api_entry
  617.     jmp    func_supported_segDX
  618. ENDIF ;api_entry
  619.  
  620. int2D_func_02:
  621. IFNB <remover>
  622.     call    remover
  623. ELSE
  624. ;    mov    al,3            ; safe to remove, no resident uninstaller
  625.     inc    ax            ; AL was 02h, now 03h
  626. IFNB <psp>
  627.     mov    bx,0            ; will be patched at installation time
  628. ALTMPX$PSP equ word ptr ($-2)
  629. ELSE
  630.     mov    bx,cs
  631. hw_reset_2Dh equ near ptr ($-1) ; prev instruction happens to expand to 8Ch CBh
  632. ENDIF ;psp
  633. ENDIF ;remover
  634.     iret
  635.  
  636. IFNB <popup>
  637. int2D_func_03:
  638.     call    popup
  639.     iret
  640. ENDIF ;popup
  641.  
  642. int2D_func_04:
  643.     ;mov    al,4 ;not needed since AL=04h anyway
  644.     mov    dx,cs
  645.     mov    bx,offset cs:hooked_int_list
  646.     iret
  647.  
  648. IFNB <priv_funcs>
  649. private_functions:
  650.     jmp    priv_funcs
  651. ENDIF
  652.     ENDM
  653.  
  654. ;-----------------------------------------------------------------------
  655. ;
  656. GRAB_INTERRUPT MACRO intnum,handler
  657.     TSRbss@
  658.     TSR_old_INT&intnum dd ?
  659.     TSRbssEnd@
  660.  
  661.     mov    ax,3500h+intnum
  662.     int    21h
  663.     mov    word ptr TSR_old_INT&intnum,bx
  664.     mov    word ptr TSR_old_INT&intnum+2,es
  665.     mov    dx,offset TGROUP:handler
  666.     mov    ax,2500h+intnum
  667.     int    21h
  668.     ENDM
  669.  
  670. ;-----------------------------------------------------------------------
  671. ;
  672. RESTORE_INTERRUPT MACRO intnum
  673.     push    ds
  674.     lds    dx,TSR_old_INT&intnum
  675.     mov    ax,2500h+intnum
  676.     int    21h
  677.     pop    ds
  678.     ENDM
  679.  
  680. ;-----------------------------------------------------------------------
  681.  
  682. .LIST
  683.