home *** CD-ROM | disk | FTP | other *** search
- 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