/*
 * 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)
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file README.legal in the main directory of this archive
 * for more details.
 */

/*
 * Amiga support by Hamish Macdonald
 */

#include <linux/sched.h>
#include <linux/ctype.h>
#include <linux/tty.h>
#include <linux/mm.h>
#include <linux/ptrace.h>
#include <linux/keyboard.h>
#include <linux/config.h>
#include <machine/interrupt.h>
#include <machine/chipregs.h>

#include <asm/system.h>

#ifndef KBD_DEFFLAGS
#ifdef CONFIG_KBD_META
#define KBD_DEFFLAGS ((1 << VC_NUMLOCK) | (1 << VC_REPEAT) | (1 << VC_META))
#else
#define KBD_DEFFLAGS ((1 << VC_NUMLOCK) | (1 << VC_REPEAT))
#endif
#endif

extern void do_keyboard_interrupt(void);
extern void ctrl_alt_del(void);
extern void change_console(unsigned int new_console);

#define fake_keyboard_interrupt() \
__asm__ __volatile__("int $0x21")

unsigned long kbd_flags = 0;
unsigned long kbd_dead_keys = 0;
unsigned long kbd_prev_dead_keys = 0;

struct kbd_struct kbd_table[NR_CONSOLES];
static struct kbd_struct * kbd = kbd_table;
static struct tty_struct * tty = NULL;

typedef void (*fptr)(int);

static int diacr = -1;
static int npadch = 0;
fptr key_table[];

static void put_queue(int);
static void applkey(int);
static void cur(int);
static unsigned int handle_diacr(unsigned int);

static int keyboard_interrupt(struct ISR_mask *mask, ushort sr)
{
    static unsigned char rep = 0xff;
    unsigned char scancode;

    if (!(mask->ciaa_mask & 0x08))
	return 1;

    /* switch SP pin to output */
    *ciaa_cra |= 0x40;

    kbd_prev_dead_keys |= kbd_dead_keys;
    if (!kbd_dead_keys)
	kbd_prev_dead_keys = 0;
    kbd_dead_keys = 0;

    /* get and invert scancode (keyboard is active low) */
    scancode = ~*ciaa_sdr;

    /* rotate scan code to get up/down bit in proper position */
    __asm__ __volatile__ ("rorb #1,%0" : "=g" (scancode) : "0" (scancode));

    tty = TTY_TABLE(0);
    kbd = kbd_table + fg_console;
    if (vc_kbd_flag(kbd,VC_RAW)) {
	kbd_flags = 0;
	put_queue(scancode);
	goto end_of_int;
    }

#if 0
    if (scancode == 0xe0) {
	set_kbd_dead(KGD_E0);
	continue;
    } else if (scancode == 0xe1) {
	set_kbd_dead(KGD_E1);
	continue;
    }
    /*
     *	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 (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa))
	continue;
#endif

    /*
     *	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 (scancode == rep) {
	if (!(vc_kbd_flag(kbd,VC_REPEAT) && tty &&
	      (L_ECHO(tty) ||
	       (EMPTY(&tty->secondary) &&
		EMPTY(&tty->read_q)))))
	    goto end_of_int;
    }
    rep = scancode;
    key_table[scancode](scancode);

    do_keyboard_interrupt();

end_of_int:
    /* turn off handshake */
    *ciaa_cra &= ~0x40;

    /* allow other interrupt processing */
    return 1;
}

static void put_queue(int ch)
{
    struct tty_queue *qp;
    unsigned long new_head;

    wake_up(&keypress_wait);
    if (!tty)
	return;
    qp = &tty->read_q;

    qp->buf[qp->head]=ch;
    if ((new_head=(qp->head+1)&(TTY_BUF_SIZE-1)) != qp->tail)
	qp->head=new_head;
    wake_up_interruptible(&qp->proc_list);
}

static void puts_queue(char *cp)
{
    struct tty_queue *qp;
    unsigned long new_head;
    char ch;

    wake_up(&keypress_wait);
    if (!tty)
	return;
    qp = &tty->read_q;

    while ((ch = *(cp++)) != 0) {
	qp->buf[qp->head]=ch;
	if ((new_head=(qp->head+1)&(TTY_BUF_SIZE-1))
	    != qp->tail)
	    qp->head=new_head;
    }
    wake_up_interruptible(&qp->proc_list);
}

