source: rtems/c/src/lib/libbsp/i386/pc386/console/keyboard.c @ 3cbb63a

4.104.114.84.95
Last change on this file since 3cbb63a was 3cbb63a, checked in by Joel Sherrill <joel.sherrill@…>, on 08/30/00 at 08:15:30

2000-08-26 Rosimildo da Silva <rdasilva@…>

  • Major rework of the "/dev/console" driver.
  • Added termios support for stdin ( keyboard ).
  • Added ioctls() to support modes similar to Linux( XLATE, RAW, MEDIUMRAW ).
  • Added Keyboard mapping and handling of the keyboard's leds.
  • Added Micro FrameBuffer? driver ( "/dev/fb0" ) for bare VGA controller ( 16 colors ).
  • Added PS/2 and Serial mouse support for PC386 BSP.
  • console/defkeymap.c: New file.
  • console/fb_vga.c: New file.
  • console/fb_vga.h: New file.
  • console/i386kbd.h: New file.
  • console/kd.h: New file.
  • console/keyboard.c: New file.
  • console/keyboard.h: New file.
  • console/mouse_parser.c: New file.
  • console/mouse_parser.h: New file.
  • console/pc_keyb.c: New file.
  • console/ps2_drv.h: New file.
  • console/ps2_mouse.c: New file.
  • console/ps2_mouse.h: New file.
  • console/serial_mouse.c: New file.
  • console/serial_mouse.h: New file.
  • console/vgainit.c: New file.
  • console/vt.c: New file.
  • console/Makefile.am: Reflect new files.
  • console/console.c, console/inch.c, console/outch.c: Console functionality modifications.
  • startup/Makefile.am: Pick up tty_drv.c and gdb_glue.c
  • Property mode set to 100644
