1 /***********************************************************************
2  *
3  * (C) Copyright 2004
4  * DENX Software Engineering
5  * Wolfgang Denk, wd@denx.de
6  *
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 
18 #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 
42 static ulong start_time;
43 static int init_done = 0;
44 
45 static int received_escape = 0;
46 static int received_bsync = 0;
47 static int received_selector = 0;
48 
49 static int kbd_command_active = 0;
50 static int mouse_command_active = 0;
51 static int ctl_command_active = 0;
52 
53 static u_char command_byte = 0;
54 
55 static void (*keyb_handler)(void *dev_id);
56 
57 static u_char ps2mult_buf [PS2BUF_SIZE];
58 static atomic_t ps2mult_buf_cnt;
59 static int ps2mult_buf_in_idx;
60 static int ps2mult_buf_out_idx;
61 
62 static u_char ps2mult_buf_status [PS2BUF_SIZE];
63 
64 #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
ps2mult_early_init(void)67 void ps2mult_early_init (void)
68 {
69 	start_time = get_timer(0);
70 }
71 
ps2mult_send_byte(u_char byte,u_char sel)72 static 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 
ps2mult_receive_byte(u_char byte,u_char sel)100 static 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 
ps2mult_callback(int in_cnt)149 void 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 
ps2mult_read_status(void)203 u_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 
ps2mult_read_input(void)220 u_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 
ps2mult_write_output(u_char val)237 void 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 
ps2mult_write_command(u_char val)288 void 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 
ps2mult_getc_w(void)337 static 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 
ps2mult_init(void)362 int ps2mult_init (void)
363 {
364 	int byte;
365 	int kbd_found = 0;
366 	int mouse_found = 0;
367 
368 	while (get_timer(start_time) < CONFIG_PS2MULT_DELAY);
369 
370 	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 
ps2mult_request_irq(void (* handler)(void *))456 int ps2mult_request_irq(void (*handler)(void *))
457 {
458 	keyb_handler = handler;
459 
460 	return 0;
461 }
462