keyboard.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,264 行 · 第 1/3 页

C
1,264
字号
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();}void register_leds(struct kbd_struct *kbd, unsigned int led,		   unsigned int *addr, unsigned int mask){	if (led < 3) {		ledptrs[led].addr = addr;		ledptrs[led].mask = mask;		ledptrs[led].valid = 1;		kbd->ledmode = LED_SHOW_MEM;	} else		kbd->ledmode = LED_SHOW_FLAGS;}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_refresh_leds => input_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_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01));			input_event(handle->dev, EV_LED, LED_NUML,    !!(leds & 0x02));			input_event(handle->dev, EV_LED, LED_CAPSL,   !!(leds & 0x04));			input_sync(handle->dev);		}	}	ledstate = leds;}DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);/* * This allows a newly plugged keyboard to pick the LED state. */void kbd_refresh_leds(struct input_handle *handle){	unsigned char leds = ledstate;	tasklet_disable(&keyboard_tasklet);	if (leds != 0xff) {		input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01));		input_event(handle->dev, EV_LED, LED_NUML,    !!(leds & 0x02));		input_event(handle->dev, EV_LED, LED_CAPSL,   !!(leds & 0x04));		input_sync(handle->dev);	}	tasklet_enable(&keyboard_tasklet);}#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SUPERH)#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 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,298,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,306,106,274,107,294,364,358,363,362,361,	291,108,381,281,290,272,292,305,280, 99,112,257,258,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_MAC_EMUMOUSEBTNextern int mac_hid_mouse_emulate_buttons(int, int, int);#endif /* CONFIG_MAC_EMUMOUSEBTN */#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64)static 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){	if (keycode > 255 || !x86_keycodes[keycode])		return -1; 	switch (keycode) {		case KEY_PAUSE:			put_queue(vc, 0xe1);			put_queue(vc, 0x1d | up_flag);			put_queue(vc, 0x45 | up_flag);			return 0;		case KEY_HANGUEL:			if (!up_flag) put_queue(vc, 0xf1);			return 0;		case KEY_HANJA:			if (!up_flag) put_queue(vc, 0xf2);			return 0;	} 	if (keycode == KEY_SYSRQ && sysrq_alt) {		put_queue(vc, 0x54 | up_flag);		return 0;	}	if (x86_keycodes[keycode] & 0x100)		put_queue(vc, 0xe0);	put_queue(vc, (x86_keycodes[keycode] & 0x7f) | up_flag);	if (keycode == KEY_SYSRQ) {		put_queue(vc, 0xe0);		put_queue(vc, 0x37 | up_flag);	}	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;}#endifvoid 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);}void kbd_keycode(unsigned int keycode, int down, int hw_raw, struct pt_regs *regs){	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;	if (down != 2)		add_keyboard_randomness((keycode << 1) ^ 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;#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64)	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(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))) {		sysrq_down = down;		return;	}	if (sysrq_down && down && !rep) {		handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);		return;	}#endif#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64)	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;	}	shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;	key_map = key_maps[shift_final];	if (!key_map) {		compute_shiftstate();		kbd->slockstate = 0;		return;	}	if (keycode > NR_KEYS)		return;	keysym = key_map[keycode];	type = KTYP(keysym);	if (type < 0xf0) {		if (down && !raw_mode) to_utf8(vc, keysym);		return;	}	type -= 0xf0;	if (raw_mode && type != KT_SPEC && type != KT_SHIFT)		return;	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];		}	}	(*k_handler[type])(vc, keysym & 0xff, !down, regs);	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), handle->dev->regs);	tasklet_schedule(&keyboard_tasklet);	do_poke_blanked_console = 1;	schedule_console_callback();}static char kbd_name[] = "kbd";/* * 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 struct input_handle *kbd_connect(struct input_handler *handler, 					struct input_dev *dev,					struct input_device_id *id){	struct input_handle *handle;	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 NULL;	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) 		return NULL;	memset(handle, 0, sizeof(struct input_handle));	handle->dev = dev;	handle->handler = handler;	handle->name = kbd_name;	input_open_device(handle);	kbd_refresh_leds(handle);	return handle;}static void kbd_disconnect(struct input_handle *handle){	input_close_device(handle);	kfree(handle);}static struct input_device_id kbd_ids[] = {	{                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,                .evbit = { BIT(EV_KEY) },        },		{                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,                .evbit = { BIT(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,	.name		= "kbd",	.id_table	= kbd_ids,};int __init kbd_init(void){	int i;        kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;        kbd0.ledmode = LED_SHOW_FLAGS;        kbd0.lockstate = KBD_DEFLOCK;        kbd0.slockstate = 0;        kbd0.modeflags = KBD_DEFMODE;        kbd0.kbdmode = VC_XLATE;        for (i = 0 ; i < MAX_NR_CONSOLES ; i++)                kbd_table[i] = kbd0;	input_register_handler(&kbd_handler);	tasklet_enable(&keyboard_tasklet);	tasklet_schedule(&keyboard_tasklet);	return 0;}

⌨️ 快捷键说明

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