1 /***********************************************************************
4 * DENX Software Engineering
5 * Wolfgang Denk, wd@denx.de
7 * PS/2 multiplexer driver
9 * Originally from linux source (drivers/char/ps2mult.c)
11 * Uses simple serial driver (ps2ser.c) to access the multiplexer
12 * Used by PS/2 keyboard driver (pc_keyb.c)
14 ***********************************************************************/
19 #include <asm/atomic.h>
22 /* #define DEBUG_MULT */
23 /* #define DEBUG_KEYB */
25 #define KBD_STAT_DEFAULT (KBD_STAT_SELFTEST | KBD_STAT_UNLOCKED)
27 #define PRINTF(format, args...) printf("ps2mult.c: " format, ## args)
30 #define PRINTF_MULT(format, args...) printf("PS2MULT: " format, ## args)
32 #define PRINTF_MULT(format, args...)
36 #define PRINTF_KEYB(format, args...) printf("KEYB: " format, ## args)
38 #define PRINTF_KEYB(format, args...)
42 static ulong start_time
;
43 static int init_done
= 0;
45 static int received_escape
= 0;
46 static int received_bsync
= 0;
47 static int received_selector
= 0;
49 static int kbd_command_active
= 0;
50 static int mouse_command_active
= 0;
51 static int ctl_command_active
= 0;
53 static u_char command_byte
= 0;
55 static void (*keyb_handler
)(void *dev_id
);
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
;
62 static u_char ps2mult_buf_status
[PS2BUF_SIZE
];
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()
67 void ps2mult_early_init (void)
69 start_time
= get_timer(0);
72 static void ps2mult_send_byte(u_char byte
, u_char sel
)
76 if (sel
== PS2MULT_KB_SELECTOR
) {
77 PRINTF_MULT("0x%02x send KEYBOARD\n", byte
);
78 kbd_command_active
= 1;
80 PRINTF_MULT("0x%02x send MOUSE\n", byte
);
81 mouse_command_active
= 1;
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
);
100 static void ps2mult_receive_byte(u_char byte
, u_char sel
)
102 u_char status
= KBD_STAT_DEFAULT
;
104 #if 1 /* Ignore mouse in U-Boot */
105 if (sel
== PS2MULT_MS_SELECTOR
) return;
108 if (sel
== PS2MULT_KB_SELECTOR
) {
109 if (kbd_command_active
) {
110 if (!received_bsync
) {
111 PRINTF_MULT("0x%02x lost KEYBOARD !!!\n", byte
);
114 kbd_command_active
= 0;
118 PRINTF_MULT("0x%02x receive KEYBOARD\n", byte
);
119 status
|= KBD_STAT_IBF
| KBD_STAT_OBF
;
121 if (mouse_command_active
) {
122 if (!received_bsync
) {
123 PRINTF_MULT("0x%02x lost MOUSE !!!\n", byte
);
126 mouse_command_active
= 0;
130 PRINTF_MULT("0x%02x receive MOUSE\n", byte
);
131 status
|= KBD_STAT_IBF
| KBD_STAT_OBF
| KBD_STAT_MOUSE_OBF
;
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
);
140 PRINTF("buffer overflow\n");
143 if (received_bsync
) {
144 PRINTF("unexpected BSYNC\n");
149 void ps2mult_callback (int in_cnt
)
153 static int keyb_handler_active
= 0;
159 for (i
= 0; i
< in_cnt
; i
++) {
160 byte
= ps2ser_getc();
162 if (received_escape
) {
163 ps2mult_receive_byte(byte
, received_selector
);
165 } else switch (byte
) {
167 PRINTF_MULT("ESCAPE receive\n");
172 PRINTF_MULT("BSYNC receive\n");
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
;
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");
191 ps2mult_receive_byte(byte
, received_selector
);
195 if (keyb_handler
&& !keyb_handler_active
&&
196 atomic_read(&ps2mult_buf_cnt
)) {
197 keyb_handler_active
= 1;
199 keyb_handler_active
= 0;
203 u_char
ps2mult_read_status(void)
207 if (atomic_read(&ps2mult_buf_cnt
) == 0) {
211 if (atomic_read(&ps2mult_buf_cnt
)) {
212 byte
= ps2mult_buf_status
[ps2mult_buf_out_idx
];
214 byte
= KBD_STAT_DEFAULT
;
216 PRINTF_KEYB("read_status()=0x%02x\n", byte
);
220 u_char
ps2mult_read_input(void)
224 if (atomic_read(&ps2mult_buf_cnt
) == 0) {
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
);
233 PRINTF_KEYB("read_input()=0x%02x\n", byte
);
237 void ps2mult_write_output(u_char val
)
241 PRINTF_KEYB("write_output(0x%02x)\n", val
);
243 for (i
= 0; i
< KBD_TIMEOUT
; i
++) {
244 if (!kbd_command_active
&& !mouse_command_active
) {
251 if (kbd_command_active
) {
252 PRINTF("keyboard command not acknoledged\n");
253 kbd_command_active
= 0;
256 if (mouse_command_active
) {
257 PRINTF("mouse command not acknoledged\n");
258 mouse_command_active
= 0;
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
;
268 case KBD_CCMD_WRITE_AUX_OBUF
:
269 ps2mult_receive_byte(val
, PS2MULT_MS_SELECTOR
);
272 case KBD_CCMD_WRITE_MOUSE
:
273 ps2mult_send_byte(val
, PS2MULT_MS_SELECTOR
);
277 PRINTF("invalid controller command\n");
281 ctl_command_active
= 0;
285 ps2mult_send_byte(val
, PS2MULT_KB_SELECTOR
);
288 void ps2mult_write_command(u_char val
)
290 ctl_command_active
= 0;
292 PRINTF_KEYB("write_command(0x%02x)\n", val
);
295 case KBD_CCMD_READ_MODE
:
296 ps2mult_receive_byte(command_byte
, PS2MULT_KB_SELECTOR
);
299 case KBD_CCMD_WRITE_MODE
:
300 ctl_command_active
= val
;
303 case KBD_CCMD_MOUSE_DISABLE
:
306 case KBD_CCMD_MOUSE_ENABLE
:
309 case KBD_CCMD_SELF_TEST
:
310 ps2mult_receive_byte(0x55, PS2MULT_KB_SELECTOR
);
313 case KBD_CCMD_KBD_TEST
:
314 ps2mult_receive_byte(0x00, PS2MULT_KB_SELECTOR
);
317 case KBD_CCMD_KBD_DISABLE
:
320 case KBD_CCMD_KBD_ENABLE
:
323 case KBD_CCMD_WRITE_AUX_OBUF
:
324 ctl_command_active
= val
;
327 case KBD_CCMD_WRITE_MOUSE
:
328 ctl_command_active
= val
;
332 PRINTF("invalid controller command\n");
337 static int ps2mult_getc_w (void)
342 for (i
= 0; i
< KBD_TIMEOUT
; i
++) {
343 if (ps2ser_check()) {
351 case PS2MULT_KB_SELECTOR
:
352 case PS2MULT_MS_SELECTOR
:
353 received_selector
= res
;
362 int ps2mult_init (void)
368 while (get_timer(start_time
) < CONFIG_PS2MULT_DELAY
);
372 ps2ser_putc(PS2MULT_SESSION_START
);
374 ps2ser_putc(PS2MULT_KB_SELECTOR
);
375 ps2ser_putc(KBD_CMD_RESET
);
378 byte
= ps2mult_getc_w();
379 } while (byte
>= 0 && byte
!= KBD_REPLY_ACK
);
381 if (byte
== KBD_REPLY_ACK
) {
382 byte
= ps2mult_getc_w();
391 byte
= ps2mult_getc_w();
395 #if 1 /* detect mouse */
396 ps2ser_putc(PS2MULT_MS_SELECTOR
);
397 ps2ser_putc(AUX_RESET
);
400 byte
= ps2mult_getc_w();
401 } while (byte
>= 0 && byte
!= AUX_ACK
);
403 if (byte
== AUX_ACK
) {
404 byte
= ps2mult_getc_w();
406 byte
= ps2mult_getc_w();
416 byte
= ps2mult_getc_w();
421 if (mouse_found
|| kbd_found
) {
422 if (!received_selector
) {
424 received_selector
= PS2MULT_MS_SELECTOR
;
426 received_selector
= PS2MULT_KB_SELECTOR
;
432 puts("No device found");
437 #if 0 /* for testing */
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 */
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
);
453 return init_done
? 0 : -1;
456 int ps2mult_request_irq(void (*handler
)(void *))
458 keyb_handler
= handler
;