OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [armnommu/] [drivers/] [char/] [keyboard.c] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*
/*
 * linux/arch/arm/drivers/block/keyboard.c
 * linux/arch/arm/drivers/block/keyboard.c
 *
 *
 * Keyboard driver for Linux using Latin-1.
 * Keyboard driver for Linux using Latin-1.
 *
 *
 * Written for linux by Johan Myreen as a translation from
 * Written for linux by Johan Myreen as a translation from
 * the assembly version by Linus (with diacriticals added)
 * the assembly version by Linus (with diacriticals added)
 *
 *
 * Some additional features added by Christoph Niemann (ChN), March 1993
 * Some additional features added by Christoph Niemann (ChN), March 1993
 *
 *
 * Loadable keymaps by Risto Kankkunen, May 1993
 * Loadable keymaps by Risto Kankkunen, May 1993
 *
 *
 * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
 * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
 * Added decr/incr_console, dynamic keymaps, Unicode support,
 * Added decr/incr_console, dynamic keymaps, Unicode support,
 * dynamic function/string keys, led setting,  Sept 1994
 * dynamic function/string keys, led setting,  Sept 1994
 * `Sticky' modifier keys, 951006.
 * `Sticky' modifier keys, 951006.
 *
 *
 * Majorly altered for use with arm Russell King (rmk@ecs.soton.ac.uk)
 * Majorly altered for use with arm Russell King (rmk@ecs.soton.ac.uk)
 *  The low-level keyboard driver is now separate.
 *  The low-level keyboard driver is now separate.
 *  Interfaces:
 *  Interfaces:
 *    Driver supplies:
 *    Driver supplies:
 *      kbd_drv_init    - initialise keyboard driver proper
 *      kbd_drv_init    - initialise keyboard driver proper
 *      kbd_drv_setleds - set leds on keyboard
 *      kbd_drv_setleds - set leds on keyboard
 *    Driver uses:
 *    Driver uses:
 *      kbd_keyboardkey - process a keypress/release
 *      kbd_keyboardkey - process a keypress/release
 *      kbd_reset       - reset keyboard down array
 *      kbd_reset       - reset keyboard down array
 *      kbd_setregs     - set regs for scroll-lock debug
 *      kbd_setregs     - set regs for scroll-lock debug
 */
 */
 
 
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/tty_flip.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/malloc.h>
#include <linux/ptrace.h>
#include <linux/ptrace.h>
#include <linux/signal.h>
#include <linux/signal.h>
#include <linux/timer.h>
#include <linux/timer.h>
#include <linux/random.h>
#include <linux/random.h>
#include <linux/ctype.h>
#include <linux/ctype.h>
 
 
#include <asm/bitops.h>
#include <asm/bitops.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/irq.h>
#include <asm/segment.h>
#include <asm/segment.h>
 
 
#include "kbd_kern.h"
#include "kbd_kern.h"
#include "diacr.h"
#include "diacr.h"
#include "vt_kern.h"
#include "vt_kern.h"
 
 
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
 
#define KBD_REPORT_ERR
#define KBD_REPORT_ERR
#define KBD_REPORT_UNKN
#define KBD_REPORT_UNKN
 
 
#ifndef KBD_DEFMODE
#ifndef KBD_DEFMODE
#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
#endif
#endif
 
 
/*
/*
 * Starts with NumLock off.
 * Starts with NumLock off.
 */
 */
#ifndef KBD_DEFLEDS
#ifndef KBD_DEFLEDS
#define KBD_DEFLEDS 0
#define KBD_DEFLEDS 0
#endif
#endif
 
 
#ifndef KBD_DEFLOCK
#ifndef KBD_DEFLOCK
#define KBD_DEFLOCK 0
#define KBD_DEFLOCK 0
#endif
#endif
 
 
#define REPEAT_TIMEOUT HZ*300/1000
#define REPEAT_TIMEOUT HZ*300/1000
#define REPEAT_RATE    HZ*30/1000
#define REPEAT_RATE    HZ*30/1000
 
 
extern void ctrl_alt_del (void);
extern void ctrl_alt_del (void);
extern void scrollback(int);
extern void scrollback(int);
extern void scrollfront(int);
extern void scrollfront(int);
extern int kbd_drv_init(void);
extern int kbd_drv_init(void);
extern void kbd_drv_setleds(unsigned int leds);
extern void kbd_drv_setleds(unsigned int leds);
extern unsigned int keymap_count;
extern unsigned int keymap_count;
 
 
/*
/*
 * these are the valid i/o ports we're allowed to change. they map all the
 * these are the valid i/o ports we're allowed to change. they map all the
 * video ports
 * video ports
 */
 */
#define GPFIRST 0x3b4
#define GPFIRST 0x3b4
#define GPLAST 0x3df
#define GPLAST 0x3df
#define GPNUM (GPLAST - GPFIRST + 1)
#define GPNUM (GPLAST - GPFIRST + 1)
 
 
/*
/*
 * global state includes the following, and various static variables
 * global state includes the following, and various static variables
 * in this module: shift_state, diacr, npadch, dead_key_next.
 * in this module: shift_state, diacr, npadch, dead_key_next.
 * (last_console is now a global variable)
 * (last_console is now a global variable)
 */
 */
 
 
/* shift state counters.. */
/* shift state counters.. */
static unsigned char k_down[NR_SHIFT] = {0, };
static unsigned char k_down[NR_SHIFT] = {0, };
/* keyboard key bitmap */
/* keyboard key bitmap */
#define BITS_PER_LONG (8*sizeof (unsigned long))
#define BITS_PER_LONG (8*sizeof (unsigned long))
static unsigned long key_down[256/BITS_PER_LONG] = {0, };
static unsigned long key_down[256/BITS_PER_LONG] = {0, };
static int dead_key_next;
static int dead_key_next;
 
 
/*
/*
 * In order to retrieve the shift_state (for the mouse server), either
 * In order to retrieve the shift_state (for the mouse server), either
 * the variable must be global, or a new procedure must be created to
 * the variable must be global, or a new procedure must be created to
 * return the value. I chose the former way.
 * return the value. I chose the former way.
 */
 */
/*static*/ int shift_state;
/*static*/ int shift_state;
static int npadch            = -1;              /* -1 or number assembled on pad */
static int npadch            = -1;              /* -1 or number assembled on pad */
static unsigned char diacr;
static unsigned char diacr;
static char rep;                                /* Flag telling character repeat */
static char rep;                                /* Flag telling character repeat */
static int kbd_repeatkey     = -1;
static int kbd_repeatkey     = -1;
static int kbd_repeattimeout = REPEAT_TIMEOUT;
static int kbd_repeattimeout = REPEAT_TIMEOUT;
static int kbd_repeatrate    = REPEAT_RATE;
static int kbd_repeatrate    = REPEAT_RATE;
 
 
static struct kbd_struct * kbd;
static struct kbd_struct * kbd;
static struct tty_struct * tty;
static struct tty_struct * tty;
 
 
extern void compute_shiftstate (void);
extern void compute_shiftstate (void);
 
 
typedef void (*k_hand)(unsigned char value, char up_flag);
typedef void (*k_hand)(unsigned char value, char up_flag);
typedef void (k_handfn)(unsigned char value, char up_flag);
typedef void (k_handfn)(unsigned char value, char up_flag);
 
 
static k_handfn
static k_handfn
        do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
        do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
        do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
        do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
 
 
static k_hand key_handler[16] = {
static k_hand key_handler[16] = {
        do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
        do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
        do_meta, do_ascii, do_lock, do_lowercase, do_slock,
        do_meta, do_ascii, do_lock, do_lowercase, do_slock,
        do_ignore, do_ignore, do_ignore
        do_ignore, do_ignore, do_ignore
};
};
 
 
typedef void (*void_fnp)(void);
typedef void (*void_fnp)(void);
typedef void (void_fn)(void);
typedef void (void_fn)(void);
 
 
static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
        num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
        num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
        SAK, decr_console, incr_console, spawn_console, show_stack, bare_num;
        SAK, decr_console, incr_console, spawn_console, show_stack, bare_num;
 
 
static void_fnp spec_fn_table[] = {
static void_fnp spec_fn_table[] = {
        do_null,        enter,          show_ptregs,    show_mem,
        do_null,        enter,          show_ptregs,    show_mem,
        show_state,     send_intr,      lastcons,       caps_toggle,
        show_state,     send_intr,      lastcons,       caps_toggle,
        num,            hold,           scroll_forw,    scroll_back,
        num,            hold,           scroll_forw,    scroll_back,
        boot_it,        caps_on,        compose,        SAK,
        boot_it,        caps_on,        compose,        SAK,
        decr_console,   incr_console,   show_stack,     bare_num
        decr_console,   incr_console,   show_stack,     bare_num
};
};
 
 
/* maximum values each key_handler can handle */
/* maximum values each key_handler can handle */
const int max_vals[] = {
const int max_vals[] = {
        255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
        255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
        NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
        NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
        255, NR_ASCII - 1, NR_LOCK - 1, 255,
        255, NR_ASCII - 1, NR_LOCK - 1, 255,
        NR_LOCK - 1
        NR_LOCK - 1
};
};
 
 
const int NR_TYPES = SIZE(max_vals);
const int NR_TYPES = SIZE(max_vals);
 
 
static void put_queue(int);
static void put_queue(int);
static unsigned char handle_diacr(unsigned char);
static unsigned char handle_diacr(unsigned char);
 
 
/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
static struct pt_regs * pt_regs;
static struct pt_regs * pt_regs;
 
 
/*
/*
 * Many other routines do put_queue, but I think either
 * Many other routines do put_queue, but I think either
 * they produce ASCII, or they produce some user-assigned
 * they produce ASCII, or they produce some user-assigned
 * string, and in both cases we might assume that it is
 * string, and in both cases we might assume that it is
 * in utf-8 already.
 * in utf-8 already.
 */
 */
