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