source: rtems/c/src/lib/libbsp/i386/pc386/console/keyboard.c @ 6b54dcb

5
Last change on this file since 6b54dcb was 6b54dcb, checked in by Pavel Pisa <pisa@…>, on 10/12/16 at 07:40:41

bsps/i386: replace global interrupt disable by SMP build supporting locking.

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