📄 pc_keyb.c
字号:
/* * linux/drivers/char/pc_keyb.c * * Separation of the PC low-level part by Geert Uytterhoeven, May 1997 * See keyboard.c for the whole history. * * Major cleanup by Martin Mares, May 1997 * * Combined the keyboard and PS/2 mouse handling into one file, * because they share the same hardware. * Johan Myreen <jem@iki.fi> 1998-10-08. * * Code fixes to handle mouse ACKs properly. * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29. * */#include <linux/config.h>#include <linux/spinlock.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/mm.h>#include <linux/signal.h>#include <linux/init.h>#include <linux/kbd_ll.h>#include <linux/delay.h>#include <linux/random.h>#include <linux/poll.h>#include <linux/miscdevice.h>#include <linux/slab.h>#include <linux/kbd_kern.h>#include <linux/vt_kern.h>#include <linux/smp_lock.h>#include <linux/kd.h>#include <linux/pm.h>#include <asm/keyboard.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/io.h>/* Some configuration switches are present in the include file... */#include <linux/pc_keyb.h>/* Simple translation table for the SysRq keys *//*********************************************************** cao add ************************************************************************/#define AUX_IRQ 32#define aux_request_irq(hand, dev_id) \ request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)#define WB977BASE SIO_BASE_VIRT #define SEL 0x3f0#define outbm(val,port) *((volatile unsigned char *)(WB977BASE+((port)<<2))) = (unsigned char)(val)#define inbm(port) *((volatile unsigned char *)(WB977BASE+((port)<<2)))#define kbd_read_status() inbm(0x64)#define kbd_read_input() inbm(0x60)#define kbd_write_output(val) outbm(val, 0x60)#define kbd_write_command(val) outbm(val, 0x64)static void wb977_open(void){ outbm(0x87,SEL); outbm(0x87,SEL);}static void wb977_close(void){ outbm(0xaa,SEL);}static void wb977_wb(int reg, int val){ outbm(reg,SEL); outbm(val,SEL+1);}static void wb977_ww(int reg, int val){ outbm(reg,SEL); outbm(val >> 8,SEL+1); outbm(reg + 1,SEL); outbm(val,SEL+1);}static int wb977_kbc_rb(void){ int timeout=0xffffff; while(timeout-->0){ if(inbm(0x64)&0x01) return inbm(0x60); } return -1;;}static int wb977_kbc_wb(int cmd){ int timeout=0xfffff; while(timeout-->0){ if(!(inbm(0x64)&0x02)){ outbm(cmd,0x64); return 0; } } return -1;}static int wb977_kbc_mouse_wb(int cmd){ int timeout=0xfffff; while(timeout-->0){ if(!(inbm(0x64)&0x02)){ outbm(0x60,0x64); //direct to auxiliary while(inbm(0x64)&0x02); outbm(0xd4,0x64); outbm(cmd,0x60); return 0; } } return -1;}static int wb977_kbc_rbsys(void){ if(wb977_kbc_wb(0x20)==0){ return wb977_kbc_rb(); } else return -1;}static int wb977_kbc_wbsys(int parm){ int timeout=0xfffff; while(timeout-->0){ if(!(inbm(0x64)&0x02)){ outbm(0x60,0x64); while(inbm(0x64)&0x02); outbm(parm,0x60); return 0; } } return -1;}#define wb977_device_select(dev) wb977_wb(0x07, dev)#define wb977_device_disable() wb977_wb(0x30, 0x00)#define wb977_device_enable() wb977_wb(0x30, 0x01)/*********************************************************** cao add end *******************************************************************/#ifdef CONFIG_MAGIC_SYSRQunsigned char pckbd_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 */#endifstatic void kbd_write_command_w(int data);static void kbd_write_output_w(int data);#ifdef CONFIG_PSMOUSEstatic void aux_write_ack(int val);static void __aux_write_ack(int val);static int aux_reconnect = 0;#endif#ifndef kbd_controller_present#define kbd_controller_present() 1#endifstatic spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;static unsigned char handle_kbd_event(void);/* used only by send_data - set by keyboard_interrupt */static volatile unsigned char reply_expected;static volatile unsigned char acknowledge;static volatile unsigned char resend;#if defined CONFIG_PSMOUSE/* * PS/2 Auxiliary Device */static int __init psaux_init(void);#define AUX_RECONNECT1 0xaa /* scancode1 when ps2 device is plugged (back) in */#define AUX_RECONNECT2 0x00 /* scancode2 when ps2 device is plugged (back) in */ static struct aux_queue *queue; /* Mouse data buffer. */static int aux_count;/* used when we send commands to the mouse that expect an ACK. */static unsigned char mouse_reply_expected;#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)#define MAX_RETRIES 60 /* some aux operations take long time*/#endif /* CONFIG_PSMOUSE *//* * Wait for keyboard controller input buffer to drain. * * Don't use 'jiffies' so that we don't depend on * interrupts.. * * Quote from PS/2 System Reference Manual: * * "Address hex 0060 and address hex 0064 should be written only when * the input-buffer-full bit and output-buffer-full bit in the * Controller Status register are set 0." */static void kb_wait(void){ unsigned long timeout = KBC_TIMEOUT; do { /* * "handle_kbd_event()" will handle any incoming events * while we wait - keypresses or mouse movement. */ unsigned char status = handle_kbd_event(); if (! (status & KBD_STAT_IBF)) return; mdelay(1); timeout--; } while (timeout);#ifdef KBD_REPORT_TIMEOUTS printk(KERN_WARNING "Keyboard timed out[1]\n");#endif}/* * 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/* * The keycodes below are randomly located in 89-95,112-118,120-127. * They could be thrown away (and all occurrences below replaced by 0), * but that would force many users to use the `setkeycodes' utility, where * they needed not before. It does not matter that there are duplicates, as * long as no duplication occurs for any single keyboard. */#define SC_LIM 89#define FOCUS_PF1 85 /* actual code! */#define FOCUS_PF2 89#define FOCUS_PF3 90#define FOCUS_PF4 91#define FOCUS_PF5 92#define FOCUS_PF6 93#define FOCUS_PF7 94#define FOCUS_PF8 95#define FOCUS_PF9 120#define FOCUS_PF10 121#define FOCUS_PF11 122#define FOCUS_PF12 123#define JAP_86 124/* tfj@olivia.ping.dk: * The four keys are located over the numeric keypad, and are * labelled A1-A4. It's an rc930 keyboard, from * Regnecentralen/RC International, Now ICL. * Scancodes: 59, 5a, 5b, 5c. */#define RGN1 124#define RGN2 125#define RGN3 126#define RGN4 127static unsigned char high_keys[128 - SC_LIM] = { RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */};/* 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 unsigned char e0_keys[128] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */};int pckbd_setkeycode(unsigned int scancode, unsigned int keycode){ if (scancode < SC_LIM || scancode > 255 || keycode > 127) return -EINVAL; if (scancode < 128) high_keys[scancode - SC_LIM] = keycode; else e0_keys[scancode - 128] = keycode; return 0;}int pckbd_getkeycode(unsigned int scancode){ return (scancode < SC_LIM || scancode > 255) ? -EINVAL : (scancode < 128) ? high_keys[scancode - SC_LIM] : e0_keys[scancode - 128];}static int do_acknowledge(unsigned char scancode){ if (reply_expected) { /* Unfortunately, we must recognise these codes only if we know they * are known to be valid (i.e., after sending a command), because there * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have * keys with such codes :( */ if (scancode == KBD_REPLY_ACK) { acknowledge = 1; reply_expected = 0; return 0; } else if (scancode == KBD_REPLY_RESEND) { resend = 1; reply_expected = 0; return 0; } /* Should not happen... */#if 0 printk(KERN_DEBUG "keyboard reply expected - got %02x\n", scancode);#endif } return 1;}int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode){ static int prev_scancode; /* 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) { /* * usually it will be 0xe0, but a Pause key generates * e1 1d 45 e1 9d c5 when pressed, and nothing when released */ if (prev_scancode != 0xe0) { if (prev_scancode == 0xe1 && scancode == 0x1d) { prev_scancode = 0x100; return 0; } else if (prev_scancode == 0x100 && scancode == 0x45) { *keycode = E1_PAUSE; prev_scancode = 0; } else {#ifdef KBD_REPORT_UNKN if (!raw_mode) printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");#endif prev_scancode = 0; return 0; } } else { prev_scancode = 0; /* * The keyboard maintains its own internal caps lock and * num lock statuses. In caps lock mode E0 AA precedes make * code and E0 2A follows break code. In num lock 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 {#ifdef KBD_REPORT_UNKN if (!raw_mode) printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -