keyboard.c

来自「linux 内核源代码」· C语言 代码 · 共 1,426 行 · 第 1/3 页

C
1,426
字号
			committing = pressed;	}}/* * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, * or (ii) whatever pattern of lights people want to show using KDSETLED, * or (iii) specified bits of specified words in kernel memory. */unsigned char getledstate(void){	return ledstate;}void setledstate(struct kbd_struct *kbd, unsigned int led){	if (!(led & ~7)) {		ledioctl = led;		kbd->ledmode = LED_SHOW_IOCTL;	} else		kbd->ledmode = LED_SHOW_FLAGS;	set_leds();}static inline unsigned char getleds(void){	struct kbd_struct *kbd = kbd_table + fg_console;	unsigned char leds;	int i;	if (kbd->ledmode == LED_SHOW_IOCTL)		return ledioctl;	leds = kbd->ledflagstate;	if (kbd->ledmode == LED_SHOW_MEM) {		for (i = 0; i < 3; i++)			if (ledptrs[i].valid) {				if (*ledptrs[i].addr & ledptrs[i].mask)					leds |= (1 << i);				else					leds &= ~(1 << i);			}	}	return leds;}/* * This routine is the bottom half of the keyboard interrupt * routine, and runs with all interrupts enabled. It does * console changing, led setting and copy_to_cooked, which can * take a reasonably long time. * * Aside from timing (which isn't really that important for * keyboard interrupts as they happen often), using the software * interrupt routines for this thing allows us to easily mask * this when we don't want any of the above to happen. * This allows for easy and efficient race-condition prevention * for kbd_start => input_inject_event(dev, EV_LED, ...) => ... */static void kbd_bh(unsigned long dummy){	struct list_head *node;	unsigned char leds = getleds();	if (leds != ledstate) {		list_for_each(node, &kbd_handler.h_list) {			struct input_handle *handle = to_handle_h(node);			input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));			input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));			input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));			input_inject_event(handle, EV_SYN, SYN_REPORT, 0);		}	}	ledstate = leds;}DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\    defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\    defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC))#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\			((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))static const unsigned short x86_keycodes[256] =	{ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,	 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,	 80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,	284,285,309,  0,312, 91,327,328,329,331,333,335,336,337,338,339,	367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,	360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,	103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361,	291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114,	264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116,	377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307,	308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,	332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };#ifdef CONFIG_SPARCstatic int sparc_l1_a_state = 0;extern void sun_do_break(void);#endifstatic int emulate_raw(struct vc_data *vc, unsigned int keycode,		       unsigned char up_flag){	int code;	switch (keycode) {		case KEY_PAUSE:			put_queue(vc, 0xe1);			put_queue(vc, 0x1d | up_flag);			put_queue(vc, 0x45 | up_flag);			break;		case KEY_HANGEUL:			if (!up_flag)				put_queue(vc, 0xf2);			break;		case KEY_HANJA:			if (!up_flag)				put_queue(vc, 0xf1);			break;		case KEY_SYSRQ:			/*			 * Real AT keyboards (that's what we're trying			 * to emulate here emit 0xe0 0x2a 0xe0 0x37 when			 * pressing PrtSc/SysRq alone, but simply 0x54			 * when pressing Alt+PrtSc/SysRq.			 */			if (sysrq_alt) {				put_queue(vc, 0x54 | up_flag);			} else {				put_queue(vc, 0xe0);				put_queue(vc, 0x2a | up_flag);				put_queue(vc, 0xe0);				put_queue(vc, 0x37 | up_flag);			}			break;		default:			if (keycode > 255)				return -1;			code = x86_keycodes[keycode];			if (!code)				return -1;			if (code & 0x100)				put_queue(vc, 0xe0);			put_queue(vc, (code & 0x7f) | up_flag);			break;	}	return 0;}#else#define HW_RAW(dev)	0#warning "Cannot generate rawmode keyboard for your architecture yet."static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag){	if (keycode > 127)		return -1;	put_queue(vc, keycode | up_flag);	return 0;}#endifstatic void kbd_rawcode(unsigned char data){	struct vc_data *vc = vc_cons[fg_console].d;	kbd = kbd_table + fg_console;	if (kbd->kbdmode == VC_RAW)		put_queue(vc, data);}static void kbd_keycode(unsigned int keycode, int down, int hw_raw){	struct vc_data *vc = vc_cons[fg_console].d;	unsigned short keysym, *key_map;	unsigned char type, raw_mode;	struct tty_struct *tty;	int shift_final;	struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };	tty = vc->vc_tty;	if (tty && (!tty->driver_data)) {		/* No driver data? Strange. Okay we fix it then. */		tty->driver_data = vc;	}	kbd = kbd_table + fg_console;	if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)		sysrq_alt = down ? keycode : 0;#ifdef CONFIG_SPARC	if (keycode == KEY_STOP)		sparc_l1_a_state = down;#endif	rep = (down == 2);#ifdef CONFIG_MAC_EMUMOUSEBTN	if (mac_hid_mouse_emulate_buttons(1, keycode, down))		return;#endif /* CONFIG_MAC_EMUMOUSEBTN */	if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)		if (emulate_raw(vc, keycode, !down << 7))			if (keycode < BTN_MISC && printk_ratelimit())				printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);#ifdef CONFIG_MAGIC_SYSRQ	       /* Handle the SysRq Hack */	if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) {		if (!sysrq_down) {			sysrq_down = down;			sysrq_alt_use = sysrq_alt;		}		return;	}	if (sysrq_down && !down && keycode == sysrq_alt_use)		sysrq_down = 0;	if (sysrq_down && down && !rep) {		handle_sysrq(kbd_sysrq_xlate[keycode], tty);		return;	}#endif#ifdef CONFIG_SPARC	if (keycode == KEY_A && sparc_l1_a_state) {		sparc_l1_a_state = 0;		sun_do_break();	}#endif	if (kbd->kbdmode == VC_MEDIUMRAW) {		/*		 * This is extended medium raw mode, with keys above 127		 * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing		 * the 'up' flag if needed. 0 is reserved, so this shouldn't		 * interfere with anything else. The two bytes after 0 will		 * always have the up flag set not to interfere with older		 * applications. This allows for 16384 different keycodes,		 * which should be enough.		 */		if (keycode < 128) {			put_queue(vc, keycode | (!down << 7));		} else {			put_queue(vc, !down << 7);			put_queue(vc, (keycode >> 7) | 0x80);			put_queue(vc, keycode | 0x80);		}		raw_mode = 1;	}	if (down)		set_bit(keycode, key_down);	else		clear_bit(keycode, key_down);	if (rep &&	    (!vc_kbd_mode(kbd, VC_REPEAT) ||	     (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) {		/*		 * Don't repeat a key if the input buffers are not empty and the		 * characters get aren't echoed locally. This makes key repeat		 * usable with slow applications and under heavy loads.		 */		return;	}	param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;	key_map = key_maps[shift_final];	if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYCODE, &param) == NOTIFY_STOP || !key_map) {		atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNBOUND_KEYCODE, &param);		compute_shiftstate();		kbd->slockstate = 0;		return;	}	if (keycode > NR_KEYS)		if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)			keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1);		else			return;	else		keysym = key_map[keycode];	type = KTYP(keysym);	if (type < 0xf0) {		param.value = keysym;		if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNICODE, &param) == NOTIFY_STOP)			return;		if (down && !raw_mode)			to_utf8(vc, keysym);		return;	}	type -= 0xf0;	if (type == KT_LETTER) {		type = KT_LATIN;		if (vc_kbd_led(kbd, VC_CAPSLOCK)) {			key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];			if (key_map)				keysym = key_map[keycode];		}	}	param.value = keysym;	if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYSYM, &param) == NOTIFY_STOP)		return;	if (raw_mode && type != KT_SPEC && type != KT_SHIFT)		return;	(*k_handler[type])(vc, keysym & 0xff, !down);	atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);	if (type != KT_SLOCK)		kbd->slockstate = 0;}static void kbd_event(struct input_handle *handle, unsigned int event_type,		      unsigned int event_code, int value){	if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))		kbd_rawcode(value);	if (event_type == EV_KEY)		kbd_keycode(event_code, value, HW_RAW(handle->dev));	tasklet_schedule(&keyboard_tasklet);	do_poke_blanked_console = 1;	schedule_console_callback();}/* * When a keyboard (or other input device) is found, the kbd_connect * function is called. The function then looks at the device, and if it * likes it, it can open it and get events from it. In this (kbd_connect) * function, we should decide which VT to bind that keyboard to initially. */static int kbd_connect(struct input_handler *handler, struct input_dev *dev,			const struct input_device_id *id){	struct input_handle *handle;	int error;	int i;	for (i = KEY_RESERVED; i < BTN_MISC; i++)		if (test_bit(i, dev->keybit))			break;	if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))		return -ENODEV;	handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);	if (!handle)		return -ENOMEM;	handle->dev = dev;	handle->handler = handler;	handle->name = "kbd";	error = input_register_handle(handle);	if (error)		goto err_free_handle;	error = input_open_device(handle);	if (error)		goto err_unregister_handle;	return 0; err_unregister_handle:	input_unregister_handle(handle); err_free_handle:	kfree(handle);	return error;}static void kbd_disconnect(struct input_handle *handle){	input_close_device(handle);	input_unregister_handle(handle);	kfree(handle);}/* * Start keyboard handler on the new keyboard by refreshing LED state to * match the rest of the system. */static void kbd_start(struct input_handle *handle){	unsigned char leds = ledstate;	tasklet_disable(&keyboard_tasklet);	if (leds != 0xff) {		input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));		input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));		input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));		input_inject_event(handle, EV_SYN, SYN_REPORT, 0);	}	tasklet_enable(&keyboard_tasklet);}static const struct input_device_id kbd_ids[] = {	{                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,                .evbit = { BIT_MASK(EV_KEY) },        },	{                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,                .evbit = { BIT_MASK(EV_SND) },        },	{ },    /* Terminating entry */};MODULE_DEVICE_TABLE(input, kbd_ids);static struct input_handler kbd_handler = {	.event		= kbd_event,	.connect	= kbd_connect,	.disconnect	= kbd_disconnect,	.start		= kbd_start,	.name		= "kbd",	.id_table	= kbd_ids,};int __init kbd_init(void){	int i;	int error;        for (i = 0; i < MAX_NR_CONSOLES; i++) {		kbd_table[i].ledflagstate = KBD_DEFLEDS;		kbd_table[i].default_ledflagstate = KBD_DEFLEDS;		kbd_table[i].ledmode = LED_SHOW_FLAGS;		kbd_table[i].lockstate = KBD_DEFLOCK;		kbd_table[i].slockstate = 0;		kbd_table[i].modeflags = KBD_DEFMODE;		kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;	}	error = input_register_handler(&kbd_handler);	if (error)		return error;	tasklet_enable(&keyboard_tasklet);	tasklet_schedule(&keyboard_tasklet);	return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?