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