480 lines
9.8 KiB
NASM
480 lines
9.8 KiB
NASM
title "Keyboard Detection"
|
||
;++
|
||
;
|
||
; Copyright (c) 1989 Microsoft Corporation
|
||
;
|
||
; Module Name:
|
||
;
|
||
; cpu.asm
|
||
;
|
||
; Abstract:
|
||
;
|
||
; This module implements the assembley code necessary to determine
|
||
; keyboard.
|
||
;
|
||
; Author:
|
||
;
|
||
; Shie-Lin Tzong (shielint) 16-Dec-1991. Most of the code is extracted
|
||
; from Win31 Setup.
|
||
;
|
||
; Environment:
|
||
;
|
||
; 80x86 Real Mode.
|
||
;
|
||
; Revision History:
|
||
;
|
||
;
|
||
;--
|
||
|
||
extrn _READ_PORT_UCHAR:proc
|
||
|
||
;
|
||
; Now define the needed equates.
|
||
;
|
||
|
||
TRUE equ -1
|
||
FALSE equ 0
|
||
|
||
;
|
||
; equates for ports -- these are used in the keyboard detection module.
|
||
;
|
||
|
||
ack_port equ 20h ; 8259 acknowledge port
|
||
eoi equ 20h ; 8259 end of interrupt
|
||
|
||
kb_data equ 60h
|
||
kb_ctl equ 61h
|
||
kb_command equ 64h ;
|
||
kb_status equ 64h ; status port -- bit 1: ok to write
|
||
|
||
ENABLE_KEYBOARD_COMMAND EQU 0AEH
|
||
DISABLE_KEYBOARD_COMMAND EQU 0ADH
|
||
|
||
.386
|
||
|
||
_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
|
||
ASSUME CS: _TEXT, DS:NOTHING, SS:NOTHING
|
||
|
||
|
||
;++
|
||
;
|
||
; BOOLEAN
|
||
; IsEnhancedKeyboard (
|
||
; VOID
|
||
; )
|
||
;
|
||
; Routine Description:
|
||
;
|
||
; Function looks at bios data area 40:96 to see if an enhanced keyboard
|
||
; is present.
|
||
;
|
||
; Arguments:
|
||
;
|
||
; None.
|
||
;
|
||
; Return Value:
|
||
;
|
||
; TRUE if Enhanced keyboard is present. Else a value of FALSE is returned.
|
||
;
|
||
;--
|
||
|
||
Public _IsEnhancedKeyboard
|
||
_IsEnhancedKeyboard proc near
|
||
|
||
push es
|
||
|
||
mov ax,40h
|
||
mov es,ax
|
||
xor ax,ax
|
||
mov al,byte ptr es:[96h]
|
||
and al,00010000b
|
||
|
||
pop es
|
||
ret
|
||
|
||
_IsEnhancedKeyboard endp
|
||
|
||
|
||
;++
|
||
;
|
||
; SHORT
|
||
; GetKeyboardIdBytes (
|
||
; PCHAR IdBuffer,
|
||
; SHORT Length
|
||
; )
|
||
;
|
||
; Routine Description:
|
||
;
|
||
; This routine returns keyboard identification bytes.
|
||
;
|
||
; Note that this function accepts one argument. The arg is a pointer to a
|
||
; character buffer allocated to hold five (five) bytes. Upon return from
|
||
; this function the buffer will contain between 1 and 5 bytes of keyboard
|
||
; ID information. The number of valid ID bytes in the buffer is returned
|
||
; in AX as a C proc return value.
|
||
;
|
||
; Arguments:
|
||
;
|
||
; None.
|
||
;
|
||
; Return Value:
|
||
;
|
||
; Id bytes are stored in IdBuffer and the length of Id bytes is returned.
|
||
;
|
||
;--
|
||
|
||
KeybID EQU [bp + 4] ; parameters
|
||
ReqByte EQU [bp + 6]
|
||
|
||
nKeyID EQU [bp - 2] ; Local variables
|
||
AckByte EQU [bp - 3]
|
||
|
||
public _GetKeyboardIdBytes
|
||
_GetKeyboardIdBytes proc near
|
||
|
||
push bp
|
||
mov bp, sp
|
||
sub sp, 4 ; space for local variables
|
||
push bx
|
||
push es
|
||
|
||
;
|
||
; First I initialize needed local vars. Next I find out if machine is AT
|
||
; type or non AT type for the purpose of selecting proper acknowledgement
|
||
; byte so I can talk to the interrupt controler.
|
||
;
|
||
|
||
mov bx, KeybID ; Initialize base pointer to buffer.
|
||
mov word ptr nKeyID, 0 ; Initialize count to zero.
|
||
mov byte ptr AckByte, 20h ; for all but AT-like. acknowledge for
|
||
; interrupt controller. 61h for AT's.
|
||
mov ax, 0fff0h ; look into 0FFF0:0FE location.
|
||
mov es, ax ; this is where the model byte is.
|
||
mov al, byte ptr es:[0feh]
|
||
cmp al, 0fch ; is it AT-like?
|
||
jne UnlikeAT
|
||
mov byte ptr AckByte, 61h
|
||
call _Empty8042
|
||
if 0
|
||
;
|
||
; Disable keyboard is a right thing to do. But, it turned out
|
||
; this causes some keyboards to fail GetId.
|
||
;
|
||
|
||
call DisableKeyboard
|
||
endif
|
||
|
||
UnlikeAT:
|
||
|
||
;
|
||
; Now, let's see if we can get some ID bytes from the keyboard controler.
|
||
;
|
||
|
||
mov ah, ReqByte ; AT: send second command.
|
||
mov dx, 60h ; write to data port
|
||
call Write8042 ; Output command byte to keyboard, bytes in AH
|
||
call ReadKeyboard ; Get byte from keyboard, byte in AL if No CF
|
||
jc gotNoByte
|
||
mov [bx], al ; save a byte. remember bx is pointer.
|
||
inc word ptr nKeyID
|
||
call ReadKeyboard ; Get byte from keyboard, byte in AL if No CF
|
||
jc gotNoByte
|
||
mov [bx]+1, al ; save a byte. remember bx is pointer.
|
||
inc word ptr nKeyID
|
||
call ReadKeyboard ; check for extra bytes.
|
||
jc gotNoByte
|
||
mov [bx]+2, al ; save a byte. remember bx is pointer.
|
||
inc word ptr nKeyID
|
||
|
||
gotNoByte:
|
||
mov al, AckByte
|
||
out ack_port, al
|
||
call EnableKeyboard
|
||
call _Empty8042
|
||
mov ax, nKeyID ; Return number of valid ID bytes obtained.
|
||
|
||
pop es
|
||
pop bx
|
||
mov sp, bp
|
||
pop bp
|
||
ret
|
||
_GetKeyboardIdBytes endp
|
||
|
||
;++
|
||
;
|
||
; UCHAR
|
||
; ReadKeyboard (
|
||
; VOID
|
||
; )
|
||
;
|
||
; Routine Description:
|
||
;
|
||
; This routine reads character from keyboard.
|
||
;
|
||
; It is assumed that a command (05H or 0F2H) has been set to request
|
||
; that the keyboard send an identification byte.
|
||
; It is also assumed that interrupts are disabled.
|
||
;
|
||
; Arguments:
|
||
;
|
||
; None.
|
||
;
|
||
; Return Value:
|
||
;
|
||
; If a character is returned, the carry bit is reset.
|
||
; If no character is returned, the carry bit is set.
|
||
;
|
||
;--
|
||
|
||
public ReadKeyboard
|
||
ReadKeyboard proc near
|
||
|
||
push cx
|
||
push bx
|
||
mov bx, 2 ; set outer timeout for double nested.
|
||
cli
|
||
|
||
inner_timeout:
|
||
xor cx, cx ; set inner timeout for double nested.
|
||
|
||
kbiwait:
|
||
in al, kb_status ; wait for port ready
|
||
test al, 1 ; ready?
|
||
jnz kbiAvailable
|
||
loop kbiwait
|
||
|
||
dec bx ; decrement outer timeout loop.
|
||
jnz inner_timeout ; zero out inner loop again.
|
||
stc
|
||
jmp short no_byte
|
||
|
||
kbiAvailable: ; we received a byte.
|
||
mov cx,100
|
||
|
||
;
|
||
; We need to let some time elapse before we try to read the data
|
||
; because of a problem running this code in the DOS box under
|
||
; OS/2.
|
||
;
|
||
|
||
wait_for_data:
|
||
loop wait_for_data
|
||
|
||
in al, kb_data ; get data byte.
|
||
clc
|
||
|
||
no_byte:
|
||
sti
|
||
pop bx
|
||
pop cx
|
||
ret
|
||
|
||
ReadKeyboard endp
|
||
|
||
|
||
;++
|
||
;
|
||
; UCHAR
|
||
; Write8042 (
|
||
; USHORT Port,
|
||
; UCHAR Command
|
||
; )
|
||
;
|
||
; Routine Description:
|
||
;
|
||
; This routine writes command byte to keyboard.
|
||
;
|
||
; It is assumed that a command (05H or 0F2H) has been set to request
|
||
; that the keyboard send an identification byte.
|
||
; It is also assumed that interrupts are disabled.
|
||
;
|
||
; Arguments:
|
||
;
|
||
; Port (dx) - Port to write data to
|
||
; Command (ah) - to be written to keyboard.
|
||
;
|
||
; Return Value:
|
||
;
|
||
; None.
|
||
;
|
||
;--
|
||
public Write8042
|
||
Write8042 proc near
|
||
|
||
push cx
|
||
push bx
|
||
mov bx, 4 ; set outer timeout for double nested.
|
||
cli
|
||
|
||
reset_inner:
|
||
xor cx, cx ; set inner timeout for double dested.
|
||
|
||
koutwait:
|
||
in al, kb_status ; get 8042 status
|
||
test al, 10b ; can we output a byte?
|
||
jz ok_to_send
|
||
loop koutwait
|
||
|
||
dec bx ; decrement outer timeout loop.
|
||
jnz reset_inner ; zero out inner loop again.
|
||
jmp short nosiree ; timeout expired, don't try to send.
|
||
|
||
ok_to_send:
|
||
call _Empty8042
|
||
mov al, ah ; ok, send the byte
|
||
out dx, al
|
||
|
||
nosiree:
|
||
sti
|
||
pop bx
|
||
pop cx
|
||
ret
|
||
|
||
Write8042 endp
|
||
|
||
;++
|
||
;
|
||
; UCHAR
|
||
; GetKeyboardFlags (
|
||
; VOID
|
||
; )
|
||
;
|
||
; Routine Description:
|
||
;
|
||
; This routine returns the ROM BIOS flags byte that describes the state
|
||
; of the various keyboard toggles and shift keys.
|
||
;
|
||
; Arguments:
|
||
;
|
||
; None.
|
||
;
|
||
; Return Value:
|
||
;
|
||
; Keyboard ROM BIOS Flags byte.
|
||
;
|
||
;--
|
||
|
||
public _GetKeyboardFlags
|
||
_GetKeyboardFlags proc near
|
||
|
||
mov ah, 02
|
||
int 16h
|
||
ret
|
||
|
||
_GetKeyboardFlags endp
|
||
|
||
|
||
;++
|
||
;
|
||
; VOID
|
||
; EnableKeyboard (
|
||
; VOID
|
||
; )
|
||
;
|
||
; Routine Description:
|
||
;
|
||
; This routine enables 8042 keyboard interface.
|
||
;
|
||
; Arguments:
|
||
;
|
||
; None.
|
||
;
|
||
; Return Value:
|
||
;
|
||
; None.
|
||
;
|
||
;--
|
||
|
||
public EnableKeyboard
|
||
EnableKeyboard proc near
|
||
|
||
mov ah, ENABLE_KEYBOARD_COMMAND
|
||
mov dx, kb_command
|
||
call Write8042
|
||
ret
|
||
|
||
EnableKeyboard endp
|
||
|
||
;++
|
||
;
|
||
; VOID
|
||
; DisableKeyboard (
|
||
; VOID
|
||
; )
|
||
;
|
||
; Routine Description:
|
||
;
|
||
; This routine disables 8042 keyboard interface.
|
||
;
|
||
; Arguments:
|
||
;
|
||
; None.
|
||
;
|
||
; Return Value:
|
||
;
|
||
; None.
|
||
;
|
||
;--
|
||
|
||
public DisableKeyboard
|
||
DisableKeyboard proc near
|
||
|
||
mov ah, DISABLE_KEYBOARD_COMMAND
|
||
mov dx, kb_command
|
||
call Write8042
|
||
ret
|
||
|
||
DisableKeyboard endp
|
||
|
||
;++
|
||
;
|
||
; VOID
|
||
; Empty8042 (
|
||
; VOID
|
||
; )
|
||
;
|
||
; Routine Description:
|
||
;
|
||
; This routine drains the i8042 controller's output buffer. This gets
|
||
; rid of stale data that may have resulted from the user hitting a key
|
||
; or moving the mouse, prior to the execution of keyboard initialization.
|
||
;
|
||
; Arguments:
|
||
;
|
||
; None.
|
||
;
|
||
; Return Value:
|
||
;
|
||
; None.
|
||
;
|
||
;--
|
||
|
||
public _Empty8042
|
||
_Empty8042 proc near
|
||
|
||
push ax
|
||
push dx
|
||
pushf
|
||
cli
|
||
E8Check:
|
||
in al, kb_status ; wait for port ready
|
||
test al, 1 ; ready?
|
||
jz E8Exit
|
||
|
||
mov dx, kb_data
|
||
push dx
|
||
call _READ_PORT_UCHAR ; use this call to delay I/O
|
||
add sp, 2
|
||
jmp E8Check
|
||
E8Exit:
|
||
popf
|
||
pop dx
|
||
pop ax
|
||
ret
|
||
|
||
_Empty8042 endp
|
||
|
||
_TEXT ends
|
||
|
||
END
|