OSD Home

Assembly-language keyboard functions using the BIOS

For information on using BIOS keyboard functions, see INT 16h in Ralf Brown's interrupt list: http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html

C-language keyboard functions using the BIOS

Both DJGPP and Turbo C getch() and kbhit() call DOS (not BIOS) interrupts. They will not work for OS code. With both compilers, you may use int86() to access BIOS INT 16h. As with text output, 32-bit code requires a V86 mode monitor (VMM) to call 16-bit BIOS routines.

Keyboard input without the BIOS

The keyboard itself contains an 8048 microprocessor. There is a second microprocessor (an 8042) on the motherboard. The keyboard produces one or more bytes (the make code) when a key is pressed, and zero, one, or more bytes (the break code) when a key is released. An IRQ 1 interrupt is generated for each byte. The keyboard interrupt handler must read the make or break code (collectively called the scan code) from I/O port 60h. Additional IRQ 1 interrupts are inhibited (masked) until you read port 60h.

You may also use polling to read from the keyboard without using interrupts (see code snippets below).

Make and break codes for each key depend on the scancode set:

For exact scancode values, # - see below.

Only scancode set 2 is widely supported and relatively free of bugs. However, the 8042 can be (and usually is) programmed to convert set 2 scancodes from the keyboard to set 1. The 8042 also handles some non-keyboard functions, such as resetting the CPU, controlling the A20 gate, and communicating with a PS/2 mouse.

8042 and 8048 registers and command bytes

Keycaps and scancodes for different keyboard types

104-key US keyboard Set 1 scancodes Set 2 scancodes Set 3 scancodes
105-key British keyboard
(from Tim Robinson and Beth Stone)
Set 1 scancodes Set 2 scancodes Set 3 scancodes
104-key German keyboard
(this is guesswork)
Set 1 scancodes Set 2 scancodes Set 3 scancodes

Keyboard code snippets

Keyboard driver code (DOS; DJGPP or Turbo C or Watcom C)

Polled keyboard input routine (does not use interrupts):

read_kbd:
        in al,64h       ; read status byte
	and al,01h      ; wait for OBF==1
        jz read_kbd
        in al,60h       ; read scancode byte
        ret

Enable A20 gate and verify it's on: see bootstrap code snippets

Turn on all three keyboard LEDs:

                call kbd
		mov al,0EDh     ; 8048 command byte to set LEDs
		out 60h,al
		call kbd
	; b0 is ScrollLock, b1 is NumLock, b2 is CapsLock
		mov al,07h
		out 60h,al

	    ...

	kbd0:   jmp short $+2
		in al,60h
	kbd:    jmp short $+2
		in al,64h
		test al,1
		jnz kbd0
		test al,2
		jnz kbd
		ret				
Reset the PC:
	; Warning: this function may not work unless A20 is enabled
        ; See http://my.execpc.com/~geezer/osd/gotchas/index.htm#a20_reboot
	;
	; set the POST reset word at 0040h:0072h
	; 0000h for cold boot, 1234h to bypass memory test (warm boot)
		mov ax,40h
		mov es,ax
		mov ax,0
		mov [es:72h],ax

        ; bit b0 of the 8042 'Output Port' drives the CPU reset line
	; pulse it low to reset the system
		call kbd	; kbd routine above
		mov al,0FEh	; 8042 command byte to pulse Output Port pin
		out 64h,al			

Links

http://homepages.cwi.nl/~aeb/linux/kbd/scancodes.html
http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/keyboard/atkeyboard.html
http://www.nondot.org/sabre/os/articles/HumanInterfaceDevices/

TO DO

- converting scan codes to ASCII, Unicode, UTF, etc.

REPORT BUGS OR ERRORS IN THIS DOCUMENT