The Linux keyboard driver

Our Kernel Korner series continues with an article describing the linux Keyboard driver. This artilce is not for “Kernel Hackers” only—in fact, it will be most useful to those who wish to use their own keyboard to its fullest potential, and those who want to write programs to take advantage of the many features in the Linux keyboard driver.

When you press a key on the console keyboard, the corresponding character is not simply added to the tty (generic terminal handling) input buffers as if it had come in over a serial port. A lot of processing is required before the kernel knows what the correct characters are. Only after processing can the generic tty code, which handles all interactive terminal devices, take over.

Roughly speaking, the picture is this: the keyboard produces scancodes, the scancodes are assembled into keycodes (one unique code for each key), and keycodes are converted to tty input characters using the kernel keymaps. After that, the normal `stty' processing takes place, just as for any other terminal.

Scancodes First

The usual PC keyboards are capable of producing three sets of scancodes. Writing 0xf0 followed by 1, 2 or 3 to port 0x60 will put the keyboard in scancode mode 1, 2 or 3. Writing 0xf0 followed by 0 queries the mode, resulting in a scancode byte 0x43, 0x41 or 0x3f from the keyboard. (Don't try this at home, kids. If you are not very careful, you will end up in a situation where rebooting is the only way out—and control-alt-delete will not be available to shut the computer down correctly. See the accompanying listing of kbd_cmd.c for details.)

Scancode mode 2 is the default. In this mode, a key press usually produces a value s in the range 0x01-0x5f and the corresponding key release produces s+0x80. In scancode mode 3, the only key releases that produce a scan code are of both Shift keys, and the left Ctrl and Alt keys; for all other keys only the key presses are noted. The produced scancodes are mostly equal to those for scancode mode 2.

In scancode mode 1 most key releases produce the same values as in scancode mode 2, but for key presses there are entirely different, unrelated values. The details are somewhat messy.

A program can request the raw scancodes by


ioctl(0, KDSKBMODE, K_RAW);

For example, X, dosemu, svgadoom, and showkey -s do this. The default keycode translation mode is restored by


ioctl(0, KDSKBMODE, K_XLATE);

See the keyboard FAQ (in kbd-0.90.tar.gz) for some advice about how to get out of raw scancode mode from the shell prompt. (At a shell prompt the commands kbd_mode [-s|-k|-a|-u] will set the keyboard mode to scancode mode, keycode mode, translation (`ASCII') mode and Unicode mode, respectively. But it is difficult to type this command when the keyboard is in raw scancode mode.)

Scancodes to Keycodes

Life would have been easy had there been a 1-1 correspondence between keys and scancodes. (And in fact there is, in scancode mode 3, but that does not suffice for Linux, since X requires both the key press and the key release events.)

But as it is, a single key press can produce a sequence of up to six scancodes, and the kernel has to parse the stream of scancodes and convert it into a series of key press and key release events. To this end, each key is provided with a unique keycode k in the range 1-127, and pressing key k produces keycode k, while releasing it produces keycode k+128. The assignment of key codes is in principle arbitrary (and has no relation to the key codes used by X), but at present the key code equals the scan code for those keys that produce a single scancode in the range 0x01-0x58.

The parsing works by

  • recognizing the special sequence 0xe1 0x1d 0x45 0xe1 0x9d 0xc5 produced by the Pause key

  • throwing out any fake Shift-down and Shift-up codes, inserted by the keyboard to make the kernel believe that you pressed Shift to undo the effect of NumLock

  • recognizing scancode pairs 0xe0 s

  • recognizing single scancodes s.