void to_utf8(ushort c)
void to_utf8(ushort c)
{
{
        if (c < 0x80)
        if (c < 0x80)
                put_queue(c);                   /*  0*******  */
                put_queue(c);                   /*  0*******  */
        else if (c < 0x800) {
        else if (c < 0x800) {
                put_queue(0xc0 | (c >> 6));     /*  110***** 10******  */
                put_queue(0xc0 | (c >> 6));     /*  110***** 10******  */
                put_queue(0x80 | (c & 0x3f));
                put_queue(0x80 | (c & 0x3f));
        } else {
        } else {
                put_queue(0xe0 | (c >> 12));    /*  1110**** 10****** 10******  */
                put_queue(0xe0 | (c >> 12));    /*  1110**** 10****** 10******  */
                put_queue(0x80 | ((c >> 6) & 0x3f));
                put_queue(0x80 | ((c >> 6) & 0x3f));
                put_queue(0x80 | (c & 0x3f));
                put_queue(0x80 | (c & 0x3f));
        }
        }
        /* UTF-8 is defined for words of up to 31 bits,
        /* UTF-8 is defined for words of up to 31 bits,
           but we need only 16 bits here */
           but we need only 16 bits here */
}
}
 
 
/*
/*
 * As yet, we don't support setting and getting the
 * As yet, we don't support setting and getting the
 * key codes.  I'll have to find out where this is used.
 * key codes.  I'll have to find out where this is used.
 */
 */
int setkeycode(unsigned int scancode, unsigned int keycode)
int setkeycode(unsigned int scancode, unsigned int keycode)
{
{
        return -EINVAL;
        return -EINVAL;
}
}
 
 
int getkeycode(unsigned int scancode)
int getkeycode(unsigned int scancode)
{
{
        return -EINVAL;
        return -EINVAL;
}
}
 
 
static void key_callback(unsigned long nr)
static void key_callback(unsigned long nr)
{
{
        rep = 1;
        rep = 1;
        mark_bh (KEYBOARD_BH);
        mark_bh (KEYBOARD_BH);
}
}
 
 
static struct timer_list key_timer =
static struct timer_list key_timer =
{
{
        NULL, NULL, 0, 0, key_callback
        NULL, NULL, 0, 0, key_callback
};
};
 
 
void kbd_reset(void)
void kbd_reset(void)
{
{
        int i;
        int i;
 
 
        for (i = 0; i < NR_SHIFT; i++)
        for (i = 0; i < NR_SHIFT; i++)
                k_down[i] = 0;
                k_down[i] = 0;
        for (i = 0; i < 256/BITS_PER_LONG; i++)
        for (i = 0; i < 256/BITS_PER_LONG; i++)
                key_down[i] = 0;
                key_down[i] = 0;
        shift_state = 0;
        shift_state = 0;
}
}
 
 
void kbd_setregs(struct pt_regs *regs)
void kbd_setregs(struct pt_regs *regs)
{
{
        pt_regs = regs;
        pt_regs = regs;
}
}
 
 
static void kbd_processkey(unsigned int keycode, unsigned int up_flag, unsigned int autorepeat)
static void kbd_processkey(unsigned int keycode, unsigned int up_flag, unsigned int autorepeat)
{
{
        del_timer(&key_timer);
        del_timer(&key_timer);
        show_console();
        show_console();
        add_keyboard_randomness (keycode|(up_flag?0x100:0));
        add_keyboard_randomness (keycode|(up_flag?0x100:0));
 
 
        tty = *vtdata.fgconsole->tty;
        tty = *vtdata.fgconsole->tty;
        kbd = vtdata.fgconsole->kbd;
        kbd = vtdata.fgconsole->kbd;
 
 
        if (up_flag) {
        if (up_flag) {
                rep = 0;
                rep = 0;
                clear_bit (keycode, key_down);
                clear_bit (keycode, key_down);
                /* don't report an error if key is already up - happens when a ghost key is released */
                /* don't report an error if key is already up - happens when a ghost key is released */
        } else
        } else
                rep = set_bit (keycode, key_down);
                rep = set_bit (keycode, key_down);
 
 
        if (rep && !autorepeat)
        if (rep && !autorepeat)
                return;
                return;
 
 
        if (kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) {
        if (kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) {
                put_queue(keycode + (up_flag ? 0x80 : 0));
                put_queue(keycode + (up_flag ? 0x80 : 0));
                return;
                return;
        }
        }
 
 
        /*
        /*
         * We have to do our own auto-repeat processing...
         * We have to do our own auto-repeat processing...
         */
         */
        if (!up_flag) {
        if (!up_flag) {
                kbd_repeatkey = keycode;
                kbd_repeatkey = keycode;
                if (vc_kbd_mode(kbd, VC_REPEAT)) {
                if (vc_kbd_mode(kbd, VC_REPEAT)) {
                        if (rep)
                        if (rep)
                                key_timer.expires = jiffies + kbd_repeatrate;
                                key_timer.expires = jiffies + kbd_repeatrate;
                        else
                        else
                                key_timer.expires = jiffies + kbd_repeattimeout;
                                key_timer.expires = jiffies + kbd_repeattimeout;
                        add_timer(&key_timer);
                        add_timer(&key_timer);
                }
                }
        } else
        } else
                kbd_repeatkey = -1;
                kbd_repeatkey = -1;
 
 
        /*
        /*
         * Repeat a key only if the input buffers are empty or the
         * Repeat a key only if the input buffers are empty or the
         * characters get echoed locally.  This makes key repeat usable
         * characters get echoed locally.  This makes key repeat usable
         * with slow applications and under heavy loads.
         * with slow applications and under heavy loads.
         */
         */
        if (!rep ||
        if (!rep ||
            (vc_kbd_mode (kbd, VC_REPEAT) && tty &&
            (vc_kbd_mode (kbd, VC_REPEAT) && tty &&
             (L_ECHO(tty) || (tty->driver.chars_in_buffer (tty) == 0)))) {
             (L_ECHO(tty) || (tty->driver.chars_in_buffer (tty) == 0)))) {
                u_short keysym;
                u_short keysym;
                u_char  type;
                u_char  type;
 
 
                /* the XOR below used to be an OR */
                /* the XOR below used to be an OR */
                int     shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
                int     shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
                u_short *key_map = key_maps[shift_final];
                u_short *key_map = key_maps[shift_final];
 
 
                if (key_map != NULL) {
                if (key_map != NULL) {
                        keysym = key_map[keycode];
                        keysym = key_map[keycode];
                        type   = KTYP(keysym);
                        type   = KTYP(keysym);
 
 
                        if (type >= 0xf0) {
                        if (type >= 0xf0) {
                                type -= 0xf0;
                                type -= 0xf0;
                                if (type == KT_LETTER) {
                                if (type == KT_LETTER) {
                                        type = KT_LATIN;
                                        type = KT_LATIN;
                                        if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
                                        if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
                                                key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
                                                key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
                                                if (key_map)
                                                if (key_map)
                                                        keysym = key_map[keycode];
                                                        keysym = key_map[keycode];
                                        }
                                        }
                                }
                                }
                                (*key_handler[type])(keysym & 0xff, up_flag);
                                (*key_handler[type])(keysym & 0xff, up_flag);
                                if (type != KT_SLOCK)
                                if (type != KT_SLOCK)
                                        kbd->slockstate = 0;
                                        kbd->slockstate = 0;
                        } else {
                        } else {
                                /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
                                /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
                                if (!up_flag)
                                if (!up_flag)
                                        to_utf8(keysym);
                                        to_utf8(keysym);
                        }
                        }
                } else {
                } else {
                        /*
                        /*
                         * maybe beep?
                         * maybe beep?
                         * we have at least to update shift_state
                         * we have at least to update shift_state
                         * how? two almost equivalent choices follow
                         * how? two almost equivalent choices follow
                         */
                         */
#if 1
#if 1
                        compute_shiftstate ();
                        compute_shiftstate ();
#else
#else
                        keysym = U(plain_map[keycode]);
                        keysym = U(plain_map[keycode]);
                        type   = KTYP(keysym);
                        type   = KTYP(keysym);
                        if (type == KT_SHIFT)
                        if (type == KT_SHIFT)
                                (*key_handler[type]) (keysym & 0xff, up_flag);
                                (*key_handler[type]) (keysym & 0xff, up_flag);
#endif
#endif
                }
                }
        }
        }
}
}
 
 
void kbd_keyboardkey(unsigned int keycode, unsigned int up_flag)
void kbd_keyboardkey(unsigned int keycode, unsigned int up_flag)
{
{
        kbd_processkey(keycode, up_flag, 0);
        kbd_processkey(keycode, up_flag, 0);
}
}
 
 
static void put_queue (int ch)
static void put_queue (int ch)
{
{
        wake_up (&keypress_wait);
        wake_up (&keypress_wait);
        if (tty) {
        if (tty) {
                tty_insert_flip_char (tty, ch, 0);
                tty_insert_flip_char (tty, ch, 0);
                tty_schedule_flip (tty);
                tty_schedule_flip (tty);
        }
        }
}
}
 
 
static void puts_queue(char *cp)
static void puts_queue(char *cp)
{
{
        wake_up (&keypress_wait);
        wake_up (&keypress_wait);
        if (!tty)
        if (!tty)
                return;
                return;
 
 
        while (*cp) {
        while (*cp) {
                tty_insert_flip_char (tty, *cp, 0);
                tty_insert_flip_char (tty, *cp, 0);
                cp++;
                cp++;
        }
        }
        tty_schedule_flip (tty);
        tty_schedule_flip (tty);
}
}
 
 
static void show_stack (void)
static void show_stack (void)
{
{
        unsigned long *p;
        unsigned long *p;
        unsigned long *q = (unsigned long *)((int)current->kernel_stack_page + 4096);
        unsigned long *q = (unsigned long *)((int)current->kernel_stack_page + 4096);
        int i;
        int i;
        __asm__("mov %0, sp\n\t": "=r" (p));
        __asm__("mov %0, sp\n\t": "=r" (p));
 
 
        for (i = 0; p < q; p++, i++) {
        for (i = 0; p < q; p++, i++) {
                if(i && !(i & 7))
                if(i && !(i & 7))
                        printk("\n");
                        printk("\n");
                printk("%08lX ", *p);
                printk("%08lX ", *p);
        }
        }
}
}
 
 
static void applkey(int key, char mode)
static void applkey(int key, char mode)
{
{
        static char buf[] = { 0x1b, 'O', 0x00, 0x00};
        static char buf[] = { 0x1b, 'O', 0x00, 0x00};
 
 
        buf[1] = (mode ? 'O' : '[');
        buf[1] = (mode ? 'O' : '[');
        buf[2] = key;
        buf[2] = key;
        puts_queue(buf);
        puts_queue(buf);
}
}
 
 
static void enter(void)
static void enter(void)
{
{
        put_queue (13);
        put_queue (13);
        if (vc_kbd_mode(kbd, VC_CRLF))
        if (vc_kbd_mode(kbd, VC_CRLF))
                put_queue (10);
                put_queue (10);
}
}
 
 
static void caps_toggle(void)
static void caps_toggle(void)
{
{
        if(rep)
        if(rep)
                return;
                return;
        chg_vc_kbd_led(kbd, VC_CAPSLOCK);
        chg_vc_kbd_led(kbd, VC_CAPSLOCK);
}
}
 
 
static void caps_on (void)
static void caps_on (void)
{
{
        if (rep)
        if (rep)
                return;
                return;
        set_vc_kbd_led (kbd, VC_CAPSLOCK);
        set_vc_kbd_led (kbd, VC_CAPSLOCK);
}
}
 
 
static void show_ptregs (void)
static void show_ptregs (void)
{
{
        if (pt_regs)
        if (pt_regs)
                show_regs (pt_regs);
                show_regs (pt_regs);
}
}
 
 
static void hold (void)
static void hold (void)
{
{
        if(rep || !tty)
        if(rep || !tty)
                return;
                return;
 
 
        /*
        /*
         * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
         * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
         * these routines are also activated by ^S/^Q.
         * these routines are also activated by ^S/^Q.
         * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
         * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
         */
         */
        if (tty->stopped)
        if (tty->stopped)
                start_tty (tty);
                start_tty (tty);
        else
        else
                stop_tty (tty);
                stop_tty (tty);
}
}
 
 
static void num (void)
static void num (void)
{
{
        if(vc_kbd_mode(kbd,VC_APPLIC))
        if(vc_kbd_mode(kbd,VC_APPLIC))
                applkey('P', 1);
                applkey('P', 1);
        else
        else
                bare_num ();
                bare_num ();
}
}
 
 
/*
/*
 * Bind this to Shift-NumLock if you work in application keypad mode
 * Bind this to Shift-NumLock if you work in application keypad mode
 * but want to be able to change the NumLock flag.
 * but want to be able to change the NumLock flag.
 * Bind this to NumLock if you prefer that the NumLock key always
 * Bind this to NumLock if you prefer that the NumLock key always
 * changes the NumLock flag.
 * changes the NumLock flag.
 */
 */
