blob: fad6a84c5d84268f886c67961c7f0a917ec2607f [file] [log] [blame]
/*
* 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 ? ? ? ? */
};