]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/AmigaOneG3SE/ps2kbd.c
imported Freescale specific U-Boot additions for i.MX28,... release L2.6.31_10.08.01
[karo-tx-uboot.git] / board / MAI / AmigaOneG3SE / ps2kbd.c
1 /*
2  * (C) Copyright 2002
3  * John W. Linville, linville@tuxdriver.com
4  *
5  * Modified from code for support of MIP405 and PIP405 boards.  Previous
6  * copyright follows.
7  *
8  * (C) Copyright 2001
9  * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
10  *
11  * See file CREDITS for list of people who contributed to this
12  * project.
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License as
16  * published by the Free Software Foundation; either version 2 of
17  * the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27  * MA 02111-1307 USA
28  *
29  *
30  * Source partly derived from:
31  * linux/drivers/char/pc_keyb.c
32  *
33  *
34  */
35 #include <common.h>
36 #include <asm/processor.h>
37 #include <stdio_dev.h>
38 #include "ps2kbd.h"
39
40
41 unsigned char kbd_read_status(void);
42 unsigned char kbd_read_input(void);
43 void kbd_send_data(unsigned char data);
44 void i8259_mask_irq(unsigned int irq);
45 void i8259_unmask_irq(unsigned int irq);
46
47 /* used only by send_data - set by keyboard_interrupt */
48
49
50 #undef KBG_DEBUG
51
52 #ifdef KBG_DEBUG
53 #define PRINTF(fmt,args...)     printf (fmt ,##args)
54 #else
55 #define PRINTF(fmt,args...)
56 #endif
57
58 #define KBD_STAT_KOBF           0x01
59 #define KBD_STAT_IBF            0x02
60 #define KBD_STAT_SYS            0x04
61 #define KBD_STAT_CD             0x08
62 #define KBD_STAT_LOCK           0x10
63 #define KBD_STAT_MOBF           0x20
64 #define KBD_STAT_TI_OUT 0x40
65 #define KBD_STAT_PARERR 0x80
66
67 #define KBD_INIT_TIMEOUT 2000           /* Timeout in ms for initializing the keyboard */
68 #define KBC_TIMEOUT 250                 /* Timeout in ms for sending to keyboard controller */
69 #define KBD_TIMEOUT 2000                /* Timeout in ms for keyboard command acknowledge */
70 /*
71  *      Keyboard Controller Commands
72  */
73
74 #define KBD_CCMD_READ_MODE      0x20    /* Read mode bits */
75 #define KBD_CCMD_WRITE_MODE     0x60    /* Write mode bits */
76 #define KBD_CCMD_GET_VERSION    0xA1    /* Get controller version */
77 #define KBD_CCMD_MOUSE_DISABLE  0xA7    /* Disable mouse interface */
78 #define KBD_CCMD_MOUSE_ENABLE   0xA8    /* Enable mouse interface */
79 #define KBD_CCMD_TEST_MOUSE     0xA9    /* Mouse interface test */
80 #define KBD_CCMD_SELF_TEST      0xAA    /* Controller self test */
81 #define KBD_CCMD_KBD_TEST       0xAB    /* Keyboard interface test */
82 #define KBD_CCMD_KBD_DISABLE    0xAD    /* Keyboard interface disable */
83 #define KBD_CCMD_KBD_ENABLE     0xAE    /* Keyboard interface enable */
84 #define KBD_CCMD_WRITE_AUX_OBUF 0xD3    /* Write to output buffer as if
85                                            initiated by the auxiliary device */
86 #define KBD_CCMD_WRITE_MOUSE    0xD4    /* Write the following byte to the mouse */
87
88 /*
89  *      Keyboard Commands
90  */
91
92 #define KBD_CMD_SET_LEDS        0xED    /* Set keyboard leds */
93 #define KBD_CMD_SET_RATE        0xF3    /* Set typematic rate */
94 #define KBD_CMD_ENABLE          0xF4    /* Enable scanning */
95 #define KBD_CMD_DISABLE         0xF5    /* Disable scanning */
96 #define KBD_CMD_RESET           0xFF    /* Reset */
97
98 /*
99  *      Keyboard Replies
100  */
101
102 #define KBD_REPLY_POR           0xAA    /* Power on reset */
103 #define KBD_REPLY_ACK           0xFA    /* Command ACK */
104 #define KBD_REPLY_RESEND        0xFE    /* Command NACK, send the cmd again */
105
106 /*
107  *      Status Register Bits
108  */
109
110 #define KBD_STAT_OBF            0x01    /* Keyboard output buffer full */
111 #define KBD_STAT_IBF            0x02    /* Keyboard input buffer full */
112 #define KBD_STAT_SELFTEST       0x04    /* Self test successful */
113 #define KBD_STAT_CMD            0x08    /* Last write was a command write (0=data) */
114 #define KBD_STAT_UNLOCKED       0x10    /* Zero if keyboard locked */
115 #define KBD_STAT_MOUSE_OBF      0x20    /* Mouse output buffer full */
116 #define KBD_STAT_GTO            0x40    /* General receive/xmit timeout */
117 #define KBD_STAT_PERR           0x80    /* Parity error */
118
119 #define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
120
121 /*
122  *      Controller Mode Register Bits
123  */
124
125 #define KBD_MODE_KBD_INT        0x01    /* Keyboard data generate IRQ1 */
126 #define KBD_MODE_MOUSE_INT      0x02    /* Mouse data generate IRQ12 */
127 #define KBD_MODE_SYS            0x04    /* The system flag (?) */
128 #define KBD_MODE_NO_KEYLOCK     0x08    /* The keylock doesn't affect the keyboard if set */
129 #define KBD_MODE_DISABLE_KBD    0x10    /* Disable keyboard interface */
130 #define KBD_MODE_DISABLE_MOUSE  0x20    /* Disable mouse interface */
131 #define KBD_MODE_KCC            0x40    /* Scan code conversion to PC format */
132 #define KBD_MODE_RFU            0x80
133
134
135 #define KDB_DATA_PORT           0x60
136 #define KDB_COMMAND_PORT        0x64
137
138 #define LED_SCR                 0x01    /* scroll lock led */
139 #define LED_CAP                 0x04    /* caps lock led */
140 #define LED_NUM                 0x02    /* num lock led */
141
142 #define KBD_BUFFER_LEN          0x20    /* size of the keyboardbuffer */
143
144
145 static volatile char kbd_buffer[KBD_BUFFER_LEN];
146 static volatile int in_pointer = 0;
147 static volatile int out_pointer = 0;
148
149
150 static unsigned char num_lock = 0;
151 static unsigned char caps_lock = 0;
152 static unsigned char scroll_lock = 0;
153 static unsigned char shift = 0;
154 static unsigned char ctrl = 0;
155 static unsigned char alt = 0;
156 static unsigned char e0 = 0;
157 static unsigned char leds = 0;
158
159 #define DEVNAME "ps2kbd"
160
161 /* Simple translation table for the keys */
162
163 static unsigned char kbd_plain_xlate[] = {
164         0xff,0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t',        /* 0x00 - 0x0f */
165          'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\r',0xff, 'a', 's',        /* 0x10 - 0x1f */
166          'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`',0xff,'\\', 'z', 'x', 'c', 'v',        /* 0x20 - 0x2f */
167          'b', 'n', 'm', ',', '.', '/',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff,        /* 0x30 - 0x3f */
168         0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',        /* 0x40 - 0x4f */
169          '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,  /* 0x50 - 0x5F */
170         '\r',0xff,0xff
171         };
172
173 static unsigned char kbd_shift_xlate[] = {
174         0xff,0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t',        /* 0x00 - 0x0f */
175          'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\r',0xff, 'A', 'S',        /* 0x10 - 0x1f */
176          'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',0xff, '|', 'Z', 'X', 'C', 'V',        /* 0x20 - 0x2f */
177          'B', 'N', 'M', '<', '>', '?',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff,        /* 0x30 - 0x3f */
178         0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',        /* 0x40 - 0x4f */
179          '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,  /* 0x50 - 0x5F */
180         '\r',0xff,0xff
181         };
182
183 static unsigned char kbd_ctrl_xlate[] = {
184         0xff,0x1b, '1',0x00, '3', '4', '5',0x1E, '7', '8', '9', '0',0x1F, '=','\b','\t',        /* 0x00 - 0x0f */
185         0x11,0x17,0x05,0x12,0x14,0x18,0x15,0x09,0x0f,0x10,0x1b,0x1d,'\n',0xff,0x01,0x13,        /* 0x10 - 0x1f */
186         0x04,0x06,0x08,0x09,0x0a,0x0b,0x0c, ';','\'', '~',0x00,0x1c,0x1a,0x18,0x03,0x16,        /* 0x20 - 0x2f */
187         0x02,0x0e,0x0d, '<', '>', '?',0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff,        /* 0x30 - 0x3f */
188         0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',        /* 0x40 - 0x4f */
189          '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,  /* 0x50 - 0x5F */
190         '\r',0xff,0xff
191         };
192
193 /******************************************************************
194  * Init
195  ******************************************************************/
196
197 int isa_kbd_init (void)
198 {
199         char *result;
200
201         result = kbd_initialize ();
202         if (result != NULL) {
203                 result = kbd_initialize ();
204         }
205         if (result == NULL) {
206                 printf ("AT Keyboard initialized\n");
207                 irq_install_handler (KBD_INTERRUPT,
208                                      (interrupt_handler_t *) kbd_interrupt,
209                                      NULL);
210                 return (1);
211         } else {
212                 printf ("%s\n", result);
213                 return (-1);
214         }
215 }
216
217 #ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
218 extern int overwrite_console (void);
219 #else
220 int overwrite_console (void)
221 {
222         return (0);
223 }
224 #endif
225
226 int drv_isa_kbd_init (void)
227 {
228         int error;
229         struct stdio_dev kbddev ;
230         char *stdinname  = getenv ("stdin");
231
232         if(isa_kbd_init() == -1)
233                 return -1;
234         memset (&kbddev, 0, sizeof(kbddev));
235         strcpy(kbddev.name, DEVNAME);
236         kbddev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
237         kbddev.putc = NULL ;
238         kbddev.puts = NULL ;
239         kbddev.getc = kbd_getc ;
240         kbddev.tstc = kbd_testc ;
241
242         error = stdio_register (&kbddev);
243         if(error==0) {
244                 /* check if this is the standard input device */
245                 if(strcmp(stdinname,DEVNAME)==0) {
246                         /* reassign the console */
247                         if(overwrite_console()) {
248                                 return 1;
249                         }
250                         error=console_assign(stdin,DEVNAME);
251                         if(error==0)
252                                 return 1;
253                         else
254                                 return error;
255                 }
256                 return 1;
257         }
258         return error;
259 }
260
261 /******************************************************************
262  * Queue handling
263  ******************************************************************/
264 /* puts character in the queue and sets up the in and out pointer */
265 void kbd_put_queue(char data)
266 {
267         if((in_pointer+1)==KBD_BUFFER_LEN) {
268                 if(out_pointer==0) {
269                         return; /* buffer full */
270                 } else{
271                         in_pointer=0;
272                 }
273         } else {
274                 if((in_pointer+1)==out_pointer)
275                         return; /* buffer full */
276                 in_pointer++;
277         }
278         kbd_buffer[in_pointer]=data;
279         return;
280 }
281
282 /* test if a character is in the queue */
283 int kbd_testc(void)
284 {
285         if(in_pointer==out_pointer)
286                 return(0); /* no data */
287         else
288                 return(1);
289 }
290 /* gets the character from the queue */
291 int kbd_getc(void)
292 {
293         char c;
294
295         while(in_pointer==out_pointer);
296         if((out_pointer+1)==KBD_BUFFER_LEN)
297                 out_pointer=0;
298         else
299                 out_pointer++;
300         c=kbd_buffer[out_pointer];
301         return (int)c;
302
303 }
304
305 /* set LEDs */
306
307 void kbd_set_leds(void)
308 {
309         if(caps_lock==0)
310                 leds&=~LED_CAP; /* switch caps_lock off */
311         else
312                 leds|=LED_CAP; /* switch on LED */
313         if(num_lock==0)
314                 leds&=~LED_NUM; /* switch LED off */
315         else
316                 leds|=LED_NUM;  /* switch on LED */
317         if(scroll_lock==0)
318                 leds&=~LED_SCR; /* switch LED off */
319         else
320                 leds|=LED_SCR; /* switch on LED */
321         kbd_send_data(KBD_CMD_SET_LEDS);
322         kbd_send_data(leds);
323 }
324
325 void handle_keyboard_event (unsigned char scancode)
326 {
327         unsigned char keycode;
328
329         /*  Convert scancode to keycode */
330         PRINTF ("scancode %x\n", scancode);
331         if (scancode == 0xe0) {
332                 e0 = 1;         /* special charakters */
333                 return;
334         }
335         if (e0 == 1) {
336                 e0 = 0;         /* delete flag */
337                 if (!(((scancode & 0x7F) == 0x38) ||    /* the right ctrl key */
338                       ((scancode & 0x7F) == 0x1D) ||    /* the right alt key */
339                       ((scancode & 0x7F) == 0x35) ||    /* the right '/' key */
340                       ((scancode & 0x7F) == 0x1C) ||    /* the right enter key */
341                       ((scancode) == 0x48) ||   /* arrow up */
342                       ((scancode) == 0x50) ||   /* arrow down */
343                       ((scancode) == 0x4b) ||   /* arrow left */
344                       ((scancode) == 0x4d)))
345                         /* arrow right */
346                         /* we swallow unknown e0 codes */
347                         return;
348         }
349         /* special cntrl keys */
350         switch (scancode) {
351         case 0x48:
352                 kbd_put_queue (27);
353                 kbd_put_queue (91);
354                 kbd_put_queue ('A');
355                 return;
356         case 0x50:
357                 kbd_put_queue (27);
358                 kbd_put_queue (91);
359                 kbd_put_queue ('B');
360                 return;
361         case 0x4b:
362                 kbd_put_queue (27);
363                 kbd_put_queue (91);
364                 kbd_put_queue ('D');
365                 return;
366         case 0x4D:
367                 kbd_put_queue (27);
368                 kbd_put_queue (91);
369                 kbd_put_queue ('C');
370                 return;
371         case 0x58:              /* F12 key */
372                 if (ctrl == 1) {
373                         extern int console_changed;
374
375                         setenv ("stdin", DEVNAME);
376                         setenv ("stdout", "vga");
377                         console_changed = 1;
378                 }
379                 return;
380         case 0x2A:
381         case 0x36:              /* shift pressed */
382                 shift = 1;
383                 return;         /* do nothing else */
384         case 0xAA:
385         case 0xB6:              /* shift released */
386                 shift = 0;
387                 return;         /* do nothing else */
388         case 0x38:              /* alt pressed */
389                 alt = 1;
390                 return;         /* do nothing else */
391         case 0xB8:              /* alt released */
392                 alt = 0;
393                 return;         /* do nothing else */
394         case 0x1d:              /* ctrl pressed */
395                 ctrl = 1;
396                 return;         /* do nothing else */
397         case 0x9d:              /* ctrl released */
398                 ctrl = 0;
399                 return;         /* do nothing else */
400         case 0x46:              /* scrollock pressed */
401                 scroll_lock = ~scroll_lock;
402                 kbd_set_leds ();
403                 return;         /* do nothing else */
404         case 0x3A:              /* capslock pressed */
405                 caps_lock = ~caps_lock;
406                 kbd_set_leds ();
407                 return;
408         case 0x45:              /* numlock pressed */
409                 num_lock = ~num_lock;
410                 kbd_set_leds ();
411                 return;
412         case 0xC6:              /* scroll lock released */
413         case 0xC5:              /* num lock released */
414         case 0xBA:              /* caps lock released */
415                 return;         /* just swallow */
416         }
417         if ((scancode & 0x80) == 0x80)  /* key released */
418                 return;
419         /* now, decide which table we need */
420         if (scancode > (sizeof (kbd_plain_xlate) / sizeof (kbd_plain_xlate[0]))) {      /* scancode not in list */
421                 PRINTF ("unkown scancode %X\n", scancode);
422                 return;         /* swallow it */
423         }
424         /* setup plain code first */
425         keycode = kbd_plain_xlate[scancode];
426         if (caps_lock == 1) {   /* caps_lock is pressed, overwrite plain code */
427                 if (scancode > (sizeof (kbd_shift_xlate) / sizeof (kbd_shift_xlate[0]))) {      /* scancode not in list */
428                         PRINTF ("unkown caps-locked scancode %X\n", scancode);
429                         return; /* swallow it */
430                 }
431                 keycode = kbd_shift_xlate[scancode];
432                 if (keycode < 'A') {    /* we only want the alphas capital */
433                         keycode = kbd_plain_xlate[scancode];
434                 }
435         }
436         if (shift == 1) {       /* shift overwrites caps_lock */
437                 if (scancode > (sizeof (kbd_shift_xlate) / sizeof (kbd_shift_xlate[0]))) {      /* scancode not in list */
438                         PRINTF ("unkown shifted scancode %X\n", scancode);
439                         return; /* swallow it */
440                 }
441                 keycode = kbd_shift_xlate[scancode];
442         }
443         if (ctrl == 1) {        /* ctrl overwrites caps_lock and shift */
444                 if (scancode > (sizeof (kbd_ctrl_xlate) / sizeof (kbd_ctrl_xlate[0]))) {        /* scancode not in list */
445                         PRINTF ("unkown ctrl scancode %X\n", scancode);
446                         return; /* swallow it */
447                 }
448                 keycode = kbd_ctrl_xlate[scancode];
449         }
450         /* check if valid keycode */
451         if (keycode == 0xff) {
452                 PRINTF ("unkown scancode %X\n", scancode);
453                 return;         /* swallow unknown codes */
454         }
455
456         kbd_put_queue (keycode);
457         PRINTF ("%x\n", keycode);
458 }
459
460 /*
461  * This reads the keyboard status port, and does the
462  * appropriate action.
463  *
464  */
465 unsigned char handle_kbd_event (void)
466 {
467         unsigned char status = kbd_read_status ();
468         unsigned int work = 10000;
469
470         while ((--work > 0) && (status & KBD_STAT_OBF)) {
471                 unsigned char scancode;
472
473                 scancode = kbd_read_input ();
474
475                 /* Error bytes must be ignored to make the
476                    Synaptics touchpads compaq use work */
477                 /* Ignore error bytes */
478                 if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) {
479                         if (status & KBD_STAT_MOUSE_OBF);       /* not supported: handle_mouse_event(scancode); */
480                         else
481                                 handle_keyboard_event (scancode);
482                 }
483                 status = kbd_read_status ();
484         }
485         if (!work)
486                 PRINTF ("pc_keyb: controller jammed (0x%02X).\n", status);
487         return status;
488 }
489
490 /******************************************************************************
491  * Lowlevel Part of keyboard section
492  */
493 unsigned char kbd_read_status(void)
494 {
495         return(in8(CONFIG_SYS_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT));
496 }
497
498 unsigned char kbd_read_input(void)
499 {
500         return(in8(CONFIG_SYS_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT));
501 }
502
503 void kbd_write_command(unsigned char cmd)
504 {
505         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT,cmd);
506 }
507
508 void kbd_write_output(unsigned char data)
509 {
510         out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT, data);
511 }
512
513 int kbd_read_data(void)
514 {
515         int val;
516         unsigned char status;
517
518         val = -1;
519         status = kbd_read_status();
520         if (status & KBD_STAT_OBF) {
521                 val = kbd_read_input();
522                 if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
523                         val = -2;
524         }
525         return val;
526 }
527
528 int kbd_wait_for_input (void)
529 {
530         unsigned long timeout;
531         int val;
532
533         timeout = KBD_TIMEOUT;
534         val = kbd_read_data ();
535         while (val < 0) {
536                 if (timeout-- == 0)
537                         return -1;
538                 udelay (1000);
539                 val = kbd_read_data ();
540         }
541         return val;
542 }
543
544
545 int kb_wait (void)
546 {
547         unsigned long timeout = KBC_TIMEOUT * 10;
548
549         do {
550                 unsigned char status = handle_kbd_event ();
551
552                 if (!(status & KBD_STAT_IBF))
553                         return 0;       /* ok */
554                 udelay (1000);
555                 timeout--;
556         } while (timeout);
557         return 1;
558 }
559
560 void kbd_write_command_w (int data)
561 {
562         if (kb_wait ())
563                 PRINTF ("timeout in kbd_write_command_w\n");
564         kbd_write_command (data);
565 }
566
567 void kbd_write_output_w (int data)
568 {
569         if (kb_wait ())
570                 PRINTF ("timeout in kbd_write_output_w\n");
571         kbd_write_output (data);
572 }
573
574 void kbd_send_data (unsigned char data)
575 {
576         unsigned char status;
577
578         i8259_mask_irq (KBD_INTERRUPT); /* disable interrupt */
579         kbd_write_output_w (data);
580         status = kbd_wait_for_input ();
581         if (status == KBD_REPLY_ACK)
582                 i8259_unmask_irq (KBD_INTERRUPT);       /* enable interrupt */
583 }
584
585
586 char *kbd_initialize (void)
587 {
588         int status;
589
590         in_pointer = 0;         /* delete in Buffer */
591         out_pointer = 0;
592         /*
593          * Test the keyboard interface.
594          * This seems to be the only way to get it going.
595          * If the test is successful a x55 is placed in the input buffer.
596          */
597         kbd_write_command_w (KBD_CCMD_SELF_TEST);
598         if (kbd_wait_for_input () != 0x55)
599                 return "Kbd:   failed self test";
600         /*
601          * Perform a keyboard interface test.  This causes the controller
602          * to test the keyboard clock and data lines.  The results of the
603          * test are placed in the input buffer.
604          */
605         kbd_write_command_w (KBD_CCMD_KBD_TEST);
606         if (kbd_wait_for_input () != 0x00)
607                 return "Kbd:   interface failed self test";
608         /*
609          * Enable the keyboard by allowing the keyboard clock to run.
610          */
611         kbd_write_command_w (KBD_CCMD_KBD_ENABLE);
612         status = kbd_wait_for_input ();
613         /*
614          * Reset keyboard. If the read times out
615          * then the assumption is that no keyboard is
616          * plugged into the machine.
617          * This defaults the keyboard to scan-code set 2.
618          *
619          * Set up to try again if the keyboard asks for RESEND.
620          */
621         do {
622                 kbd_write_output_w (KBD_CMD_RESET);
623                 status = kbd_wait_for_input ();
624                 if (status == KBD_REPLY_ACK)
625                         break;
626                 if (status != KBD_REPLY_RESEND) {
627                         PRINTF ("status: %X\n", status);
628                         return "Kbd:   reset failed, no ACK";
629                 }
630         } while (1);
631         if (kbd_wait_for_input () != KBD_REPLY_POR)
632                 return "Kbd:   reset failed, no POR";
633
634         /*
635          * Set keyboard controller mode. During this, the keyboard should be
636          * in the disabled state.
637          *
638          * Set up to try again if the keyboard asks for RESEND.
639          */
640         do {
641                 kbd_write_output_w (KBD_CMD_DISABLE);
642                 status = kbd_wait_for_input ();
643                 if (status == KBD_REPLY_ACK)
644                         break;
645                 if (status != KBD_REPLY_RESEND)
646                         return "Kbd:   disable keyboard: no ACK";
647         } while (1);
648
649         kbd_write_command_w (KBD_CCMD_WRITE_MODE);
650         kbd_write_output_w (KBD_MODE_KBD_INT
651                             | KBD_MODE_SYS
652                             | KBD_MODE_DISABLE_MOUSE | KBD_MODE_KCC);
653
654         /* AMCC powerpc portables need this to use scan-code set 1 -- Cort */
655         kbd_write_command_w (KBD_CCMD_READ_MODE);
656         if (!(kbd_wait_for_input () & KBD_MODE_KCC)) {
657                 /*
658                  * If the controller does not support conversion,
659                  * Set the keyboard to scan-code set 1.
660                  */
661                 kbd_write_output_w (0xF0);
662                 kbd_wait_for_input ();
663                 kbd_write_output_w (0x01);
664                 kbd_wait_for_input ();
665         }
666         kbd_write_output_w (KBD_CMD_ENABLE);
667         if (kbd_wait_for_input () != KBD_REPLY_ACK)
668                 return "Kbd:   enable keyboard: no ACK";
669
670         /*
671          * Finally, set the typematic rate to maximum.
672          */
673         kbd_write_output_w (KBD_CMD_SET_RATE);
674         if (kbd_wait_for_input () != KBD_REPLY_ACK)
675                 return "Kbd:   Set rate: no ACK";
676         kbd_write_output_w (0x00);
677         if (kbd_wait_for_input () != KBD_REPLY_ACK)
678                 return "Kbd:   Set rate: no ACK";
679         return NULL;
680 }
681
682 void kbd_interrupt(void)
683 {
684         handle_kbd_event();
685 }