1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#include <common.h>
30#include <asm/processor.h>
31#include <stdio_dev.h>
32#include "isa.h"
33#include "kbd.h"
34
35
36unsigned char kbd_read_status(void);
37unsigned char kbd_read_input(void);
38void kbd_send_data(unsigned char data);
39void disable_8259A_irq(unsigned int irq);
40void enable_8259A_irq(unsigned int irq);
41
42
43
44
45#undef KBG_DEBUG
46
47#ifdef KBG_DEBUG
48#define PRINTF(fmt,args...) printf (fmt ,##args)
49#else
50#define PRINTF(fmt,args...)
51#endif
52
53#define KBD_STAT_KOBF 0x01
54#define KBD_STAT_IBF 0x02
55#define KBD_STAT_SYS 0x04
56#define KBD_STAT_CD 0x08
57#define KBD_STAT_LOCK 0x10
58#define KBD_STAT_MOBF 0x20
59#define KBD_STAT_TI_OUT 0x40
60#define KBD_STAT_PARERR 0x80
61
62#define KBD_INIT_TIMEOUT 1000
63#define KBC_TIMEOUT 250
64#define KBD_TIMEOUT 2000
65
66
67
68
69#define KBD_CCMD_READ_MODE 0x20
70#define KBD_CCMD_WRITE_MODE 0x60
71#define KBD_CCMD_GET_VERSION 0xA1
72#define KBD_CCMD_MOUSE_DISABLE 0xA7
73#define KBD_CCMD_MOUSE_ENABLE 0xA8
74#define KBD_CCMD_TEST_MOUSE 0xA9
75#define KBD_CCMD_SELF_TEST 0xAA
76#define KBD_CCMD_KBD_TEST 0xAB
77#define KBD_CCMD_KBD_DISABLE 0xAD
78#define KBD_CCMD_KBD_ENABLE 0xAE
79#define KBD_CCMD_WRITE_AUX_OBUF 0xD3
80
81#define KBD_CCMD_WRITE_MOUSE 0xD4
82
83
84
85
86
87#define KBD_CMD_SET_LEDS 0xED
88#define KBD_CMD_SET_RATE 0xF3
89#define KBD_CMD_ENABLE 0xF4
90#define KBD_CMD_DISABLE 0xF5
91#define KBD_CMD_RESET 0xFF
92
93
94
95
96
97#define KBD_REPLY_POR 0xAA
98#define KBD_REPLY_ACK 0xFA
99#define KBD_REPLY_RESEND 0xFE
100
101
102
103
104
105#define KBD_STAT_OBF 0x01
106#define KBD_STAT_IBF 0x02
107#define KBD_STAT_SELFTEST 0x04
108#define KBD_STAT_CMD 0x08
109#define KBD_STAT_UNLOCKED 0x10
110#define KBD_STAT_MOUSE_OBF 0x20
111#define KBD_STAT_GTO 0x40
112#define KBD_STAT_PERR 0x80
113
114#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
115
116
117
118
119
120#define KBD_MODE_KBD_INT 0x01
121#define KBD_MODE_MOUSE_INT 0x02
122#define KBD_MODE_SYS 0x04
123#define KBD_MODE_NO_KEYLOCK 0x08
124#define KBD_MODE_DISABLE_KBD 0x10
125#define KBD_MODE_DISABLE_MOUSE 0x20
126#define KBD_MODE_KCC 0x40
127#define KBD_MODE_RFU 0x80
128
129
130#define KDB_DATA_PORT 0x60
131#define KDB_COMMAND_PORT 0x64
132
133#define LED_SCR 0x01
134#define LED_CAP 0x04
135#define LED_NUM 0x02
136
137#define KBD_BUFFER_LEN 0x20
138
139
140static volatile char kbd_buffer[KBD_BUFFER_LEN];
141static volatile int in_pointer = 0;
142static volatile int out_pointer = 0;
143
144
145static unsigned char num_lock = 0;
146static unsigned char caps_lock = 0;
147static unsigned char scroll_lock = 0;
148static unsigned char shift = 0;
149static unsigned char ctrl = 0;
150static unsigned char alt = 0;
151static unsigned char e0 = 0;
152static unsigned char leds = 0;
153
154#define DEVNAME "kbd"
155
156
157
158static unsigned char kbd_plain_xlate[] = {
159 0xff,0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t',
160 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\r',0xff, 'a', 's',
161 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`',0xff,'\\', 'z', 'x', 'c', 'v',
162 'b', 'n', 'm', ',', '.', '/',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff,
163 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',
164 '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
165 '\r',0xff,0xff
166 };
167
168static unsigned char kbd_shift_xlate[] = {
169 0xff,0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t',
170 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\r',0xff, 'A', 'S',
171 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',0xff, '|', 'Z', 'X', 'C', 'V',
172 'B', 'N', 'M', '<', '>', '?',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff,
173 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',
174 '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
175 '\r',0xff,0xff
176 };
177
178static unsigned char kbd_ctrl_xlate[] = {
179 0xff,0x1b, '1',0x00, '3', '4', '5',0x1E, '7', '8', '9', '0',0x1F, '=','\b','\t',
180 0x11,0x17,0x05,0x12,0x14,0x18,0x15,0x09,0x0f,0x10,0x1b,0x1d,'\n',0xff,0x01,0x13,
181 0x04,0x06,0x08,0x09,0x0a,0x0b,0x0c, ';','\'', '~',0x00,0x1c,0x1a,0x18,0x03,0x16,
182 0x02,0x0e,0x0d, '<', '>', '?',0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
183 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',
184 '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
185 '\r',0xff,0xff
186 };
187
188
189
190
191int isa_kbd_init(void)
192{
193 char* result;
194 result=kbd_initialize();
195 if(result==NULL) {
196 PRINTF("AT Keyboard initialized\n");
197 irq_install_handler(25, (interrupt_handler_t *)handle_isa_int, NULL);
198 isa_irq_install_handler(KBD_INTERRUPT, (interrupt_handler_t *)kbd_interrupt, NULL);
199 return (1);
200 } else {
201 printf("%s\n",result);
202 return (-1);
203 }
204}
205
206#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
207extern int overwrite_console (void);
208#else
209int overwrite_console (void)
210{
211 return (0);
212}
213#endif
214
215int drv_isa_kbd_init (void)
216{
217 int error;
218 struct stdio_dev kbddev ;
219 char *stdinname = getenv ("stdin");
220
221 if(isa_kbd_init()==-1)
222 return -1;
223 memset (&kbddev, 0, sizeof(kbddev));
224 strcpy(kbddev.name, DEVNAME);
225 kbddev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
226 kbddev.putc = NULL ;
227 kbddev.puts = NULL ;
228 kbddev.getc = kbd_getc ;
229 kbddev.tstc = kbd_testc ;
230
231 error = stdio_register (&kbddev);
232 if(error==0) {
233
234 if(strcmp(stdinname,DEVNAME)==0) {
235
236 if(overwrite_console()) {
237 return 1;
238 }
239 error=console_assign(stdin,DEVNAME);
240 if(error==0)
241 return 1;
242 else
243 return error;
244 }
245 return 1;
246 }
247 return error;
248}
249
250
251
252
253
254void kbd_put_queue(char data)
255{
256 if((in_pointer+1)==KBD_BUFFER_LEN) {
257 if(out_pointer==0) {
258 return;
259 } else{
260 in_pointer=0;
261 }
262 } else {
263 if((in_pointer+1)==out_pointer)
264 return;
265 in_pointer++;
266 }
267 kbd_buffer[in_pointer]=data;
268 return;
269}
270
271
272int kbd_testc(void)
273{
274 if(in_pointer==out_pointer)
275 return(0);
276 else
277 return(1);
278}
279
280int kbd_getc(void)
281{
282 char c;
283 while(in_pointer==out_pointer);
284 if((out_pointer+1)==KBD_BUFFER_LEN)
285 out_pointer=0;
286 else
287 out_pointer++;
288 c=kbd_buffer[out_pointer];
289 return (int)c;
290
291}
292
293
294
295
296void kbd_set_leds(void)
297{
298 if(caps_lock==0)
299 leds&=~LED_CAP;
300 else
301 leds|=LED_CAP;
302 if(num_lock==0)
303 leds&=~LED_NUM;
304 else
305 leds|=LED_NUM;
306 if(scroll_lock==0)
307 leds&=~LED_SCR;
308 else
309 leds|=LED_SCR;
310 kbd_send_data(KBD_CMD_SET_LEDS);
311 kbd_send_data(leds);
312}
313
314
315void handle_keyboard_event (unsigned char scancode)
316{
317 unsigned char keycode;
318
319
320 PRINTF ("scancode %x\n", scancode);
321 if (scancode == 0xe0) {
322 e0 = 1;
323 return;
324 }
325 if (e0 == 1) {
326 e0 = 0;
327 if (!(((scancode & 0x7F) == 0x38) ||
328 ((scancode & 0x7F) == 0x1D) ||
329 ((scancode & 0x7F) == 0x35) ||
330 ((scancode & 0x7F) == 0x1C)))
331
332
333 return;
334 }
335
336 switch (scancode) {
337 case 0x2A:
338 case 0x36:
339 shift = 1;
340 return;
341 case 0xAA:
342 case 0xB6:
343 shift = 0;
344 return;
345 case 0x38:
346 alt = 1;
347 return;
348 case 0xB8:
349 alt = 0;
350 return;
351 case 0x1d:
352 ctrl = 1;
353 return;
354 case 0x9d:
355 ctrl = 0;
356 return;
357 case 0x46:
358 scroll_lock = ~scroll_lock;
359 kbd_set_leds ();
360 return;
361 case 0x3A:
362 caps_lock = ~caps_lock;
363 kbd_set_leds ();
364 return;
365 case 0x45:
366 num_lock = ~num_lock;
367 kbd_set_leds ();
368 return;
369 case 0xC6:
370 case 0xC5:
371 case 0xBA:
372 return;
373 }
374 if ((scancode & 0x80) == 0x80)
375 return;
376
377 if (scancode > (sizeof (kbd_plain_xlate) / sizeof (kbd_plain_xlate[0]))) {
378 PRINTF ("unkown scancode %X\n", scancode);
379 return;
380 }
381
382 keycode = kbd_plain_xlate[scancode];
383 if (caps_lock == 1) {
384 if (scancode > (sizeof (kbd_shift_xlate) / sizeof (kbd_shift_xlate[0]))) {
385 PRINTF ("unkown caps-locked scancode %X\n", scancode);
386 return;
387 }
388 keycode = kbd_shift_xlate[scancode];
389 if (keycode < 'A') {
390 keycode = kbd_plain_xlate[scancode];
391 }
392 }
393 if (shift == 1) {
394 if (scancode > (sizeof (kbd_shift_xlate) / sizeof (kbd_shift_xlate[0]))) {
395 PRINTF ("unkown shifted scancode %X\n", scancode);
396 return;
397 }
398 keycode = kbd_shift_xlate[scancode];
399 }
400 if (ctrl == 1) {
401 if (scancode > (sizeof (kbd_ctrl_xlate) / sizeof (kbd_ctrl_xlate[0]))) {
402 PRINTF ("unkown ctrl scancode %X\n", scancode);
403 return;
404 }
405 keycode = kbd_ctrl_xlate[scancode];
406 }
407
408 if (keycode == 0xff) {
409 PRINTF ("unkown scancode %X\n", scancode);
410 return;
411 }
412
413 kbd_put_queue (keycode);
414 PRINTF ("%x\n", keycode);
415}
416
417
418
419
420
421
422unsigned char handle_kbd_event(void)
423{
424 unsigned char status = kbd_read_status();
425 unsigned int work = 10000;
426
427 while ((--work > 0) && (status & KBD_STAT_OBF)) {
428 unsigned char scancode;
429
430 scancode = kbd_read_input();
431
432
433
434
435 if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
436 {
437 if (status & KBD_STAT_MOUSE_OBF)
438 ;
439 else
440 handle_keyboard_event(scancode);
441 }
442 status = kbd_read_status();
443 }
444 if (!work)
445 PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
446 return status;
447}
448
449
450
451
452
453unsigned char kbd_read_status(void)
454{
455 return(in8(CONFIG_SYS_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT));
456}
457
458unsigned char kbd_read_input(void)
459{
460 return(in8(CONFIG_SYS_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT));
461}
462
463void kbd_write_command(unsigned char cmd)
464{
465 out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT,cmd);
466}
467
468void kbd_write_output(unsigned char data)
469{
470 out8(CONFIG_SYS_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT, data);
471}
472
473int kbd_read_data(void)
474{
475 int val;
476 unsigned char status;
477
478 val = -1;
479 status = kbd_read_status();
480 if (status & KBD_STAT_OBF) {
481 val = kbd_read_input();
482 if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
483 val = -2;
484 }
485 return val;
486}
487
488int kbd_wait_for_input(void)
489{
490 unsigned long timeout;
491 int val;
492
493 timeout = KBD_TIMEOUT;
494 val=kbd_read_data();
495 while(val < 0)
496 {
497 if(timeout--==0)
498 return -1;
499 udelay(1000);
500 val=kbd_read_data();
501 }
502 return val;
503}
504
505
506int kb_wait(void)
507{
508 unsigned long timeout = KBC_TIMEOUT * 10;
509
510 do {
511 unsigned char status = handle_kbd_event();
512 if (!(status & KBD_STAT_IBF))
513 return 0;
514 udelay(1000);
515 timeout--;
516 } while (timeout);
517 return 1;
518}
519
520void kbd_write_command_w(int data)
521{
522 if(kb_wait())
523 PRINTF("timeout in kbd_write_command_w\n");
524 kbd_write_command(data);
525}
526
527void kbd_write_output_w(int data)
528{
529 if(kb_wait())
530 PRINTF("timeout in kbd_write_output_w\n");
531 kbd_write_output(data);
532}
533
534void kbd_send_data(unsigned char data)
535{
536 unsigned char status;
537 disable_8259A_irq(1);
538 kbd_write_output_w(data);
539 status = kbd_wait_for_input();
540 if (status == KBD_REPLY_ACK)
541 enable_8259A_irq(1);
542}
543
544
545char * kbd_initialize(void)
546{
547 int status;
548
549 in_pointer = 0;
550 out_pointer = 0;
551
552
553
554
555
556 kbd_write_command_w(KBD_CCMD_SELF_TEST);
557 if (kbd_wait_for_input() != 0x55)
558 return "Kbd: failed self test";
559
560
561
562
563
564 kbd_write_command_w(KBD_CCMD_KBD_TEST);
565 if (kbd_wait_for_input() != 0x00)
566 return "Kbd: interface failed self test";
567
568
569
570 kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
571 status = kbd_wait_for_input();
572
573
574
575
576
577
578
579
580 do {
581 kbd_write_output_w(KBD_CMD_RESET);
582 status = kbd_wait_for_input();
583 if (status == KBD_REPLY_ACK)
584 break;
585 if (status != KBD_REPLY_RESEND) {
586 PRINTF("status: %X\n",status);
587 return "Kbd: reset failed, no ACK";
588 }
589 } while (1);
590 if (kbd_wait_for_input() != KBD_REPLY_POR)
591 return "Kbd: reset failed, no POR";
592
593
594
595
596
597
598
599 do {
600 kbd_write_output_w(KBD_CMD_DISABLE);
601 status = kbd_wait_for_input();
602 if (status == KBD_REPLY_ACK)
603 break;
604 if (status != KBD_REPLY_RESEND)
605 return "Kbd: disable keyboard: no ACK";
606 } while (1);
607
608 kbd_write_command_w(KBD_CCMD_WRITE_MODE);
609 kbd_write_output_w(KBD_MODE_KBD_INT
610 | KBD_MODE_SYS
611 | KBD_MODE_DISABLE_MOUSE
612 | KBD_MODE_KCC);
613
614
615 kbd_write_command_w(KBD_CCMD_READ_MODE);
616 if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
617
618
619
620
621 kbd_write_output_w(0xF0);
622 kbd_wait_for_input();
623 kbd_write_output_w(0x01);
624 kbd_wait_for_input();
625 }
626 kbd_write_output_w(KBD_CMD_ENABLE);
627 if (kbd_wait_for_input() != KBD_REPLY_ACK)
628 return "Kbd: enable keyboard: no ACK";
629
630
631
632
633 kbd_write_output_w(KBD_CMD_SET_RATE);
634 if (kbd_wait_for_input() != KBD_REPLY_ACK)
635 return "Kbd: Set rate: no ACK";
636 kbd_write_output_w(0x00);
637 if (kbd_wait_for_input() != KBD_REPLY_ACK)
638 return "Kbd: Set rate: no ACK";
639 return NULL;
640}
641
642void kbd_interrupt(void)
643{
644 handle_kbd_event();
645}
646