static void ctrl(int sc)
{
    if (kbd_dead(KGD_E0))
	    set_kbd_flag(KG_RCTRL);
    else
	set_kbd_flag(KG_LCTRL);
}

static void alt(int sc)
{
    if (kbd_dead(KGD_E0))
	set_kbd_flag(KG_ALTGR);
    else
	set_kbd_flag(KG_ALT);
}

static void unctrl(int sc)
{
    if (kbd_dead(KGD_E0))
	clr_kbd_flag(KG_RCTRL);
    else
	clr_kbd_flag(KG_LCTRL);
}

static void unalt(int sc)
{
    if (kbd_dead(KGD_E0))
	clr_kbd_flag(KG_ALTGR);
    else {
	clr_kbd_flag(KG_ALT);
	if (npadch != 0) {
	    put_queue(npadch);
	    npadch=0;
	}
    }
}

static void lshift(int sc)
{
    set_kbd_flag(KG_LSHIFT);
}

static void unlshift(int sc)
{
    clr_kbd_flag(KG_LSHIFT);
}

static void rshift(int sc)
{
    set_kbd_flag(KG_RSHIFT);
}

static void unrshift(int sc)
{
    clr_kbd_flag(KG_RSHIFT);
}

static void caps(int sc)
{
    if (kbd_flag(KG_CAPSLOCK))
	return; 	/* key already pressed: defeat repeat */
    set_kbd_flag(KG_CAPSLOCK);
    chg_vc_kbd_flag(kbd,VC_CAPSLOCK);
}

static void uncaps(int sc)
{
    clr_kbd_flag(KG_CAPSLOCK);
    chg_vc_kbd_flag(kbd,VC_CAPSLOCK);
}

static void lamiga(int sc)
{
    set_kbd_flag(KG_LAMIGA);
}

static void unlamiga(int sc)
{
    clr_kbd_flag(KG_LAMIGA);
}

static void ramiga(int sc)
{
    set_kbd_flag(KG_RAMIGA);
}

static void unramiga(int sc)
{
    clr_kbd_flag(KG_RAMIGA);
}

static void scroll(int sc)
{
    if (kbd_flag(KG_LCTRL) || kbd_flag(KG_RCTRL))
	show_state();
    else
	chg_vc_kbd_flag(kbd,VC_SCROLLOCK);
}

static void num(int sc)
{
    if (vc_kbd_flag(kbd,VC_APPLIC))
	applkey(0x50);
    else
	chg_vc_kbd_flag(kbd,VC_NUMLOCK);
}

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[] = {
	'`',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
	'8',  '9',  '0',  '-',  '=',  '\\',   0,    0,
	'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',
	'o',  'p',  '[',  ']',    0,    0,    0,    0,
	'a',  's',  'd',  'f',  'g',  'h',  'j',  'k',
	'l',  ';', '\'',    0,    0,    0,    0,    0,
	  0,  'z',  'x',  'c',  'v',  'b',  'n',  'm',
	',',  '.',  '/',    0,    0,    0,    0,    0,
	' ', '\b', '\t',    0,    0,   27,  127,    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,    0,
	'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',
	'O',  'P',  '{',  '}',    0,    0,    0,    0,
	'A',  'S',  'D',  'F',  'G',  'H',  'J',  'K',
	'L',  ':',  '"',    0,    0,    0,    0,    0,
	  0,  'Z',  'X',  'C',  'V',  'B',  'N',  'M',
	'<',  '>',  '?',    0,    0,    0,    0,    0,
	  0,	0,    0,    0,	  0,	0,    0,    0,
	' ', '\b', '\t',    0,    0,   27,  127,    0,
	  0,	0,    0,    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 };

#elif defined KBD_SG

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',    0,    0,   13,    0,  'a',  's',
	'd',  'f',  'g',  'h',  'j',  'k',  'l',    0,
	  0,	0,    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,  '+',  '"',  '*',    0,  '%',  '&',
	'/',  '(',  ')',  '=',  '?',  '`',  127,    9,
	'Q',  'W',  'E',  'R',  'T',  'Z',  'U',  'I',
	'O',  'P',    0,  '!',   13,    0,  'A',  'S',
	'D',  'F',  'G',  'H',  'J',  'K',  'L',    0,
	  0,	0,    0,    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,	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 };

