📄 int9.asm
字号:
; If the H.O. bit is set at this point, we'd best only have a zero in AL.
; Otherwise, this is an up code which we can safely ignore.
call Convert
test ax, ax ;Check for illegal code.
je QuitPIB
PutCharInBuf: push cx
mov cx, ax
mov ah, 5 ;Store scan code into
int 16h ; type ahead buffer.
pop cx
QuitPIB: and KbdFlags3, 0FCh ;E0, E1 not last code.
Done: pop bx
pop ds
ret
PutInBuffer endp
;****************************************************************************
;
; Convert- AL contains a PC Scan code. Convert it to an ASCII char/Scan
; code pair and return the result in AX. This code assumes
; that DS points at the BIOS variable space (40h).
Convert proc near
push bx
test al, 80h ;See if up code
jz DownScanCode
mov ah, al
mov al, 0
jmp CSDone
; Okay, we've got a down key. But before going on, let's see if we've
; got an ALT-Keypad sequence.
DownScanCode: mov bh, 0
mov bl, al
shl bx, 1 ;Multiply by eight to compute
shl bx, 1 ; row index index the scan
shl bx, 1 ; code xlat table
; Compute modifier index as follows:
;
; if alt then modifier = 3
test KbdFlags, AltBit
je NotAlt
add bl, 3
jmp DoConvert
; if ctrl, then modifier = 2
NotAlt: test KbdFlags, CtrlBit
je NotCtrl
add bl, 2
jmp DoConvert
; Regardless of the shift setting, we've got to deal with numlock
; and capslock. Numlock is only a concern if the scan code is greater
; than or equal to 47h. Capslock is only a concern if the scan code
; is less than this.
NotCtrl: cmp al, 47h
jb DoCapsLk
test KbdFlags, NLBit ;Test Numlock bit
je NoNumLck
test KbdFlags, LShfBit or RShfBit ;Check l/r shift.
je NumOnly
add bl, 7 ;Numlock and shift.
jmp DoConvert
NumOnly: add bl, 4 ;Numlock only.
jmp DoConvert
; If numlock is not active, see if a shift key is:
NoNumLck: test KbdFlags, LShfBit or RShfBit ;Check l/r shift.
je DoConvert ;normal if no shift.
add bl, 1
jmp DoConvert
; If the scan code's value is below 47h, we need to check for capslock.
DoCapsLk: test KbdFlags, CLBit ;Chk capslock bit
je DoShift
test KbdFlags, LShfBit or RShfBit ;Chk for l/r shift
je CapsOnly
add bl, 6 ;Shift and capslock.
jmp DoConvert
CapsOnly: add bl, 5 ;Capslock
jmp DoConvert
; Well, nothing else is active, check for just a shift key.
DoShift: test KbdFlags, LShfBit or RShfBit ;l/r shift.
je DoConvert
add bl, 1 ;Shift
DoConvert: shl bx, 1 ;Word array
mov ax, ScanXlat[bx]
CSDone: pop bx
ret
Convert endp
; SetCmd- Sends the command byte in the AL register to the 8042
; keyboard microcontroller chip (command register at
; port 64h).
SetCmd proc near
push cx
push ax ;Save command value.
cli ;Critical region, no ints now.
; Wait until the 8042 is done processing the current command.
xor cx, cx ;Allow 65,536 times thru loop.
Wait4Empty: in al, 64h ;Read keyboard status register.
test al, 10b ;Input buffer full?
loopnz Wait4Empty ;If so, wait until empty.
; Okay, send the command to the 8042:
pop ax ;Retrieve command.
out 64h, al
sti ;Okay, ints can happen again.
pop cx
ret
SetCmd endp
; SendCmd- The following routine sends a command or data byte to the
; keyboard data port (port 60h).
SendCmd proc near
push ds
push bx
push cx
mov cx, 40h
mov ds, cx
mov bx, ax ;Save data byte
mov bh, 3 ;Retry cnt.
RetryLp: cli ;Disable ints while accessing HW.
; Clear the Error, Acknowledge received, and resend received flags
; in KbdFlags4
and byte ptr KbdFlags4, 4fh
; Wait until the 8042 is done processing the current command.
xor cx, cx ;Allow 65,536 times thru loop.
Wait4Empty: in al, 64h ;Read keyboard status register.
test al, 10b ;Input buffer full?
loopnz Wait4Empty ;If so, wait until empty.
; Okay, send the data to port 60h
mov al, bl
out 60h, al
sti ;Allow interrupts now.
; Wait for the arrival of an acknowledgement from the keyboard ISR:
xor cx, cx ;Wait a long time, if need be.
Wait4Ack: test byp KbdFlags4, 10h ;Acknowledge received bit.
jnz GotAck
loop Wait4Ack
dec bh ;Do a retry on this guy.
jne RetryLp
; If the operation failed after 3 retries, set the error bit and quit.
or byp KbdFlags4, 80h ;Set error bit.
GotAck: pop cx
pop bx
pop ds
ret
SendCmd endp
; SetLEDs- Updates the KbdFlags4 LED bits from the KbdFlags
; variable and then transmits new flag settings to
; the keyboard.
SetLEDs proc near
push ax
push cx
mov al, KbdFlags
mov cl, 4
shr al, cl
and al, 111b
and KbdFlags4, 0F8h ;Clear LED bits.
or KbdFlags4, al ;Mask in new bits.
mov ah, al ;Save LED bits.
mov al, 0ADh ;Disable kbd for now.
call SetCmd
mov al, 0EDh ;8042 set LEDs cmd.
call SendCmd ;Send the command to 8042.
mov al, ah ;Get parameter byte
call SendCmd ;Send parameter to the 8042.
mov al, 0AEh ;Reenable keyboard.
call SetCmd
mov al, 0F4h ;Restart kbd scanning.
call SendCmd
pop cx
pop ax
ret
SetLEDs endp
; MyInt9- Interrupt service routine for the keyboard hardware
; interrupt.
MyInt9 proc far
push ds
push ax
push cx
mov ax, 40h
mov ds, ax
mov al, 0ADh ;Disable keyboard
call SetCmd
cli ;Disable interrupts.
xor cx, cx
Wait4Data: in al, 64h ;Read kbd status port.
test al, 10b ;Data in buffer?
loopz Wait4Data ;Wait until data available.
in al, 60h ;Get keyboard data.
cmp al, 0EEh ;Echo response?
je QuitInt9
cmp al, 0FAh ;Acknowledge?
jne NotAck
or KbdFlags4, 10h ;Set ack bit.
jmp QuitInt9
NotAck: cmp al, 0FEh ;Resend command?
jne NotResend
or KbdFlags4, 20h ;Set resend bit.
jmp QuitInt9
; Note: other keyboard controller commands all have their H.O. bit set
; and the PutInBuffer routine will ignore them.
NotResend: call PutInBuffer ;Put in type ahead buffer.
QuitInt9: mov al, 0AEh ;Reenable the keyboard
call SetCmd
mov al, 20h ;Send EOI (end of interrupt)
out 20h, al ; to the 8259A PIC.
pop cx
pop ax
pop ds
iret
MyInt9 endp
Main proc
assume ds:cseg
mov ax, cseg
mov ds, ax
print
byte "INT 9 Replacement",cr,lf
byte "Installing....",cr,lf,0
; Patch into the INT 9 interrupt vector. Note that the
; statements above have made cseg the current data segment,
; so we can store the old INT 9 value directly into
; the OldInt9 variable.
cli ;Turn off interrupts!
mov ax, 0
mov es, ax
mov ax, es:[9*4]
mov word ptr OldInt9, ax
mov ax, es:[9*4 + 2]
mov word ptr OldInt9+2, ax
mov es:[9*4], offset MyInt9
mov es:[9*4+2], cs
sti ;Okay, ints back on.
; We're hooked up, the only thing that remains is to terminate and
; stay resident.
print
byte "Installed.",cr,lf,0
mov ah, 62h ;Get this program's PSP
int 21h ; value.
mov dx, EndResident ;Compute size of program.
sub dx, bx
mov ax, 3100h ;DOS TSR command.
int 21h
Main endp
cseg ends
sseg segment para stack 'stack'
stk db 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes db 16 dup (?)
zzzzzzseg ends
end Main
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -