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 #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 43 static ulong start_time; 44 static int init_done = 0; 45 46 static int received_escape = 0; 47 static int received_bsync = 0; 48 static int received_selector = 0; 49 50 static int kbd_command_active = 0; 51 static int mouse_command_active = 0; 52 static int ctl_command_active = 0; 53 54 static u_char command_byte = 0; 55 56 static void (*keyb_handler)(void *dev_id); 57 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; 62 63 static u_char ps2mult_buf_status [PS2BUF_SIZE]; 64 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() 67 #endif 68 void ps2mult_early_init (void) 69 { 70 start_time = get_timer(0); 71 } 72 73 static 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 101 static 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 150 void 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 204 u_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 221 u_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 238 void 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 289 void 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 338 static 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 363 int ps2mult_init (void) 364 { 365 int byte; 366 int kbd_found = 0; 367 int mouse_found = 0; 368 369 while (get_timer(start_time) < CONFIG_PS2MULT_DELAY); 370 371 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 457 int ps2mult_request_irq(void (*handler)(void *)) 458 { 459 keyb_handler = handler; 460 461 return 0; 462 } 463