File size: 19.8 KB
Line 
1/*
2 * linux/drivers/char/keyboard.c
3 *
4 * Written for linux by Johan Myreen as a translation from
5 * the assembly version by Linus (with diacriticals added)
6 *
7 * Some additional features added by Christoph Niemann (ChN), March 1993
8 *
9 * Loadable keymaps by Risto Kankkunen, May 1993
10 *
11 * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
12 * Added decr/incr_console, dynamic keymaps, Unicode support,
13 * dynamic function/string keys, led setting,  Sept 1994
14 * `Sticky' modifier keys, 951006.
15 *
16 * 11-11-96: SAK should now work in the raw mode (Martin Mares)
17 *
18 * Modified to provide 'generic' keyboard support by Hamish Macdonald
19 * Merge with the m68k keyboard driver and split-off of the PC low-level
20 * parts by Geert Uytterhoeven, May 1997
21 *
22 * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
23 * 30-07-98: Dead keys redone, aeb@cwi.nl.
24 * -------------------------------------------------------------------
25 * End of Linux - Copyright notes...
26 *
27 * Ported to RTEMS to provide the basic fuctionality to the console driver.
28 * by: Rosimildo da Silva:  rdasilva@connecttel.com
29 *
30 */
31
32#include <sys/types.h>
33#include <rtems/keyboard.h>
34#include "i386kbd.h"
35#include <rtems/kd.h>
36#include <bsp.h>
37
38#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
39
40#ifndef KBD_DEFMODE
41#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
42#endif
43
44#ifndef KBD_DEFLEDS
45/*
46 * Some laptops take the 789uiojklm,. keys as number pad when NumLock
47 * is on. This seems a good reason to start with NumLock off.
48 */
49#define KBD_DEFLEDS 0
50#endif
51
52#ifndef KBD_DEFLOCK
53#define KBD_DEFLOCK 0
54#endif
55
56extern void add_to_queue( unsigned short );
57extern void rtemsReboot( void );
58
59
60
61int set_bit(int nr, unsigned long * addr)
62{
63        int     mask, retval;
64
65        addr += nr >> 5;
66        mask = 1 << (nr & 0x1f);
67        cli();
68        retval = (mask & *addr) != 0;
69        *addr |= mask;
70        sti();
71        return retval;
72}
73
74int clear_bit(int nr, unsigned long * addr)
75{
76        int     mask, retval;
77
78        addr += nr >> 5;
79        mask = 1 << (nr & 0x1f);
80        cli();
81        retval = (mask & *addr) != 0;
82        *addr &= ~mask;
83        sti();
84        return retval;
85}
86
87int test_bit(int nr, unsigned long * addr)
88{
89        int     mask;
90
91        addr += nr >> 5;
92        mask = 1 << (nr & 0x1f);
93        return ((mask & *addr) != 0);
94}
95
96#define  test_and_set_bit(x,y)      set_bit(x,y)
97#define  test_and_clear_bit(x,y)    clear_bit(x,y)
98
99
100/*
101 * global state includes the following, and various static variables
102 * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
103 * (last_console is now a global variable)
104 */
105#define  BITS_PER_LONG  32
106
107/* shift state counters.. */
108static unsigned char k_down[NR_SHIFT] = {0, };
109/* keyboard key bitmap */
110static unsigned long key_down[256/BITS_PER_LONG] = { 0, };
111
112static int dead_key_next = 0;
113/*
114 * In order to retrieve the shift_state (for the mouse server), either
115 * the variable must be global, or a new procedure must be created to
116 * return the value. I chose the former way.
117 */
118int shift_state = 0;
119static int npadch = -1;                 /* -1 or number assembled on pad */
120static unsigned char diacr = 0;
121static char rep = 0;                    /* flag telling character repeat */
122
123/* default console for RTEMS */
124static int  fg_console = 0;
125
126
127struct kbd_struct kbd_table[MAX_NR_CONSOLES];
128static struct kbd_struct * kbd = kbd_table;
129
130void compute_shiftstate(void);
131
132typedef void (*k_hand)(unsigned char value, char up_flag);
133typedef void (k_handfn)(unsigned char value, char up_flag);
134
135static k_handfn
136        do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
137        do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2,
138        do_ignore;
139
140static k_hand key_handler[16] = {
141        do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
142        do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2,
143        do_ignore, do_ignore
144};
145
146/* Key types processed even in raw modes */
147
148#define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT))
149
150typedef void (*void_fnp)(void);
151typedef void (void_fn)(void);
152
153
154static void show_mem(void)
155{
156}
157static void show_state(void)
158{
159}
160
161static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
162        num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
163        SAK, decr_console, incr_console, spawn_console, bare_num;
164
165static void_fnp spec_fn_table[] = {
166        do_null,        enter,          show_ptregs,    show_mem,
167        show_state,     send_intr,      lastcons,       caps_toggle,
168        num,            hold,           scroll_forw,    scroll_back,
169        boot_it,        caps_on,        compose,        SAK,
170        decr_console,   incr_console,   spawn_console,  bare_num
171};
172
173#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK))
174
175/* maximum values each key_handler can handle */
176const int max_vals[] = {
177        255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
178        NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
179        255, NR_ASCII - 1, NR_LOCK - 1, 255,
180        NR_LOCK - 1, 255
181};
182
183const int NR_TYPES = SIZE(max_vals);
184
185/* N.B. drivers/macintosh/mac_keyb.c needs to call put_queue */
186static void put_queue(int);
187static unsigned char handle_diacr(unsigned char);
188
189#ifdef CONFIG_MAGIC_SYSRQ
190static int sysrq_pressed;
191#endif
192
193/*
194 * Many other routines do put_queue, but I think either
195 * they produce ASCII, or they produce some user-assigned
196 * string, and in both cases we might assume that it is
197 * in utf-8 already.
198 */
199void to_utf8(ushort c) {
200    if (c < 0x80)
201        put_queue(c);                   /*  0*******  */
202    else if (c < 0x800) {
203        put_queue(0xc0 | (c >> 6));     /*  110***** 10******  */
204        put_queue(0x80 | (c & 0x3f));
205    } else {
206        put_queue(0xe0 | (c >> 12));    /*  1110**** 10****** 10******  */
207        put_queue(0x80 | ((c >> 6) & 0x3f));
208        put_queue(0x80 | (c & 0x3f));
209    }
210    /* UTF-8 is defined for words of up to 31 bits,
211       but we need only 16 bits here */
212}
213
214
215/*
216 * Translation of escaped scancodes to keycodes.
217 * This is now user-settable (for machines were it makes sense).
218 */
219
220int setkeycode(unsigned int scancode, unsigned int keycode)
221{
222    return kbd_setkeycode(scancode, keycode);
223}
224
225int getkeycode(unsigned int scancode)
226{
227    return kbd_getkeycode(scancode);
228}
229
230void handle_scancode(unsigned char scancode, int down)
231{
232        unsigned char keycode;
233        char up_flag = down ? 0 : 0200;
234        char raw_mode;
235
236        mark_bh(CONSOLE_BH);
237
238#if 0
239        tty = ttytab? ttytab[fg_console]: NULL;
240        if (tty && (!tty->driver_data)) {
241                /*
242                 * We touch the tty structure via the the ttytab array
243                 * without knowing whether or not tty is open, which
244                 * is inherently dangerous.  We currently rely on that
245                 * fact that console_open sets tty->driver_data when
246                 * it opens it, and clears it when it closes it.
247                 */
248                tty = NULL;
249        }
250#endif
251
252        kbd = kbd_table + fg_console;
253        if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
254                put_queue(scancode | up_flag);
255                /* we do not return yet, because we want to maintain
256                   the key_down array, so that we have the correct
257                   values when finishing RAW mode or when changing VT's */
258        }
259
260        /*
261         *  Convert scancode to keycode
262         */
263        if (!kbd_translate(scancode, &keycode, raw_mode))
264            return;
265
266        /*
267         * At this point the variable `keycode' contains the keycode.
268         * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid).
269         * We keep track of the up/down status of the key, and
270         * return the keycode if in MEDIUMRAW mode.
271         */
272
273        if (up_flag) {
274                rep = 0;
275                if(!test_and_clear_bit(keycode, key_down))
276                    up_flag = kbd_unexpected_up(keycode);
277        } else
278                rep = test_and_set_bit(keycode, key_down);
279
280
281#ifdef CONFIG_MAGIC_SYSRQ               /* Handle the SysRq Hack */
282        if (keycode == SYSRQ_KEY) {
283                sysrq_pressed = !up_flag;
284                return;
285        } else if (sysrq_pressed) {
286                if (!up_flag && sysrq_enabled)
287                        handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
288                return;
289        }
290#endif
291
292
293        if (kbd->kbdmode == VC_MEDIUMRAW) {
294                /* soon keycodes will require more than one byte */
295                put_queue(keycode + up_flag);
296                raw_mode = 1;   /* Most key classes will be ignored */
297        }
298        /*
299         * Small change in philosophy: earlier we defined repetition by
300         *       rep = keycode == prev_keycode;
301         *       prev_keycode = keycode;
302         * but now by the fact that the depressed key was down already.
303         * Does this ever make a difference? Yes.
304         */
305
306        /*
307         *  Repeat a key only if the input buffers are empty or the
308         *  characters get echoed locally. This makes key repeat usable
309         *  with slow applications and under heavy loads.
310         */
311        if (!rep || vc_kbd_mode(kbd,VC_REPEAT) ) {
312/*
313        ||  (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
314             (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) {
315*/
316                u_short keysym;
317                u_char type;
318
319                /* the XOR below used to be an OR */
320                int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
321                ushort *key_map = key_maps[shift_final];
322
323
324                if (key_map != NULL) {
325                        keysym = key_map[keycode];
326                        type = KTYP(keysym);
327
328                        if (type >= 0xf0) {
329                            type -= 0xf0;
330                            if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type)))
331                                return;
332                    if (type == KT_LETTER) {
333                                type = KT_LATIN;
334                                if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
335                                    key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
336                                    if (key_map)
337                                      keysym = key_map[keycode];
338                                }
339                            }
340
341                            (*key_handler[type])(keysym & 0xff, up_flag);
342
343                            if (type != KT_SLOCK)
344                              kbd->slockstate = 0;
345
346                        } else {
347                            /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
348                            if (!up_flag && !raw_mode)
349                              to_utf8(keysym);
350                        }
351                } else {
352                        /* maybe beep? */
353                        /* we have at least to update shift_state */
354#if 1                   /* how? two almost equivalent choices follow */
355                        compute_shiftstate();
356#else
357                        keysym = U(plain_map[keycode]);
358                        type = KTYP(keysym);
359                        if (type == KT_SHIFT)
360                          (*key_handler[type])(keysym & 0xff, up_flag);
361#endif
362                }
363        }
364}
365
366static void ( *driver_input_handler_kbd )( void *, unsigned short, unsigned long ) = 0;
367/*
368 */
369void kbd_set_driver_handler( void ( *handler )( void *, unsigned short, unsigned long ) )
370{
371  driver_input_handler_kbd = handler;
372}
373
374static void put_queue(int ch)
375{
376  if( driver_input_handler_kbd )
377  {
378     driver_input_handler_kbd(  ( void *)kbd, (unsigned short)ch,  0 );
379  }
380  else
381  {
382     add_to_queue( ch );
383  }
384}
385
386
387static void puts_queue(char *cp)
388{
389        while (*cp) {
390     put_queue( *cp );
391                cp++;
392        }
393}
394
395static void applkey(int key, char mode)
396{
397        static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
398
399        buf[1] = (mode ? 'O' : '[');
400        buf[2] = key;
401        puts_queue(buf);
402}
403
404static void enter(void)
405{
406        if (diacr) {
407                put_queue(diacr);
408                diacr = 0;
409        }
410        put_queue(13);
411
412        if (vc_kbd_mode(kbd,VC_CRLF))
413                put_queue(10);
414
415}
416
417static void caps_toggle(void)
418{
419        if (rep)
420                return;
421        chg_vc_kbd_led(kbd, VC_CAPSLOCK);
422}
423
424static void caps_on(void)
425{
426        if (rep)
427                return;
428        set_vc_kbd_led(kbd, VC_CAPSLOCK);
429}
430
431static void show_ptregs(void)
432{
433}
434
435static void hold(void)
436{
437        if (rep )
438                return;
439   chg_vc_kbd_led(kbd, VC_SCROLLOCK );
440
441}
442
443static void num(void)
444{
445
446        if (vc_kbd_mode(kbd,VC_APPLIC))
447                applkey('P', 1);
448        else
449                bare_num();
450}
451
452/*
453 * Bind this to Shift-NumLock if you work in application keypad mode
454 * but want to be able to change the NumLock flag.
455 * Bind this to NumLock if you prefer that the NumLock key always
456 * changes the NumLock flag.
457 */
458static void bare_num(void)
459{
460        if (!rep)
461                chg_vc_kbd_led(kbd,VC_NUMLOCK);
462}
463
464static void lastcons(void)
465{
466}
467
468static void decr_console(void)
469{
470}
471
472static void incr_console(void)
473{
474}
475
476static void send_intr(void)
477{
478}
479
480static void scroll_forw(void)
481{
482}
483
484static void scroll_back(void)
485{
486}
487
488static void boot_it(void)
489{
490   printk( "boot_it() " );
491   rtemsReboot();
492}
493
494static void compose(void)
495{
496        dead_key_next = 1;
497}
498
499int spawnpid, spawnsig;
500
501static void spawn_console(void)
502{
503}
504
505static void SAK(void)
506{
507}
508
509static void do_ignore(unsigned char value, char up_flag)
510{
511}
512
513static void do_null()
514{
515        compute_shiftstate();
516}
517
518static void do_spec(unsigned char value, char up_flag)
519{
520        if (up_flag)
521                return;
522        if (value >= SIZE(spec_fn_table))
523                return;
524
525        if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) &&
526            !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value)))
527                return;
528
529        spec_fn_table[value]();
530}
531
532static void do_lowercase(unsigned char value, char up_flag)
533{
534}
535
536static void do_self(unsigned char value, char up_flag)
537{
538        if (up_flag)
539                return;         /* no action, if this is a key release */
540
541        if (diacr)
542                value = handle_diacr(value);
543
544        if (dead_key_next) {
545                dead_key_next = 0;
546                diacr = value;
547                return;
548        }
549        put_queue(value);
550}
551
552#define A_GRAVE  '`'
553#define A_ACUTE  '\''
554#define A_CFLEX  '^'
555#define A_TILDE  '~'
556#define A_DIAER  '"'
557#define A_CEDIL  ','
558static unsigned char ret_diacr[NR_DEAD] =
559        {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL };
560
561/* Obsolete - for backwards compatibility only */
562static void do_dead(unsigned char value, char up_flag)
563{
564        value = ret_diacr[value];
565   printk( " do_dead( %X ) ", value );
566        do_dead2(value,up_flag);
567}
568
569/*
570 * Handle dead key. Note that we now may have several
571 * dead keys modifying the same character. Very useful
572 * for Vietnamese.
573 */
574static void do_dead2(unsigned char value, char up_flag)
575{
576        if (up_flag)
577                return;
578        diacr = (diacr ? handle_diacr(value) : value);
579}
580
581
582/*
583 * We have a combining character DIACR here, followed by the character CH.
584 * If the combination occurs in the table, return the corresponding value.
585 * Otherwise, if CH is a space or equals DIACR, return DIACR.
586 * Otherwise, conclude that DIACR was not combining after all,
587 * queue it and return CH.
588 */
589unsigned char handle_diacr(unsigned char ch)
590{
591        int d = diacr;
592        int i;
593
594        diacr = 0;
595
596        for (i = 0; i < accent_table_size; i++) {
597                if (accent_table[i].diacr == d && accent_table[i].base == ch)
598                        return accent_table[i].result;
599        }
600        if (ch == ' ' || ch == d)
601                return d;
602
603        put_queue(d);
604        return ch;
605}
606
607static void do_cons(unsigned char value, char up_flag)
608{
609        if (up_flag)
610                return;
611}
612
613static void do_fn(unsigned char value, char up_flag)
614{
615        if (up_flag)
616                return;
617
618        if (value < SIZE(func_table)) {
619                if (func_table[value])
620                        puts_queue(func_table[value]);
621        } else
622                printk( "do_fn called with value=%d\n", value);
623}
624
625static void do_pad(unsigned char value, char up_flag)
626{
627        static const char *pad_chars = "0123456789+-*/\015,.?()";
628        static const char *app_map = "pqrstuvwxylSRQMnnmPQ";
629
630        if (up_flag)
631                return;         /* no action, if this is a key release */
632
633        /* kludge... shift forces cursor/number keys */
634        if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
635                applkey(app_map[value], 1);
636                return;
637        }
638        if (!vc_kbd_led(kbd,VC_NUMLOCK))
639                switch (value) {
640                        case KVAL(K_PCOMMA):
641                        case KVAL(K_PDOT):
642                                do_fn(KVAL(K_REMOVE), 0);
643                                return;
644                        case KVAL(K_P0):
645                                do_fn(KVAL(K_INSERT), 0);
646                                return;
647                        case KVAL(K_P1):
648                                do_fn(KVAL(K_SELECT), 0);
649                                return;
650                        case KVAL(K_P2):
651                                do_cur(KVAL(K_DOWN), 0);
652                                return;
653                        case KVAL(K_P3):
654                                do_fn(KVAL(K_PGDN), 0);
655                                return;
656                        case KVAL(K_P4):
657                                do_cur(KVAL(K_LEFT), 0);
658                                return;
659                        case KVAL(K_P6):
660                                do_cur(KVAL(K_RIGHT), 0);
661                                return;
662                        case KVAL(K_P7):
663                                do_fn(KVAL(K_FIND), 0);
664                                return;
665                        case KVAL(K_P8):
666                                do_cur(KVAL(K_UP), 0);
667                                return;
668                        case KVAL(K_P9):
669                                do_fn(KVAL(K_PGUP), 0);
670                                return;
671                        case KVAL(K_P5):
672                                applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
673                                return;
674                }
675
676        put_queue(pad_chars[value]);
677
678        if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
679                put_queue(10);
680
681}
682
683static void do_cur(unsigned char value, char up_flag)
684{
685        static const char *cur_chars = "BDCA";
686        if (up_flag)
687                return;
688
689  applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
690}
691
692static void do_shift(unsigned char value, char up_flag)
693{
694        int old_state = shift_state;
695
696        if (rep)
697                return;
698
699        /* Mimic typewriter:
700           a CapsShift key acts like Shift but undoes CapsLock */
701        if (value == KVAL(K_CAPSSHIFT)) {
702                value = KVAL(K_SHIFT);
703                if (!up_flag)
704                        clr_vc_kbd_led(kbd, VC_CAPSLOCK);
705        }
706
707        if (up_flag) {
708                /* handle the case that two shift or control
709                   keys are depressed simultaneously */
710                if (k_down[value])
711                        k_down[value]--;
712        } else
713                k_down[value]++;
714
715        if (k_down[value])
716                shift_state |= (1 << value);
717        else
718                shift_state &= ~ (1 << value);
719
720        /* kludge */
721        if (up_flag && shift_state != old_state && npadch != -1) {
722                if (kbd->kbdmode == VC_UNICODE)
723                  to_utf8(npadch & 0xffff);
724                else
725           put_queue(npadch & 0xff);
726                npadch = -1;
727        }
728}
729
730/* called after returning from RAW mode or when changing consoles -
731   recompute k_down[] and shift_state from key_down[] */
732/* maybe called when keymap is undefined, so that shiftkey release is seen */
733void compute_shiftstate(void)
734{
735        int i, j, k, sym, val;
736
737        shift_state = 0;
738        for(i=0; i < SIZE(k_down); i++)
739          k_down[i] = 0;
740
741        for(i=0; i < SIZE(key_down); i++)
742          if(key_down[i]) {     /* skip this word if not a single bit on */
743            k = i*BITS_PER_LONG;
744            for(j=0; j<BITS_PER_LONG; j++,k++)
745              if(test_bit(k, key_down)) {
746                sym = U(plain_map[k]);
747                if(KTYP(sym) == KT_SHIFT) {
748                  val = KVAL(sym);
749                  if (val == KVAL(K_CAPSSHIFT))
750                    val = KVAL(K_SHIFT);
751                  k_down[val]++;
752                  shift_state |= (1<<val);
753                }
754              }
755          }
756}
757
758static void do_meta(unsigned char value, char up_flag)
759{
760        if (up_flag)
761                return;
762
763        if (vc_kbd_mode(kbd, VC_META)) {
764                put_queue('\033');
765                put_queue(value);
766        } else
767                put_queue(value | 0x80);
768}
769
770static void do_ascii(unsigned char value, char up_flag)
771{
772        int base;
773
774        if (up_flag)
775                return;
776
777        if (value < 10)    /* decimal input of code, while Alt depressed */
778            base = 10;
779        else {       /* hexadecimal input of code, while AltGr depressed */
780            value -= 10;
781            base = 16;
782        }
783
784        if (npadch == -1)
785          npadch = value;
786        else
787          npadch = npadch * base + value;
788}
789
790static void do_lock(unsigned char value, char up_flag)
791{
792        if (up_flag || rep)
793                return;
794        chg_vc_kbd_lock(kbd, value);
795}
796
797static void do_slock(unsigned char value, char up_flag)
798{
799        if (up_flag || rep)
800                return;
801
802  chg_vc_kbd_slock(kbd, value);
803}
804
805/*
806 * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
807 * or (ii) whatever pattern of lights people want to show using KDSETLED,
808 * or (iii) specified bits of specified words in kernel memory.
809 */
810
811static unsigned char ledstate = 0xff; /* undefined */
812static unsigned char ledioctl;
813
814unsigned char getledstate(void) {
815    return ledstate;
816}
817
818void setledstate(struct kbd_struct *kbd, unsigned int led) {
819    if (!(led & ~7)) {
820        ledioctl = led;
821         kbd->ledmode = LED_SHOW_IOCTL;
822    } else
823    ;
824         kbd->ledmode = LED_SHOW_FLAGS;
825    set_leds();
826}
827
828static struct ledptr {
829    unsigned int *addr;
830    unsigned int mask;
831    unsigned char valid:1;
832} ledptrs[3];
833
834void register_leds(int console, unsigned int led,
835                   unsigned int *addr, unsigned int mask) {
836    struct kbd_struct *kbd = kbd_table + console;
837
838   if (led < 3) {
839        ledptrs[led].addr = addr;
840        ledptrs[led].mask = mask;
841        ledptrs[led].valid = 1;
842        kbd->ledmode = LED_SHOW_MEM;
843    } else
844        kbd->ledmode = LED_SHOW_FLAGS;
845}
846
847static inline unsigned char getleds(void){
848
849
850    struct kbd_struct *kbd = kbd_table + fg_console;
851
852    unsigned char leds;
853
854    if (kbd->ledmode == LED_SHOW_IOCTL)
855      return ledioctl;
856    leds = kbd->ledflagstate;
857    if (kbd->ledmode == LED_SHOW_MEM) {
858        if (ledptrs[0].valid) {
859            if (*ledptrs[0].addr & ledptrs[0].mask)
860              leds |= 1;
861            else
862              leds &= ~1;
863        }
864        if (ledptrs[1].valid) {
865            if (*ledptrs[1].addr & ledptrs[1].mask)
866              leds |= 2;
867            else
868              leds &= ~2;
869        }
870        if (ledptrs[2].valid) {
871            if (*ledptrs[2].addr & ledptrs[2].mask)
872              leds |= 4;
873            else
874              leds &= ~4;
875        }
876    }
877   return leds;
878}
879
880/*
881 * This routine is the bottom half of the keyboard interrupt
882 * routine, and runs with all interrupts enabled. It does
883 * console changing, led setting and copy_to_cooked, which can
884 * take a reasonably long time.
885 *
886 * Aside from timing (which isn't really that important for
887 * keyboard interrupts as they happen often), using the software
888 * interrupt routines for this thing allows us to easily mask
889 * this when we don't want any of the above to happen. Not yet
890 * used, but this allows for easy and efficient race-condition
891 * prevention later on.
892 */
893static void kbd_bh(void)
894{
895        unsigned char leds = getleds();
896        if (leds != ledstate) {
897                ledstate = leds;
898                kbd_leds(leds);
899        }
900}
901
902
903void set_leds(void)
904{
905  kbd_bh();
906}
907
908
909int kbd_init(void)
910{
911
912        int i;
913        struct kbd_struct kbd0;
914        kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
915   kbd0.ledmode = LED_SHOW_MEM;
916        kbd0.lockstate = KBD_DEFLOCK;
917        kbd0.slockstate = 0;
918        kbd0.modeflags = KBD_DEFMODE;
919        kbd0.kbdmode = VC_XLATE;
920
921        for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
922                kbd_table[i] = kbd0;
923
924        kbd_init_hw();
925        mark_bh(KEYBOARD_BH);
926        return 0;
927}
928
Note: See TracBrowser for help on using the repository browser.