home *** CD-ROM | disk | FTP | other *** search
- ; *********** EVENTHDW.ASM *******************************************
-
- .model medium, basic
- .data
-
- IRQLevel dw -1 ; the requested IRQ level
- OrigMask db 0 ; how the 8259 IMR was on entry
- Chained db 0 ; did we chain in or take over?
-
- .code
-
- PreviousVector LABEL DWORD ; placed in the code segment to...
- PVOffset dw -1 ; ...facilitate chaining if req'd
- PVSegment dw 77 ; a signature to avoid multi-installs
-
- EXTRN SetUEvent:FAR ; this is in the BC runtime
- EXTRN B_OnExit:FAR ; ditto
-
- InstallHandler PROC irqnum, chnd ; both passed BYVAL
-
- ; This takes care of wrapping our metaphorical tentacles around the
- ; PC. We take over the interrupt vector associated with the IRQ level
- ; passed, saving the previous contents so that we can put things back
- ; the way they were when we exit, and we enable the interrupt level in
- ; the PC hardware.
-
- cmp PVSegment, 77 ; insure this is first time
- jne iherr
- mov ax, irqnum ; test for correct range
- cmp ax, 2
- jb iherr ; vector too low, < 2
- cmp ax, 7
- ja iherr ; vector too high, > 7
- mov dx, offset RemoveInt
- push cs ; push far address of RemoveInt
- push dx ; to register the exit routine
- call B_OnExit ; so that we don't hang machine
- or ax, ax ; registered OK?
- jz iherr ; error: too many registered routines
- mov ax, chnd ; will we chain or not?
- mov chained, al ; keep local copy
- mov ax, irqnum ; get this again
- mov IRQLevel, ax ; save for removal routine
- mov cx, ax ; hold value a moment as shift count
- add al, 8 ; add 8 to turn low IRQ into INT
- mov ah, 35H ; use DOS to get current...
- INT 21H ; ...holder of the vector
- mov PVSegment, es ; save for chaining, removal
- mov PVOffset, bx
- test chained, -1 ; who does the 8259?
- jnz @f ; ...not me...
-
- mov ah, 1 ; turn IRQ # into bit mask
- shl ah, cl
- push ax ; preserve mask
- cli ; do this with all interrupts off
- in al, 21H ; get PC's Interrupt Mask Register
- mov OrigMask, al ; save for later removal
- or al, ah ; set this IRQ level OFF...
- out 21H, al ; ...in the IMR
- sti ; interrupts back on
- mov ax, cx ; get IRQ number again
- add al, 8 ; turn into INT number
- @@:
- mov ah, 25H ; tell DOS we're taking this vector
- push ds ; hold DS a moment
- mov bx, cs ; transfer CS to DS
- mov ds, bx
- mov dx, offset IntHandler; get address of our MASM handler
- INT 21H ; grab the vector, Victor
- pop ds ; restore DS
- test chained, -1 ; who's doing the 8259?
- jnz @f ; ..the other guy is
-
- pop ax ; get mask back
- not ax ; invert mask bits
- cli ; all interrupts off
- in al, 21H ; get IMR
- and al, ah ; set this IRQ level ON
- out 21H, al ; set IMR
- sti ; interrupts back on again
- @@:
- xor ax, ax ; return zero: all OK
- @@: ret
-
- iherr: mov ax, -1 ; couldn't install: return TRUE
- jmp @b
-
- InstallHandler ENDP
-
- RemoveInt PROC
-
- ; RemoveInt will undo the InstallHandler by restoring the PC to the
- ; state it was in before we came along. This is vital, because
- ; otherwise when the program terminates the interrupt vector will
- ; point into volatile space, guaranteeing an eventual machine hang.
-
- ; Because we "register" this routine with B_OnExit, restoring the
- ; machine state becomes a part of BASIC's normal shutdown process...
- ; we don't need to call this routine explicitly.
-
- test chained, -1 ; who's job is the 8259?
- jnz @f ; not ours, skip mask stuff
- mov cx, IRQLevel ; level we're using
- mov ax, 1 ; turn into bit mask
- shl ax, cl ; by shifting
- mov ah, al ; protect it
- push ax ; save AH for later
- cli ; do this with interrupts off
- in al, 21H ; get IMR
- or al, ah ; this IRQ level OFF
- out 21H, al ; set IMR
- sti ; interrupts on again
- @@: mov ax, IRQLevel ; IRQ number
- add al, 8 ; becomes INT number
- mov ah, 25H ; SET VECTOR call
- push ds ; protect DS
- lds dx, PreviousVector; get original vector
- INT 21H ; restore it
- pop ds ; so we can read OrigMask
- test chained, -1 ; who's job is the 8259?
- jnz @f ; not ours, skip mask stuff
- pop ax ; recover mask in AH
- test OrigMask, ah ; the state before we interfered
- jnz @f ; originally off, leave off
- not ah ; bit clear = ON
- cli ; all interrupts off
- in al, 21H ; get IMR
- and al, ah ; this IRQ level ON
- out 21H, al ; set IMR
- sti ; interrupts back on
- @@: ret
-
- RemoveInt ENDP
-
- IntHandler PROC FAR ;note that we don't just say "PROC" here
-
- ; This routine notifies the BASIC runtime that an event has occurred.
- ; You MUST save and restore any registers you use. In this example
- ; we're overly pessimistic, assuming that BC will destroy everything.
-
- assume cs:@code, ds:nothing, es:nothing, ss:nothing
-
- sti ; allow more important interrupts
- push ax
- push ds ; only save the registers you really need to
- push di
- push es ; here, we assume BC can destroy anything
- push si
- push dx
- push cx
- push bx
- call SetUEvent ; notify BC/QB that the event occurred
- ;
- ; If there are hardware-specific duties, do them here
- ;
- pop bx
- pop cx
- pop dx
- pop si
- pop es
- pop di
- mov ax, @data
- mov ds, ax
- assume ds:@data
- test chained, -1 ; is someone else doing the 8259?
- pop ds
- assume ds:nothing
- jnz @f ; yes, skip the following
- mov al, 20H ; clear PC's interrupt by
- out 20H, al ; using a non-specific EOI
- pop ax
- iret ; resume program in progress
- @@:
- pop ax
- jmp [PreviousVector]
-
- IntHandler ENDP
-
- END
-
-