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