| /* |
| * linux/kernel/chr_drv/keyboard.c |
| * |
| * Keyboard driver for Linux v0.96 using Latin-1. |
| * |
| * Written for linux by Johan Myreen as a translation from |
| * the assembly version by Linus (with diacriticals added) |
| */ |
| |
| #include <linux/sched.h> |
| #include <linux/ctype.h> |
| #include <linux/tty.h> |
| #include <linux/mm.h> |
| #include <asm/io.h> |
| #include <asm/system.h> |
| |
| #define LSHIFT 0x01 |
| #define RSHIFT 0x02 |
| #define LCTRL 0x04 |
| #define RCTRL 0x08 |
| #define ALT 0x10 |
| #define ALTGR 0x20 |
| #define CAPS 0x40 |
| #define CAPSDOWN 0x80 |
| |
| #define SCRLED 0x01 |
| #define NUMLED 0x02 |
| #define CAPSLED 0x04 |
| |
| #define NO_META_BIT 0x80 |
| |
| unsigned char kapplic = 0; |
| unsigned char ckmode = 0; |
| unsigned char krepeat = 1; |
| unsigned char kmode = 0; |
| unsigned char kleds = NUMLED; |
| unsigned char ke0 = 0; |
| unsigned char kraw = 0; |
| unsigned char kbd_flags = KBDFLAGS; |
| unsigned char lfnlmode = 0; |
| |
| extern void do_keyboard_interrupt(void); |
| extern void ctrl_alt_del(void); |
| extern void change_console(unsigned int new_console); |
| extern struct tty_queue *table_list[]; |
| |
| typedef void (*fptr)(int); |
| |
| static unsigned char old_leds = 2; |
| static int diacr = -1; |
| static int npadch = 0; |
| fptr key_table[]; |
| |
| static void put_queue(int); |
| void set_leds(void); |
| static void applkey(int); |
| static void cur(int); |
| static void kb_wait(void), kb_ack(void); |
| static unsigned int handle_diacr(unsigned int); |
| |
| void do_keyboard(void) |
| { |
| static unsigned char rep = 0xff, repke0 = 0; |
| unsigned char scancode, x; |
| struct tty_struct * tty = TTY_TABLE(0); |
| |
| scancode=inb_p(0x60); |
| x=inb_p(0x61); |
| outb_p(x|0x80, 0x61); |
| outb_p(x&0x7f, 0x61); |
| outb(0x20, 0x20); |
| sti(); |
| |
| if (kraw) { |
| put_queue(scancode); |
| do_keyboard_interrupt(); |
| return; |
| } |
| if (scancode == 0xe0) { |
| ke0 = 1; |
| return; |
| } |
| if (scancode == 0xe1) { |
| ke0 = 2; |
| return; |
| } |
| /* |
| * 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. |
| */ |
| if (ke0 == 1 && (scancode == 0x2a || scancode == 0xaa)) { |
| ke0 = 0; |
| return; |
| } |
| /* |
| * Repeat a key only if the input buffers are empty or the |
| * characters get echoed locally. This makes key repeat usable |
| * with slow applications and unders heavy loads. |
| */ |
| if (rep == 0xff) { |
| if (scancode < 0x80) { |
| rep = scancode; |
| repke0 = ke0; |
| } |
| } else if (ke0 == repke0 && (scancode & 0x7f) == rep) |
| if (scancode & 0x80) |
| rep = 0xff; |
| else if (!(krepeat && (L_ECHO(tty) || (EMPTY(tty->secondary) && |
| EMPTY(tty->read_q))))) { |
| ke0 = 0; |
| return; |
| } |
| key_table[scancode](scancode); |
| do_keyboard_interrupt(); |
| ke0 = 0; |
| } |
| |
| static void put_queue(int ch) |
| { |
| register struct tty_queue *qp = table_list[0]; |
| unsigned long new_head; |
| |
| qp->buf[qp->head]=ch; |
| if ((new_head=(qp->head+1)&(TTY_BUF_SIZE-1)) != qp->tail) |
| qp->head=new_head; |
| if (qp->proc_list != NULL) |
| qp->proc_list->state=0; |
| } |
| |
| static void puts_queue(char *cp) |
| { |
| register struct tty_queue *qp = table_list[0]; |
| unsigned long new_head; |
| char ch; |
| |
| while (ch=*cp++) { |
| qp->buf[qp->head]=ch; |
| if ((new_head=(qp->head+1)&(TTY_BUF_SIZE-1)) |
| != qp->tail) |
| qp->head=new_head; |
| } |
| if (qp->proc_list != NULL) |
| qp->proc_list->state=0; |
| } |
| |
| static void ctrl(int sc) |
| { |
| if (ke0) |
| kmode|=RCTRL; |
| else |
| kmode|=LCTRL; |
| } |
| |
| static void alt(int sc) |
| { |
| if (ke0) |
| kmode|=ALTGR; |
| else |
| kmode|=ALT; |
| } |
| |
| static void unctrl(int sc) |
| { |
| if (ke0) |
| kmode&=(~RCTRL); |
| else |
| kmode&=(~LCTRL); |
| } |
| |
| static void unalt(int sc) |
| { |
| if (ke0) |
| kmode&=(~ALTGR); |
| else { |
| kmode&=(~ALT); |
| if (npadch != 0) { |
| put_queue(npadch); |
| npadch=0; |
| } |
| } |
| } |
| |
| static void lshift(int sc) |
| { |
| kmode|=LSHIFT; |
| } |
| |
| static void unlshift(int sc) |
| { |
| kmode&=(~LSHIFT); |
| } |
| |
| static void rshift(int sc) |
| { |
| kmode|=RSHIFT; |
| } |
| |
| static void unrshift(int sc) |
| { |
| kmode&=(~RSHIFT); |
| } |
| |
| static void caps(int sc) |
| { |
| if (!(kmode & CAPSDOWN)) { |
| kleds ^= CAPSLED; |
| kmode ^= CAPS; |
| kmode |= CAPSDOWN; |
| set_leds(); |
| } |
| } |
| |
| void set_leds(void) |
| { |
| if (kleds != old_leds) { |
| old_leds = kleds; |
| kb_wait(); |
| outb(0xed, 0x60); /* set leds command */ |
| kb_ack(); |
| kb_wait(); |
| outb(kleds, 0x60); |
| kb_ack(); |
| } |
| } |
| |
| static void uncaps(int sc) |
| { |
| kmode &= ~CAPSDOWN; |
| } |
| |
| static void scroll(int sc) |
| { |
| if (kmode & (LSHIFT | RSHIFT)) |
| show_mem(); |
| else |
| show_state(); |
| kleds ^= SCRLED; |
| set_leds(); |
| } |
| |
| static void num(int sc) |
| { |
| if (kapplic) |
| applkey(0x50); |
| else { |
| kleds ^= NUMLED; |
| set_leds(); |
| } |
| } |
| |
| static void applkey(int key) |
| { |
| char buf[] = { 0x1b, 0x4f, 0x00, 0x00 }; |
| |
| buf[2] = key; |
| puts_queue(buf); |
| } |
| |
| |
| #if defined KBD_FINNISH |
| |
| static unsigned char key_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', '+', '\'', 127, 9, |
| 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', |
| 'o', 'p', '}', 0, 13, 0, 'a', 's', |
| 'd', 'f', 'g', 'h', 'j', 'k', 'l', '|', |
| '{', 0, 0, '\'', 'z', 'x', 'c', 'v', |
| 'b', 'n', 'm', ',', '.', '-', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '!', '\"', '#', '$', '%', '&', |
| '/', '(', ')', '=', '?', '`', 127, 9, |
| 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', |
| 'O', 'P', ']', '^', 13, 0, 'A', 'S', |
| 'D', 'F', 'G', 'H', 'J', 'K', 'L', '\\', |
| '[', 0, 0, '*', 'Z', 'X', 'C', 'V', |
| 'B', 'N', 'M', ';', ':', '_', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, '@', 163, '$', 0, 0, |
| '{', '[', ']', '}', '\\', 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, '~', 13, 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, 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, 0, '|', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #elif defined KBD_FINNISH_LATIN1 |
| |
| static unsigned char key_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', '+', 180, 127, 9, |
| 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', |
| 'o', 'p', 229, 168, 13, 0, 'a', 's', |
| 'd', 'f', 'g', 'h', 'j', 'k', 'l', 246, |
| 228, 167, 0, '\'', 'z', 'x', 'c', 'v', |
| 'b', 'n', 'm', ',', '.', '-', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '!', '"', '#', '$', '%', '&', |
| '/', '(', ')', '=', '?', '`', 127, 9, |
| 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', |
| 'O', 'P', 197, '^', 13, 0, 'A', 'S', |
| 'D', 'F', 'G', 'H', 'J', 'K', 'L', 214, |
| 196, 189, 0, '*', 'Z', 'X', 'C', 'V', |
| 'B', 'N', 'M', ';', ':', '_', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, '@', 163, '$', 0, 0, |
| '{', '[', ']', '}', '\\', 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, '~', 13, 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, 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, 0, '|', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #elif defined KBD_US |
| |
| static unsigned char key_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', '-', '=', 127, 9, |
| 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', |
| 'o', 'p', '[', ']', 13, 0, 'a', 's', |
| 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', |
| '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', |
| 'b', 'n', 'm', ',', '.', '/', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '!', '@', '#', '$', '%', '^', |
| '&', '*', '(', ')', '_', '+', 127, 9, |
| 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', |
| 'O', 'P', '{', '}', 13, 0, 'A', 'S', |
| 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', |
| '"', '~', '0', '|', 'Z', 'X', 'C', 'V', |
| 'B', 'N', 'M', '<', '>', '?', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, '@', 0, '$', 0, 0, |
| '{', '[', ']', '}', '\\', 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, '~', 13, 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, 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, 0, '|', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #elif defined KBD_UK |
| |
| static unsigned char key_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', '-', '=', 127, 9, |
| 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', |
| 'o', 'p', '[', ']', 13, 0, 'a', 's', |
| 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', |
| '\'', '`', 0, '#', 'z', 'x', 'c', 'v', |
| 'b', 'n', 'm', ',', '.', '/', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '!', '"', 163, '$', '%', '^', |
| '&', '*', '(', ')', '_', '+', 127, 9, |
| 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', |
| 'O', 'P', '{', '}', 13, 0, 'A', 'S', |
| 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', |
| '@', '~', '0', '~', 'Z', 'X', 'C', 'V', |
| 'B', 'N', 'M', '<', '>', '?', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, '@', 0, '$', 0, 0, |
| '{', '[', ']', '}', '\\', 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, '~', 13, 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, 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, 0, '|', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #elif defined KBD_GR |
| |
| static unsigned char key_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', '\\', '\'', 127, 9, |
| 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', |
| 'o', 'p', '@', '+', 13, 0, 'a', 's', |
| 'd', 'f', 'g', 'h', 'j', 'k', 'l', '[', |
| ']', '^', 0, '#', 'y', 'x', 'c', 'v', |
| 'b', 'n', 'm', ',', '.', '-', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '!', '"', '#', '$', '%', '&', |
| '/', '(', ')', '=', '?', '`', 127, 9, |
| 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I', |
| 'O', 'P', '\\', '*', 13, 0, 'A', 'S', |
| 'D', 'F', 'G', 'H', 'J', 'K', 'L', '{', |
| '}', '~', 0, '\'', 'Y', 'X', 'C', 'V', |
| 'B', 'N', 'M', ';', ':', '_', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, '@', 0, '$', 0, 0, |
| '{', '[', ']', '}', '\\', 0, 0, 0, |
| '@', 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, '~', 13, 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, 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, 0, '|', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #elif defined KBD_GR_LATIN1 |
| |
| static unsigned char key_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', 223, 180, 127, 9, |
| 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', |
| 'o', 'p', 252, '+', 13, 0, 'a', 's', |
| 'd', 'f', 'g', 'h', 'j', 'k', 'l', 246, |
| 228, 94, 0, '#', 'y', 'x', 'c', 'v', |
| 'b', 'n', 'm', ',', '.', '-', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '!', '"', 167, '$', '%', '&', |
| '/', '(', ')', '=', '?', '`', 127, 9, |
| 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I', |
| 'O', 'P', 220, '*', 13, 0, 'A', 'S', |
| 'D', 'F', 'G', 'H', 'J', 'K', 'L', 214, |
| 196, 176, 0, '\'', 'Y', 'X', 'C', 'V', |
| 'B', 'N', 'M', ';', ':', '_', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, 178, 179, '$', 0, 0, |
| '{', '[', ']', '}', '\\', 0, 0, 0, |
| '@', 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, '~', 13, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 181, 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, 0, |
| 0, 0, 0, 0, 0, 0, '|', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #elif defined KBD_FR |
| |
| static unsigned char key_map[] = { |
| 0, 27, '&', '{', '"', '\'', '(', '-', |
| '}', '_', '/', '@', ')', '=', 127, 9, |
| 'a', 'z', 'e', 'r', 't', 'y', 'u', 'i', |
| 'o', 'p', '^', '$', 13, 0, 'q', 's', |
| 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', |
| '|', '`', 0, 42, 'w', 'x', 'c', 'v', |
| 'b', 'n', ',', ';', ':', '!', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', ']', '+', 127, 9, |
| 'A', 'Z', 'E', 'R', 'T', 'Y', 'U', 'I', |
| 'O', 'P', '<', '>', 13, 0, 'Q', 'S', |
| 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', |
| '%', '~', 0, '#', 'W', 'X', 'C', 'V', |
| 'B', 'N', '?', '.', '/', '\\', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, '~', '#', '{', '[', '|', |
| '`', '\\', '^', '@', ']', '}', 0, 0, |
| '@', 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, '~', 13, 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, 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, 0, '|', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #elif defined KBD_FR_LATIN1 |
| |
| static unsigned char key_map[] = { |
| 0, 27, '&', 233, '"', '\'', '(', '-', |
| 232, '_', 231, 224, ')', '=', 127, 9, |
| 'a', 'z', 'e', 'r', 't', 'y', 'u', 'i', |
| 'o', 'p', '^', '$', 13, 0, 'q', 's', |
| 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', |
| 249, 178, 0, 42, 'w', 'x', 'c', 'v', |
| 'b', 'n', ',', ';', ':', '!', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', 176, '+', 127, 9, |
| 'A', 'Z', 'E', 'R', 'T', 'Y', 'U', 'I', |
| 'O', 'P', 168, 163, 13, 0, 'Q', 'S', |
| 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', |
| '%', 0, 0, 181, 'W', 'X', 'C', 'V', |
| 'B', 'N', '?', '.', '/', 167, 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, '~', '#', '{', '[', '|', |
| '`', '\\', '^', '@', ']', '}', 0, 0, |
| '@', 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 164, 13, 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, 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, 0, '|', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #elif defined KBD_DK |
| |
| static unsigned char key_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', '+', '\'', 127, 9, |
| 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', |
| 'o', 'p', 229, 0, 13, 0, 'a', 's', |
| 'd', 'f', 'g', 'h', 'j', 'k', 'l', 230, |
| 162, 0, 0, '\'', 'z', 'x', 'c', 'v', |
| 'b', 'n', 'm', ',', '.', '-', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '!', '\"', '#', '$', '%', '&', |
| '/', '(', ')', '=', '?', '`', 127, 9, |
| 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', |
| 'O', 'P', 197, '^', 13, 0, 'A', 'S', |
| 'D', 'F', 'G', 'H', 'J', 'K', 'L', 198, |
| 165, 0, 0, '*', 'Z', 'X', 'C', 'V', |
| 'B', 'N', 'M', ';', ':', '_', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, '@', 163, '$', 0, 0, |
| '{', '[', ']', '}', 0, '|', 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, '~', 13, 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, 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, 0, '\\', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #elif defined KBD_DK_LATIN1 |
| |
| static unsigned char key_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', '+', 180, 127, 9, |
| 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', |
| 'o', 'p', 229, 168, 13, 0, 'a', 's', |
| 'd', 'f', 'g', 'h', 'j', 'k', 'l', 230, |
| 162, 189, 0, '\'', 'z', 'x', 'c', 'v', |
| 'b', 'n', 'm', ',', '.', '-', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '!', '\"', '#', '$', '%', '&', |
| '/', '(', ')', '=', '?', '`', 127, 9, |
| 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', |
| 'O', 'P', 197, '^', 13, 0, 'A', 'S', |
| 'D', 'F', 'G', 'H', 'J', 'K', 'L', 198, |
| 165, 167, 0, '*', 'Z', 'X', 'C', 'V', |
| 'B', 'N', 'M', ';', ':', '_', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, '@', 163, '$', 0, 0, |
| '{', '[', ']', '}', 0, '|', 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, '~', 13, 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, 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, 0, '\\', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #elif defined KBD_DVORAK |
| |
| static unsigned char key_map[] = { |
| 0, 27, '1', '2', '3', '4', '5', '6', |
| '7', '8', '9', '0', '\\', '=', 127, 9, |
| '\'', ',', '.', 'p', 'y', 'f', 'g', 'c', |
| 'r', 'l', '/', ']', 13, 0, 'a', 'o', |
| 'e', 'u', 'i', 'd', 'h', 't', 'n', 's', |
| '-', '`', 0, '[', ';', 'q', 'j', 'k', |
| 'x', 'b', 'm', 'w', 'v', 'z', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char shift_map[] = { |
| 0, 27, '!', '@', '#', '$', '%', '^', |
| '&', '*', '(', ')', '|', '+', 127, 9, |
| '"', '<', '>', 'P', 'Y', 'F', 'G', 'C', |
| 'R', 'L', '?', '}', 13, 0, 'A', 'O', |
| 'E', 'U', 'I', 'D', 'H', 'T', 'N', 'S', |
| '_', '~', 0, '{', ':', 'Q', 'J', 'K', |
| 'X', 'B', 'M', 'W', 'V', 'Z', 0, '*', |
| 0, 32, 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, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| static unsigned char alt_map[] = { |
| 0, 0, 0, '@', 0, '$', 0, 0, |
| '{', '[', ']', '}', '\\', 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, '~', 13, 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, 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, 0, '|', 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0 }; |
| |
| #else |
| #error "KBD-type not defined" |
| #endif |
| |
| static void do_self(int sc) |
| { |
| unsigned char ch; |
| |
| if (kmode & ALTGR) |
| ch = alt_map[sc]; |
| else if (kmode & (LSHIFT | RSHIFT | LCTRL | RCTRL)) |
| ch = shift_map[sc]; |
| else |
| ch = key_map[sc]; |
| |
| if (ch == 0) |
| return; |
| |
| if ((ch = handle_diacr(ch)) == 0) |
| return; |
| |
| if (kmode & (LCTRL | RCTRL | CAPS)) /* ctrl or caps */ |
| if ((ch >= 'a' && ch <= 'z') || (ch >= 224 && ch <= 254)) |
| ch -= 32; |
| if (kmode & (LCTRL | RCTRL)) /* ctrl */ |
| ch &= 0x1f; |
| |
| if (kmode & ALT) |
| if (kbd_flags & NO_META_BIT) { |
| put_queue('\033'); |
| put_queue(ch); |
| } else |
| put_queue(ch|0x80); |
| else |
| put_queue(ch); |
| } |
| |
| unsigned char accent_table[5][64] = { |
| " \300BCD\310FGH\314JKLMN\322PQRST\331VWXYZ[\\]^_" |
| "`\340bcd\350fgh\354jklmn\362pqrst\371vwxyz{|}~", /* accent grave */ |
| |
| " \301BCD\311FGH\315JKLMN\323PQRST\332VWX\335Z[\\]^_" |
| "`\341bcd\351fgh\355jklmn\363pqrst\372vwxyz{|}~", /* accent acute */ |
| |
| " \302BCD\312FGH\316JKLMN\324PQRST\333VWXYZ[\\]^_" |
| "`\342bcd\352fgh\356jklmn\364pqrst\373vwxyz{|}~", /* circumflex */ |
| |
| " \303BCDEFGHIJKLMN\325PQRSTUVWXYZ[\\]^_" |
| "`\343bcdefghijklm\361\365pqrstuvwxyz{|}~", /* tilde */ |
| |
| " \304BCD\313FGH\316JKLMN\326PQRST\334VWXYZ[\\]^_" |
| "`\344bcd\353fgh\357jklmn\366pqrst\374vwx\377z{|}~" /* dieresis */ |
| }; |
| |
| |
| /* |
| * Check if dead key pressed. If so, check if same key pressed twice; |
| * in that case return the char, otherwise store char and return 0. |
| * If dead key not pressed, check if accented character pending. If |
| * not: return the char, otherwise check if char is a space. If it is |
| * a space return the diacritical. Else combine char with diacritical |
| * mark and return. |
| */ |
| |
| unsigned int handle_diacr(unsigned int ch) |
| { |
| static unsigned char diacr_table[] = |
| {'`', 180, '^', '~', 168, 0}; /* Must end with 0 */ |
| int i; |
| |
| for(i=0; diacr_table[i]; i++) |
| if (ch==diacr_table[i] && ((1<<i)&kbd_flags)) { |
| if (diacr == i) { |
| diacr=-1; |
| return ch; /* pressed twice */ |
| } else { |
| diacr=i; /* key is dead */ |
| return 0; |
| } |
| } |
| if (diacr == -1) |
| return ch; |
| else if (ch == ' ') { |
| ch=diacr_table[diacr]; |
| diacr=-1; |
| return ch; |
| } else if (ch<64 || ch>122) { |
| diacr=-1; |
| return ch; |
| } else { |
| ch=accent_table[diacr][ch-64]; |
| diacr=-1; |
| return ch; |
| } |
| } |
| |
| |
| #if defined KBD_FR || defined KBD_US |
| static unsigned char num_table[] = "789-456+1230."; |
| #else |
| static unsigned char num_table[] = "789-456+1230,"; |
| #endif |
| |
| static unsigned char cur_table[] = "HA5-DGC+YB623"; |
| static unsigned int pad_table[] = { 7,8,9,0,4,5,6,0,1,2,3,0,0 }; |
| |
| /* |
| Keypad / 35 B7 Q |
| Keypad * (PrtSc) 37 B7 R |
| Keypad NumLock 45 ?? P |
| Keypad 7 (Home) 47 C7 w |
| Keypad 8 (Up arrow) 48 C8 x |
| Keypad 9 (PgUp) 49 C9 y |
| Keypad - 4A CA S |
| Keypad 4 (Left arrow) 4B CB t |
| Keypad 5 4C CC u |
| Keypad 6 (Right arrow) 4D CD v |
| Keypad + 4E CE l |
| Keypad 1 (End) 4F CF q |
| Keypad 2 (Down arrow) 50 D0 r |
| Keypad 3 (PgDn) 51 D1 s |
| Keypad 0 (Ins) 52 D2 p |
| Keypad . (Del) 53 D3 n |
| */ |
| |
| static unsigned char appl_table[] = "wxyStuvlqrspn"; |
| |
| static char *func_table[] = { |
| "\033[[A", "\033[[B", "\033[[C", "\033[[D", |
| "\033[[E", "\033[[F", "\033[[G", "\033[[H", |
| "\033[[I", "\033[[J", "\033[[K", "\033[[L" |
| }; |
| |
| |
| static void cursor(int sc) |
| { |
| if (sc < 0x47 || sc > 0x53) |
| return; |
| sc-=0x47; |
| if (sc == 12 && (kmode&(LCTRL|RCTRL)) && (kmode&(ALT|ALTGR))) { |
| ctrl_alt_del(); |
| return; |
| } |
| if (ke0 == 1) { |
| cur(sc); |
| return; |
| } |
| |
| if ((kmode&ALT) && sc!=12) { /* Alt-numpad */ |
| npadch=npadch*10+pad_table[sc]; |
| return; |
| } |
| |
| if (kapplic && !(kmode&(LSHIFT|RSHIFT))) { /* shift forces cursor */ |
| applkey(appl_table[sc]); |
| return; |
| } |
| |
| if (kleds&NUMLED) { |
| put_queue(num_table[sc]); |
| } else |
| cur(sc); |
| } |
| |
| static void cur(int sc) |
| { |
| char buf[] = { 0x1b, '[', 0, 0, 0 }; /* must not be static */ |
| |
| buf[2]=cur_table[sc]; |
| if (buf[2] < '9') |
| buf[3]='~'; |
| if ((buf[2] >= 'A' && buf[2] <= 'D') ? ckmode : kapplic) |
| buf[1]='O'; |
| puts_queue(buf); |
| } |
| |
| static void func(int sc) |
| { |
| if (sc < 0x3b) |
| return; |
| sc-=0x3b; |
| if (sc > 9) { |
| sc-=18; |
| if (sc < 10 || sc > 11) |
| return; |
| } |
| if (kmode&ALT) |
| change_console(sc); |
| else |
| puts_queue(func_table[sc]); |
| } |
| |
| |
| static void slash(int sc) |
| { |
| if (ke0 != 1) |
| do_self(sc); |
| else if (kapplic) |
| applkey('Q'); |
| else |
| put_queue('/'); |
| } |
| |
| static void star(int sc) |
| { |
| if (kapplic) |
| applkey('R'); |
| else |
| do_self(sc); |
| } |
| |
| static void enter(int sc) |
| { |
| if (ke0 == 1 && kapplic) |
| applkey('M'); |
| else { |
| put_queue(13); |
| if (lfnlmode) |
| put_queue(10); |
| } |
| } |
| |
| static void minus(int sc) |
| { |
| if (kapplic) |
| applkey('S'); |
| else |
| do_self(sc); |
| } |
| |
| static void plus(int sc) |
| { |
| if (kapplic) |
| applkey('l'); |
| else |
| do_self(sc); |
| } |
| |
| |
| static void none(int sc) |
| { |
| } |
| |
| |
| /* |
| * kb_wait waits for the keyboard controller buffer to empty. |
| */ |
| |
| static void kb_wait(void) |
| { |
| int i; |
| |
| for (i=0; i<0x10000; i++) |
| if ((inb(0x64)&0x02) == 0) |
| break; |
| } |
| |
| /* |
| * kb_ack waits for 0xfa to appear in port 0x60 |
| * |
| * Suggested by Bruce Evans |
| * Added by Niels Skou Olsen [NSO] |
| * April 21, 1992 |
| * |
| * Heavily inspired by kb_wait :-) |
| * I don't know how much waiting actually is required, |
| * but this seems to work |
| */ |
| |
| void kb_ack(void) |
| { |
| int i; |
| |
| for(i=0; i<0x10000; i++) |
| if (inb(0x60) == 0xfa) |
| break; |
| } |
| |
| long no_idt[2] = {0, 0}; |
| |
| /* |
| * This routine reboots the machine by asking the keyboard |
| * controller to pulse the reset-line low. We try that for a while, |
| * and if it doesn't work, we do some other stupid things. |
| */ |
| void hard_reset_now(void) |
| { |
| int i; |
| |
| sti(); |
| for (;;) { |
| for (i=0; i<100; i++) { |
| kb_wait(); |
| *((unsigned short *)0x472)=0x1234; |
| outb(0xfe,0x64); /* pulse reset low */ |
| } |
| __asm__("\tlidt _no_idt"::); |
| } |
| } |
| |
| |
| static fptr key_table[] = { |
| none,do_self,do_self,do_self, /* 00-03 s0 esc 1 2 */ |
| do_self,do_self,do_self,do_self, /* 04-07 3 4 5 6 */ |
| do_self,do_self,do_self,do_self, /* 08-0B 7 8 9 0 */ |
| do_self,do_self,do_self,do_self, /* 0C-0F + ' bs tab */ |
| do_self,do_self,do_self,do_self, /* 10-13 q w e r */ |
| do_self,do_self,do_self,do_self, /* 14-17 t y u i */ |
| do_self,do_self,do_self,do_self, /* 18-1B o p } ^ */ |
| enter,ctrl,do_self,do_self, /* 1C-1F enter ctrl a s */ |
| do_self,do_self,do_self,do_self, /* 20-23 d f g h */ |
| do_self,do_self,do_self,do_self, /* 24-27 j k l | */ |
| do_self,do_self,lshift,do_self, /* 28-2B { para lshift , */ |
| do_self,do_self,do_self,do_self, /* 2C-2F z x c v */ |
| do_self,do_self,do_self,do_self, /* 30-33 b n m , */ |
| do_self,slash,rshift,star, /* 34-37 . - rshift * */ |
| alt,do_self,caps,func, /* 38-3B alt sp caps f1 */ |
| func,func,func,func, /* 3C-3F f2 f3 f4 f5 */ |
| func,func,func,func, /* 40-43 f6 f7 f8 f9 */ |
| func,num,scroll,cursor, /* 44-47 f10 num scr home */ |
| cursor,cursor,minus,cursor, /* 48-4B up pgup - left */ |
| cursor,cursor,plus,cursor, /* 4C-4F n5 right + end */ |
| cursor,cursor,cursor,cursor, /* 50-53 dn pgdn ins del */ |
| none,none,do_self,func, /* 54-57 sysreq ? < f11 */ |
| func,none,none,none, /* 58-5B f12 ? ? ? */ |
| none,none,none,none, /* 5C-5F ? ? ? ? */ |
| none,none,none,none, /* 60-63 ? ? ? ? */ |
| none,none,none,none, /* 64-67 ? ? ? ? */ |
| none,none,none,none, /* 68-6B ? ? ? ? */ |
| none,none,none,none, /* 6C-6F ? ? ? ? */ |
| none,none,none,none, /* 70-73 ? ? ? ? */ |
| none,none,none,none, /* 74-77 ? ? ? ? */ |
| none,none,none,none, /* 78-7B ? ? ? ? */ |
| none,none,none,none, /* 7C-7F ? ? ? ? */ |
| none,none,none,none, /* 80-83 ? br br br */ |
| none,none,none,none, /* 84-87 br br br br */ |
| none,none,none,none, /* 88-8B br br br br */ |
| none,none,none,none, /* 8C-8F br br br br */ |
| none,none,none,none, /* 90-93 br br br br */ |
| none,none,none,none, /* 94-97 br br br br */ |
| none,none,none,none, /* 98-9B br br br br */ |
| none,unctrl,none,none, /* 9C-9F br unctrl br br */ |
| none,none,none,none, /* A0-A3 br br br br */ |
| none,none,none,none, /* A4-A7 br br br br */ |
| none,none,unlshift,none, /* A8-AB br br unlshift br */ |
| none,none,none,none, /* AC-AF br br br br */ |
| none,none,none,none, /* B0-B3 br br br br */ |
| none,none,unrshift,none, /* B4-B7 br br unrshift br */ |
| unalt,none,uncaps,none, /* B8-BB unalt br uncaps br */ |
| none,none,none,none, /* BC-BF br br br br */ |
| none,none,none,none, /* C0-C3 br br br br */ |
| none,none,none,none, /* C4-C7 br br br br */ |
| none,none,none,none, /* C8-CB br br br br */ |
| none,none,none,none, /* CC-CF br br br br */ |
| none,none,none,none, /* D0-D3 br br br br */ |
| none,none,none,none, /* D4-D7 br br br br */ |
| none,none,none,none, /* D8-DB br ? ? ? */ |
| none,none,none,none, /* DC-DF ? ? ? ? */ |
| none,none,none,none, /* E0-E3 e0 e1 ? ? */ |
| none,none,none,none, /* E4-E7 ? ? ? ? */ |
| none,none,none,none, /* E8-EB ? ? ? ? */ |
| none,none,none,none, /* EC-EF ? ? ? ? */ |
| none,none,none,none, /* F0-F3 ? ? ? ? */ |
| none,none,none,none, /* F4-F7 ? ? ? ? */ |
| none,none,none,none, /* F8-FB ? ? ? ? */ |
| none,none,none,none /* FC-FF ? ? ? ? */ |
| }; |