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