keyboard.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,264 行 · 第 1/3 页
C
1,264 行
/* * 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. * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik) */#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/random.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/kbd_kern.h>#include <linux/kbd_diacr.h>#include <linux/vt_kern.h>#include <linux/sysrq.h>#include <linux/input.h>static void kbd_disconnect(struct input_handle *handle);extern void ctrl_alt_del(void);/* * Exported functions/variables */#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))/* * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. * This seems a good reason to start with NumLock off. On HIL keyboards * of PARISC machines however there is no NumLock key and everyone expects the keypad * to be used for numbers. */#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))#define KBD_DEFLEDS (1 << VC_NUMLOCK)#else#define KBD_DEFLEDS 0#endif#define KBD_DEFLOCK 0void compute_shiftstate(void);/* * Handler Tables. */#define K_HANDLERS\ k_self, k_fn, k_spec, k_pad,\ k_dead, k_cons, k_cur, k_shift,\ k_meta, k_ascii, k_lock, k_lowercase,\ k_slock, k_dead2, k_ignore, k_ignoretypedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs);static k_handler_fn K_HANDLERS;static k_handler_fn *k_handler[16] = { K_HANDLERS };#define FN_HANDLERS\ fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_numtypedef void (fn_handler_fn)(struct vc_data *vc, struct pt_regs *regs);static fn_handler_fn FN_HANDLERS;static fn_handler_fn *fn_handler[] = { FN_HANDLERS };/* * Variables exported for vt_ioctl.c *//* maximum values each key_handler can handle */const int max_vals[] = { 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 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 = ARRAY_SIZE(max_vals);struct kbd_struct kbd_table[MAX_NR_CONSOLES];static struct kbd_struct *kbd = kbd_table;static struct kbd_struct kbd0;int spawnpid, spawnsig;/* * Variables exported for vt.c */int shift_state = 0;/* * Internal Data. */static struct input_handler kbd_handler;static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */static int dead_key_next;static int npadch = -1; /* -1 or number assembled on pad */static unsigned char diacr;static char rep; /* flag telling character repeat */static unsigned char ledstate = 0xff; /* undefined */static unsigned char ledioctl;static struct ledptr { unsigned int *addr; unsigned int mask; unsigned char valid:1;} ledptrs[3];/* Simple translation table for the SysRq keys */#ifdef CONFIG_MAGIC_SYSRQunsigned char kbd_sysrq_xlate[KEY_MAX] = "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ "\r\000/"; /* 0x60 - 0x6f */static int sysrq_down;#endifstatic int sysrq_alt;/* * Translation of scancodes to keycodes. We set them on only the first attached * keyboard - for per-keyboard setting, /dev/input/event is more useful. */int getkeycode(unsigned int scancode){ struct list_head * node; struct input_dev *dev = NULL; list_for_each(node,&kbd_handler.h_list) { struct input_handle * handle = to_handle_h(node); if (handle->dev->keycodesize) { dev = handle->dev; break; } } if (!dev) return -ENODEV; if (scancode < 0 || scancode >= dev->keycodemax) return -EINVAL; return INPUT_KEYCODE(dev, scancode);}int setkeycode(unsigned int scancode, unsigned int keycode){ struct list_head * node; struct input_dev *dev = NULL; int i, oldkey; list_for_each(node,&kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); if (handle->dev->keycodesize) { dev = handle->dev; break; } } if (!dev) return -ENODEV; if (scancode < 0 || scancode >= dev->keycodemax) return -EINVAL; oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode); clear_bit(oldkey, dev->keybit); set_bit(keycode, dev->keybit); for (i = 0; i < dev->keycodemax; i++) if (INPUT_KEYCODE(dev,i) == oldkey) set_bit(oldkey, dev->keybit); return 0;}/* * Making beeps and bells. */static void kd_nosound(unsigned long ignored){ struct list_head * node; list_for_each(node,&kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) input_event(handle->dev, EV_SND, SND_TONE, 0); if (test_bit(SND_BELL, handle->dev->sndbit)) input_event(handle->dev, EV_SND, SND_BELL, 0); } }}static struct timer_list kd_mksound_timer = TIMER_INITIALIZER(kd_nosound, 0, 0);void kd_mksound(unsigned int hz, unsigned int ticks){ struct list_head * node; del_timer(&kd_mksound_timer); if (hz) { list_for_each_prev(node,&kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) { input_event(handle->dev, EV_SND, SND_TONE, hz); break; } if (test_bit(SND_BELL, handle->dev->sndbit)) { input_event(handle->dev, EV_SND, SND_BELL, 1); break; } } } if (ticks) mod_timer(&kd_mksound_timer, jiffies + ticks); } else kd_nosound(0);}/* * Setting the keyboard rate. */int kbd_rate(struct kbd_repeat *rep){ struct list_head *node; unsigned int d = 0; unsigned int p = 0; list_for_each(node,&kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); struct input_dev *dev = handle->dev; if (test_bit(EV_REP, dev->evbit)) { if (rep->delay > 0) input_event(dev, EV_REP, REP_DELAY, rep->delay); if (rep->period > 0) input_event(dev, EV_REP, REP_PERIOD, rep->period); d = dev->rep[REP_DELAY]; p = dev->rep[REP_PERIOD]; } } rep->delay = d; rep->period = p; return 0;}/* * Helper Functions. */static void put_queue(struct vc_data *vc, int ch){ struct tty_struct *tty = vc->vc_tty; if (tty) { tty_insert_flip_char(tty, ch, 0); con_schedule_flip(tty); }}static void puts_queue(struct vc_data *vc, char *cp){ struct tty_struct *tty = vc->vc_tty; if (!tty) return; while (*cp) { tty_insert_flip_char(tty, *cp, 0); cp++; } con_schedule_flip(tty);}static void applkey(struct vc_data *vc, int key, char mode){ static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; buf[1] = (mode ? 'O' : '['); buf[2] = key; puts_queue(vc, buf);}/* * 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. UTF-8 is defined for words of up to 31 bits, * but we need only 16 bits here */void to_utf8(struct vc_data *vc, ushort c) { if (c < 0x80) /* 0******* */ put_queue(vc, c); else if (c < 0x800) { /* 110***** 10****** */ put_queue(vc, 0xc0 | (c >> 6)); put_queue(vc, 0x80 | (c & 0x3f)); } else { /* 1110**** 10****** 10****** */ put_queue(vc, 0xe0 | (c >> 12)); put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); put_queue(vc, 0x80 | (c & 0x3f)); }}/* * Called after returning from RAW mode or when changing consoles - recompute * shift_down[] and shift_state from key_down[] maybe called when keymap is * undefined, so that shiftkey release is seen */void compute_shiftstate(void){ int i, j, k, sym, val; shift_state = 0; memset(shift_down, 0, sizeof(shift_down)); for (i = 0; i < ARRAY_SIZE(key_down); i++) { if (!key_down[i]) continue; k = i * BITS_PER_LONG; for (j = 0; j < BITS_PER_LONG; j++, k++) { if (!test_bit(k, key_down)) continue; sym = U(key_maps[0][k]); if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) continue; val = KVAL(sym); if (val == KVAL(K_CAPSSHIFT)) val = KVAL(K_SHIFT); shift_down[val]++; shift_state |= (1 << val); } }}/* * We have a combining character DIACR here, followed by the character CH. * If the combination occurs in the table, return the corresponding value. * Otherwise, if CH is a space or equals DIACR, return DIACR. * Otherwise, conclude that DIACR was not combining after all, * queue it and return CH. */unsigned char handle_diacr(struct vc_data *vc, unsigned char ch){ int d = diacr; int i; diacr = 0; for (i = 0; i < accent_table_size; i++) { if (accent_table[i].diacr == d && accent_table[i].base == ch) return accent_table[i].result; } if (ch == ' ' || ch == d) return d; put_queue(vc, d); return ch;}/* * Special function handlers */static void fn_enter(struct vc_data *vc, struct pt_regs *regs){ if (diacr) { put_queue(vc, diacr); diacr = 0; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?