1 /***********************************************************************
4 * DENX Software Engineering
5 * Wolfgang Denk, wd@denx.de
8 * PS/2 multiplexer driver
10 * Originally from linux source (drivers/char/ps2mult.c)
12 * Uses simple serial driver (ps2ser.c) to access the multiplexer
13 * Used by PS/2 keyboard driver (pc_keyb.c)
15 ***********************************************************************/
20 #include <asm/atomic.h>
23 /* #define DEBUG_MULT */
24 /* #define DEBUG_KEYB */
26 #define KBD_STAT_DEFAULT (KBD_STAT_SELFTEST | KBD_STAT_UNLOCKED)
28 #define PRINTF(format, args...) printf("ps2mult.c: " format, ## args)
31 #define PRINTF_MULT(format, args...) printf("PS2MULT: " format, ## args)
33 #define PRINTF_MULT(format, args...)
37 #define PRINTF_KEYB(format, args...) printf("KEYB: " format, ## args)
39 #define PRINTF_KEYB(format, args...)
43 static ulong start_time;
44 static int init_done = 0;
46 static int received_escape = 0;
47 static int received_bsync = 0;
48 static int received_selector = 0;
50 static int kbd_command_active = 0;
51 static int mouse_command_active = 0;
52 static int ctl_command_active = 0;
54 static u_char command_byte = 0;
56 static void (*keyb_handler)(void *dev_id);
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;
63 static u_char ps2mult_buf_status [PS2BUF_SIZE];
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()
68 void ps2mult_early_init (void)
70 start_time = get_timer(0);
73 static void ps2mult_send_byte(u_char byte, u_char sel)
77 if (sel == PS2MULT_KB_SELECTOR) {
78 PRINTF_MULT("0x%02x send KEYBOARD\n", byte);
79 kbd_command_active = 1;
81 PRINTF_MULT("0x%02x send MOUSE\n", byte);
82 mouse_command_active = 1;
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);
101 static void ps2mult_receive_byte(u_char byte, u_char sel)
103 u_char status = KBD_STAT_DEFAULT;
105 #if 1 /* Ignore mouse in U-Boot */
106 if (sel == PS2MULT_MS_SELECTOR) return;
109 if (sel == PS2MULT_KB_SELECTOR) {
110 if (kbd_command_active) {
111 if (!received_bsync) {
112 PRINTF_MULT("0x%02x lost KEYBOARD !!!\n", byte);
115 kbd_command_active = 0;
119 PRINTF_MULT("0x%02x receive KEYBOARD\n", byte);
120 status |= KBD_STAT_IBF | KBD_STAT_OBF;
122 if (mouse_command_active) {
123 if (!received_bsync) {
124 PRINTF_MULT("0x%02x lost MOUSE !!!\n", byte);
127 mouse_command_active = 0;
131 PRINTF_MULT("0x%02x receive MOUSE\n", byte);
132 status |= KBD_STAT_IBF | KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
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);
141 PRINTF("buffer overflow\n");
144 if (received_bsync) {
145 PRINTF("unexpected BSYNC\n");
150 void ps2mult_callback (int in_cnt)
154 static int keyb_handler_active = 0;
160 for (i = 0; i < in_cnt; i ++) {
161 byte = ps2ser_getc();
163 if (received_escape) {
164 ps2mult_receive_byte(byte, received_selector);
166 } else switch (byte) {
168 PRINTF_MULT("ESCAPE receive\n");
173 PRINTF_MULT("BSYNC receive\n");
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;
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");
192 ps2mult_receive_byte(byte, received_selector);
196 if (keyb_handler && !keyb_handler_active &&
197 atomic_read(&ps2mult_buf_cnt)) {
198 keyb_handler_active = 1;
200 keyb_handler_active = 0;
204 u_char ps2mult_read_status(void)
208 if (atomic_read(&ps2mult_buf_cnt) == 0) {
212 if (atomic_read(&ps2mult_buf_cnt)) {
213 byte = ps2mult_buf_status[ps2mult_buf_out_idx];
215 byte = KBD_STAT_DEFAULT;
217 PRINTF_KEYB("read_status()=0x%02x\n", byte);
221 u_char ps2mult_read_input(void)
225 if (atomic_read(&ps2mult_buf_cnt) == 0) {
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);
234 PRINTF_KEYB("read_input()=0x%02x\n", byte);
238 void ps2mult_write_output(u_char val)
242 PRINTF_KEYB("write_output(0x%02x)\n", val);
244 for (i = 0; i < KBD_TIMEOUT; i++) {
245 if (!kbd_command_active && !mouse_command_active) {
252 if (kbd_command_active) {
253 PRINTF("keyboard command not acknoledged\n");
254 kbd_command_active = 0;
257 if (mouse_command_active) {
258 PRINTF("mouse command not acknoledged\n");
259 mouse_command_active = 0;
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;
269 case KBD_CCMD_WRITE_AUX_OBUF:
270 ps2mult_receive_byte(val, PS2MULT_MS_SELECTOR);
273 case KBD_CCMD_WRITE_MOUSE:
274 ps2mult_send_byte(val, PS2MULT_MS_SELECTOR);
278 PRINTF("invalid controller command\n");
282 ctl_command_active = 0;
286 ps2mult_send_byte(val, PS2MULT_KB_SELECTOR);
289 void ps2mult_write_command(u_char val)
291 ctl_command_active = 0;
293 PRINTF_KEYB("write_command(0x%02x)\n", val);
296 case KBD_CCMD_READ_MODE:
297 ps2mult_receive_byte(command_byte, PS2MULT_KB_SELECTOR);
300 case KBD_CCMD_WRITE_MODE:
301 ctl_command_active = val;
304 case KBD_CCMD_MOUSE_DISABLE:
307 case KBD_CCMD_MOUSE_ENABLE:
310 case KBD_CCMD_SELF_TEST:
311 ps2mult_receive_byte(0x55, PS2MULT_KB_SELECTOR);
314 case KBD_CCMD_KBD_TEST:
315 ps2mult_receive_byte(0x00, PS2MULT_KB_SELECTOR);
318 case KBD_CCMD_KBD_DISABLE:
321 case KBD_CCMD_KBD_ENABLE:
324 case KBD_CCMD_WRITE_AUX_OBUF:
325 ctl_command_active = val;
328 case KBD_CCMD_WRITE_MOUSE:
329 ctl_command_active = val;
333 PRINTF("invalid controller command\n");
338 static int ps2mult_getc_w (void)
343 for (i = 0; i < KBD_TIMEOUT; i++) {
344 if (ps2ser_check()) {
352 case PS2MULT_KB_SELECTOR:
353 case PS2MULT_MS_SELECTOR:
354 received_selector = res;
363 int ps2mult_init (void)
369 while (get_timer(start_time) < CONFIG_PS2MULT_DELAY);
373 ps2ser_putc(PS2MULT_SESSION_START);
375 ps2ser_putc(PS2MULT_KB_SELECTOR);
376 ps2ser_putc(KBD_CMD_RESET);
379 byte = ps2mult_getc_w();
380 } while (byte >= 0 && byte != KBD_REPLY_ACK);
382 if (byte == KBD_REPLY_ACK) {
383 byte = ps2mult_getc_w();
392 byte = ps2mult_getc_w();
396 #if 1 /* detect mouse */
397 ps2ser_putc(PS2MULT_MS_SELECTOR);
398 ps2ser_putc(AUX_RESET);
401 byte = ps2mult_getc_w();
402 } while (byte >= 0 && byte != AUX_ACK);
404 if (byte == AUX_ACK) {
405 byte = ps2mult_getc_w();
407 byte = ps2mult_getc_w();
417 byte = ps2mult_getc_w();
422 if (mouse_found || kbd_found) {
423 if (!received_selector) {
425 received_selector = PS2MULT_MS_SELECTOR;
427 received_selector = PS2MULT_KB_SELECTOR;
433 puts("No device found");
438 #if 0 /* for testing */
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 */
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);
454 return init_done ? 0 : -1;
457 int ps2mult_request_irq(void (*handler)(void *))
459 keyb_handler = handler;