static void bare_num (void)
static void bare_num (void)
{
{
        if (!rep)
        if (!rep)
                chg_vc_kbd_led (kbd, VC_NUMLOCK);
                chg_vc_kbd_led (kbd, VC_NUMLOCK);
}
}
 
 
static void lastcons (void)
static void lastcons (void)
{
{
        /* switch to the last used console, ChN */
        /* switch to the last used console, ChN */
        set_console(last_console);
        set_console(last_console);
}
}
 
 
static void decr_console (void)
static void decr_console (void)
{
{
        int i;
        int i;
        int fgnum = vtdata.fgconsole->num - 1;
        int fgnum = vtdata.fgconsole->num - 1;
 
 
        for (i = fgnum - 1; i != fgnum; i--) {
        for (i = fgnum - 1; i != fgnum; i--) {
                if (i == -1)
                if (i == -1)
                        i = MAX_NR_CONSOLES - 1;
                        i = MAX_NR_CONSOLES - 1;
                if (vt_allocated (vt_con_data + i))
                if (vt_allocated (vt_con_data + i))
                        break;
                        break;
        }
        }
        set_console(vt_con_data + i);
        set_console(vt_con_data + i);
}
}
 
 
static void incr_console (void)
static void incr_console (void)
{
{
        int i;
        int i;
        int fgnum = vtdata.fgconsole->num - 1;
        int fgnum = vtdata.fgconsole->num - 1;
 
 
        for (i = fgnum + 1; i != fgnum; i++) {
        for (i = fgnum + 1; i != fgnum; i++) {
                if (i == MAX_NR_CONSOLES)
                if (i == MAX_NR_CONSOLES)
                        i = 0;
                        i = 0;
                if (vt_allocated (vt_con_data + i))
                if (vt_allocated (vt_con_data + i))
                        break;
                        break;
        }
        }
        set_console(vt_con_data + i);
        set_console(vt_con_data + i);
}
}
 
 
static void send_intr (void)
static void send_intr (void)
{
{
        if (!tty)
        if (!tty)
                return;
                return;
        tty_insert_flip_char (tty, 0, TTY_BREAK);
        tty_insert_flip_char (tty, 0, TTY_BREAK);
        tty_schedule_flip (tty);
        tty_schedule_flip (tty);
}
}
 
 
static void scroll_forw (void)
static void scroll_forw (void)
{
{
        scrollfront(0);
        scrollfront(0);
}
}
 
 
static void scroll_back (void)
static void scroll_back (void)
{
{
        scrollback(0);
        scrollback(0);
}
}
 
 
static void boot_it (void)
static void boot_it (void)
{
{
        ctrl_alt_del();
        ctrl_alt_del();
}
}
 
 
static void compose (void)
static void compose (void)
{
{
        dead_key_next = 1;
        dead_key_next = 1;
}
}
 
 
int spawnpid, spawnsig;
int spawnpid, spawnsig;
 
 
static void spawn_console (void)
static void spawn_console (void)
{
{
        if (spawnpid)
        if (spawnpid)
                if (kill_proc (spawnpid, spawnsig, 1))
                if (kill_proc (spawnpid, spawnsig, 1))
                        spawnpid = 0;
                        spawnpid = 0;
}
}
 
 
static void SAK (void)
static void SAK (void)
{
{
        do_SAK(tty);
        do_SAK(tty);
#if 0
#if 0
        /*
        /*
         * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and
         * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and
         * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK
         * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK
         * handling.
         * handling.
         *
         *
         * We should do this some day --- the whole point of a secure
         * We should do this some day --- the whole point of a secure
         * attention key is that it should be guaranteed to always
         * attention key is that it should be guaranteed to always
         * work.
         * work.
         */
         */
        vt_reset (vtdata.fgconsole);
        vt_reset (vtdata.fgconsole);
        do_unblank_screen ();   /* not in interrupt routine? */
        do_unblank_screen ();   /* not in interrupt routine? */
#endif
#endif
}
}
 
 
static void do_ignore (unsigned char value, char up_flag)
static void do_ignore (unsigned char value, char up_flag)
{
{
}
}
 
 
static void do_null (void)
static void do_null (void)
{
{
        compute_shiftstate ();
        compute_shiftstate ();
}
}
 
 
static void do_spec (unsigned char value,char up_flag)
static void do_spec (unsigned char value,char up_flag)
{
{
        if (up_flag)
        if (up_flag)
                return;
                return;
        if (value >= SIZE(spec_fn_table))
        if (value >= SIZE(spec_fn_table))
                return;
                return;
        spec_fn_table[value] ();
        spec_fn_table[value] ();
}
}
 
 
static void do_lowercase (unsigned char value, char up_flag)
static void do_lowercase (unsigned char value, char up_flag)
{
{
        printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n");
        printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n");
}
}
 
 
static void do_self(unsigned char value, char up_flag)
static void do_self(unsigned char value, char up_flag)
{
{
        if (up_flag)
        if (up_flag)
                return;         /* no action, if this is a key release */
                return;         /* no action, if this is a key release */
 
 
        if (diacr)
        if (diacr)
                value = handle_diacr (value);
                value = handle_diacr (value);
 
 
        if (dead_key_next) {
        if (dead_key_next) {
                dead_key_next = 0;
                dead_key_next = 0;
                diacr = value;
                diacr = value;
                return;
                return;
        }
        }
 
 
        put_queue (value);
        put_queue (value);
}
}
 
 
#define A_GRAVE '`'
#define A_GRAVE '`'
#define A_ACUTE '\''
#define A_ACUTE '\''
#define A_CFLEX '^'
#define A_CFLEX '^'
#define A_TILDE '~'
#define A_TILDE '~'
#define A_DIAER '"'
#define A_DIAER '"'
#define A_CEDIL ','
#define A_CEDIL ','
static unsigned char ret_diacr[] =
static unsigned char ret_diacr[] =
        {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL };
        {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL };
 
 
