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