Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
[platform/kernel/u-boot.git] / drivers / input / ps2mult.c
1 /***********************************************************************
2  *
3  * (C) Copyright 2004
4  * DENX Software Engineering
5  * Wolfgang Denk, wd@denx.de
6  * All rights reserved.
7  *
8  * PS/2 multiplexer driver
9  *
10  * Originally from linux source (drivers/char/ps2mult.c)
11  *
12  * Uses simple serial driver (ps2ser.c) to access the multiplexer
13  * Used by PS/2 keyboard driver (pc_keyb.c)
14  *
15  ***********************************************************************/
16
17 #include <common.h>
18
19 #include <pc_keyb.h>
20 #include <asm/atomic.h>
21 #include <ps2mult.h>
22
23 /* #define DEBUG_MULT */
24 /* #define DEBUG_KEYB */
25
26 #define KBD_STAT_DEFAULT                (KBD_STAT_SELFTEST | KBD_STAT_UNLOCKED)
27
28 #define PRINTF(format, args...)         printf("ps2mult.c: " format, ## args)
29
30 #ifdef DEBUG_MULT
31 #define PRINTF_MULT(format, args...)    printf("PS2MULT: " format, ## args)
32 #else
33 #define PRINTF_MULT(format, args...)
34 #endif
35
36 #ifdef DEBUG_KEYB
37 #define PRINTF_KEYB(format, args...)    printf("KEYB: " format, ## args)
38 #else
39 #define PRINTF_KEYB(format, args...)
40 #endif
41
42
43 static ulong start_time;
44 static int init_done = 0;
45
46 static int received_escape = 0;
47 static int received_bsync = 0;
48 static int received_selector = 0;
49
50 static int kbd_command_active = 0;
51 static int mouse_command_active = 0;
52 static int ctl_command_active = 0;
53
54 static u_char command_byte = 0;
55
56 static void (*keyb_handler)(void *dev_id);
57
58 static u_char ps2mult_buf [PS2BUF_SIZE];
59 static atomic_t ps2mult_buf_cnt;
60 static int ps2mult_buf_in_idx;
61 static int ps2mult_buf_out_idx;
62
63 static u_char ps2mult_buf_status [PS2BUF_SIZE];
64
65 #ifndef CONFIG_BOARD_EARLY_INIT_R
66 #error #define CONFIG_BOARD_EARLY_INIT_R and call ps2mult_early_init() in board_early_init_r()
67 #endif
68 void ps2mult_early_init (void)
69 {
70         start_time = get_timer(0);
71 }
72
73 static void ps2mult_send_byte(u_char byte, u_char sel)
74 {
75         ps2ser_putc(sel);
76
77         if (sel == PS2MULT_KB_SELECTOR) {
78                 PRINTF_MULT("0x%02x send KEYBOARD\n", byte);
79                 kbd_command_active = 1;
80         } else {
81                 PRINTF_MULT("0x%02x send MOUSE\n", byte);
82                 mouse_command_active = 1;
83         }
84
85         switch (byte) {
86         case PS2MULT_ESCAPE:
87         case PS2MULT_BSYNC:
88         case PS2MULT_KB_SELECTOR:
89         case PS2MULT_MS_SELECTOR:
90         case PS2MULT_SESSION_START:
91         case PS2MULT_SESSION_END:
92                 ps2ser_putc(PS2MULT_ESCAPE);
93                 break;
94         default:
95                 break;
96         }
97
98         ps2ser_putc(byte);
99 }
100
101 static void ps2mult_receive_byte(u_char byte, u_char sel)
102 {
103         u_char status = KBD_STAT_DEFAULT;
104
105 #if 1 /* Ignore mouse in U-Boot */
106         if (sel == PS2MULT_MS_SELECTOR) return;
107 #endif
108
109         if (sel == PS2MULT_KB_SELECTOR) {
110                 if (kbd_command_active) {
111                         if (!received_bsync) {
112                                 PRINTF_MULT("0x%02x lost KEYBOARD !!!\n", byte);
113                                 return;
114                         } else {
115                                 kbd_command_active = 0;
116                                 received_bsync = 0;
117                         }
118                 }
119                 PRINTF_MULT("0x%02x receive KEYBOARD\n", byte);
120                 status |= KBD_STAT_IBF | KBD_STAT_OBF;
121         } else {
122                 if (mouse_command_active) {
123                         if (!received_bsync) {
124                                 PRINTF_MULT("0x%02x lost MOUSE !!!\n", byte);
125                                 return;
126                         } else {
127                                 mouse_command_active = 0;
128                                 received_bsync = 0;
129                         }
130                 }
131                 PRINTF_MULT("0x%02x receive MOUSE\n", byte);
132                 status |= KBD_STAT_IBF | KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
133         }
134
135         if (atomic_read(&ps2mult_buf_cnt) < PS2BUF_SIZE) {
136                 ps2mult_buf_status[ps2mult_buf_in_idx] = status;
137                 ps2mult_buf[ps2mult_buf_in_idx++] = byte;
138                 ps2mult_buf_in_idx &= (PS2BUF_SIZE - 1);
139                 atomic_inc(&ps2mult_buf_cnt);
140         } else {
141                 PRINTF("buffer overflow\n");
142         }
143
144         if (received_bsync) {
145                 PRINTF("unexpected BSYNC\n");
146                 received_bsync = 0;
147         }
148 }
149
150 void ps2mult_callback (int in_cnt)
151 {
152         int i;
153         u_char byte;
154         static int keyb_handler_active = 0;
155
156         if (!init_done) {
157                 return;
158         }
159
160         for (i = 0; i < in_cnt; i ++) {
161                 byte = ps2ser_getc();
162
163                 if (received_escape) {
164                         ps2mult_receive_byte(byte, received_selector);
165                         received_escape = 0;
166                 } else switch (byte) {
167                 case PS2MULT_ESCAPE:
168                         PRINTF_MULT("ESCAPE receive\n");
169                         received_escape = 1;
170                         break;
171
172                 case PS2MULT_BSYNC:
173                         PRINTF_MULT("BSYNC receive\n");
174                         received_bsync = 1;
175                         break;
176
177                 case PS2MULT_KB_SELECTOR:
178                 case PS2MULT_MS_SELECTOR:
179                         PRINTF_MULT("%s receive\n",
180                             byte == PS2MULT_KB_SELECTOR ? "KB_SEL" : "MS_SEL");
181                         received_selector = byte;
182                         break;
183
184                 case PS2MULT_SESSION_START:
185                 case PS2MULT_SESSION_END:
186                         PRINTF_MULT("%s receive\n",
187                             byte == PS2MULT_SESSION_START ?
188                             "SESSION_START" : "SESSION_END");
189                         break;
190
191                 default:
192                         ps2mult_receive_byte(byte, received_selector);
193                 }
194         }
195
196         if (keyb_handler && !keyb_handler_active &&
197             atomic_read(&ps2mult_buf_cnt)) {
198                 keyb_handler_active = 1;
199                 keyb_handler(NULL);
200                 keyb_handler_active = 0;
201         }
202 }
203
204 u_char ps2mult_read_status(void)
205 {
206         u_char byte;
207
208         if (atomic_read(&ps2mult_buf_cnt) == 0) {
209                 ps2ser_check();
210         }
211
212         if (atomic_read(&ps2mult_buf_cnt)) {
213                 byte = ps2mult_buf_status[ps2mult_buf_out_idx];
214         } else {
215                 byte = KBD_STAT_DEFAULT;
216         }
217         PRINTF_KEYB("read_status()=0x%02x\n", byte);
218         return byte;
219 }
220
221 u_char ps2mult_read_input(void)
222 {
223         u_char byte = 0;
224
225         if (atomic_read(&ps2mult_buf_cnt) == 0) {
226                 ps2ser_check();
227         }
228
229         if (atomic_read(&ps2mult_buf_cnt)) {
230                 byte = ps2mult_buf[ps2mult_buf_out_idx++];
231                 ps2mult_buf_out_idx &= (PS2BUF_SIZE - 1);
232                 atomic_dec(&ps2mult_buf_cnt);
233         }
234         PRINTF_KEYB("read_input()=0x%02x\n", byte);
235         return byte;
236 }
237
238 void ps2mult_write_output(u_char val)
239 {
240         int i;
241
242         PRINTF_KEYB("write_output(0x%02x)\n", val);
243
244         for (i = 0; i < KBD_TIMEOUT; i++) {
245                 if (!kbd_command_active && !mouse_command_active) {
246                         break;
247                 }
248                 udelay(1000);
249                 ps2ser_check();
250         }
251
252         if (kbd_command_active) {
253                 PRINTF("keyboard command not acknoledged\n");
254                 kbd_command_active = 0;
255         }
256
257         if (mouse_command_active) {
258                 PRINTF("mouse command not acknoledged\n");
259                 mouse_command_active = 0;
260         }
261
262         if (ctl_command_active) {
263                 switch (ctl_command_active) {
264                 case KBD_CCMD_WRITE_MODE:
265                           /* Scan code conversion not supported */
266                         command_byte = val & ~KBD_MODE_KCC;
267                         break;
268
269                 case KBD_CCMD_WRITE_AUX_OBUF:
270                         ps2mult_receive_byte(val, PS2MULT_MS_SELECTOR);
271                         break;
272
273                 case KBD_CCMD_WRITE_MOUSE:
274                         ps2mult_send_byte(val, PS2MULT_MS_SELECTOR);
275                         break;
276
277                 default:
278                         PRINTF("invalid controller command\n");
279                         break;
280                 }
281
282                 ctl_command_active = 0;
283                 return;
284         }
285
286         ps2mult_send_byte(val, PS2MULT_KB_SELECTOR);
287 }
288
289 void ps2mult_write_command(u_char val)
290 {
291         ctl_command_active = 0;
292
293         PRINTF_KEYB("write_command(0x%02x)\n", val);
294
295         switch (val) {
296         case KBD_CCMD_READ_MODE:
297                 ps2mult_receive_byte(command_byte, PS2MULT_KB_SELECTOR);
298                 break;
299
300         case KBD_CCMD_WRITE_MODE:
301                 ctl_command_active = val;
302                 break;
303
304         case KBD_CCMD_MOUSE_DISABLE:
305                 break;
306
307         case KBD_CCMD_MOUSE_ENABLE:
308                 break;
309
310         case KBD_CCMD_SELF_TEST:
311                 ps2mult_receive_byte(0x55, PS2MULT_KB_SELECTOR);
312                 break;
313
314         case KBD_CCMD_KBD_TEST:
315                 ps2mult_receive_byte(0x00, PS2MULT_KB_SELECTOR);
316                 break;
317
318         case KBD_CCMD_KBD_DISABLE:
319                 break;
320
321         case KBD_CCMD_KBD_ENABLE:
322                 break;
323
324         case KBD_CCMD_WRITE_AUX_OBUF:
325                 ctl_command_active = val;
326                 break;
327
328         case KBD_CCMD_WRITE_MOUSE:
329                 ctl_command_active = val;
330                 break;
331
332         default:
333                 PRINTF("invalid controller command\n");
334                 break;
335         }
336 }
337
338 static int ps2mult_getc_w (void)
339 {
340         int res = -1;
341         int i;
342
343         for (i = 0; i < KBD_TIMEOUT; i++) {
344                 if (ps2ser_check()) {
345                         res = ps2ser_getc();
346                         break;
347                 }
348                 udelay(1000);
349         }
350
351         switch (res) {
352         case PS2MULT_KB_SELECTOR:
353         case PS2MULT_MS_SELECTOR:
354                 received_selector = res;
355                 break;
356         default:
357                 break;
358         }
359
360         return res;
361 }
362
363 int ps2mult_init (void)
364 {
365         int byte;
366         int kbd_found = 0;
367         int mouse_found = 0;
368
369         while (get_timer(start_time) < CONFIG_PS2MULT_DELAY);
370
371         ps2ser_init();
372
373         ps2ser_putc(PS2MULT_SESSION_START);
374
375         ps2ser_putc(PS2MULT_KB_SELECTOR);
376         ps2ser_putc(KBD_CMD_RESET);
377
378         do {
379                 byte = ps2mult_getc_w();
380         } while (byte >= 0 && byte != KBD_REPLY_ACK);
381
382         if (byte == KBD_REPLY_ACK) {
383                 byte = ps2mult_getc_w();
384                 if (byte == 0xaa) {
385                         kbd_found = 1;
386                         puts("keyboard");
387                 }
388         }
389
390         if (!kbd_found) {
391                 while (byte >= 0) {
392                         byte = ps2mult_getc_w();
393                 }
394         }
395
396 #if 1 /* detect mouse */
397         ps2ser_putc(PS2MULT_MS_SELECTOR);
398         ps2ser_putc(AUX_RESET);
399
400         do {
401                 byte = ps2mult_getc_w();
402         } while (byte >= 0 && byte != AUX_ACK);
403
404         if (byte == AUX_ACK) {
405                 byte = ps2mult_getc_w();
406                 if (byte == 0xaa) {
407                         byte = ps2mult_getc_w();
408                         if (byte == 0x00) {
409                                 mouse_found = 1;
410                                 puts(", mouse");
411                         }
412                 }
413         }
414
415         if (!mouse_found) {
416                 while (byte >= 0) {
417                         byte = ps2mult_getc_w();
418                 }
419         }
420 #endif
421
422         if (mouse_found || kbd_found) {
423                 if (!received_selector) {
424                         if (mouse_found) {
425                                 received_selector = PS2MULT_MS_SELECTOR;
426                         } else {
427                                 received_selector = PS2MULT_KB_SELECTOR;
428                         }
429                 }
430
431                 init_done = 1;
432         } else {
433                 puts("No device found");
434         }
435
436         puts("\n");
437
438 #if 0 /* for testing */
439         {
440                 int i;
441                 u_char key[] = {
442                         0x1f, 0x12, 0x14, 0x12, 0x31, 0x2f, 0x39,       /* setenv */
443                         0x1f, 0x14, 0x20, 0x17, 0x31, 0x39,             /* stdin */
444                         0x1f, 0x12, 0x13, 0x17, 0x1e, 0x26, 0x1c,       /* serial */
445                 };
446
447                 for (i = 0; i < sizeof (key); i++) {
448                         ps2mult_receive_byte (key[i],        PS2MULT_KB_SELECTOR);
449                         ps2mult_receive_byte (key[i] | 0x80, PS2MULT_KB_SELECTOR);
450                 }
451         }
452 #endif
453
454         return init_done ? 0 : -1;
455 }
456
457 int ps2mult_request_irq(void (*handler)(void *))
458 {
459         keyb_handler = handler;
460
461         return 0;
462 }