home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
turbopas
/
tppop16.arc
/
TPOP.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-10-05
|
20KB
|
518 lines
TITLE Turbo Pop Version 1.6 beta
SUBTTL Copyright (c)1988 Ross Neilson Wentworth
; This code is Copyright (c)1988 by Ross Neilson Wentworth
; All Rights Reserved
;
; No part of this code may be reproduced, modified, sold, or used
; as an incentive to buy without the expressed written consent of
; the author.
; Routine Quick Reference
;
; EnterPopUp Saves and sets the stack then calls a high-level routine
; InitializePopUp Sets the low-level interrupt vectors
; Installed Sees if the program is already loaded
; new05Int Optional print-screen trap
; new09int Checks for our hotkey combo at each keypress
; new10Int Optional video BIOS trap
; new13int Keeps track of when the disk is busy
; new1Cint Called at each timer tick and checks to see if we
; want to pop up and whether it is safe to do so
; new28int Interrupt routine that is called whenever it is safe
; to interrupt DOS
; new2Fint Intercepts the Multiplex interupt
TRUE equ 1
FALSE equ 0
TRAPINT05 EQU FALSE ; change to TRUE to trap print-screens
TRAPINT10 EQU FALSE ; change to TRUE to trap video BIOS
PUBLIC InitializePopUp,Installed
CSEG SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CSEG
EXTRN callpopup:FAR,ReleaseProgram:FAR
;----------------------------------------------------------------------------
; Miscellaneous data
;----------------------------------------------------------------------------
hotkey LABEL WORD
scancode DB 0 ; scan code of our hotkey
shiftstatus DB 0 ; shift key status (alt,ctrl, etc. )
program_status DB 0 ; true if the program is active
request_flag DB 0 ; true if we want to pop-up
notsafe DB 0 ; non-zero if unsafe to pop up
multiplexID DB 0 ; unique program ID code
stack_pointer DW 0 ; holds our program's stack pointer
stack_segment DW 0 ; holds our program's stack segment
old_pointer DW 0 ; holds the interrupted stack pointer
old_stack DW 0 ; holds the interrupted stack segment
dos_busy_flag DD 0 ; points to DOS's busy flag
; Follows is the interrupt service routine (ISR) installation table.
; Each interrupt will have three entries, the interrupt number, the
; original interrupt vector, and the offset of the ISR. The entire
; table is terminated with a zero byte (this disallows the automatic
; installation of interrupt 00h). There are two ISR's that are optional.
; One traps the print-screen interrupt (05h) and the other traps the video
; BIOS interrupt (10h). By default, these traps are not used. If you wish
; to include them in the interrupt trapping list you must change the EQU's
; above to TRUE. TRAPINT05 is the EQU for trapping the print-screen
; interrupt and TRAPINT10 is the EQU for trapping the video BIOS.
;----------------------------------------------------------------------------
; Interrupt Vector Table
;----------------------------------------------------------------------------
Vectors LABEL BYTE
IF TRAPINT05 ; optional interrupt trap
DB 05h ; print screen vector number
old05int DD ? ; the original print screen interrupt vector
DW offset new05int
ENDIF
DB 09h ; keyboard vector number
old09int DD ? ; the original keyboard interrupt vector
DW offset new09int
IF TRAPINT10 ; optional interrupt trap
DB 10h ; video BIOS vector number
old10int DD ? ; the original video BIOS interrupt vector
DW offset new10int
ENDIF
DB 13h ; disk i/o vector number
old13int DD ? ; the original disk interrupt vector
DW offset new13int
DB 1Ch ; timer vector number
old1Cint DD ? ; the original timer interrupt vector
DW offset new1Cint
DB 28h ; backprocess vector number
old28int DD ? ; the original backprocess interrupt vector
DW offset new28int
DB 2Fh ; multiplex interrupt
old2Fint DD ? ; the original multiplex interrupt vector
DW offset new2Fint
DB 0 ; end of table
;----------------------------------------------------------------------------
; Print-Screen Interrupt Service Routine - 05h
;----------------------------------------------------------------------------
; This is an optional interrupt trap. Change the value of TRAPINT05 to
; TRUE if you want it compiled. This one traps the PRINT SCREEN interrupt
; and prevents popping up in the middle of a screen print.
IF trapInt05
new05int PROC FAR
inc cs:[notsafe] ; increment status flag
pushf
cli
call cs:[old05int] ; chain to original INT 05h handler
pushf ; preserve flags
dec cs:[notsafe] ; decrement status flag
popf ; restore flags
sti ; enable interrupts
ret 2 ; return with flags
new05int ENDP
ENDIF
;----------------------------------------------------------------------------
; Keyboard Interrupt Service Routine - 09h
;----------------------------------------------------------------------------
; Every keystroke is checked through here for our hot_key combination.
; If our's is pressed, a service request flag is set to TRUE. If the
; program is already active we let the keystroke by so that conflicting
; hot-keys will work.
new09int PROC FAR
sti
pushf ; save the flags
push ax ; and a register that gets used
in al,60h ; get the keystroke
cmp al,cs:[scancode] ; is it our key?
jne @F ; no, so jump to original vector
mov ah,2
int 16h ; get the keyboard flags
and al,0Fh ; mask off unused bits
cmp al,cs:[shiftstatus] ; does it match our mask?
jne @F ; no, so jump to original vector
cmp cs:[program_status],FALSE ; are we already active?
jne @F ; yes, so chain to original vector
cmp cs:[request_flag],FALSE ; do we already want serveice?
je L200 ; yes, so chain to original vector
@@:
pop ax ; restore used register
popf ; restore flags
jmp cs:[old09int] ; jump to original vector
L200:
mov cs:[request_flag],TRUE ; say service is desired
cli ; turn off interrupts
mov al,20h ; say interrupt is finished
out 20h,al
in al,61h ; trash the keystroke
mov ah,al
or al,80h
out 61h,al
jmp @F ; jump to nowhere for delay
@@:
mov al,ah
out 61h,al
pop ax ; restore used register
popf ; restore flags
iret ; all done
new09int ENDP
;----------------------------------------------------------------------------
; Video BIOS Interrupt Service Routine - 10h
;----------------------------------------------------------------------------
; This is an optional interrupt trap. Change the value of TRAPINT10 to
; TRUE if you want it compiled. This one traps the video BIOS interrupt
; and prevents popping up in the middle of any screen activity.
IF trapInt10
new10int PROC FAR
inc cs:[notsafe] ; increment status flag
pushf
cli
call cs:[old10int] ; chain to original INT 10h handler
pushf ; preserve flags
dec cs:[notsafe] ; decrement status flag
popf ; restore flags
sti ; enable interrupts
ret 2 ; return with flags
new10int ENDP
ENDIF
;----------------------------------------------------------------------------
; Disk I/O Interrupt Service Routine - 13h
;----------------------------------------------------------------------------
; At each disk call, increments an unsafe flag, finishes
; the disk call, then decrements the unsafe flag. This
; prevents an unsafe "popup" during disk i/o.
new13int PROC FAR
inc cs:[notsafe] ; increment status flag
pushf ; chain to original INT 13h handler
cli
call cs:[old13int]
pushf ; preserve flags
dec cs:[notsafe] ; decrement status flag
popf ; restore flags
sti ; enable interrupts
ret 2 ; return with flags, this is to retain
; any carry flag (error) that may
; have occurred.
new13int ENDP
;----------------------------------------------------------------------------
; Timer Tick Interrupt Service Routine - 1Ch
;----------------------------------------------------------------------------
; At each timer tick, this routine sees if our routine wants service.
; If it does, and it's safe to run, it saves junk and calls our routine.
new1Cint PROC FAR
pushf ; call original timer interrupt
cli
call cs:[old1Cint]
cmp cs:[request_flag],FALSE ; request flag set?
je L400 ; no, then exit
push di
push es ; save es and di
les di,cs:[dos_busy_flag] ; address of DOS BUSY_FLAG in DI
cmp byte ptr es:[di],FALSE ; DOS service currently active?
pop es
pop di ; clean up the stack
jne L400 ; dos active, so wait
cmp cs:[notsafe],FALSE ; is it safe to pop-up?
je EnterPopUp ; yes, go for it
L400:
iret ; busy or no request
new1Cint ENDP
;----------------------------------------------------------------------------
; Backprocess Interrupt Service Routine - 28h
;----------------------------------------------------------------------------
; Whenever it is safe for a program to interrupt, DOS issues an
; INT 28h. This normally occurs while sitting at the command line.
; This routine checks to see if our program wants service and pops
; it up if it does.
new28int PROC FAR
pushf ; call the original interrupt routine
cli
call cs:[old28int]
cmp cs:[request_flag],FALSE ; do we want to pop up?
jne EnterPopUp ; yes, go pop up
iret ; no. exit
new28int ENDP
;----------------------------------------------------------------------------
; Multiplex Interrupt Service Routine - 2Fh
;----------------------------------------------------------------------------
; We use this ISR to check if a program is already loaded as well as to
; provide special routines needed to unload the program safely.
;
; function 0, returns 0FFh in AL to indicate the program is already loaded
; function 1, returns the vector table in DX:AX
; function 2, returns the module's code segment (CS) in AX
; function 3, releases the memory for this program
;
; Examine the UNHOOK unit to see how these are used
new2Fint PROC FAR
cmp ah,cs:[MultiplexID]
je @F
jmp cs:[old2Fint]
@@:
test al,al ; function 0, loaded flag
jnz @F
mov al,0FFh
jmp short L300
@@:
cmp al,1 ; function 1, return vector table pointer
jne @F
mov dx,cs
lea ax,cs:[vectors]
jmp short L300
@@:
cmp al,2 ; function 2, return code segment
jne @F
mov ax,cs
jmp short L300
@@:
cmp al,3 ; function 3, release program memory
jne L300
pushf
call ReleaseProgram
L300:
iret
new2Fint ENDP
;----------------------------------------------------------------------------
; Setup For Entering Application
;----------------------------------------------------------------------------
; Sets SS, and SP, then calls the popup program.
; After returning, it restores them.
EnterPopUp PROC NEAR
mov cs:[request_flag],FALSE ; clear the pop up request flag
mov cs:[program_status],TRUE ; say program is active
mov cs:[old_stack],ss ; save the stack segment
mov cs:[old_pointer],sp ; save the stack pointer
cli ; turn off interrupts
mov ss,cs:[stack_segment] ; get our program's stack segment
mov sp,cs:[stack_pointer] ; get our program's stack pointer
sti ; turn interrupts back on
; call the popup procedure indirectly
pushf ; simulate an interrupt
call CallPopUp
; restore the stack segment and pointer
cli ; old cpu bug require ints be off
mov ss,cs:[old_stack]
mov sp,cs:[old_pointer]
sti
mov cs:[program_status],FALSE ; say program is not active
iret ; all done
EnterPopUp ENDP
stk_str STRUC
oldbp DW ?
return DW ?
keycombo DW ?
multID DW ?
stk_str ENDS
;----------------------------------------------------------------------------
; Initialize memory and the vectors
;----------------------------------------------------------------------------
; We save some interrupt vectors and flags in the code segment for
; efficiency. We don't want to be pushing and popping all of the
; registers at every single timer tick and key press.
;
; It's too bad there isn't any way of releasing the space used by the
; initialization code. This is the reason the most efficient resident
; programs are written in entirely assembler, complete control of segment
; ordering.
InitializePopUp PROC NEAR
; save the stack pointer and segment
push bp
mov bp,sp
; save our hot key combo
mov ax,keycombo[bp]
mov cs:[hotkey],ax
; save the TSR's unique ID
mov ax,multID[bp]
mov cs:[multiplexID],al
; save the stack segment and pointer
mov cs:[stack_segment],ss
mov cs:[stack_pointer],sp
; get the DOS busy flag address
mov ah,34h
int 21h
mov cs:word ptr [dos_busy_flag+2],es
mov cs:word ptr [dos_busy_flag],bx
push ds ; save the data segment
push cs
pop ds ; point to the code segment
; set all of the interrupt vectors
lea si,vectors
cld
@@:
lodsb ; get a vector number
or al,al ; are we done
jz @F ; yes
push ax ; save the interrupt number
mov ah,35h
int 21h ; get the old vector
mov [si],bx ; save the offset
mov [si+2],es ; save the segment
pop ax ; get back interrupt number
mov ah,25h ; set the interrupt vector
mov dx,[si+4] ; get the routine offset assume this code segment
int 21h
add si,6 ; point to next item in table
jmp short @B ; do it again
@@:
pop ds ; restore the data segment
pop bp
ret 2
InitializePopUp ENDP
;----------------------------------------------------------------------------
; Checks for a previously installed program
;----------------------------------------------------------------------------
; Checks to see if the program is already loaded by using the Multiplex
; interrupt (2Fh). It must do some convaluted crap to avoid problems
; under DOS 2.x.
Installed PROC FAR
push bp
mov bp,sp
mov ah,30h
int 21h ; get the DOS version
cmp al,2
ja L101 ; jump if version 3.0 or later
mov ax,352Fh ; get vector for 2Fh
int 21h
mov ax,es
or ax,bx ; jump if current INT 2Fh vector ..
jnz L100 ; .. is nonzero
mov ax,0F000h
mov es,ax
mov di,-1
mov cx,-1
std
mov al,0CFh
repne scasb ; find an IRET in the BIOS
inc di
mov dx,di
push ds
push es
pop ds
mov ax,252Fh
int 21h ; point 2Fh to an IRET in the BIOS
pop ds
jmp short L103 ; now go and install it
L100:
mov ax,0FF00h ; look for PRINT.COM
int 2Fh ; if resident AH = print queue length
cmp ah,0FFh ; otherwise AH is unchanged
je L101 ; use multiplex interrupt
mov al,1
jmp short L104 ; abort if PRINT.COM already installed
L101:
mov ax,[bp+6] ; get interrupt ID number
mov ah,al
xor al,al
int 2Fh ; poll for the ID number
test al,al ; installed already?
jz L103 ; jump if ok to install
cmp al,0FFh
jne L102 ; jump if not already installed
mov al,2
jmp short L104 ; error, already installed
L102:
mov al,3
jmp short L104 ; error, can't install
L103:
xor al,al
L104:
xor ah,ah
pop bp
ret 2
Installed ENDP
CSEG ENDS
END