]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/input/pc_keyb.c
net: fec_mxc: move CONFIG_FEC_MXC_PHYADDR from Kconfig to include/configs/*.h
[karo-tx-uboot.git] / drivers / input / pc_keyb.c
1 /***********************************************************************
2  *
3  * (C) Copyright 2004
4  * DENX Software Engineering
5  * Wolfgang Denk, wd@denx.de
6  *
7  * PS/2 keyboard driver
8  *
9  * Originally from linux source (drivers/char/pc_keyb.c)
10  *
11  ***********************************************************************/
12
13 #include <common.h>
14
15 #include <keyboard.h>
16 #include <pc_keyb.h>
17
18 #undef KBG_DEBUG
19
20 #ifdef KBG_DEBUG
21 #define PRINTF(fmt,args...)     printf (fmt ,##args)
22 #else
23 #define PRINTF(fmt,args...)
24 #endif
25
26
27 /*
28  * This reads the keyboard status port, and does the
29  * appropriate action.
30  *
31  */
32 static unsigned char handle_kbd_event(void)
33 {
34         unsigned char status = kbd_read_status();
35         unsigned int work = 10000;
36
37         while ((--work > 0) && (status & KBD_STAT_OBF)) {
38                 unsigned char scancode;
39
40                 scancode = kbd_read_input();
41
42                 /* Error bytes must be ignored to make the
43                    Synaptics touchpads compaq use work */
44                 /* Ignore error bytes */
45                 if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) {
46                         if (status & KBD_STAT_MOUSE_OBF)
47                                 ; /* not supported: handle_mouse_event(scancode); */
48                         else
49                                 handle_scancode(scancode);
50                 }
51                 status = kbd_read_status();
52         }
53         if (!work)
54                 PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
55         return status;
56 }
57
58
59 static int kbd_read_data(void)
60 {
61         int val;
62         unsigned char status;
63
64         val = -1;
65         status = kbd_read_status();
66         if (status & KBD_STAT_OBF) {
67                 val = kbd_read_input();
68                 if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
69                         val = -2;
70         }
71         return val;
72 }
73
74 static int kbd_wait_for_input(void)
75 {
76         unsigned long timeout;
77         int val;
78
79         timeout = KBD_TIMEOUT;
80         val=kbd_read_data();
81         while(val < 0) {
82                 if(timeout--==0)
83                         return -1;
84                 udelay(1000);
85                 val=kbd_read_data();
86         }
87         return val;
88 }
89
90
91 static int kb_wait(void)
92 {
93         unsigned long timeout = KBC_TIMEOUT * 10;
94
95         do {
96                 unsigned char status = handle_kbd_event();
97                 if (!(status & KBD_STAT_IBF))
98                         return 0; /* ok */
99                 udelay(1000);
100                 timeout--;
101         } while (timeout);
102         return 1;
103 }
104
105 static void kbd_write_command_w(int data)
106 {
107         if(kb_wait())
108                 PRINTF("timeout in kbd_write_command_w\n");
109         kbd_write_command(data);
110 }
111
112 static void kbd_write_output_w(int data)
113 {
114         if(kb_wait())
115                 PRINTF("timeout in kbd_write_output_w\n");
116         kbd_write_output(data);
117 }
118
119 static void kbd_send_data(unsigned char data)
120 {
121         kbd_write_output_w(data);
122         kbd_wait_for_input();
123 }
124
125
126 static char * kbd_initialize(void)
127 {
128         int status;
129
130         /*
131          * Test the keyboard interface.
132          * This seems to be the only way to get it going.
133          * If the test is successful a x55 is placed in the input buffer.
134          */
135         kbd_write_command_w(KBD_CCMD_SELF_TEST);
136         if (kbd_wait_for_input() != 0x55)
137                 return "Kbd:   failed self test";
138         /*
139          * Perform a keyboard interface test.  This causes the controller
140          * to test the keyboard clock and data lines.  The results of the
141          * test are placed in the input buffer.
142          */
143         kbd_write_command_w(KBD_CCMD_KBD_TEST);
144         if (kbd_wait_for_input() != 0x00)
145                 return "Kbd:   interface failed self test";
146         /*
147          * Enable the keyboard by allowing the keyboard clock to run.
148          */
149         kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
150
151         /*
152          * Reset keyboard. If the read times out
153          * then the assumption is that no keyboard is
154          * plugged into the machine.
155          * This defaults the keyboard to scan-code set 2.
156          *
157          * Set up to try again if the keyboard asks for RESEND.
158          */
159         do {
160                 kbd_write_output_w(KBD_CMD_RESET);
161                 status = kbd_wait_for_input();
162                 if (status == KBD_REPLY_ACK)
163                         break;
164                 if (status != KBD_REPLY_RESEND) {
165                         PRINTF("status: %X\n",status);
166                         return "Kbd:   reset failed, no ACK";
167                 }
168         } while (1);
169         if (kbd_wait_for_input() != KBD_REPLY_POR)
170                 return "Kbd:   reset failed, no POR";
171
172         /*
173          * Set keyboard controller mode. During this, the keyboard should be
174          * in the disabled state.
175          *
176          * Set up to try again if the keyboard asks for RESEND.
177          */
178         do {
179                 kbd_write_output_w(KBD_CMD_DISABLE);
180                 status = kbd_wait_for_input();
181                 if (status == KBD_REPLY_ACK)
182                         break;
183                 if (status != KBD_REPLY_RESEND)
184                         return "Kbd:   disable keyboard: no ACK";
185         } while (1);
186
187         kbd_write_command_w(KBD_CCMD_WRITE_MODE);
188         kbd_write_output_w(KBD_MODE_KBD_INT
189                               | KBD_MODE_SYS
190                               | KBD_MODE_DISABLE_MOUSE
191                               | KBD_MODE_KCC);
192
193         /* AMCC powerpc portables need this to use scan-code set 1 -- Cort */
194         kbd_write_command_w(KBD_CCMD_READ_MODE);
195         if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
196                 /*
197                  * If the controller does not support conversion,
198                  * Set the keyboard to scan-code set 1.
199                  */
200                 kbd_write_output_w(0xF0);
201                 kbd_wait_for_input();
202                 kbd_write_output_w(0x01);
203                 kbd_wait_for_input();
204         }
205         kbd_write_output_w(KBD_CMD_ENABLE);
206         if (kbd_wait_for_input() != KBD_REPLY_ACK)
207                 return "Kbd:   enable keyboard: no ACK";
208
209         /*
210          * Finally, set the typematic rate to maximum.
211          */
212         kbd_write_output_w(KBD_CMD_SET_RATE);
213         if (kbd_wait_for_input() != KBD_REPLY_ACK)
214                 return "Kbd:   Set rate: no ACK";
215         kbd_write_output_w(0x00);
216         if (kbd_wait_for_input() != KBD_REPLY_ACK)
217                 return "Kbd:   Set rate: no ACK";
218         return NULL;
219 }
220
221 static void kbd_interrupt(void *dev_id)
222 {
223         handle_kbd_event();
224 }
225
226 /******************************************************************
227  * Init
228  ******************************************************************/
229
230 int kbd_init_hw(void)
231 {
232         char* result;
233
234         kbd_request_region();
235
236         result=kbd_initialize();
237         if (result==NULL) {
238                 PRINTF("AT Keyboard initialized\n");
239                 kbd_request_irq(kbd_interrupt);
240                 return (1);
241         } else {
242                 printf("%s\n",result);
243                 return (-1);
244         }
245 }
246
247 void pckbd_leds(unsigned char leds)
248 {
249         kbd_send_data(KBD_CMD_SET_LEDS);
250         kbd_send_data(leds);
251 }