/*
* linux/drivers/char/keyboard.c
*
* Written for linux by Johan Myreen as a translation from
* the assembly version by Linus (with diacriticals added)
*
* Some additional features added by Christoph Niemann (ChN), March 1993
*
* Loadable keymaps by Risto Kankkunen, May 1993
*
* Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
* Added decr/incr_console, dynamic keymaps, Unicode support,
* dynamic function/string keys, led setting, Sept 1994
* `Sticky' modifier keys, 951006.
*
* 11-11-96: SAK should now work in the raw mode (Martin Mares)
*
* Modified to provide 'generic' keyboard support by Hamish Macdonald
* Merge with the m68k keyboard driver and split-off of the PC low-level
* parts by Geert Uytterhoeven, May 1997
*
* 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
* 30-07-98: Dead keys redone, aeb@cwi.nl.
*
* 04-04-1998: Added keyboard autorepeat support (some keyboards don't
* autorepeat, and some keyboard changers interfere with keyboard
* autorepeat settings). - Russell King (rmk@arm.linux.org.uk)
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/random.h>
#include <linux/init.h>
#include <asm/keyboard.h>
#include <asm/bitops.h>
#include <linux/kbd_kern.h>
#include <linux/kbd_diacr.h>
#include <linux/vt_kern.h>
#include <linux/kbd_ll.h>
#include <linux/sysrq.h>
#include <linux/pm.h>
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
#ifndef KBD_DEFMODE
#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
#endif
#ifndef KBD_DEFLEDS
/*
* Some laptops take the 789uiojklm,. keys as number pad when NumLock
* is on. This seems a good reason to start with NumLock off.
*/
#define KBD_DEFLEDS 0
#endif
#ifndef KBD_DEFLOCK
#define KBD_DEFLOCK 0
#endif
/*
* Default autorepeat settings.
* DEFAULT_REPEAT_TIMEOUT is the timeout from the keypress to the first repeat
* DEFAULT_REPEAT_INTERVAL is the timeout between successive repeats
*/
#define DEFAULT_REPEAT_TIMEOUT HZ*300/1000
#define DEFAULT_REPEAT_INTERVAL HZ*30/1000
void (*kbd_ledfunc)(unsigned int led);
EXPORT_SYMBOL(handle_scancode);
EXPORT_SYMBOL(kbd_ledfunc);
extern void ctrl_alt_del(void);
DECLARE_WAIT_QUEUE_HEAD(keypress_wait);
struct console;
int keyboard_wait_for_keypress(struct console *co)
{
sleep_on(&keypress_wait);
return 0;
}
/*
* global state includes the following, and various static variables
* in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
* (last_console is now a global variable)
*/
/* shift state counters.. */
static unsigned char k_down[NR_SHIFT];
/* keyboard key bitmap */
static unsigned long key_down[256/BITS_PER_LONG];
static int dead_key_next;
/*
* In order to retrieve the shift_state (for the mouse server), either
* the variable must be global, or a new procedure must be created to
* return the value. I chose the former way.
*/
int shift_state;
static int npadch = -1; /* -1 or number assembled on pad */
static unsigned char diacr;
static char rep; /* flag telling character repeat */
static int kbd_repeatkeycode= -1;
static int kbd_repeattimeout = DEFAULT_REPEAT_TIMEOUT;
static int kbd_repeatinterval= DEFAULT_REPEAT_INTERVAL;
struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct tty_struct **ttytab;
static struct kbd_struct * kbd = kbd_table;
static struct tty_struct * tty;
static void kbd_processkeycode(unsigned char scancode, char up_flag, int autorepeat);
void compute_shiftstate(void);
typedef void (*k_hand)(unsigned char value, char up_flag);
typedef void (k_handfn)(unsigned char value, char up_flag);
static k_handfn
do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2,
do_ignore;
static k_hand key_handler[16] = {
do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2,
do_ignore, do_ignore
};
/* Key types processed even in raw modes */
#define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT))
typedef void (*void_fnp)(void);
typedef void (void_fn)(void);
static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
SAK, decr_console, incr_console, spawn_console, bare_num;
static void_fnp spec_fn_table[] = {
do_null, enter, show_ptregs, show_mem,
show_state, send_intr, lastcons, caps_toggle,
num, hold, scroll_forw, scroll_back,
boot_it, caps_on, compose, SAK,
decr_console, incr_console, spawn_console, bare_num
};
#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK))
/* maximum values each key_handler can handle */
const int max_vals[] = {
255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
255, NR_ASCII - 1, NR_LOCK - 1, 255,
NR_LOCK - 1, 255
};
const int NR_TYPES = SIZE(max_vals);
/* N.B. drivers/macintosh/mac_keyb.c needs to call put_queue */
void put_queue(int);
static unsigned char handle_diacr(unsigned char);
/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
struct pt_regs * kbd_pt_regs;
#ifdef CONFIG_MAGIC_SYSRQ
static int sysrq_pressed;
#endif
static struct pm_dev *pm_kbd;
/*
* Many other routines do put_queue, but I think either
* they produce ASCII, or they produce some user-assigned
* string, and in both cases we might assume that it is
* in utf-8 already.
*/
void to_utf8(ushort c)
{
if (c < 0x80)
put_queue(c); /* 0******* */
else if (c < 0x800) {
put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */
put_queue(0x80 | (c & 0x3f));
} else {
put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */
put_queue(0x80 | ((c >> 6) & 0x3f));
put_queue(0x80 | (c & 0x3f));
}
/* UTF-8 is defined for words of up to 31 bits,
but we need only 16 bits here */
}
/*
* Translation of escaped scancodes to keycodes.
* This is now user-settable (for machines were it makes sense).
*/
int setkeycode(unsigned int scancode, unsigned int keycode)
{
return kbd_setkeycode(scancode, keycode);
}
int getkeycode(unsigned int scancode)
{
return kbd_getkeycode(scancode);
}
static void key_callback(unsigned long nr);
static struct timer_list key_autorepeat_timer =
{
function: key_callback
};
void handle_scancode(unsigned char scancode, int down)
{
unsigned char keycode;
char up_flag = down ? 0 : 0200;
char raw_mode;
pm_access(pm_kbd);
add_keyboard_randomness(scancode | up_flag);
tty = ttytab? ttytab[fg_console]: NULL;
if (tty && (!tty->driver_data)) {
/*
* We touch the tty structure via the ttytab array
* without knowing whether or not tty is open, which
* is inherently dangerous. We currently rely on that
* fact that console_open sets tty->driver_data when
* it opens it, and clears it when it closes it.
*/
tty = NULL;
}
kbd = kbd_table + fg_console;
if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
put_queue(scancode | up_flag);
/* we do not return yet, because we want to maintain
the key_down array, so that we have the correct
values when finishing RAW mode or when changing VT's */
}
/*
* Convert scancode to keycode
*/
if (!kbd_translate(scancode, &keycode, raw_mode))
goto out;
/*
* At this point the variable `keycode' contains the keycode.
* Note: the keycode must not be 0 (++Geert: on m68k 0 is valid).
* We keep track of the up/down status of the key, and
* return the keycode if in MEDIUMRAW mode.
*/
kbd_processkeycode(keycode, up_flag, 0);
out:
#ifdef CONFIG_CONSOLE_PM // bushi
do_poke_blanked_console = 1;
#endif
schedule_console_callback();
}
static void
kbd_processkeycode(unsigned char keycode, char up_flag, int autorepeat)
{
char raw_mode = (kbd->kbdmode == VC_RAW);
if (up_flag) {
rep = 0;
if(!test_and_clear_bit(k