q40_keyb.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
- /*
- * linux/drivers/char/q40_keyb.c
- *
- */
- #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/keyboard.h>
- #include <linux/signal.h>
- #include <linux/ioport.h>
- #include <linux/init.h>
- #include <linux/kbd_ll.h>
- #include <linux/kbd_kern.h>
- #include <linux/delay.h>
- #include <linux/sysrq.h>
- #include <linux/random.h>
- #include <linux/poll.h>
- #include <linux/miscdevice.h>
- #include <linux/slab.h>
- #include <asm/keyboard.h>
- #include <asm/bitops.h>
- #include <asm/io.h>
- #include <asm/uaccess.h>
- #include <asm/q40_master.h>
- #include <asm/irq.h>
- #include <asm/q40ints.h>
- /* Simple translation table for the SysRq keys */
- #define SYSRQ_KEY 0x54
- #ifdef CONFIG_MAGIC_SYSRQ
- unsigned char q40kbd_sysrq_xlate[128] =
- "00331234567890-=177t" /* 0x00 - 0x0f */
- "qwertyuiop[]r00as" /* 0x10 - 0x1f */
- "dfghjkl;'`00\zxcv" /* 0x20 - 0x2f */
- "bnm,./00*00 00201202203204205" /* 0x30 - 0x3f */
- "2062072102112120000789-456+1" /* 0x40 - 0x4f */
- "230177000021321400000000000000000000" /* 0x50 - 0x5f */
- "r00/"; /* 0x60 - 0x6f */
- #endif
- /* Q40 uses AT scancodes - no way to change it. so we have to translate ..*/
- /* 0x00 means not a valid entry or no conversion known */
- unsigned static char q40cl[256] =
- {/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, */
- 0x00,0x43,0x00,0x3f,0x3d,0x3b,0x3c,0x58,0x00,0x44,0x42,0x40,0x3e,0x0f,0x29,0x00, /* 0x00 - 0x0f */
- 0x00,0x38,0x2a,0x00,0x1d,0x10,0x02,0x00,0x00,0x00,0x2c,0x1f,0x1e,0x11,0x03,0x00, /* 0x10 - 0x1f */
- 0x00,0x2e,0x2d,0x20,0x12,0x05,0x04,0x00,0x21,0x39,0x2f,0x21,0x14,0x13,0x06,0x00, /* 0x20 - 0x2f 'f' is at 0x2b, what is 0x28 ???*/
- 0x00,0x31,0x30,0x23,0x22,0x15,0x07,0x00,0x24,0x00,0x32,0x24,0x16,0x08,0x09,0x00, /* 0x30 - 0x3f */
- 0x00,0x33,0x25,0x17,0x18,0x0b,0x0a,0x00,0x00,0x34,0x35,0x26,0x27,0x19,0x0c,0x00, /* 0x40 - 0x4f */
- 0x00,0x00,0x28,0x00,0x1a,0x0d,0x00,0x00,0x3a,0x36,0x1c,0x1b,0x00,0x2b,0x00,0x00, /* 0x50 - 0x5f*/
- 0x00,0x56,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00, /* 0x60 - 0x6f */
- 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x00, /* 0x70 - 0x7f */
- 0x00,0x00,0x00,0x41,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x80 - 0x8f 0x84/0x37 is SySrq*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x90 - 0x9f */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xa0 - 0xaf */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xb0 - 0xbf */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xc0 - 0xcf */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xd0 - 0xdf */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xe0 - 0xef */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xf0 - 0xff */
- };
- /* another table, AT 0xe0 codes to PC 0xe0 codes,
- 0xff special entry for SysRq - DROPPED right now */
- static unsigned char q40ecl[]=
- {/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x00 - 0x0f*/
- 0x00,0x38,0x2a,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x10 - 0x1f */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x20 - 0x2f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x30 - 0x3f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x00,0x00, /* 0x40 - 0x4f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x1c,0x00,0x00,0x00,0x00,0x00, /* 0x50 - 0x5f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00, /* 0x60 - 0x6f*/
- 0x52,0x53,0x50,0x00,0x4d,0x48,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x49,0x00,0x00, /* 0x70 - 0x7f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x80 - 0x8f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x90 - 0x9f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xa0 - 0xaf*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xb0 - 0xbf*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xc0 - 0xcf*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xd0 - 0xdf*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xe0 - 0xef*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 0xf0 - 0xff*/
- };
- static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
- /*
- * 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 127
- static 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 127
- /* this can be changed using setkeys : */
- static 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 q40kbd_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 q40kbd_getkeycode(unsigned int scancode)
- {
- return
- (scancode < SC_LIM || scancode > 255) ? -EINVAL :
- (scancode < 128) ? high_keys[scancode - SC_LIM] :
- e0_keys[scancode - 128];
- }
- #define disable_keyboard()
- #define enable_keyboard()
- int q40kbd_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 sequencen");
- #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 %02xn",
- scancode);
- #endif
- return 0;
- }
- }
- } else if (scancode >= SC_LIM) {
- /* This happens with the FOCUS 9000 keyboard
- Its keys PF1..PF12 are reported to generate
- 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
- Moreover, unless repeated, they do not generate
- key-down events, so we have to zero up_flag below */
- /* Also, Japanese 86/106 keyboards are reported to
- generate 0x73 and 0x7d for - and | respectively. */
- /* Also, some Brazilian keyboard is reported to produce
- 0x73 and 0x7e for ? and KP-dot, respectively. */
- *keycode = high_keys[scancode - SC_LIM];
- if (!*keycode) {
- if (!raw_mode) {
- #ifdef KBD_REPORT_UNKN
- printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
- " - ignoredn", scancode);
- #endif
- }
- return 0;
- }
- } else
- *keycode = scancode;
- return 1;
- }
- char q40kbd_unexpected_up(unsigned char keycode)
- {
- /* unexpected, but this can happen: maybe this was a key release for a
- FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
- if (keycode >= SC_LIM || keycode == 85)
- return 0;
- else
- return 0200;
- }
- static int keyup=0;
- static int qprev=0;
- static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
- {
- unsigned char status;
- spin_lock(&kbd_controller_lock);
- kbd_pt_regs = regs;
- status = Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
- if (status )
- {
- unsigned char scancode,qcode;
-
- qcode = master_inb(KEYCODE_REG);
-
- if (qcode != 0xf0)
- {
- if (qcode == 0xe0)
- {
- qprev=0xe0;
- handle_scancode(qprev , 1);
- goto exit;
- }
-
- scancode=qprev ? q40ecl[qcode] : q40cl[qcode];
- #if 0
- /* next line is last resort to hanlde some oddities */
- if (qprev && !scancode) scancode=q40cl[qcode];
- #endif
- qprev=0;
- if (!scancode)
- {
- printk("unknown scancode %xn",qcode);
- goto exit;
- }
- if (scancode==0xff) /* SySrq */
- scancode=SYSRQ_KEY;
- handle_scancode(scancode, ! keyup );
- keyup=0;
- tasklet_schedule(&keyboard_tasklet);
- }
- else
- keyup=1;
- }
- exit:
- spin_unlock(&kbd_controller_lock);
- master_outb(-1,KEYBOARD_UNLOCK_REG); /* keyb ints reenabled herewith */
- }
- #define KBD_NO_DATA (-1) /* No data */
- #define KBD_BAD_DATA (-2) /* Parity or other error */
- static int __init kbd_read_input(void)
- {
- int retval = KBD_NO_DATA;
- unsigned char status;
- status = Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
- if (status) {
- unsigned char data = master_inb(KEYCODE_REG);
- retval = data;
- master_outb(-1,KEYBOARD_UNLOCK_REG);
- }
- return retval;
- }
- static void __init kbd_clear_input(void)
- {
- int maxread = 100; /* Random number */
- do {
- if (kbd_read_input() == KBD_NO_DATA)
- break;
- } while (--maxread);
- }
- int __init q40kbd_init_hw(void)
- {
- /* Flush any pending input. */
- kbd_clear_input();
- /* Ok, finally allocate the IRQ, and off we go.. */
- request_irq(Q40_IRQ_KEYBOARD, keyboard_interrupt, 0, "keyboard", NULL);
- master_outb(-1,KEYBOARD_UNLOCK_REG);
- master_outb(1,KEY_IRQ_ENABLE_REG);
- return 0;
- }