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 + -
显示快捷键?