#elif defined KBD_SG_LATIN1

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',  252,    0,   13,    0,  'a',  's',
	'd',  'f',  'g',  'h',  'j',  'k',  'l',  246,
	228,  167,    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,  '+',  '"',  '*',  231,  '%',  '&',
	'/',  '(',  ')',  '=',  '?',  '`',  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,  163,	'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,  172,
	'|',  162,    0,    0, '\'',  '~',    0,    0,
	'@',    0,    0,    0,    0,    0,    0,    0,
	  0,	0,  '[',  ']',   13,    0,    0,    0,
	  0,	0,    0,    0,	  0,	0,    0,  233,
	'{',    0,    0,  '}',    0,    0,    0,    0,
	  0,	0,    0,    0,	  0,	0,    0,    0,
	  0,	0,    0,    0,	  0,	0,    0,    0,
	  0,	0,    0,    0,	  0,	0,    0,    0,
	  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_NO

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,    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,
	  0 };

#elif defined KBD_SF

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',    0,    0,   13,    0,  'a',  's',
	'd',  'f',  'g',  'h',  'j',  'k',  'l',    0,
	  0,	0,   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,  '+',  '"',  '*',    0,  '%',  '&',
	'/',  '(',  ')',  '=',  '?',  '`',  127,    9,
	'Q',  'W',  'E',  'R',  'T',  'Z',  'U',  'I',
	'O',  'P',    0,  '!',   13,    0,  'A',  'S',
	'D',  'F',  'G',  'H',  'J',  'K',  'L',    0,
	  0,	0,    0,    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,
	  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 };

#elif defined KBD_SF_LATIN1

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',  232,  168,   13,    0,  'a',  's',
	'd',  'f',  'g',  'h',  'j',  'k',  'l',  233,
	224,  167,    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,  '+',  '"',  '*',  231,  '%',  '&',
	'/',  '(',  ')',  '=',  '?',  '`',  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,  176,    0,  163,	'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,  172,
	'|',   162,   0,    0,  180,  '~',    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 };
#else
#error "KBD-type not defined"
#endif

