blob: ecd585323f92107ea32470d4df3c511447f02ee0 [file] [log] [blame]
wdenk1c437712004-01-16 00:30:56 +00001/***********************************************************************
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
wdenk1c437712004-01-16 00:30:56 +000019#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
wdenkc837dcb2004-01-20 23:12:12 +000043static ulong start_time;
wdenk1c437712004-01-16 00:30:56 +000044static int init_done = 0;
45
46static int received_escape = 0;
47static int received_bsync = 0;
48static int received_selector = 0;
49
50static int kbd_command_active = 0;
51static int mouse_command_active = 0;
52static int ctl_command_active = 0;
53
54static u_char command_byte = 0;
55
56static void (*keyb_handler)(void *dev_id);
57
58static u_char ps2mult_buf [PS2BUF_SIZE];
59static atomic_t ps2mult_buf_cnt;
60static int ps2mult_buf_in_idx;
61static int ps2mult_buf_out_idx;
62
63static u_char ps2mult_buf_status [PS2BUF_SIZE];
64
wdenkc837dcb2004-01-20 23:12:12 +000065#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
68void ps2mult_early_init (void)
69{
70 start_time = get_timer(0);
71}
wdenk1c437712004-01-16 00:30:56 +000072
73static 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
101static 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
150void 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
204u_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
221u_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
238void 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
289void 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
338static 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
363int ps2mult_init (void)
364{
365 int byte;
366 int kbd_found = 0;
367 int mouse_found = 0;
368
wdenkc837dcb2004-01-20 23:12:12 +0000369 while (get_timer(start_time) < CONFIG_PS2MULT_DELAY);
370
wdenk1c437712004-01-16 00:30:56 +0000371 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
457int ps2mult_request_irq(void (*handler)(void *))
458{
459 keyb_handler = handler;
460
461 return 0;
462}