home *** CD-ROM | disk | FTP | other *** search
- .XLIST
- ;-----------------------------------------------------------------------
- ; Alternate Multiplex Interrupt Specification Library
- ; AMIS.MAC Public Domain 1992 Ralf Brown
- ; You may do with this software whatever you want, but
- ; common courtesy dictates that you not remove my name
- ; from it.
- ;
- ; Version 0.83
- ; LastEdit: 5/2/92
- ;-----------------------------------------------------------------------
-
- AMIS_VERSION equ 340 ;(version 3.4 of the Alternate Multiplex Interrupt Spec)
- AMISLIB_VERSION equ 083 ;(version 0.83 of this library)
-
- ;-----------------------------------------------------------------------
- ; Return codes for various API calls
- ;
-
- ; general, applies to all standard calls
- AMIS_NOTIMPLEMENTED equ 0
- AMIS_SUCCESSFUL equ 0FFh
-
- ; additional return codes for Uninstall (function 02h)
- AMIS_UNINST_FAILED equ 1
- AMIS_UNINST_WILL_DO equ 2
- AMIS_UNINST_SAFE_ON equ 3
- AMIS_UNINST_SAFE_OFF equ 4
- AMIS_UNINST_TRYLATER equ 5
-
- ; additional return codes for Popup (function 03h)
- AMIS_POPUP_TRYLATER equ 1
- AMIS_POPUP_WILLDO equ 2
- AMIS_POPUP_BUSY equ 3
- AMIS_POPUP_NEEDHELP equ 4
-
- ; additional return codes for Check Interrupt Chained (function 04h)
- AMIS_CHAIN_DONTKNOW equ 1
- AMIS_CHAIN_HOOKED equ 2
- AMIS_CHAIN_HOOKED_ADDR equ 3
- AMIS_CHAIN_HOOKLIST equ 4
- AMIS_CHAIN_NOTUSED equ 0FFh
-
- ;-----------------------------------------------------------------------
- ;
- ; Set up a shorthand for the segment containing all the resident code and
- ; data.
- ; Note: the alignment must be PARA for the code to be properly relocatable
- ; in small-code memory models.
- ;
- TSRcode@ MACRO
- TGROUP GROUP RESIDENT_CODE
- RESIDENT_CODE SEGMENT PUBLIC PARA 'TSRCODE'
- ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
- ASSUME CS:TGROUP
- ENDM
- TSRcodeEnd@ MACRO
- RESIDENT_CODE ENDS
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- ; Set up shorthands for the segments containing all the resident data,
- ; initialized and uninitialized.
- ;
- TSRdata@ MACRO
- RESIDENT_DATA SEGMENT PUBLIC BYTE 'TSRCODE'
- ENDM
- TSRdataEnd@ MACRO
- RESIDENT_DATA ENDS
- ENDM
-
- TSRbss@ MACRO
- RESIDENT_BSS SEGMENT PUBLIC BYTE 'TSRCODE'
- ENDM
- TSRbssEnd@ MACRO
- RESIDENT_BSS ENDS
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- ; Set up a shorthand for declaring all three resident segments and a group
- ; TGROUP for those segments.
- ;
- TSRgroup@ MACRO
- TSRcode@
- TSRcodeEnd@
- TSRdata@
- TSRdataEnd@
- TSRbss@
- TSRbssEnd@
- TGROUP GROUP RESIDENT_CODE,RESIDENT_DATA,RESIDENT_BSS
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- ; Some of the code in ALTMPX.ASM uses conditional assembly to handle
- ; segment registers differently in Tiny model than in other models, so
- ; we need to ensure that __TINY__ is defined in tiny model.
- ;
- IFDEF @Model ; simplified memory models being used?
- IF @Model eq 1 ; tiny model
- IFNDEF __TINY__
- __TINY__ equ 1
- ENDIF ;NDEF
- ENDIF
- IF (@Model eq 1) or (@Model eq 2) or (@Model eq 3) ; Tiny, Small, or Compact?
- DIST equ NEAR
- ELSE
- DIST equ FAR
- ENDIF
- ELSE ;DEF @Model ; else assume TCC/BCC memory-model #defines
- IFDEF __TINY__
- DIST equ NEAR
- ELSEIFDEF __SMALL__
- DIST equ NEAR
- ELSEIFDEF __COMPACT__
- DIST equ NEAR
- ELSE
- DIST equ FAR
- ENDIF
- ENDIF
-
- ;-----------------------------------------------------------------------
- ;
- ; installation flags (mainly internal use--see INSTALL_TSR below)
- ;
- BEST_FIT equ 1 ; use best-fit rather than first-fit
- UMB_ONLY equ 2 ; don't load into low memory, only into a UMB
- LOW_ONLY equ 4 ; don't use UMB even if high memory available
- ; (note: can't set both UMB_ONLY and LOW_ONLY)
- USE_TOPMEM equ 8 ; use the top of low memory if no high memory
- ; (this is not always the best place to load)
- PATCH_RESIDENT equ 80h ; patch resident code with actual memory block address
-
- ;-----------------------------------------------------------------------
- ;
- ; DISPLAY_STRING output a '$'-terminated string to standard output
- ; arguments: string the label of the string to be displayed
- ; dataseg [opt] the segment of the string
- ;
- DISPLAY_STRING MACRO string,dataseg
- IFNB <dataseg>
- push ds
- mov ax,dataseg
- mov ds,ax
- ENDIF
- mov dx,offset string
- mov ah,9
- int 21h
- IFNB <dataseg>
- pop ds
- ENDIF
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- ; CHECK_DOS_VER ensure that the program is running under the proper
- ; version of DOS, and terminate with an error message
- ; specifying the minimum required version if not.
- ;
- CHECK_DOS_VER MACRO major,minor
- LOCAL bad_version_msg,version_OK
- IF major GE 5
- mov ax,3306h ; get true DOS version
- ELSE
- mov ax,3000h
- ENDIF
- int 21h
- xchg al,ah
- cmp ax,256*major + minor
- jae version_OK
- IFNDEF __TINY__
- push cs
- pop ds
- ENDIF
- DISPLAY_STRING bad_version_msg
- int 20h ; terminate program
-
- bad_version_msg label byte
- db "This program requires DOS "
- db major+'0',".",(minor/10)+'0',(minor mod 10)+'0'
- db " or higher.",13,10,"$"
-
- version_OK:
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- ; IF_INSTALLED conditionally branch somewhere if TSR is already installed
- ; arguments:
- ; rescode segment of TSR code within executable (to get signature and
- ; hook list)
- ; rtype type of segment reference: REL = paras offset from CS
- ; ABS = absolute segment number
- ; dest label to branch to if already installed
- ; at exit:
- ; CF set if installed
- ; AH = multiplex number
- ; CX = version number
- ; CF clear if not installed
- ;
- IF_INSTALLED MACRO rescode,rtype,dest
- LOCAL not_installed
- IFIDNI <rtype>,<REL>
- mov ax,cs
- add ax,rescode
- ELSE
- IFIDNI <rtype>,<RELBYTE>
- mov bx,rescode
- ; note: loc must always be paragraph-aligned; TSRcode@ ensures this
- mov cl,4
- shr bx,cl
- mov ax,cs
- add ax,bx
- ELSE
- mov ax,rescode
- ENDIF
- ENDIF
- extrn check_if_installed:DIST
- call check_if_installed
- jnc not_installed
- jmp dest
- not_installed:
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- ; INSTALL_TSR
- ; arguments:
- ; loc location of resident code
- ; ltype type of above location: REL = para offset from CS
- ; ABS = absolute paragraph number
- ; siz size of resident code
- ; stype type of above size: BYTE or PARA
- ; extra [opt] number of additional paragraphs needed in resident part
- ; fit [opt] FIRST (default) or BEST fit allocation
- ; high [opt] HIGHONLY to only use UMBs, TOPMEM to allocate block at
- ; high end of conventional memory if no UMBs available,
- ; LOWONLY to ignore UMBs, and TOPLOW to allocate at high
- ; end of conventional memory whether or not UMBs are
- ; available
- ; init [opt] function to call after installing TSR but before exiting
- ; if_inst [opt] label to branch to if already installed
- ; on_err [opt] label to branch to if unable to install
- ; more_flags [opt] label of byte containing additional flags to OR into
- ; flags setup by <fit> and <high>
- ;
- ; if 'init' is specified, the indicated function will be called with
- ; AX = segment at which TSR was loaded
- ; if 'if_inst' is specified, the indicated function will be jumped at with
- ; AH = multiplex number
- ; CX = version number
- ;
- INSTALL_TSR MACRO loc,ltype,siz,stype,extra,fit,high,init,if_inst,on_err,more_flags
- LOCAL not_installed,install_failed,iflags
- mov bx,loc
- IFIDNI <ltype>,<REL>
- mov ax,cs
- add bx,ax
- ELSE
- IFIDNI <ltype>,<RELBYTE>
- ; note: loc must always be paragraph-aligned; TSRcode@ ensures this
- mov cl,4
- shr bx,cl
- mov ax,cs
- add bx,ax
- ENDIF
- ENDIF
- push bx
- mov ax,bx
- extrn check_if_installed:DIST
- call check_if_installed
- pop bx
- jnc not_installed
- install_failure:
- IFNB <if_inst>
- jmp if_inst
- ELSE
- jmp short install_failed
- ENDIF
- not_installed:
- cmp al,1
- je install_failure
- push ax ; remember multiplex number
- IFIDNI <stype>,<PARA>
- mov cx,siz
- ELSE
- mov ax,siz
- add ax,15 ; convert bytes to paragraphs
- mov cl,4
- shr ax,cl
- mov cx,ax
- ENDIF
- IFNB <extra>
- mov dx,extra
- ELSE
- xor dx,dx ; no extra memory required
- ENDIF
- pop ax ; get back multiplex number
- iflags = 0
- IFDIFI <fit>,<FIRST>
- iflags = iflags OR BEST_FIT
- ENDIF
- IFIDNI <high>,<HIGHONLY>
- iflags = iflags OR UMB_ONLY
- ENDIF
- IFIDNI <high>,<LOWONLY>
- iflags = iflags OR LOW_ONLY
- ENDIF
- IFIDNI <high>,<TOPMEM>
- iflags = iflags OR USE_TOPMEM
- ENDIF
- IFIDNI <high>,<TOPLOW>
- iflags = iflags OR USE_TOPMEM OR LOW_ONLY
- ENDIF
- IFDEF ALTMPX$PSP
- iflags = iflags OR PATCH_RESIDENT
- ENDIF
- mov al,iflags
- IFNB <more_flags>
- or al,more_flags
- ENDIF
- extrn $install_TSR:DIST
- call $install_TSR
- ; if success, returns CF clear, AX=segment at which TSR was installed
- jc install_failed
- IFNB <&init>
- call init
- ENDIF
- extrn $go_TSR:DIST
- call $go_TSR ; never returns
-
- install_failed:
- IFNB <on_err>
- jmp on_err
- ELSE
- push cs
- pop ds
- DISPLAY_STRING cs:install_error_msg
- mov ax,4CFFh ; exit with ERRORLEVEL 255
- int 21h
-
- install_error_msg db "Unable to go resident.",13,10,"$"
- ENDIF
- ENDM
-
-
- ;-----------------------------------------------------------------------
- ;
- ; UNINSTALL remove the TSR from memory
- ; arguments:
- ; rescode segment of TSR code within executable (to get signature and
- ; hook list)
- ; rtype type of segment reference: REL = paras offset from CS
- ; ABS = absolute segment number
- ; on_err [opt] label to branch to if unable to remove from memory
- ;
- ; If 'on_err' is omitted, check CF after this macro to determine whether
- ; the removal was successful (CF clear if successful, set on error)
- ;
- UNINSTALL MACRO rescode,rtype,on_err
- LOCAL success
- IFIDNI <rtype>,<REL>
- mov ax,cs
- add ax,rescode
- ELSE
- IFIDNI <rtype>,<RELBYTE>
- mov bx,rescode
- ; note: loc must always be paragraph-aligned; TSRcode@ ensures this
- mov cl,4
- shr bx,cl
- mov ax,cs
- add ax,bx
- ELSE
- mov ax,rescode
- ENDIF
- ENDIF
- extrn $uninstall_TSR:DIST
- call $uninstall_TSR
- IFNB <on_err>
- jnc success
- jmp on_err
- ENDIF
- success:
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- ; I M P O R T A N T ! ! !
- ; Note: in order to work properly with the code in ALTMPX.ASM, all of
- ; the following macros must be used inside TSRcode@
- ;
-
- ;-----------------------------------------------------------------------
- ;
- ; ISP_HEADER set up Interrupt Sharing Protocol header for an interrupt
- ; arguments:
- ; intr interrupt number
- ; reset [opt] name of routine to perform hardware reset
- ; eoi [opt] if nonzero, this is the primary handler for a hardware int
- ; exported labels: (for example "ISP_HEADER 00h,reset_func,0")
- ; INT00h_handler (public), ORIG_INT00h (public), HWRESET_00h,
- ; EOI_FLAG_00h
- ; [in addition, hw_reset_00h would be present for ISP_HEADER 00h,,0]
- ;
- ISP_HEADER MACRO intr,reset,eoi
- public INT&intr&_handler,ORIG_INT&intr
- ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
- IFB <reset>
- hw_reset_&intr:
- db 0CBh ; RETF
- ENDIF ;reset
-
- INT&intr&_handler:
- db 0EBh,10h ; short JMP to skip the header
- ORIG_INT&intr dd ? ; previous handler in chain
- dw 424Bh ; ISP signature
- EOI_FLAG_&intr label byte
- IFB <eoi>
- db 0 ; software int or secondary hardware int
- ELSE
- IF eoi eq 0
- db 0 ; software int or secondary hardware int
- ELSE
- db 80h ; primary hardware int handler
- ENDIF ;eoi eq 0
- ENDIF ;B eoi
- IFB <reset>
- HWRESET_&intr: jmp short hw_reset_&intr
- ELSE
- HWRESET_&intr: jmp short reset
- ENDIF ;B reset
- db 7 dup (0)
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- ; HOOKED_INTS declare the interrupts this TSR hooks
- ; arguments: up to 32 interrupt numbers
- ; exported labels: HOOKED_INT_LIST (public)
- ;
- 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
- public HOOKED_INT_LIST
- HOOKED_INT_LIST label byte
- IFNB <over>
- %out Too many interrupts hooked!
- .err
- ENDIF ;NB over
- 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>
- IFNB <intrpt>
- IF intrpt ne 2Dh ; ignore INT 2Dh if in the list
- DB 0&&intrpt
- DW INT&&intrpt&&_handler
- ENDIF ;DIFI
- ENDIF ;NB
- ENDM
- ;
- ; the list terminator is INT 2Dh, since we know that one will always
- ; be hooked; thus, all interrupts from 00h to FFh may be hooked
- ;
- DB 2Dh
- DW INT2Dh_handler
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- ; ALTMPX define the alternate multiplex interrupt handler for the program
- ; arguments:
- ; manuf one- to eight-character manufacturer's name
- ; prodname one- to eight-character product name
- ; version four-digit hex version number (hi byte = major, lo = minor)
- ; descrip [opt] string (max 63 char) describing the product
- ; priv_funcs [opt] name of routine to handle private INT 2Dh functions
- ; api_entry [opt] name of FAR routine giving non-INT 2Dh API entry point
- ; popup [opt] name of function to call to request a popup
- ; remover [opt] name of function to call to remove TSR from memory
- ; psp [opt] if nonblank, set up patch word for memblk segment to
- ; be returned if <remover> omitted; returns CS if both
- ; <remover> and <psp> blank
- ; limitations on routines:
- ; all: must be located inside TSRcode@
- ; <priv_funcs>
- ; input: AL = function number (10h-FFh)
- ; AH = multiplex number (ignore)
- ; others available for handler
- ; return: via IRET, with regs as appropriate for requested func
- ; <api_entry>
- ; input: registers as desired (no limitations)
- ; return: registers as desired (no limitations)
- ; <popup>
- ; input: nothing
- ; return: AL = status
- ; 01h can not pop up now, try again later
- ; 02h can not pop up yet, will do so when able
- ; 03h already popped up
- ; 04h unable to popup, user intervention required
- ; BX = standard reason code
- ; 0000h unknown failure
- ; 0001h int chain passes through memory
- ; which must be swapped out
- ; 0002h swap-in failed
- ; CX = application's reason code if nonzero
- ; FFh TSR popped up and was exited by user
- ; BX = return value
- ; 0000h no return value
- ; 0001h TSR unloaded
- ; 0002h-00FFh reserved
- ; 0100h-FFFFh application-specific
- ; <remover>
- ; input: DX:BX = return address if uninstall successful
- ; return: AL = status
- ; 01h unable to remove from memory
- ; 02h can't remove now, will do so when able
- ; 03h safe to remove, but no resident uninstaller
- ; (TSR still enabled)
- ; BX = segment of memory block
- ; 04h safe to remove, but no resident uninstaller
- ; (TSR now disabled)
- ; BX = segment of memory block
- ; 05h not safe to remove now, try again later
- ; FFh successful (DX:BX were ignored)
- ; return at DX:BX with AX destroyed if successful and <remover>
- ; honors specific return address
- ; if <remover> omitted, ALTMPX returns AL=03h
- ; exported labels:
- ; INT2Dh_handler (public), ORIG_INT2Dh (public), HWRESET_2Dh,
- ; EOI_FLAG_2Dh, hw_reset_00h, MULTIPLEX_NUMBER (public),
- ; ALTMPX_SIGNATURE (public), ALTMPX$PSP [patch word]
- ;
- ALTMPX MACRO manuf,prodname,version,descrip,priv_funcs,api_entry,popup,remover,psp
- LOCAL our_int_2Dh,int2D_func_00,int2D_func_01,int2D_func_02
- LOCAL int2D_func_03,int2D_func_04
- LOCAL func_is_supported,func_not_supported,func_supported_segDX
- PUBLIC MULTIPLEX_NUMBER,ALTMPX_SIGNATURE,ALTMPX$PSP
-
- ALTMPX_SIGNATURE label byte
- db manuf
- IF ($-ALTMPX_SIGNATURE) gt 8
- ERR "Manufacturer name >8 chars"
- ELSEIF ($-ALTMPX_SIGNATURE) lt 8
- db (ALTMPX_SIGNATURE+8-$) dup (' ')
- ENDIF
- db prodname
- IF ($-ALTMPX_SIGNATURE) gt 16
- ERR "Product name >8 chars"
- ELSEIF ($-ALTMPX_SIGNATURE) lt 16
- db (ALTMPX_SIGNATURE+16-$) dup (' ')
- ENDIF
- IFNB <descrip>
- db descrip
- ENDIF
- db 0
- IF ($-ALTMPX_SIGNATURE) gt 80
- ERR "Description >63 chars"
- ENDIF
-
- ; save an additional byte by overlaying the null hardware reset handler over
- ; other code, if possible
- IFNB <remover>
- hw_reset_2Dh: ; <remover> not blank
- db 0CBh ; RETF
- IFNDEF ALTMPX$PSP
- ALTMPX$PSP equ word ptr ($+12) ; point harmlessly into the ISP header
- ENDIF
- ELSE
- IFB <psp>
- ALTMPX$PSP equ word ptr ($+12) ; point harmlessly into the ISP header
- ENDIF
- ENDIF
- IFNB <psp>
- IFB <remover>
- hw_reset_2Dh: ; <remover> blank but <psp> not
- db 0CBh ; RETF
- ENDIF
- ENDIF
- ; if both <remover> and <psp> blank,
- ; hw_reset_2Dh is defined below
- ; if <remover> is blank and <psp> not,
- ; ALTMPX$PSP is defined below
-
- ISP_HEADER 2Dh,hw_reset_2Dh
- cmp ah,0 ; will be patched with multiplex number
- MULTIPLEX_NUMBER equ byte ptr ($-1)
- je our_int_2Dh
- jmp ORIG_INT2Dh
- our_int_2Dh:
- sti ; OK to interrupt from now on
- cmp al,0
- je int2D_func_00
- cmp al,2
- IFNB <api_entry>
- jb int2D_func_01
- ELSE
- IFNB <popup>
- jb func_not_supported
- ENDIF
- ENDIF
- je int2D_func_02
- cmp al,4
- IFNB <popup>
- jb int2D_func_03
- ENDIF ;popup
- je int2D_func_04
- IFNB <priv_funcs>
- cmp al,10h
- jb func_not_supported
- jmp priv_funcs
- ENDIF ;priv_funcs
- func_not_supported:
- mov al,0
- iret
-
- int2D_func_00:
- mov cx,version
- mov di,offset ALTMPX_SIGNATURE
- func_supported_segDX:
- mov dx,cs
- func_is_supported:
- mov al,0FFh
- iret
-
- IFNB <api_entry>
- int2D_func_01:
- mov bx,offset api_entry
- jmp func_supported_segDX
- ENDIF ;api_entry
-
- int2D_func_02:
- IFNB <remover>
- call remover
- ELSE
- ; mov al,3 ; safe to remove, no resident uninstaller
- inc ax ; AL was 02h, now 03h
- IFNB <psp>
- mov bx,0 ; will be patched at installation time
- ALTMPX$PSP equ word ptr ($-2)
- ELSE
- mov bx,cs
- hw_reset_2Dh equ near ptr ($-1) ; prev instruction happens to expand to 8Ch CBh
- ENDIF ;psp
- ENDIF ;remover
- iret
-
- IFNB <popup>
- int2D_func_03:
- call popup
- iret
- ENDIF ;popup
-
- int2D_func_04:
- ;mov al,4 ;not needed since AL=04h anyway
- mov dx,cs
- mov bx,offset cs:hooked_int_list
- iret
-
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- GRAB_INTERRUPT MACRO intnum,handler
- TSRbss@
- TSR_old_INT&intnum dd ?
- TSRbssEnd@
-
- mov ax,3500h+intnum
- int 21h
- mov word ptr TSR_old_INT&intnum,bx
- mov word ptr TSR_old_INT&intnum+2,es
- mov dx,offset TGROUP:handler
- mov ax,2500h+intnum
- int 21h
- ENDM
-
- ;-----------------------------------------------------------------------
- ;
- RESTORE_INTERRUPT MACRO intnum
- push ds
- lds dx,TSR_old_INT&intnum
- mov ax,2500h+intnum
- int 21h
- pop ds
- ENDM
-
- ;-----------------------------------------------------------------------
-
- .LIST
-