📄 amba_kmi_keyb.c
字号:
static void kmi_kbd_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs){#ifdef CONFIG_AMBA_PS2_RECONNECT /* Try to detect a hot-plug event on the PS/2 keyboard port */ switch (kmi->hotplug_state) { case 0: /* Maybe we lost contact... */ if (val == PS2_I_BAT_OK) { kmi_send(kmi, PS2_O_SET_SCANSET); kmi->hotplug_state++; DEBUG(("%s: Saw 0xAA. Going to hotplug state %d\n", kmi->name, kmi->hotplug_state)); } break; case 1: /* Eat up acknowledge */ if (val == PS2_I_ACK) { /* Request scan code set: '2' if POR has happend, '1' is false alarm */ kmi_send(kmi, 0); kmi->hotplug_state++; } else { kmi->hotplug_state = 0; DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val)); } break; case 2: /* Eat up acknowledge */ if (val == PS2_I_ACK) kmi->hotplug_state++; else { kmi->hotplug_state = 0; DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val)); } break; case 3: kmi->hotplug_state = 0; if (val == 2) { DEBUG(("%s: POR detected. Scan code is: (%d)\n", kmi->name, val)); kmi->present = 1; tasklet_schedule(&kmikbd_init_tasklet); printk(KERN_ERR "%s: reconnected\n", kmi->name); return; } else DEBUG(("%s: False Alarm...\n", kmi->name)); break; } /* switch (kmi->hotplug_state) */#endif if (val == PS2_I_DIAGFAIL) { printk(KERN_ERR "%s: diagnostic failed\n", kmi->name); return; } /* We are waiting for the keyboard to respond to a kmi_send_and_wait() */ if (kmi->res == KMI_NO_ACK) { if (val == PS2_I_RESEND) { if (kmi->resend_count < 5) __kmi_send(kmi, kmi->last_tx); else { printk(KERN_ERR "%s: too many resends\n", kmi->name); return; } } if (val >= 0xee) { kmi->res = val; wake_up(&kmi->wait_q); } return; }#ifdef CONFIG_VT kbd_pt_regs = regs; handle_scancode(val, !(val & 0x80)); tasklet_schedule(&keyboard_tasklet);#endif}static void kmi_intr(int nr, void *devid, struct pt_regs *regs){ struct kmi_info *kmi = devid; u_int status = __raw_readb(KMIIR); if (status & KMIIR_RXINTR) { u_int val = __raw_readb(KMIDATA); if (kmi->rx) kmi->rx(kmi, val, regs); }}static int kmi_init_keyboard(struct kmi_info *kmi){ kmikbd_init_tasklet.data = (unsigned long)kmi; tasklet_enable(&kmikbd_init_tasklet); return __kmi_init_keyboard(kmi);}/* * Reset interrupt handler */static void __initkmi_reset_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs){ if (kmi->state == KMI_RESET) { if (val == PS2_I_ACK) kmi->state = KMI_RESET_POR; else { val = KMI_NO_ACK; goto finished; } } else if (kmi->state == KMI_RESET_POR) {finished: kmi->res = val; kmi->state = KMI_RESET_DONE; kmi->rx = NULL; wake_up(&kmi->wait_q); }}/* * Reset the device plugged into this interface */static int __init kmi_reset(struct kmi_info *kmi){ u_int res; int ret = 0; kmi->state = KMI_RESET; kmi->rx = kmi_reset_intr; res = kmi_send_and_wait(kmi, PS2_O_RESET, HZ); kmi->rx = NULL; if (res != PS2_I_BAT_OK) { printk(KERN_ERR "%s: reset failed; ", kmi->name); if (kmi->res != KMI_NO_ACK) printk("code 0x%2.2x\n", kmi->res); else printk("no ack\n"); ret = -EINVAL; } return ret;}static int __init kmi_init_one_interface(struct kmi_info *kmi){ u_int stat; int ret = -ENODEV; init_waitqueue_head(&kmi->wait_q); printk(KERN_INFO "%s at 0x%8.8x on irq %d (%s)\n", kmi->name, kmi->base, kmi->irq, kmi_type[kmi->type]); /* * Initialise the KMI interface */ __raw_writeb(kmi->divisor, KMICLKDIV); __raw_writeb(KMICR_EN, KMICR); /* * Check that the data and clock lines are OK. */ stat = __raw_readb(KMISTAT); if ((stat & (KMISTAT_IC|KMISTAT_ID)) != (KMISTAT_IC|KMISTAT_ID)) { printk(KERN_ERR "%s: %s%s%sline%s stuck low\n", kmi->name, (stat & KMISTAT_IC) ? "" : "clock ", (stat & (KMISTAT_IC | KMISTAT_ID)) ? "" : "and ", (stat & KMISTAT_ID) ? "" : "data ", (stat & (KMISTAT_IC | KMISTAT_ID)) ? "" : "s"); goto bad; } /* * Claim the appropriate interrupts */ ret = request_irq(kmi->irq, kmi_intr, 0, kmi->name, kmi); if (ret) goto bad; /* * Enable the receive interrupt, and reset the device. */ __raw_writeb(KMICR_EN | KMICR_RXINTREN, KMICR); kmi->present = 1; kmi->present = kmi_reset(kmi) == 0; switch (kmi->type) { case KMI_KEYBOARD: ret = kmi_init_keyboard(kmi); break;#ifdef CONFIG_KMI_MOUSE case KMI_MOUSE: ret = kmi_init_mouse(kmi); break;#endif } return ret;bad: /* * Oh dear, the interface was bad, disable it. */ __raw_writeb(0, KMICR); return ret;}#ifdef CONFIG_VT/* * The fragment between #ifdef above and #endif * CONFIG_VT * * is from the pc_keyb.c driver. It is not copyrighted under the * above notice. This code is by various authors; please see * drivers/char/pc_keyb.c for further information. *//* * Translation of escaped scancodes to keycodes. * This is now user-settable. * The keycodes 1-88,96-111,119 are fairly standard, and * should probably not be changed - changing might confuse X. * X also interprets scancode 0x5d (KEY_Begin). * * For 1-88 keycode equals scancode. */#define E0_KPENTER 96#define E0_RCTRL 97#define E0_KPSLASH 98#define E0_PRSCR 99#define E0_RALT 100#define E0_BREAK 101 /* (control-pause) */#define E0_HOME 102#define E0_UP 103#define E0_PGUP 104#define E0_LEFT 105#define E0_RIGHT 106#define E0_END 107#define E0_DOWN 108#define E0_PGDN 109#define E0_INS 110#define E0_DEL 111#define E1_PAUSE 119/* BTC */#define E0_MACRO 112/* LK450 */#define E0_F13 113#define E0_F14 114#define E0_HELP 115#define E0_DO 116#define E0_F17 117#define E0_KPMINPLUS 118/* * My OmniKey generates e0 4c for the "OMNI" key and the * right alt key does nada. [kkoller@nyx10.cs.du.edu] */#define E0_OK 124/* * New microsoft keyboard is rumoured to have * e0 5b (left window button), e0 5c (right window button), * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] * [or: Windows_L, Windows_R, TaskMan] */#define E0_MSLW 125#define E0_MSRW 126#define E0_MSTM 127static u_char e0_keys[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END, E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, E0_MACRO, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};#ifdef CONFIG_MAGIC_SYSRQu_char kmi_kbd_sysrq_xlate[128] = "\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 */#endifint kmi_kbd_setkeycode(u_int scancode, u_int keycode){ if (scancode < 128 || scancode > 255 || keycode > 127) return -EINVAL; e0_keys[scancode - 128] = keycode; return 0;}int kmi_kbd_getkeycode(u_int scancode){ if (scancode < 128 || scancode > 255) return -EINVAL; return e0_keys[scancode - 128];} int kmi_kbd_translate(u_char scancode, u_char *keycode, char raw_mode){ static int prev_scancode = 0; /* special prefix scancodes.. */ if (scancode == 0xe0 || scancode == 0xe1) { prev_scancode = scancode; return 0; } /* 0xff is sent by a few keyboards, ignore it. 0x00 is error */ if (scancode == 0x00 || scancode == 0xff) { prev_scancode = 0; return 0; } scancode &= 0x7f; if (prev_scancode) { int old_scancode = prev_scancode; prev_scancode = 0; switch (old_scancode) { case 0xe0: /* * The keyboard maintains its own internal caps lock * and num lock status. In caps lock mode, E0 AA * precedes make code and E0 2A follows break code. * In numlock mode, E0 2A precedes make code, and * E0 AA follows break code. We do our own book- * keeping, so we will just ignore these. * * For my keyboard there is no caps lock mode, but * there are both Shift-L and Shift-R modes. The * former mode generates E0 2A / E0 AA pairs, the * latter E0 B6 / E0 36 pairs. So, we should also * ignore the latter. - aeb@cwi.nl */ if (scancode == 0x2a || scancode == 0x36) return 0; if (e0_keys[scancode]) *keycode = e0_keys[scancode]; else { if (!raw_mode) printk(KERN_INFO "kbd: unknown " "scancode e0 %02x\n", scancode); return 0; } break; case 0xe1: if (scancode == 0x1d) prev_scancode = 0x100; else { if (!raw_mode) printk(KERN_INFO "kbd: unknown " "scancode e1 %02x\n", scancode); return 0; } break; case 0x100: if (scancode == 0x45) *keycode = E1_PAUSE; else { if (!raw_mode) printk(KERN_INFO "kbd: unknown " "scan code e1 1d %02x\n", scancode); return 0; } break; } } else *keycode = scancode; return 1;}char kmi_kbd_unexpected_up(u_char keycode){ return 0x80;}void kmi_kbd_leds(u_char leds){ struct kmi_info *kmi = kmi_keyb; u_int ret; if (kmi) { ret = kmi_send_and_wait(kmi, PS2_O_INDICATORS, HZ); if (ret != KMI_NO_ACK) ret = kmi_send_and_wait(kmi, leds, HZ); if (ret == KMI_NO_ACK) kmi->present = 0; }}int __init kmi_kbd_init(void){ int ret = -ENODEV; if (kmi_keyb) { strcpy(kmi_keyb->name, "kmikbd"); ret = kmi_init_one_interface(kmi_keyb); } if (ret == 0) { k_setkeycode = kmi_kbd_setkeycode; k_getkeycode = kmi_kbd_getkeycode; k_translate = kmi_kbd_translate; k_unexpected_up = kmi_kbd_unexpected_up; k_leds = kmi_kbd_leds;#ifdef CONFIG_MAGIC_SYSRQ k_sysrq_xlate = kmi_kbd_sysrq_xlate; k_sysrq_key = 0x54;#endif } return ret;}#endif /* CONFIG_VT */int register_kmi(struct kmi_info *kmi){ struct kmi_info **kmip = NULL; int ret; if (kmi->type == KMI_KEYBOARD) kmip = &kmi_keyb; else if (kmi->type == KMI_MOUSE) kmip = &kmi_mouse; ret = -EINVAL; if (kmip) { ret = -EBUSY; if (!*kmip) { *kmip = kmi; ret = 0; } } return ret;}#ifdef CONFIG_KMI_MOUSEstatic int __init kmi_init(void){ int ret = -ENODEV; if (kmi_mouse) { strcpy(kmi_mouse->name, "kmimouse"); ret = kmi_init_one_interface(kmi_mouse); } return ret;}__initcall(kmi_init);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -