|
|
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
|