Since s can take 127 values (0 is a keyboard error condition, and the high order bit indicates press/release) this means that parsing could result in 1+127+126=254 distinct keycodes. However, at present keycodes are restricted to the range 1-127 and we have to work a little to make things fit. (No doubt sooner or later keycodes will be integers instead of 7-bit quantities, and the keymaps will be sparse, but for the time being we can avoid that—since to my knowledge no actual PC keyboard has more than 127 keys.) So, there are small tables that assign a keycode to a scancode pair 0xe0 s or to a single scancode in the range 0x59-0x7f. In the default setting everything works for most current keyboards, but in case you have some strange keyboard, you can get the kernel to recognize an otherwise unrecognized key by filling an entry in these tables using the KDSETKEYCODE ioctl; see setkeycodes(8).

Two keys are unusual in the sense that their keycode is not constant, but depends on modifiers. The PrintScrn key will yield keycode 84 when combined with either Alt key, but keycode 99 otherwise. The Pause key will yield keycode 101 when combined with either Ctrl key, but keycode 119 otherwise. (This has historic reasons, but might change, to free keycodes 99 and 119 for other purposes.)

At present there is no way to tell X about strange key(board)s. The easiest solution would be to make X use keycodes instead of scancodes, so that the information about strange keys and the scancodes they produce is located a single place.

A program can request to get keycodes by doing


ioctl(0, KDSKBMODE,
K_MEDIUMRAW);

For example, showkey does this. Warning: the details of the function of both the KDSETKEYCODE ioctl and the K_MEDIUMRAW keyboard mode are likely to change in the future.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

how to test power and ptt keys??

lakshmi's picture

Hai i want to test power and ptt keys. I am using evtest to test my keys on the keypad. But my driver wont generate any interrupt for power and ptt keys so how to test these keys??

general awareness

Anonymous's picture

general awareness

Getting keyboard scancodes

email's picture

The article is confused.
Please write a simple non-blocking function.

This can be the prototype:

bool keypressed( int& scancode );

bye
miro

linux keypad driver

Anonymous's picture

the scancode related information are good

Re : Kernel Korner: The Linux keyboard driver

Anonymous's picture

Good One !! But really missing the source code as example.

Re: Kernel Korner: The Linux keyboard driver

Anonymous's picture

It's better to explain with a practical keyboard source code.

Re: Kernel Korner: The Linux keyboard driver

Anonymous's picture

can u pls send the c code for keyboard device driver

need c code of keyboard driver

G Abbas's picture

i will be greatful if someone help me. i need c code fo generic keyboard driver.

Can you please send me

Anonymous's picture

Can you please send me source code of a generic keyboard driver?

Need it for Windows/Dos environment

Anonymous's picture

Hi

I need to access certain keys on a Pentuim PC keyboard using ISO. But ISO just specifies the H and no C files and it only gives you the CRT device not the keyboard-subdevice of the CRT.

So I've decided to do a search for keyboard-drivers. And now I want the complete c code for a keyboard driver, please?

Re: Kernel Korner: The Linux keyboard driver

Anonymous's picture

not a practical example... too confuse

Yes you are right

Kenson Goo's picture

Linux needs to simplify everything so that our grandparents can use the system easily. I bet my grandparents would prefer Microsoft keyboard like http://www.compkeyboard.com/archives/microsoft-natural-ergonomic-keyboar...

than a Linux system with 4 pages of tutorial on keyboard

Dude, your an idiot. Your

Anonymous's picture

Dude, your an idiot. Your grandparents are very unlikely to be writing keyboard drivers for Linux or Windows.

Grandparents

Anonymous's picture

Oh, yeah? Well, my grandparents are awesome like that: 'Cept they write drivers for *nix only!

key state

Anonymous's picture

getchar() is a blocking call and when you press a button the corresponding character is output to the terminal. Would if all I wanted was the state of any given key at any given time? Doing this on PS2 Linux is quite easy with the js0 device for composing a bit-feild containing the state of each controller button this frame. Is their a non-blocking, non-printing way to obtain the key state of any given key?

Source code for keyboard.c in on your computer

Tim Crawford's picture

If you install the kernel source code you can find the source
code in /usr/src/linux/drivers/char/keyboard.c

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix