source: rtems/bsps/i386/pc386/console/pc_keyb.c @ d7d66d7

5
Last change on this file since d7d66d7 was d7d66d7, checked in by Sebastian Huber <sebastian.huber@…>, on 04/19/18 at 04:28:01

bsps: Move console drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 15.9 KB
Line 
1/*
2 * linux/drivers/char/pc_keyb.c
3 *
4 * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
5 * See keyboard.c for the whole history.
6 *
7 * Major cleanup by Martin Mares, May 1997
8 *
9 * Combined the keyboard and PS/2 mouse handling into one file,
10 * because they share the same hardware.
11 * Johan Myreen <jem@iki.fi> 1998-10-08.
12 *
13 * Code fixes to handle mouse ACKs properly.
14 * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
15 *
16 * Ported to RTEMS by Rosimildo da Silva
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <errno.h>
22
23#include <bsp.h>
24#include <rtems/keyboard.h>
25#include "i386kbd.h"
26
27static unsigned char handle_kbd_event(void);
28static void kbd_write_command_w(int data);
29static void kbd_write_output_w(int data);
30
31/* Some configuration switches are present in the include file... */
32
33/* Simple translation table for the SysRq keys */
34
35#ifdef CONFIG_MAGIC_SYSRQ
36unsigned char pckbd_sysrq_xlate[128] =
37        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
38        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
39        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
40        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
41        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
42        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
43        "\r\000/";                                      /* 0x60 - 0x6f */
44#endif
45
46/* used only by send_data - set by keyboard_interrupt */
47static volatile unsigned char reply_expected = 0;
48static volatile unsigned char acknowledge = 0;
49static volatile unsigned char resend = 0;
50
51/*
52 * Translation of escaped scancodes to keycodes.
53 * This is now user-settable.
54 * The keycodes 1-88,96-111,119 are fairly standard, and
55 * should probably not be changed - changing might confuse X.
56 * X also interprets scancode 0x5d (KEY_Begin).
57 *
58 * For 1-88 keycode equals scancode.
59 */
60
61#define E0_KPENTER 96
62#define E0_RCTRL   97
63#define E0_KPSLASH 98
64#define E0_PRSCR   99
65#define E0_RALT    100
66#define E0_BREAK   101  /* (control-pause) */
67#define E0_HOME    102
68#define E0_UP      103
69#define E0_PGUP    104
70#define E0_LEFT    105
71#define E0_RIGHT   106
72#define E0_END     107
73#define E0_DOWN    108
74#define E0_PGDN    109
75#define E0_INS     110
76#define E0_DEL     111
77
78#define E1_PAUSE   119
79
80/*
81 * The keycodes below are randomly located in 89-95,112-118,120-127.
82 * They could be thrown away (and all occurrences below replaced by 0),
83 * but that would force many users to use the `setkeycodes' utility, where
84 * they needed not before. It does not matter that there are duplicates, as
85 * long as no duplication occurs for any single keyboard.
86 */
87#define SC_LIM 89
88
89#define FOCUS_PF1 85           /* actual code! */
90#define FOCUS_PF2 89
91#define FOCUS_PF3 90
92#define FOCUS_PF4 91
93#define FOCUS_PF5 92
94#define FOCUS_PF6 93
95#define FOCUS_PF7 94
96#define FOCUS_PF8 95
97#define FOCUS_PF9 120
98#define FOCUS_PF10 121
99#define FOCUS_PF11 122
100#define FOCUS_PF12 123
101
102#define JAP_86     124
103/* tfj@olivia.ping.dk:
104 * The four keys are located over the numeric keypad, and are
105 * labelled A1-A4. It's an rc930 keyboard, from
106 * Regnecentralen/RC International, Now ICL.
107 * Scancodes: 59, 5a, 5b, 5c.
108 */
109#define RGN1 124
110#define RGN2 125
111#define RGN3 126
112#define RGN4 127
113
114static unsigned char high_keys[128 - SC_LIM] = {
115  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
116  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
117  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
118  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
119  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
120  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
121};
122
123/* BTC */
124#define E0_MACRO   112
125/* LK450 */
126#define E0_F13     113
127#define E0_F14     114
128#define E0_HELP    115
129#define E0_DO      116
130#define E0_F17     117
131#define E0_KPMINPLUS 118
132/*
133 * My OmniKey generates e0 4c for  the "OMNI" key and the
134 * right alt key does nada. [kkoller@nyx10.cs.du.edu]
135 */
136#define E0_OK   124
137/*
138 * New microsoft keyboard is rumoured to have
139 * e0 5b (left window button), e0 5c (right window button),
140 * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
141 * [or: Windows_L, Windows_R, TaskMan]
142 */
143#define E0_MSLW 125
144#define E0_MSRW 126
145#define E0_MSTM 127
146
147static unsigned char e0_keys[128] = {
148  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x00-0x07 */
149  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x08-0x0f */
150  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x10-0x17 */
151  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,             /* 0x18-0x1f */
152  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x20-0x27 */
153  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x28-0x2f */
154  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,             /* 0x30-0x37 */
155  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,       /* 0x38-0x3f */
156  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,       /* 0x40-0x47 */
157  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
158  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,       /* 0x50-0x57 */
159  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,           /* 0x58-0x5f */
160  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x60-0x67 */
161  0, 0, 0, 0, 0, 0, 0, E0_MACRO,                      /* 0x68-0x6f */
162  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x70-0x77 */
163  0, 0, 0, 0, 0, 0, 0, 0                              /* 0x78-0x7f */
164};
165
166static void mdelay( unsigned long t )
167{
168   Wait_X_ms( t );
169}
170
171int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
172{
173        if (scancode < SC_LIM || scancode > 255 || keycode > 127)
174          return -EINVAL;
175        if (scancode < 128)
176          high_keys[scancode - SC_LIM] = keycode;
177        else
178          e0_keys[scancode - 128] = keycode;
179        return 0;
180}
181
182int pckbd_getkeycode(unsigned int scancode)
183{
184        return
185          (scancode < SC_LIM || scancode > 255) ? -EINVAL :
186          (scancode < 128) ? high_keys[scancode - SC_LIM] :
187            e0_keys[scancode - 128];
188}
189
190static int do_acknowledge(unsigned char scancode)
191{
192        if (reply_expected) {
193          /* Unfortunately, we must recognise these codes only if we know they
194           * are known to be valid (i.e., after sending a command), because there
195           * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have
196           * keys with such codes :(
197           */
198                if (scancode == KBD_REPLY_ACK) {
199                        acknowledge = 1;
200                        reply_expected = 0;
201                        return 0;
202                } else if (scancode == KBD_REPLY_RESEND) {
203                        resend = 1;
204                        reply_expected = 0;
205                        return 0;
206                }
207                /* Should not happen... */
208                printk( "keyboard reply expected - got %02x\n", scancode);
209        }
210        return 1;
211}
212
213int pckbd_translate(unsigned char scancode, unsigned char *keycode,
214                    char raw_mode)
215{
216        static int prev_scancode = 0;
217
218        /* special prefix scancodes.. */
219        if (scancode == 0xe0 || scancode == 0xe1) {
220                prev_scancode = scancode;
221                return 0;
222        }
223
224        /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
225        if (scancode == 0x00 || scancode == 0xff) {
226                prev_scancode = 0;
227                return 0;
228        }
229
230        scancode &= 0x7f;
231
232        if (prev_scancode) {
233          /*
234           * usually it will be 0xe0, but a Pause key generates
235           * e1 1d 45 e1 9d c5 when pressed, and nothing when released
236           */
237          if (prev_scancode != 0xe0) {
238              if (prev_scancode == 0xe1 && scancode == 0x1d) {
239                  prev_scancode = 0x100;
240                  return 0;
241              } else if (prev_scancode == 0x100 && scancode == 0x45) {
242                  *keycode = E1_PAUSE;
243                  prev_scancode = 0;
244              } else {
245#ifdef KBD_REPORT_UNKN
246                  if (!raw_mode)
247                    printk("keyboard: unknown e1 escape sequence\n");
248#endif
249                  prev_scancode = 0;
250                  return 0;
251              }
252          } else {
253              prev_scancode = 0;
254              /*
255               *  The keyboard maintains its own internal caps lock and
256               *  num lock statuses. In caps lock mode E0 AA precedes make
257               *  code and E0 2A follows break code. In num lock mode,
258               *  E0 2A precedes make code and E0 AA follows break code.
259               *  We do our own book-keeping, so we will just ignore these.
260               */
261              /*
262               *  For my keyboard there is no caps lock mode, but there are
263               *  both Shift-L and Shift-R modes. The former mode generates
264               *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
265               *  So, we should also ignore the latter. - aeb@cwi.nl
266               */
267              if (scancode == 0x2a || scancode == 0x36)
268                return 0;
269
270              if (e0_keys[scancode])
271                *keycode = e0_keys[scancode];
272              else {
273#ifdef KBD_REPORT_UNKN
274                  if (!raw_mode)
275                    printk( "keyboard: unknown scancode e0 %02x\n",
276                           scancode);
277#endif
278                  return 0;
279              }
280          }
281        } else if (scancode >= SC_LIM) {
282            /* This happens with the FOCUS 9000 keyboard
283               Its keys PF1..PF12 are reported to generate
284               55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
285               Moreover, unless repeated, they do not generate
286               key-down events, so we have to zero up_flag below */
287            /* Also, Japanese 86/106 keyboards are reported to
288               generate 0x73 and 0x7d for \ - and \ | respectively. */
289            /* Also, some Brazilian keyboard is reported to produce
290               0x73 and 0x7e for \ ? and KP-dot, respectively. */
291
292          *keycode = high_keys[scancode - SC_LIM];
293          if (!*keycode) {
294              if (!raw_mode) {
295#ifdef KBD_REPORT_UNKN
296                  printk( "keyboard: unrecognized scancode (%02x)"
297                         " - ignored\n", scancode);
298#endif
299              }
300              return 0;
301          }
302        } else
303          *keycode = scancode;
304        return 1;
305}
306
307char pckbd_unexpected_up(unsigned char keycode)
308{
309        /* unexpected, but this can happen: maybe this was a key release for a
310           FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
311        if (keycode >= SC_LIM || keycode == 85)
312            return 0;
313        else
314            return 0200;
315}
316
317static void kb_wait(void)
318{
319        unsigned long timeout = KBC_TIMEOUT;
320
321        do {
322                /*
323                 * "handle_kbd_event()" will handle any incoming events
324                 * while we wait - keypresses or mouse movement.
325                 */
326                unsigned char status = handle_kbd_event();
327
328                if (! (status & KBD_STAT_IBF))
329                        return;
330                mdelay(1);
331                timeout--;
332        } while (timeout);
333#ifdef KBD_REPORT_TIMEOUTS
334        printk( "Keyboard timed out[1]\n");
335#endif
336}
337
338/*
339 * This reads the keyboard status port, and does the
340 * appropriate action.
341 *
342 * It requires that we hold the keyboard controller
343 * spinlock.
344 */
345static unsigned char handle_kbd_event(void)
346{
347        unsigned char status = kbd_read_status();
348        unsigned int work = 10000;
349
350        while (status & KBD_STAT_OBF) {
351                unsigned char scancode;
352
353                scancode = kbd_read_input();
354                if (status & KBD_STAT_MOUSE_OBF) {
355#if 0
356                        handle_mouse_event(scancode);
357#endif
358                } else {
359                        if (do_acknowledge(scancode))
360                                handle_scancode(scancode, !(scancode & 0x80));
361                        mark_bh(KEYBOARD_BH);
362                }
363
364                status = kbd_read_status();
365
366                if(!work--)
367                {
368                        printk( "pc_keyb: controller jammed (0x%02X).\n", status);
369                        break;
370                }
371      return status;
372        }
373
374   /*
375    * the commands to set the leds for some reason, returns 0x14, 0x16
376    * and I am intepreting as an ACK, because the original code from
377    * Linux was timeing out here...
378    */
379        acknowledge = 1;
380        reply_expected = 0;
381        resend = 0;
382        return status;
383}
384
385void keyboard_interrupt(void *unused)
386{
387        handle_kbd_event();
388}
389
390/*
391 * send_data sends a character to the keyboard and waits
392 * for an acknowledge, possibly retrying if asked to. Returns
393 * the success status.
394 *
395 * Don't use 'jiffies', so that we don't depend on interrupts
396 */
397static int send_data(unsigned char data)
398{
399        int retries = 3;
400
401        do {
402                unsigned long timeout = KBD_TIMEOUT;
403
404                acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */
405                resend = 0;
406                reply_expected = 1;
407                kbd_write_output_w(data);
408                for (;;) {
409                        if (acknowledge)
410                                return 1;
411                        if (resend)
412                                break;
413                        mdelay(1);
414                        if (!--timeout) {
415#ifdef KBD_REPORT_TIMEOUTS
416                                printk("Keyboard timeout[2]\n");
417#endif
418                                return 0;
419                        }
420                }
421        } while (retries-- > 0);
422#ifdef KBD_REPORT_TIMEOUTS
423        printk( "keyboard: Too many NACKs -- noisy kbd cable?\n");
424#endif
425        return 0;
426}
427
428void pckbd_leds(unsigned char leds)
429{
430        if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))
431            send_data(KBD_CMD_ENABLE);  /* re-enable kbd if any errors */
432}
433
434/*
435 * In case we run on a non-x86 hardware we need to initialize both the
436 * keyboard controller and the keyboard.  On a x86, the BIOS will
437 * already have initialized them.
438 *
439 * Some x86 BIOSes do not correctly initialize the keyboard, so the
440 * "kbd-reset" command line options can be given to force a reset.
441 * [Ranger]
442 */
443#ifdef __i386__
444 int kbd_startup_reset = 0;
445#else
446 int kbd_startup_reset = 1;
447#endif
448
449/* for "kbd-reset" cmdline param */
450void kbd_reset_setup(char *str, int *ints)
451{
452        kbd_startup_reset = 1;
453}
454
455#define KBD_NO_DATA     (-1)    /* No data */
456#define KBD_BAD_DATA    (-2)    /* Parity or other error */
457
458static int kbd_read_data(void)
459{
460        int retval = KBD_NO_DATA;
461        unsigned char status;
462
463        status = kbd_read_status();
464        if (status & KBD_STAT_OBF) {
465                unsigned char data = kbd_read_input();
466
467                retval = data;
468                if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
469                        retval = KBD_BAD_DATA;
470        }
471        return retval;
472}
473
474static void kbd_clear_input(void)
475{
476        int maxread = 100;      /* Random number */
477
478        do {
479                if (kbd_read_data() == KBD_NO_DATA)
480                        break;
481        } while (--maxread);
482}
483
484static int kbd_wait_for_input(void)
485{
486        long timeout = KBD_INIT_TIMEOUT;
487
488        do {
489                int retval = kbd_read_data();
490                if (retval >= 0)
491                        return retval;
492                mdelay(1);
493        } while (--timeout);
494        return -1;
495}
496
497static void kbd_write_command_w(int data)
498{
499        kb_wait();
500        kbd_write_command(data);
501}
502
503static void kbd_write_output_w(int data)
504{
505        kb_wait();
506        kbd_write_output(data);
507}
508
509static char * initialize_kbd(void)
510{
511        int status;
512
513        /*
514         * Test the keyboard interface.
515         * This seems to be the only way to get it going.
516         * If the test is successful a x55 is placed in the input buffer.
517         */
518        kbd_write_command_w(KBD_CCMD_SELF_TEST);
519        if (kbd_wait_for_input() != 0x55)
520                return "Keyboard failed self test";
521
522        /*
523         * Perform a keyboard interface test.  This causes the controller
524         * to test the keyboard clock and data lines.  The results of the
525         * test are placed in the input buffer.
526         */
527        kbd_write_command_w(KBD_CCMD_KBD_TEST);
528        if (kbd_wait_for_input() != 0x00)
529                return "Keyboard interface failed self test";
530
531        /*
532         * Enable the keyboard by allowing the keyboard clock to run.
533         */
534        kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
535
536        /*
537         * Reset keyboard. If the read times out
538         * then the assumption is that no keyboard is
539         * plugged into the machine.
540         * This defaults the keyboard to scan-code set 2.
541         *
542         * Set up to try again if the keyboard asks for RESEND.
543         */
544        do {
545                kbd_write_output_w(KBD_CMD_RESET);
546                status = kbd_wait_for_input();
547                if (status == KBD_REPLY_ACK)
548                        break;
549                if (status != KBD_REPLY_RESEND)
550                        return "Keyboard reset failed, no ACK";
551        } while (1);
552
553        if (kbd_wait_for_input() != KBD_REPLY_POR)
554                return "Keyboard reset failed, no POR";
555
556        /*
557         * Set keyboard controller mode. During this, the keyboard should be
558         * in the disabled state.
559         *
560         * Set up to try again if the keyboard asks for RESEND.
561         */
562        do {
563                kbd_write_output_w(KBD_CMD_DISABLE);
564                status = kbd_wait_for_input();
565                if (status == KBD_REPLY_ACK)
566                        break;
567                if (status != KBD_REPLY_RESEND)
568                        return "Disable keyboard: no ACK";
569        } while (1);
570
571        kbd_write_command_w(KBD_CCMD_WRITE_MODE);
572        kbd_write_output_w(KBD_MODE_KBD_INT
573                              | KBD_MODE_SYS
574                              | KBD_MODE_DISABLE_MOUSE
575                              | KBD_MODE_KCC);
576
577        /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
578        kbd_write_command_w(KBD_CCMD_READ_MODE);
579        if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
580                /*
581                 * If the controller does not support conversion,
582                 * Set the keyboard to scan-code set 1.
583                 */
584                kbd_write_output_w(0xF0);
585                kbd_wait_for_input();
586                kbd_write_output_w(0x01);
587                kbd_wait_for_input();
588        }
589
590        kbd_write_output_w(KBD_CMD_ENABLE);
591        if (kbd_wait_for_input() != KBD_REPLY_ACK)
592                return "Enable keyboard: no ACK";
593        /*
594         * Finally, set the typematic rate to maximum.
595         */
596        kbd_write_output_w(KBD_CMD_SET_RATE);
597        if (kbd_wait_for_input() != KBD_REPLY_ACK)
598                return "Set rate: no ACK";
599        kbd_write_output_w(0x00);
600        if (kbd_wait_for_input() != KBD_REPLY_ACK)
601                return "Set rate: no ACK";
602        return NULL;
603}
604
605void pckbd_init_hw(void)
606{
607        /* kbd_request_region();  */
608
609        /*  Flush any pending input. */
610        kbd_clear_input();
611
612        if (kbd_startup_reset) {
613                char *msg = initialize_kbd();
614                if (msg)
615                        printk( "initialize_kbd: %s\n", msg);
616        }
617
618#if defined CONFIG_PSMOUSE
619        psaux_init();
620#endif
621
622        /* Ok, finally allocate the IRQ, and off we go.. */
623#if 0
624        kbd_request_irq( keyboard_interrupt );
625#endif
626
627}
Note: See TracBrowser for help on using the repository browser.