static void do_self(int sc)
{
    unsigned char ch;

    if (kbd_flag(KG_ALTGR))
	ch = alt_map[sc];
    else if (kbd_flag(KG_LSHIFT) || kbd_flag(KG_RSHIFT) ||
	     kbd_flag(KG_LCTRL) || kbd_flag(KG_RCTRL))
	ch = shift_map[sc];
    else
	ch = key_map[sc];

    if (ch == 0)
	return;

    if ((ch = handle_diacr(ch)) == 0)
	return;

    if (kbd_flag(KG_LCTRL) || kbd_flag(KG_RCTRL) ||
	vc_kbd_flag(kbd,VC_CAPSLOCK))   /* ctrl or caps */
	if ((ch >= 'a' && ch <= 'z') || (ch >= 224 && ch <= 254))
	    ch -= 32;
    if (kbd_flag(KG_LCTRL) || kbd_flag(KG_RCTRL))       /* ctrl */
	ch &= 0x1f;

    if (kbd_flag(KG_ALT))
	if (vc_kbd_flag(kbd,VC_META)) {
	    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 */
	static unsigned char ret_diacr[] =
		{'`', '\'', '^', '~', '"' };		/* Must not end with 0 */
	int i;

	for(i=0; diacr_table[i]; i++)
		if (ch==diacr_table[i] && ((1<<i)&kbd->kbd_flags)) {
			if (diacr == i) {
				diacr=-1;
				return ret_diacr[i];	/* pressed twice */
			} else {
				diacr=i;		/* key is dead */
				return 0;
			}
		}
	if (diacr == -1)
		return ch;
	else if (ch == ' ') {
		ch=ret_diacr[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 || defined KBD_UK || defined KBD_FR_LATIN1
static unsigned char num_table[] = "789-456+1230.";
#else
static unsigned char num_table[] = "789-456+1230,";
#endif

static unsigned char cur_table[] = "1A5-DGC+4B623";
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";

/*
  Set up keyboard to generate DEC VT200 F-keys.
  DEC F1  - F5	not implemented (DEC HOLD, LOCAL PRINT, SETUP, SW SESS, BREAK)
  DEC F6  - F10 are mapped to F6 - F10
  DEC F11 - F20 are mapped to Shift-F1 - Shift-F10
  DEC HELP and DEC DO are mapped to F11, F12 or Shift- F11, F12.
  Regular (?) Linux F1-F5 remain the same.
*/

static char *func_table[2][12] = { /* DEC F1 - F10 */ {
	"\033[[A",  "\033[[B",  "\033[[C",  "\033[[D",
	"\033[[E",  "\033[17~", "\033[18~", "\033[19~",
	"\033[20~", "\033[21~", "\033[28~", "\033[29~"
}, /* DEC F11 - F20 */ {
	"\033[23~", "\033[24~", "\033[25~", "\033[26~",
	"\033[28~", "\033[29~", "\033[31~", "\033[32~",
	"\033[33~", "\033[34~", "\033[28~", "\033[29~"
}};

static void arrow(int sc)
{
    static char curinds[] = { 1, 9, 4 ,6 };

    cur(curinds[sc-0x4c]);
}

static void cursor(int sc)
{
    switch (sc) {
      case 0x1d:   /* KP 1, 2, 3 */
      case 0x1e:
      case 0x1f:
	sc = sc - 0x1d + 8;
	break;
      case 0x2d:   /* KP 4, 5, 6 */
      case 0x2e:
      case 0x2f:
	sc = sc - 0x2d + 4;
	break;
      case 0x3d:   /* KP 7, 8, 9 */
      case 0x3e:
      case 0x3f:
	sc = sc - 0x3d;
	break;
      case 0x0f:   /* KP 0 */
	sc = 11;
	break;
      case 0x3c:   /* KP . */
	sc = 12;
	break;
      default:
	return;
    }

    if (kbd_flag(KG_ALT) && sc != 12) {             /* Alt-numpad */
	npadch=npadch*10+pad_table[sc];
	return;
    }

    if (vc_kbd_flag(kbd,VC_APPLIC) &&
	!kbd_flag(KG_LSHIFT) && /* shift forces cursor */
	!kbd_flag(KG_RSHIFT)) {
	applkey(appl_table[sc]);
	return;
    }

    if (vc_kbd_flag(kbd,VC_NUMLOCK)) {
	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]='~';
	else
	    if ((buf[2] >= 'A' && buf[2] <= 'D') ?
		vc_kbd_flag(kbd,VC_CKMODE) :
		vc_kbd_flag(kbd,VC_APPLIC))
		buf[1]='O';
	puts_queue(buf);
}

static void func(int sc)
{
    if (sc < 0x50 || sc > 0x59)
	return;

    sc -= 0x50;

    if (kbd_flag(KG_ALT))
	change_console(sc);
    else
	if (kbd_flag(KG_LSHIFT) || kbd_flag(KG_RSHIFT)) /* DEC F11 - F20 */
	    puts_queue(func_table[1][sc]);
	else					/* DEC F1 - F10 */
	    puts_queue(func_table[0][sc]);
}

static void help(int sc)
{
    /* help key -> DEC HELP */
    puts_queue(func_table[0][10]);
}

static void slash(int sc)
{
	if (!kbd_dead(KGD_E0))
		do_self(sc);
	else if (vc_kbd_flag(kbd,VC_APPLIC))
		applkey('Q');
	else
		put_queue('/');
}

static void star(int sc)
{
	if (vc_kbd_flag(kbd,VC_APPLIC))
		applkey('R');
	else
		do_self(sc);
}

static void enter(int sc)
{
	if (kbd_dead(KGD_E0) && vc_kbd_flag(kbd,VC_APPLIC))
		applkey('M');
	else {
		put_queue(13);
		if (vc_kbd_flag(kbd,VC_CRLF))
			put_queue(10);
	}
}

static void minus(int sc)
{
	if (vc_kbd_flag(kbd,VC_APPLIC))
		applkey('S');
	else
		do_self(sc);
}

static void plus(int sc)
{
	if (vc_kbd_flag(kbd,VC_APPLIC))
		applkey('l');
	else
		do_self(sc);
}

static void none(int sc)
{
}

/*
 * 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)
{
#if 0
    int i, j;
    extern unsigned long pg0[1024];

    sti();
    /* rebooting needs to touch the page at absolute addr 0 */
    pg0[0] = 7;
    *((unsigned short *)0x472) = 0x1234;
    for (;;) {
	for (i=0; i<100; i++) {
	    kb_wait();
	    for(j = 0; j < 100000 ; j++)
		/* nothing */;
	    outb(0xfe,0x64);     /* pulse reset low */
	}
	__asm__("\tlidt _no_idt"::);
    }
#endif
}

static fptr key_table[] = {
	do_self,do_self,do_self,do_self,	/* 00-03 ` 1 2 3 */
	do_self,do_self,do_self,do_self,	/* 04-07 4 5 6 7 */
	do_self,do_self,do_self,do_self,	/* 08-0B 8 9 0 _ */
	do_self,do_self,do_self,cursor, 	/* 0C-0F = \ ? ins */
	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 [ ] */
	none,cursor,cursor,cursor,		/* 1C-1F ? end dn pgdn */
	do_self,do_self,do_self,do_self,	/* 20-23 a s d f */
	do_self,do_self,do_self,do_self,	/* 24-27 g h j k */
	do_self,do_self,do_self,do_self,	/* 28-2B l ; ' ? */
	do_self,cursor,cursor,cursor,		/* 2C-2F ? left n5 right */
	none,do_self,do_self,do_self,		/* 30-33 ? z x c */
	do_self,do_self,do_self,do_self,	/* 34-37 v b n m */
	do_self,do_self,do_self,none,		/* 38-3B , . / ? */
	cursor,cursor,cursor,cursor,		/* 3C-3F del home up pgup */
	do_self,do_self,do_self,enter,		/* 40-43 sp bs tab enter */
	enter,do_self,do_self,none,		/* 44-47 ret esc del ? */
	none,none,minus,none,			/* 48-4B ? ? - ? */
	arrow,arrow,arrow,arrow,		/* 4C-4F up dn right left */
	func,func,func,func,			/* 50-53 f1 f2 f3 f4 */
	func,func,func,func,			/* 54-57 f5 f6 f7 f8 */
	func,func,num,scroll,			/* 58-5B f9 f10 num scr */
	slash,star,plus,help,			/* 5C-5F slash star plus help */
	lshift,rshift,caps,ctrl,		/* 60-63 lsh rsh caps ctrl */
	alt,alt,lamiga,ramiga,			/* 64-67 lalt ralt lam ram */
	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 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,none,none,none,			/* 9C-9F br br br br */
	none,none,none,none,			/* A0-A3 br br br br */
	none,none,none,none,			/* A4-A7 br br br br */
	none,none,none,none,			/* A8-AB br br br br */
	none,none,none,none,			/* AC-AF br br br br */
	none,none,none,none,			/* B0-B3 br br br br */
	none,none,none,none,			/* B4-B7 br br br br */
	none,none,none,none,			/* B8-BB br br br 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 br br br */
	none,none,none,none,			/* DC-DF br br br br */
	unlshift,unrshift,uncaps,unctrl,	/* E0-E3 unlshift unrshift
							 uncaps unctrl */
	unalt,unalt,unlamiga,unramiga,		/* E4-E7 unlalt unralt
							 unlamiga unramiga */
	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 ? ? ? ? */
};

unsigned long kbd_init(unsigned long kmem_start)
{
    int i;
    struct kbd_struct * kbd;
    struct ISR_mask mask;

    kbd = kbd_table + 0;
    for (i = 0 ; i < NR_CONSOLES ; i++,kbd++) {
	kbd->flags = KBD_DEFFLAGS;
	kbd->default_flags = KBD_DEFFLAGS;
	kbd->kbd_flags = KBDFLAGS;
    }

    /*
     * arrange for processing of keyboard interrupt
     */
    mask.intreqr_mask = IF_PORTS;
    mask.ciaa_mask    = 0x08;
    mask.ciab_mask    = 0x00;
    mask.always       = 0;
    install_ISR (2, keyboard_interrupt, 0, &mask);

    return kmem_start;
}