/* If a dead key pressed twice, output a character corresponding to it, */
/* If a dead key pressed twice, output a character corresponding to it, */
/* otherwise just remember the dead key.                                */
/* otherwise just remember the dead key.                                */
 
 
static void do_dead(unsigned char value, char up_flag)
static void do_dead(unsigned char value, char up_flag)
{
{
        if (up_flag)
        if (up_flag)
                return;
                return;
 
 
        value = ret_diacr[value];
        value = ret_diacr[value];
        if (diacr == value) { /* pressed twice */
        if (diacr == value) { /* pressed twice */
                diacr = 0;
                diacr = 0;
                put_queue (value);
                put_queue (value);
                return;
                return;
        }
        }
        diacr = value;
        diacr = value;
}
}
 
 
 
 
/* If space is pressed, return the character corresponding the pending  */
/* If space is pressed, return the character corresponding the pending  */
/* dead key, otherwise try to combine the two.                          */
/* dead key, otherwise try to combine the two.                          */
 
 
static unsigned char handle_diacr(unsigned char ch)
static unsigned char handle_diacr(unsigned char ch)
{
{
        int d = diacr;
        int d = diacr;
        int i;
        int i;
 
 
        diacr = 0;
        diacr = 0;
        if (ch == ' ')
        if (ch == ' ')
                return d;
                return d;
 
 
        for (i = 0; i < accent_table_size; i++) {
        for (i = 0; i < accent_table_size; i++) {
                if (accent_table[i].diacr == d && accent_table[i].base == ch)
                if (accent_table[i].diacr == d && accent_table[i].base == ch)
                    return accent_table[i].result;
                    return accent_table[i].result;
        }
        }
 
 
        put_queue (d);
        put_queue (d);
        return ch;
        return ch;
}
}
 
 
static void do_cons(unsigned char value, char up_flag)
static void do_cons(unsigned char value, char up_flag)
{
{
        if (up_flag)
        if (up_flag)
                return;
                return;
        set_console(vt_con_data + value);
        set_console(vt_con_data + value);
}
}
 
 
static void do_fn(unsigned char value, char up_flag)
static void do_fn(unsigned char value, char up_flag)
{
{
        if (up_flag)
        if (up_flag)
                return;
                return;
        if (value < SIZE(func_table)) {
        if (value < SIZE(func_table)) {
                if (func_table[value])
                if (func_table[value])
                        puts_queue (func_table[value]);
                        puts_queue (func_table[value]);
        } else
        } else
                printk (KERN_ERR "do_fn called with value=%d\n",value);
                printk (KERN_ERR "do_fn called with value=%d\n",value);
}
}
 
 
static void do_pad(unsigned char value, char up_flag)
static void do_pad(unsigned char value, char up_flag)
{
{
        static const char *pad_chars = "0123456789+-*/\015,.?#";
        static const char *pad_chars = "0123456789+-*/\015,.?#";
        static const char *app_map = "pqrstuvwxylmRQMnn?S";
        static const char *app_map = "pqrstuvwxylmRQMnn?S";
 
 
        if (up_flag)
        if (up_flag)
                return;         /* no action, if this is a key release */
                return;         /* no action, if this is a key release */
 
 
        /* kludge... shift forces cursor/number keys */
        /* kludge... shift forces cursor/number keys */
        if (vc_kbd_mode (kbd, VC_APPLIC) && !k_down[KG_SHIFT]) {
        if (vc_kbd_mode (kbd, VC_APPLIC) && !k_down[KG_SHIFT]) {
                applkey (app_map[value], 1);
                applkey (app_map[value], 1);
                return;
                return;
        }
        }
 
 
        if (!vc_kbd_led (kbd,VC_NUMLOCK))
        if (!vc_kbd_led (kbd,VC_NUMLOCK))
                switch (value) {
                switch (value) {
                        case KVAL(K_PCOMMA):
                        case KVAL(K_PCOMMA):
                        case KVAL(K_PDOT):
                        case KVAL(K_PDOT):
                                do_fn (KVAL(K_REMOVE), 0);
                                do_fn (KVAL(K_REMOVE), 0);
                                return;
                                return;
                        case KVAL(K_P0):
                        case KVAL(K_P0):
                                do_fn (KVAL(K_INSERT), 0);
                                do_fn (KVAL(K_INSERT), 0);
                                return;
                                return;
                        case KVAL(K_P1):
                        case KVAL(K_P1):
                                do_fn (KVAL(K_SELECT), 0);
                                do_fn (KVAL(K_SELECT), 0);
                                return;
                                return;
                        case KVAL(K_P2):
                        case KVAL(K_P2):
                                do_cur(KVAL(K_DOWN), 0);
                                do_cur(KVAL(K_DOWN), 0);
                                return;
                                return;
                        case KVAL(K_P3):
                        case KVAL(K_P3):
                                do_fn (KVAL(K_PGDN), 0);
                                do_fn (KVAL(K_PGDN), 0);
                                return;
                                return;
                        case KVAL(K_P4):
                        case KVAL(K_P4):
                                do_cur(KVAL(K_LEFT), 0);
                                do_cur(KVAL(K_LEFT), 0);
                                return;
                                return;
                        case KVAL(K_P6):
                        case KVAL(K_P6):
                                do_cur(KVAL(K_RIGHT), 0);
                                do_cur(KVAL(K_RIGHT), 0);
                                return;
                                return;
                        case KVAL(K_P7):
                        case KVAL(K_P7):
                                do_fn (KVAL(K_FIND), 0);
                                do_fn (KVAL(K_FIND), 0);
                                return;
                                return;
                        case KVAL(K_P8):
                        case KVAL(K_P8):
                                do_cur(KVAL(K_UP), 0);
                                do_cur(KVAL(K_UP), 0);
                                return;
                                return;
                        case KVAL(K_P9):
                        case KVAL(K_P9):
                                do_fn (KVAL(K_PGUP), 0);
                                do_fn (KVAL(K_PGUP), 0);
                                return;
                                return;
                        case KVAL(K_P5):
                        case KVAL(K_P5):
                                applkey('G',vc_kbd_mode(kbd, VC_APPLIC));
                                applkey('G',vc_kbd_mode(kbd, VC_APPLIC));
                                return;
                                return;
        }
        }
 
 
        put_queue (pad_chars[value]);
        put_queue (pad_chars[value]);
        if (value == KVAL(K_PENTER) && vc_kbd_mode (kbd, VC_CRLF))
        if (value == KVAL(K_PENTER) && vc_kbd_mode (kbd, VC_CRLF))
                put_queue (10);
                put_queue (10);
}
}
 
 
static void do_cur(unsigned char value, char up_flag)
static void do_cur(unsigned char value, char up_flag)
{
{
        static const char *cur_chars = "BDCA";
        static const char *cur_chars = "BDCA";
        if (up_flag)
        if (up_flag)
                return;
                return;
 
 
        applkey (cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
        applkey (cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
}
}
 
 
static void do_shift(unsigned char value, char up_flag)
static void do_shift(unsigned char value, char up_flag)
{
{
    int old_state = shift_state;
    int old_state = shift_state;
 
 
    if (rep)
    if (rep)
        return;
        return;
 
 
    /* Mimic typewriter: a CapsShift key acts like Shift but undoes CapsLock */
    /* Mimic typewriter: a CapsShift key acts like Shift but undoes CapsLock */
    if (value == KVAL(K_CAPSSHIFT)) {
    if (value == KVAL(K_CAPSSHIFT)) {
        value = KVAL(K_SHIFT);
        value = KVAL(K_SHIFT);
        if (!up_flag)
        if (!up_flag)
            clr_vc_kbd_led (kbd, VC_CAPSLOCK);
            clr_vc_kbd_led (kbd, VC_CAPSLOCK);
    }
    }
 
 
    if(up_flag) {
    if(up_flag) {
        /* handle the case that two shift or control
        /* handle the case that two shift or control
           keys are depressed simultaneously */
           keys are depressed simultaneously */
        if(k_down[value])
        if(k_down[value])
            k_down[value]--;
            k_down[value]--;
    } else
    } else
        k_down[value]++;
        k_down[value]++;
 
 
    if(k_down[value])
    if(k_down[value])
        shift_state |= (1 << value);
        shift_state |= (1 << value);
    else
    else
        shift_state &= ~ (1 << value);
        shift_state &= ~ (1 << value);
 
 
    /* kludge */
    /* kludge */
    if(up_flag && shift_state != old_state && npadch != -1) {
    if(up_flag && shift_state != old_state && npadch != -1) {
        if(kbd->kbdmode == VC_UNICODE)
        if(kbd->kbdmode == VC_UNICODE)
            to_utf8(npadch & 0xffff);
            to_utf8(npadch & 0xffff);
        else
        else
            put_queue(npadch & 0xff);
            put_queue(npadch & 0xff);
        npadch = -1;
        npadch = -1;
    }
    }
}
}
 
 
/*
/*
 * Called after returning from RAW mode or when changing consoles -
 * Called after returning from RAW mode or when changing consoles -
 * recompute k_down[] and shift_state from key_down[]
 * recompute k_down[] and shift_state from key_down[]
 * Maybe called when keymap is undefined so that shift key release is seen
 * Maybe called when keymap is undefined so that shift key release is seen
 */
 */
void compute_shiftstate(void)
void compute_shiftstate(void)
{
{
        int i, j, k, sym, val;
        int i, j, k, sym, val;
 
 
        shift_state = 0;
        shift_state = 0;
        for (i = 0; i < SIZE(k_down); i++)
        for (i = 0; i < SIZE(k_down); i++)
                k_down[i] = 0;
                k_down[i] = 0;
 
 
        for (i = 0; i < SIZE(key_down); i++)
        for (i = 0; i < SIZE(key_down); i++)
                if (key_down[i]) {      /* skip this word if not a single bit on */
                if (key_down[i]) {      /* skip this word if not a single bit on */
                        k = i * BITS_PER_LONG;
                        k = i * BITS_PER_LONG;
                        for (j = 0; j < BITS_PER_LONG; j++, k++)
                        for (j = 0; j < BITS_PER_LONG; j++, k++)
                                if (test_bit (k, key_down)) {
                                if (test_bit (k, key_down)) {
                                        sym = U(plain_map[k]);
                                        sym = U(plain_map[k]);
                                        if (KTYP(sym) == KT_SHIFT) {
                                        if (KTYP(sym) == KT_SHIFT) {
                                                val = KVAL (sym);
                                                val = KVAL (sym);
                                                if (val == KVAL(K_CAPSSHIFT))
                                                if (val == KVAL(K_CAPSSHIFT))
                                                        val = KVAL(K_SHIFT);
                                                        val = KVAL(K_SHIFT);
                                                k_down[val] ++;
                                                k_down[val] ++;
                                                shift_state |= (1 << val);
                                                shift_state |= (1 << val);
                                        }
                                        }
                                }
                                }
                }
                }
}
}
 
 
static void do_meta(unsigned char value, char up_flag)
static void do_meta(unsigned char value, char up_flag)
{
{
        if(up_flag)
        if(up_flag)
                return;
                return;
 
 
        if(vc_kbd_mode(kbd, VC_META)) {
        if(vc_kbd_mode(kbd, VC_META)) {
                put_queue ('\033');
                put_queue ('\033');
                put_queue (value);
                put_queue (value);
        } else
        } else
                put_queue (value | 0x80);
                put_queue (value | 0x80);
}
}
 
 
static void do_ascii(unsigned char value, char up_flag)
static void do_ascii(unsigned char value, char up_flag)
{
{
        int base;
        int base;
 
 
        if (up_flag)
        if (up_flag)
                return;
                return;
 
 
        if (value < 10) /* decimal input of code, while Alt depressed */
        if (value < 10) /* decimal input of code, while Alt depressed */
                base = 10;
                base = 10;
        else {          /* hexadecimal input of code, while AltGr depressed */
        else {          /* hexadecimal input of code, while AltGr depressed */
                value -= 10;
                value -= 10;
                base = 16;
                base = 16;
        }
        }
 
 
        if(npadch == -1)
        if(npadch == -1)
                npadch = value;
                npadch = value;
        else
        else
                npadch = npadch * base + value;
                npadch = npadch * base + value;
}
}
 
 
static void do_lock (unsigned char value, char up_flag)
static void do_lock (unsigned char value, char up_flag)
{
{
    if (up_flag || rep)
    if (up_flag || rep)
        return;
        return;
    chg_vc_kbd_lock (kbd, value);
    chg_vc_kbd_lock (kbd, value);
}
}
 
 
static void do_slock (unsigned char value, char up_flag)
static void do_slock (unsigned char value, char up_flag)
{
{
    if (up_flag || rep)
    if (up_flag || rep)
        return;
        return;
    chg_vc_kbd_slock (kbd, value);
    chg_vc_kbd_slock (kbd, value);
}
}
 
 
/*
/*
 * The leds display either
 * The leds display either
 * (i)   The status of NumLock, CapsLock and ScrollLock.
 * (i)   The status of NumLock, CapsLock and ScrollLock.
 * (ii)  Whatever pattern of lights people wait to show using KDSETLED.
 * (ii)  Whatever pattern of lights people wait to show using KDSETLED.
 * (iii) Specified bits of specified words in kernel memory.
 * (iii) Specified bits of specified words in kernel memory.
 */
 */
 
 
static unsigned char ledstate = 0xff; /* undefined */
static unsigned char ledstate = 0xff; /* undefined */
static unsigned char ledioctl;
static unsigned char ledioctl;
 
 
unsigned char getledstate(void)
unsigned char getledstate(void)
{
{
    return ledstate;
    return ledstate;
}
}
 
 
void setledstate(struct kbd_struct *kbd, unsigned int led)
void setledstate(struct kbd_struct *kbd, unsigned int led)
{
{
    if(!(led & ~7)) {
    if(!(led & ~7)) {
        ledioctl = led;
        ledioctl = led;
        kbd->ledmode = LED_SHOW_IOCTL;
        kbd->ledmode = LED_SHOW_IOCTL;
    } else
    } else
        kbd->ledmode = LED_SHOW_FLAGS;
        kbd->ledmode = LED_SHOW_FLAGS;
    set_leds();
    set_leds();
}
}
 
 
static struct ledptr {
static struct ledptr {
    unsigned int *addr;
    unsigned int *addr;
    unsigned int mask;
    unsigned int mask;
    unsigned char valid:1;
    unsigned char valid:1;
} ledptrs[3];
} ledptrs[3];
 
 
void register_leds(int console, unsigned int led,
void register_leds(int console, unsigned int led,
                  unsigned int *addr, unsigned int mask)
                  unsigned int *addr, unsigned int mask)
{
{
    struct kbd_struct *kbd = vt_con_data[console].kbd;
    struct kbd_struct *kbd = vt_con_data[console].kbd;
    if(led < 3) {
    if(led < 3) {
        ledptrs[led].addr = addr;
        ledptrs[led].addr = addr;
        ledptrs[led].mask = mask;
        ledptrs[led].mask = mask;
        ledptrs[led].valid= 1;
        ledptrs[led].valid= 1;
        kbd->ledmode = LED_SHOW_MEM;
        kbd->ledmode = LED_SHOW_MEM;
    } else
    } else
        kbd->ledmode = LED_SHOW_FLAGS;
        kbd->ledmode = LED_SHOW_FLAGS;
}
}
 
 
static inline unsigned char getleds(void)
static inline unsigned char getleds(void)
{
{
    struct kbd_struct *kbd = vtdata.fgconsole->kbd;
    struct kbd_struct *kbd = vtdata.fgconsole->kbd;
    unsigned char leds;
    unsigned char leds;
 
 
    if(kbd->ledmode == LED_SHOW_IOCTL)
    if(kbd->ledmode == LED_SHOW_IOCTL)
        return ledioctl;
        return ledioctl;
    leds = kbd->ledflagstate;
    leds = kbd->ledflagstate;
    if (kbd->ledmode == LED_SHOW_MEM) {
    if (kbd->ledmode == LED_SHOW_MEM) {
        if (ledptrs[0].valid) {
        if (ledptrs[0].valid) {
            if (*ledptrs[0].addr & ledptrs[0].mask)
            if (*ledptrs[0].addr & ledptrs[0].mask)
                leds |= 1;
                leds |= 1;
            else
            else
                leds &= ~1;
                leds &= ~1;
        }
        }
        if (ledptrs[1].valid) {
        if (ledptrs[1].valid) {
            if (*ledptrs[1].addr & ledptrs[1].mask)
            if (*ledptrs[1].addr & ledptrs[1].mask)
                leds |= 2;
                leds |= 2;
            else
            else
                leds &= ~2;
                leds &= ~2;
        }
        }
        if (ledptrs[2].valid) {
        if (ledptrs[2].valid) {
            if(*ledptrs[2].addr & ledptrs[2].mask)
            if(*ledptrs[2].addr & ledptrs[2].mask)
                leds |= 4;
                leds |= 4;
            else
            else
                leds &= ~4;
                leds &= ~4;
        }
        }
    }
    }
    return leds;
    return leds;
}
}
 
 
/*
/*
 * This routine is the bottom half of the keyboard interrupt
 * This routine is the bottom half of the keyboard interrupt
 * routine, and runs with all interrupts enabled.  It does
 * routine, and runs with all interrupts enabled.  It does
 * console changing, led setting and copy_to_cooked, which can
 * console changing, led setting and copy_to_cooked, which can
 * take a reasonably long time.
 * take a reasonably long time.
 *
 *
 * Aside from timing (which isn't really that important for
 * Aside from timing (which isn't really that important for
 * keyboard interrupts as they happen often), using the software
 * keyboard interrupts as they happen often), using the software
 * interrupt routines for this thing allows us to easily mask
 * interrupt routines for this thing allows us to easily mask
 * this when we don't want any of the above to happen.  Not yet
 * this when we don't want any of the above to happen.  Not yet
 * used, but this allows for easy and efficient race-condition
 * used, but this allows for easy and efficient race-condition
 * prevention later on.
 * prevention later on.
 */
 */
static void kbd_bh(void)
static void kbd_bh(void)
{
{
        unsigned char leds = getleds();
        unsigned char leds = getleds();
 
 
        tty = *vtdata.fgconsole->tty;
        tty = *vtdata.fgconsole->tty;
        kbd = vtdata.fgconsole->kbd;
        kbd = vtdata.fgconsole->kbd;
 
 
        if (rep) {
        if (rep) {
                /*
                /*
                 * This prevents the kbd_key routine from being called
                 * This prevents the kbd_key routine from being called
                 * twice, once by this BH, and once by the interrupt
                 * twice, once by this BH, and once by the interrupt
                 * routine.  Maybe we should put the key press in a
                 * routine.  Maybe we should put the key press in a
                 * buffer or variable, and then call the BH...
                 * buffer or variable, and then call the BH...
                 */
                 */
                disable_irq (IRQ_KEYBOARDRX);
                disable_irq (IRQ_KEYBOARDRX);
                if (kbd_repeatkey != -1)
                if (kbd_repeatkey != -1)
                        kbd_processkey (kbd_repeatkey, 0, 1);
                        kbd_processkey (kbd_repeatkey, 0, 1);
                enable_irq (IRQ_KEYBOARDRX);
                enable_irq (IRQ_KEYBOARDRX);
                rep = 0;
                rep = 0;
        }
        }
 
 
        if (leds != ledstate) {
        if (leds != ledstate) {
                ledstate = leds;
                ledstate = leds;
                kbd_drv_setleds(leds);
                kbd_drv_setleds(leds);
        }
        }
}
}
 
 
/*
/*
 * Initialise a kbd struct
 * Initialise a kbd struct
 */
 */
int kbd_struct_init (struct vt *vt, int init)
int kbd_struct_init (struct vt *vt, int init)
{
{
        vt->kbd->ledflagstate = vt->kbd->default_ledflagstate = KBD_DEFLEDS;
        vt->kbd->ledflagstate = vt->kbd->default_ledflagstate = KBD_DEFLEDS;
        vt->kbd->ledmode = LED_SHOW_FLAGS;
        vt->kbd->ledmode = LED_SHOW_FLAGS;
        vt->kbd->lockstate = KBD_DEFLOCK;
        vt->kbd->lockstate = KBD_DEFLOCK;
        vt->kbd->slockstate = 0;
        vt->kbd->slockstate = 0;
        vt->kbd->modeflags = KBD_DEFMODE;
        vt->kbd->modeflags = KBD_DEFMODE;
        vt->kbd->kbdmode = VC_XLATE;
        vt->kbd->kbdmode = VC_XLATE;
        return 0;
        return 0;
}
}
 
 
int kbd_ioctl (struct vt *vt, int cmd, unsigned long arg)
int kbd_ioctl (struct vt *vt, int cmd, unsigned long arg)
{
{
    asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
    asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
    int i;
    int i;
 
 
    switch (cmd) {
    switch (cmd) {
    case KDGKBTYPE:
    case KDGKBTYPE:
        /*
        /*
         * This is naive.
         * This is naive.
         */
         */
        i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned char));
        i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned char));
        if (!i)
        if (!i)
            put_user (KB_101, (char *)arg);
            put_user (KB_101, (char *)arg);
        return i;
        return i;
 
 
    case KDADDIO:
    case KDADDIO:
    case KDDELIO:
    case KDDELIO:
        /*
        /*
         * KDADDIO and KDDELIO may be able to add ports beyond what
         * KDADDIO and KDDELIO may be able to add ports beyond what
         * we reject here, but to be safe...
         * we reject here, but to be safe...
         */
         */
        if (arg < GPFIRST || arg > GPLAST)
        if (arg < GPFIRST || arg > GPLAST)
            return -EINVAL;
            return -EINVAL;
        return sys_ioperm (arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
        return sys_ioperm (arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
 
 
    case KDENABIO:
    case KDENABIO:
    case KDDISABIO:
    case KDDISABIO:
        return sys_ioperm (GPFIRST, GPLAST, (cmd == KDENABIO)) ? -ENXIO : 0;
        return sys_ioperm (GPFIRST, GPLAST, (cmd == KDENABIO)) ? -ENXIO : 0;
 
 
    case KDMAPDISP:
    case KDMAPDISP:
    case KDUNMAPDISP:
    case KDUNMAPDISP:
        /*
        /*
         * These work like a combination of mmap and KDENABIO.
         * These work like a combination of mmap and KDENABIO.
         * this could easily be finished.
         * this could easily be finished.
         */
         */
        return -EINVAL;
        return -EINVAL;
 
 
    case KDSKBMODE:
    case KDSKBMODE:
        switch (arg) {
        switch (arg) {
        case K_RAW:
        case K_RAW:
            vt->kbd->kbdmode = VC_RAW;
            vt->kbd->kbdmode = VC_RAW;
            break;
            break;
        case K_MEDIUMRAW:
        case K_MEDIUMRAW:
            vt->kbd->kbdmode = VC_MEDIUMRAW;
            vt->kbd->kbdmode = VC_MEDIUMRAW;
            break;
            break;
        case K_XLATE:
        case K_XLATE:
            vt->kbd->kbdmode = VC_XLATE;
            vt->kbd->kbdmode = VC_XLATE;
            compute_shiftstate ();
            compute_shiftstate ();
            break;
            break;
        case K_UNICODE:
        case K_UNICODE:
            vt->kbd->kbdmode = VC_UNICODE;
            vt->kbd->kbdmode = VC_UNICODE;
            compute_shiftstate ();
            compute_shiftstate ();
            break;
            break;
        default:
        default:
            return -EINVAL;
            return -EINVAL;
        }
        }
        if (tty->ldisc.flush_buffer)
        if (tty->ldisc.flush_buffer)
            tty->ldisc.flush_buffer (*vt->tty);
            tty->ldisc.flush_buffer (*vt->tty);
        return 0;
        return 0;
 
 
    case KDGKBMODE:
    case KDGKBMODE:
        i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned long));
        i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned long));
        if (!i) {
        if (!i) {
            int ucval;
            int ucval;
            ucval = ((vt->kbd->kbdmode == VC_RAW) ? K_RAW :
            ucval = ((vt->kbd->kbdmode == VC_RAW) ? K_RAW :
                     (vt->kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
                     (vt->kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
                     (vt->kbd->kbdmode == VC_UNICODE) ? K_UNICODE : K_XLATE);
                     (vt->kbd->kbdmode == VC_UNICODE) ? K_UNICODE : K_XLATE);
            put_user (ucval, (int *)arg);
            put_user (ucval, (int *)arg);
        }
        }
        return i;
        return i;
 
 
    case KDSKBMETA:
    case KDSKBMETA:
        /*
        /*
         * this could be folded into KDSKBMODE, but for compatibility
         * this could be folded into KDSKBMODE, but for compatibility
         * reasons, it is not so easy to fold kDGKBMETA into KDGKBMODE.
         * reasons, it is not so easy to fold kDGKBMETA into KDGKBMODE.
         */
         */
        switch (arg) {
        switch (arg) {
        case K_METABIT:
        case K_METABIT:
            clr_vc_kbd_mode (vt->kbd, VC_META);
            clr_vc_kbd_mode (vt->kbd, VC_META);
            break;
            break;
        case K_ESCPREFIX:
        case K_ESCPREFIX:
            set_vc_kbd_mode (vt->kbd, VC_META);
            set_vc_kbd_mode (vt->kbd, VC_META);
            break;
            break;
        default:
        default:
            return -EINVAL;
            return -EINVAL;
        }
        }
        return 0;
        return 0;
 
 
    case KDGKBMETA:
    case KDGKBMETA:
        i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned long));
        i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned long));
        if (!i) {
        if (!i) {
            int ucval;
            int ucval;
            ucval = (vc_kbd_mode (vt->kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
            ucval = (vc_kbd_mode (vt->kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
            put_user (ucval, (int *)arg);
            put_user (ucval, (int *)arg);
        }
        }
        return i;
        return i;
 
 
    case KDGETKEYCODE: {
    case KDGETKEYCODE: {
        struct kbkeycode *const a = (struct kbkeycode *)arg;
        struct kbkeycode *const a = (struct kbkeycode *)arg;
 
 
        i = verify_area (VERIFY_WRITE, a, sizeof (struct kbkeycode));
        i = verify_area (VERIFY_WRITE, a, sizeof (struct kbkeycode));
        if (!i) {
        if (!i) {
            unsigned int sc;
            unsigned int sc;
 
 
            sc = get_user (&a->scancode);
            sc = get_user (&a->scancode);
            i = getkeycode (sc);
            i = getkeycode (sc);
            if (i > 0)
            if (i > 0)
                put_user (i, &a->keycode);
                put_user (i, &a->keycode);
            i = 0;
            i = 0;
        }
        }
        return i;
        return i;
        }
        }
 
 
    case KDSETKEYCODE: {
    case KDSETKEYCODE: {
        struct kbkeycode *const a = (struct kbkeycode *)arg;
        struct kbkeycode *const a = (struct kbkeycode *)arg;
 
 
        i = verify_area (VERIFY_READ, a, sizeof (struct kbkeycode));
        i = verify_area (VERIFY_READ, a, sizeof (struct kbkeycode));
        if (!i) {
        if (!i) {
            unsigned int sc, kc;
            unsigned int sc, kc;
            sc = get_user (&a->scancode);
            sc = get_user (&a->scancode);
            kc = get_user (&a->keycode);
            kc = get_user (&a->keycode);
            i = setkeycode (sc, kc);
            i = setkeycode (sc, kc);
        }
        }
        return i;
        return i;
        }
        }
 
 
    case KDGKBENT: {
    case KDGKBENT: {
        struct kbentry *const a = (struct kbentry *)arg;
        struct kbentry *const a = (struct kbentry *)arg;
 
 
        i = verify_area (VERIFY_WRITE, a, sizeof (struct kbentry));
        i = verify_area (VERIFY_WRITE, a, sizeof (struct kbentry));
        if (!i) {
        if (!i) {
            ushort *keymap, val;
            ushort *keymap, val;
            u_char s;
            u_char s;
            i = get_user (&a->kb_index);
            i = get_user (&a->kb_index);
            if (i >= NR_KEYS)
            if (i >= NR_KEYS)
                return -EINVAL;
                return -EINVAL;
            s = get_user (&a->kb_table);
            s = get_user (&a->kb_table);
            if (s >= MAX_NR_KEYMAPS)
            if (s >= MAX_NR_KEYMAPS)
                return -EINVAL;
                return -EINVAL;
            keymap = key_maps[s];
            keymap = key_maps[s];
            if (keymap) {
            if (keymap) {
                val = U(keymap[i]);
                val = U(keymap[i]);
                if (vt->kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
                if (vt->kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
                    val = K_HOLE;
                    val = K_HOLE;
            } else
            } else
                val = (i ? K_HOLE : K_NOSUCHMAP);
                val = (i ? K_HOLE : K_NOSUCHMAP);
            put_user (val, &a->kb_value);
            put_user (val, &a->kb_value);
            i = 0;
            i = 0;
        }
        }
        return i;
        return i;
        }
        }
 
 
    case KDSKBENT: {
    case KDSKBENT: {
        struct kbentry *const a = (struct kbentry *)arg;
        struct kbentry *const a = (struct kbentry *)arg;
 
 
        i = verify_area (VERIFY_WRITE, a, sizeof (struct kbentry));
        i = verify_area (VERIFY_WRITE, a, sizeof (struct kbentry));
        if (!i) {
        if (!i) {
            ushort *key_map;
            ushort *key_map;
            u_char s;
            u_char s;
            u_short v, ov;
            u_short v, ov;
 
 
            if ((i = get_user(&a->kb_index)) >= NR_KEYS)
            if ((i = get_user(&a->kb_index)) >= NR_KEYS)
                return -EINVAL;
                return -EINVAL;
            if ((s = get_user(&a->kb_table)) >= MAX_NR_KEYMAPS)
            if ((s = get_user(&a->kb_table)) >= MAX_NR_KEYMAPS)
                return -EINVAL;
                return -EINVAL;
            v = get_user(&a->kb_value);
            v = get_user(&a->kb_value);
            if (!i && v == K_NOSUCHMAP) {
            if (!i && v == K_NOSUCHMAP) {
                /* disallocate map */
                /* disallocate map */
                key_map = key_maps[s];
                key_map = key_maps[s];
                if (s && key_map) {
                if (s && key_map) {
                    key_maps[s] = 0;
                    key_maps[s] = 0;
                    if (key_map[0] == U(K_ALLOCATED)) {
                    if (key_map[0] == U(K_ALLOCATED)) {
                        kfree_s(key_map, sizeof(plain_map));
                        kfree_s(key_map, sizeof(plain_map));
                        keymap_count--;
                        keymap_count--;
                    }
                    }
                }
                }
                return 0;
                return 0;
            }
            }
 
 
            if (KTYP(v) < NR_TYPES) {
            if (KTYP(v) < NR_TYPES) {
                if (KVAL(v) > max_vals[KTYP(v)])
                if (KVAL(v) > max_vals[KTYP(v)])
                    return -EINVAL;
                    return -EINVAL;
            } else
            } else
                if (kbd->kbdmode != VC_UNICODE)
                if (kbd->kbdmode != VC_UNICODE)
                    return -EINVAL;
                    return -EINVAL;
 
 
            /* assignment to entry 0 only tests validity of args */
            /* assignment to entry 0 only tests validity of args */
            if (!i)
            if (!i)
                return 0;
                return 0;
 
 
            if (!(key_map = key_maps[s])) {
            if (!(key_map = key_maps[s])) {
                int j;
                int j;
 
 
                if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && !suser())
                if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && !suser())
                    return -EPERM;
                    return -EPERM;
 
 
                key_map = (ushort *) kmalloc(sizeof(plain_map),
                key_map = (ushort *) kmalloc(sizeof(plain_map),
                                             GFP_KERNEL);
                                             GFP_KERNEL);
                if (!key_map)
                if (!key_map)
                    return -ENOMEM;
                    return -ENOMEM;
                key_maps[s] = key_map;
                key_maps[s] = key_map;
                key_map[0] = U(K_ALLOCATED);
                key_map[0] = U(K_ALLOCATED);
                for (j = 1; j < NR_KEYS; j++)
                for (j = 1; j < NR_KEYS; j++)
                    key_map[j] = U(K_HOLE);
                    key_map[j] = U(K_HOLE);
                keymap_count++;
                keymap_count++;
            }
            }
            ov = U(key_map[i]);
            ov = U(key_map[i]);
            if (v == ov)
            if (v == ov)
                return 0;        /* nothing to do */
                return 0;        /* nothing to do */
            /*
            /*
             * Only the Superuser can set or unset the Secure
             * Only the Superuser can set or unset the Secure
             * Attention Key.
             * Attention Key.
             */
             */
            if (((ov == K_SAK) || (v == K_SAK)) && !suser())
            if (((ov == K_SAK) || (v == K_SAK)) && !suser())
                return -EPERM;
                return -EPERM;
            key_map[i] = U(v);
            key_map[i] = U(v);
            if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
            if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
                compute_shiftstate();
                compute_shiftstate();
            return 0;
            return 0;
        }
        }
        return i;
        return i;
        }
        }
 
 
    case KDGKBSENT: {
    case KDGKBSENT: {
        struct kbsentry *a = (struct kbsentry *)arg;
        struct kbsentry *a = (struct kbsentry *)arg;
        char *p;
        char *p;
        u_char *q;
        u_char *q;
        int sz;
        int sz;
 
 
        i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
        i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
        if (i)
        if (i)
            return i;
            return i;
        if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC || i < 0)
        if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC || i < 0)
            return -EINVAL;
            return -EINVAL;
        sz = sizeof(a->kb_string) - 1; /* sz should have been
        sz = sizeof(a->kb_string) - 1; /* sz should have been
                                          a struct member */
                                          a struct member */
        q = a->kb_string;
        q = a->kb_string;
        p = func_table[i];
        p = func_table[i];
        if(p)
        if(p)
            for ( ; *p && sz; p++, sz--)
            for ( ; *p && sz; p++, sz--)
                put_user(*p, q++);
                put_user(*p, q++);
        put_user('\0', q);
        put_user('\0', q);
        return ((p && *p) ? -EOVERFLOW : 0);
        return ((p && *p) ? -EOVERFLOW : 0);
        }
        }
 
 
    case KDSKBSENT: {
    case KDSKBSENT: {
        struct kbsentry * const a = (struct kbsentry *)arg;
        struct kbsentry * const a = (struct kbsentry *)arg;
        int delta;
        int delta;
        char *first_free, *fj, *fnw;
        char *first_free, *fj, *fnw;
        int j, k, sz;
        int j, k, sz;
        u_char *p;
        u_char *p;
        char *q;
        char *q;
 
 
        i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
        i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
        if (i)
        if (i)
            return i;
            return i;
        if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC)
        if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC)
            return -EINVAL;
            return -EINVAL;
        q = func_table[i];
        q = func_table[i];
 
 
        first_free = funcbufptr + (funcbufsize - funcbufleft);
        first_free = funcbufptr + (funcbufsize - funcbufleft);
        for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) ;
        for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) ;
        if (j < MAX_NR_FUNC)
        if (j < MAX_NR_FUNC)
            fj = func_table[j];
            fj = func_table[j];
        else
        else
            fj = first_free;
            fj = first_free;
 
 
        delta = (q ? -strlen(q) : 1);
        delta = (q ? -strlen(q) : 1);
        sz = sizeof(a->kb_string);      /* sz should have been
        sz = sizeof(a->kb_string);      /* sz should have been
                                           a struct member */
                                           a struct member */
        for (p = a->kb_string; get_user(p) && sz; p++,sz--)
        for (p = a->kb_string; get_user(p) && sz; p++,sz--)
            delta++;
            delta++;
        if (!sz)
        if (!sz)
            return -EOVERFLOW;
            return -EOVERFLOW;
        if (delta <= funcbufleft) {     /* it fits in current buf */
        if (delta <= funcbufleft) {     /* it fits in current buf */
            if (j < MAX_NR_FUNC) {
            if (j < MAX_NR_FUNC) {
                memmove(fj + delta, fj, first_free - fj);
                memmove(fj + delta, fj, first_free - fj);
                for (k = j; k < MAX_NR_FUNC; k++)
                for (k = j; k < MAX_NR_FUNC; k++)
                    if (func_table[k])
                    if (func_table[k])
                        func_table[k] += delta;
                        func_table[k] += delta;
            }
            }
            if (!q)
            if (!q)
                func_table[i] = fj;
                func_table[i] = fj;
            funcbufleft -= delta;
            funcbufleft -= delta;
        } else {                        /* allocate a larger buffer */
        } else {                        /* allocate a larger buffer */
            sz = 256;
            sz = 256;
            while (sz < funcbufsize - funcbufleft + delta)
            while (sz < funcbufsize - funcbufleft + delta)
                sz <<= 1;
                sz <<= 1;
            fnw = (char *) kmalloc(sz, GFP_KERNEL);
            fnw = (char *) kmalloc(sz, GFP_KERNEL);
            if(!fnw)
            if(!fnw)
                return -ENOMEM;
                return -ENOMEM;
 
 
            if (!q)
            if (!q)
                func_table[i] = fj;
                func_table[i] = fj;
            if (fj > funcbufptr)
            if (fj > funcbufptr)
                memmove(fnw, funcbufptr, fj - funcbufptr);
                memmove(fnw, funcbufptr, fj - funcbufptr);
            for (k = 0; k < j; k++)
            for (k = 0; k < j; k++)
                if (func_table[k])
                if (func_table[k])
                    func_table[k] = fnw + (func_table[k] - funcbufptr);
                    func_table[k] = fnw + (func_table[k] - funcbufptr);
 
 
            if (first_free > fj) {
            if (first_free > fj) {
                memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
                memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
                for (k = j; k < MAX_NR_FUNC; k++)
                for (k = j; k < MAX_NR_FUNC; k++)
                    if (func_table[k])
                    if (func_table[k])
                        func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
                        func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
            }
            }
            if (funcbufptr != func_buf)
            if (funcbufptr != func_buf)
                kfree_s(funcbufptr, funcbufsize);
                kfree_s(funcbufptr, funcbufsize);
            funcbufptr = fnw;
            funcbufptr = fnw;
            funcbufleft = funcbufleft - delta + sz - funcbufsize;
            funcbufleft = funcbufleft - delta + sz - funcbufsize;
            funcbufsize = sz;
            funcbufsize = sz;
        }
        }
        for (p = a->kb_string, q = func_table[i]; ; p++, q++)
        for (p = a->kb_string, q = func_table[i]; ; p++, q++)
            if (!(*q = get_user(p)))
            if (!(*q = get_user(p)))
                break;
                break;
        return 0;
        return 0;
        }
        }
 
 
    case KDGKBDIACR: {
    case KDGKBDIACR: {
        struct kbdiacrs *a = (struct kbdiacrs *)arg;
        struct kbdiacrs *a = (struct kbdiacrs *)arg;
 
 
        i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs));
        i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs));
        if (i)
        if (i)
            return i;
            return i;
        put_user(accent_table_size, &a->kb_cnt);
        put_user(accent_table_size, &a->kb_cnt);
        memcpy_tofs(a->kbdiacr, accent_table,
        memcpy_tofs(a->kbdiacr, accent_table,
                    accent_table_size*sizeof(struct kbdiacr));
                    accent_table_size*sizeof(struct kbdiacr));
        return 0;
        return 0;
        }
        }
 
 
    case KDSKBDIACR: {
    case KDSKBDIACR: {
        struct kbdiacrs *a = (struct kbdiacrs *)arg;
        struct kbdiacrs *a = (struct kbdiacrs *)arg;
        unsigned int ct;
        unsigned int ct;
 
 
        i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
        i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
        if (i)
        if (i)
            return i;
            return i;
        ct = get_user(&a->kb_cnt);
        ct = get_user(&a->kb_cnt);
        if (ct >= MAX_DIACR)
        if (ct >= MAX_DIACR)
            return -EINVAL;
            return -EINVAL;
        accent_table_size = ct;
        accent_table_size = ct;
        memcpy_fromfs(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr));
        memcpy_fromfs(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr));
        return 0;
        return 0;
        }
        }
 
 
    /* the ioctls below read/set the flags usually shown in the leds */
    /* the ioctls below read/set the flags usually shown in the leds */
    /* don't use them - they will go away without warning */
    /* don't use them - they will go away without warning */
    case KDGKBLED:
    case KDGKBLED:
        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
        if (i)
        if (i)
            return i;
            return i;
        put_user(vt->kbd->ledflagstate |
        put_user(vt->kbd->ledflagstate |
                    (vt->kbd->default_ledflagstate << 4), (char *) arg);
                    (vt->kbd->default_ledflagstate << 4), (char *) arg);
        return 0;
        return 0;
 
 
    case KDSKBLED:
    case KDSKBLED:
        if (arg & ~0x77)
        if (arg & ~0x77)
            return -EINVAL;
            return -EINVAL;
        vt->kbd->ledflagstate = (arg & 7);
        vt->kbd->ledflagstate = (arg & 7);
        vt->kbd->default_ledflagstate = ((arg >> 4) & 7);
        vt->kbd->default_ledflagstate = ((arg >> 4) & 7);
        set_leds ();
        set_leds ();
        return 0;
        return 0;
 
 
    /* the ioctls below only set the lights, not the functions */
    /* the ioctls below only set the lights, not the functions */
    /* for those, see KDGKBLED and KDSKBLED above */
    /* for those, see KDGKBLED and KDSKBLED above */
    case KDGETLED:
    case KDGETLED:
        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
        i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
        if (i)
        if (i)
                return i;
                return i;
        put_user(getledstate(), (char *) arg);
        put_user(getledstate(), (char *) arg);
        return 0;
        return 0;
 
 
    case KDSETLED:
    case KDSETLED:
        setledstate(kbd, arg);
        setledstate(kbd, arg);
        return 0;
        return 0;
 
 
    /*
    /*
     * A process can indicate its willingness to accept signals
     * A process can indicate its willingness to accept signals
     * generated by pressing an appropriate key combination.
     * generated by pressing an appropriate key combination.
     * Thus, one can have a daemon that e.g. spawns a new console
     * Thus, one can have a daemon that e.g. spawns a new console
     * upon a keypess and then changes to it.
     * upon a keypess and then changes to it.
     * Probably init should be changed to do this (and have a
     * Probably init should be changed to do this (and have a
     * field ks (`keyboard signal') in inittab describing the
     * field ks (`keyboard signal') in inittab describing the
     * desired acion), so that the number of background daemons
     * desired acion), so that the number of background daemons
     * does not increase.
     * does not increase.
     */
     */
    case KDSIGACCEPT: {
    case KDSIGACCEPT: {
        if (arg < 1 || arg > NSIG || arg == SIGKILL)
        if (arg < 1 || arg > NSIG || arg == SIGKILL)
            return -EINVAL;
            return -EINVAL;
        spawnpid = current->pid;
        spawnpid = current->pid;
        spawnsig = arg;
        spawnsig = arg;
        return 0;
        return 0;
        }
        }
    default:
    default:
        return -ENOIOCTLCMD;
        return -ENOIOCTLCMD;
    }
    }
}
}
 
 
int kbd_init (void)
int kbd_init (void)
{
{
        int ret;
        int ret;
        init_bh(KEYBOARD_BH, kbd_bh);
        init_bh(KEYBOARD_BH, kbd_bh);
        ret = kbd_drv_init();
        ret = kbd_drv_init();
        mark_bh(KEYBOARD_BH);
        mark_bh(KEYBOARD_BH);
        return ret;
        return ret;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.