⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 int9.asm

📁 汇编编程艺术
💻 ASM
📖 第 1 页 / 共 2 页
字号:
; 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 + -