uboot/drivers/input/ps2mult.c
<<
>>
Prefs
   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
  42static ulong start_time;
  43static int init_done = 0;
  44
  45static int received_escape = 0;
  46static int received_bsync = 0;
  47static int received_selector = 0;
  48
  49static int kbd_command_active = 0;
  50static int mouse_command_active = 0;
  51static int ctl_command_active = 0;
  52
  53static u_char command_byte = 0;
  54
  55static void (*keyb_handler)(void *dev_id);
  56
  57static u_char ps2mult_buf [PS2BUF_SIZE];
  58static atomic_t ps2mult_buf_cnt;
  59static int ps2mult_buf_in_idx;
  60static int ps2mult_buf_out_idx;
  61
  62static 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
  67void ps2mult_early_init (void)
  68{
  69        start_time = get_timer(0);
  70}
  71
  72static 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
 100static 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
 149void 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
 203u_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
 220u_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
 237void 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
 288void 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
 337static 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
 362int 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
 456int ps2mult_request_irq(void (*handler)(void *))
 457{
 458        keyb_handler = handler;
 459
 460        return 0;
 461}
 462