19.2.1 Auditing Hardware Events for TSR Requests

Active TSRs commonly use a special keystroke sequence or the timer as a request signal. A TSR invoked through one of these channels must be equipped with handlers that audit keyboard or timer events.

A keyboard handler receives control at every keystroke. It examines each key, searching for the proper signal or “hot key.” Generally, a keyboard handler should not attempt to call the TSR directly when it detects the hot key. If the TSR cannot safely interrupt the current process at that moment, the keyboard handler is forced to exit to allow the process to continue. Since the handler cannot regain control until the next keystroke, the user has to press the hot key repeatedly until the handler can comply with the request.

Instead, the handler should merely set a request flag when it detects a hot-key signal and then exit normally. Examples in the following paragraphs illustrate this technique.

For computers other than the IBM PS/2̉ series, an active TSR audits keystrokes through a handler for Interrupt 09, the keyboard interrupt:

Keybrd PROC FAR

sti ; Interrupts are okay

push ax ; Save AX register

in al, 60h ; AL = scan code of current key

call CheckHotKey ; Check for hot key

.IF !carry? ; If not hot key:

; Hot key pressed. Reset the keyboard to throw away keystroke.

cli ; Disable interrupts while resetting

in al, 61h ; Get current port 61h state

or al, 10000000y ; Turn on bit 7 to signal clear keybrd

out 61h, al ; Send to port

and al, 01111111y ; Turn off bit 7 to signal break

out 61h, al ; Send to port

mov al, 20h ; Reset interrupt controller

out 20h, al

sti ; Reenable interrupts

pop ax ; Recover AX

mov cs:TsrRequestFlag, TRUE ; Raise request flag

iret ; Exit interrupt handler

.ENDIF ; End hot-key check

; No hot key was pressed, so let normal Int 09 service

; routine take over

pop ax ; Recover AX and fall through

cli ; Interrupts cleared for service

KeybrdMonitor LABEL FAR ; Installed as Int 09 handler for

; PS/2 or for time-activated TSR

; Signal that interrupt is busy

mov cs:intKeybrd.Flag, TRUE

pushf ; Simulate interrupt by pushing flags,

; far-calling old Int 09 routine

call cs:intKeybrd.OldHand

mov cs:intKeybrd.Flag, FALSE

iret

Keybrd ENDP

A TSR running on a PS/2 computer cannot reliably read key-scan codes using the above method. Instead, the TSR must search for its hot key through a handler for Interrupt 15h (Miscellaneous System Services). The handler determines the current keypress from the AL register when AH equals 4Fh, as shown here:

MiscServ PROC FAR

sti ; Interrupts okay

.IF ah == 4Fh ; If Keyboard Intercept Service:

push ax ; Preserve AX

call CheckHotKey ; Check for hot key

pop ax

.IF !carry? ; If hot key:

mov cs:TsrRequestFlag, TRUE ; Raise request flag

clc ; Signal BIOS not to process the key

ret 2 ; Simulate IRET without popping flags

.ENDIF ; End carry flag check

.ENDIF ; End Keyboard Intercept check

cli ; Disable interrupts and fall through

SkipMiscServ LABEL FAR ; Interrupt 15h handler if PC/AT

jmp cs:intMisc.OldHand

MiscServ ENDP

The example program in Section 19.8 demonstrates how a TSR tests for a PS/2 machine and then sets up a handler for either Interrupt 09 or Interrupt 15h to audit keystrokes.

Setting a request flag in the keyboard handler allows other code, such as the timer handler (Interrupt 08), to recognize a request for the TSR. The timer handler gains control at every timer interrupt; the interrupts occur an average of 18.2 times per second. The following fragment shows how a timer handler tests the request flag and continually polls until it can safely execute the TSR.

TestFlag PROC FAR

.

.

.

cmp TsrRequestFlag, FALSE ; Has TSR been requested?

je exit ; If not, exit

call CheckSystem ; Can system be interrupted

; safely?

jc exit ; If not, exit

call ActivateTsr ; If okay, call TSR

Figure 19.1 illustrates the process. It shows a time line for a typical TSR signaled from the keyboard. When the keyboard handler detects the proper hot key, it sets a request flag called TsrRequestFlag. Thereafter, the timer handler continually checks the system status until it can safely call the TSR.

The timer itself can serve as the start-up signal if the TSR executes periodically. Screen clocks that continuously show seconds and minutes are examples of TSRs that use the timer this way. ALARM.ASM, a program described in the next section, shows another example of a timer-driven TSR.