source: rtems/c/src/lib/libbsp/i386/pc386/console/pc_keyb.c @ debbc9e

4.104.115
Last change on this file since debbc9e was bd51a63, checked in by Joel Sherrill <joel.sherrill@…>, on 09/12/07 at 15:16:00

2007-09-12 Joel Sherrill <joel.sherrill@…>

PR 1257/bsps

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