uboot/board/lwmon5/kbd.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2007
   3 * Stefan Roese, DENX Software Engineering, sr@denx.de.
   4 *
   5 * (C) Copyright 2001, 2002
   6 * DENX Software Engineering
   7 * Wolfgang Denk, wd@denx.de
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License as
  11 * published by the Free Software Foundation; either version 2 of
  12 * the License, or (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  22 * MA 02111-1307 USA
  23 */
  24
  25/* define DEBUG for debugging output (obviously ;-)) */
  26#if 0
  27#define DEBUG
  28#endif
  29
  30#include <common.h>
  31#include <i2c.h>
  32#include <command.h>
  33#include <post.h>
  34#include <serial.h>
  35#include <malloc.h>
  36
  37#include <linux/types.h>
  38#include <linux/string.h>       /* for strdup */
  39
  40DECLARE_GLOBAL_DATA_PTR;
  41
  42static void kbd_init (void);
  43static int compare_magic (uchar *kbd_data, uchar *str);
  44
  45/*--------------------- Local macros and constants --------------------*/
  46#define _NOT_USED_      0xFFFFFFFF
  47
  48/*------------------------- dspic io expander -----------------------*/
  49#define DSPIC_PON_STATUS_REG    0x80A
  50#define DSPIC_PON_INV_STATUS_REG 0x80C
  51#define DSPIC_PON_KEY_REG       0x810
  52/*------------------------- Keyboard controller -----------------------*/
  53/* command codes */
  54#define KEYBD_CMD_READ_KEYS     0x01
  55#define KEYBD_CMD_READ_VERSION  0x02
  56#define KEYBD_CMD_READ_STATUS   0x03
  57#define KEYBD_CMD_RESET_ERRORS  0x10
  58
  59/* status codes */
  60#define KEYBD_STATUS_MASK       0x3F
  61#define KEYBD_STATUS_H_RESET    0x20
  62#define KEYBD_STATUS_BROWNOUT   0x10
  63#define KEYBD_STATUS_WD_RESET   0x08
  64#define KEYBD_STATUS_OVERLOAD   0x04
  65#define KEYBD_STATUS_ILLEGAL_WR 0x02
  66#define KEYBD_STATUS_ILLEGAL_RD 0x01
  67
  68/* Number of bytes returned from Keyboard Controller */
  69#define KEYBD_VERSIONLEN        2       /* version information */
  70
  71/*
  72 * This is different from the "old" lwmon dsPIC kbd controller
  73 * implementation. Now the controller still answers with 9 bytes,
  74 * but the last 3 bytes are always "0x06 0x07 0x08". So we just
  75 * set the length to compare to 6 instead of 9.
  76 */
  77#define KEYBD_DATALEN           6       /* normal key scan data */
  78
  79/* maximum number of "magic" key codes that can be assigned */
  80
  81static uchar kbd_addr = CONFIG_SYS_I2C_KEYBD_ADDR;
  82static uchar dspic_addr = CONFIG_SYS_I2C_DSPIC_IO_ADDR;
  83
  84static uchar *key_match (uchar *);
  85
  86#define KEYBD_SET_DEBUGMODE     '#'     /* Magic key to enable debug output */
  87
  88/***********************************************************************
  89F* Function:     int board_postclk_init (void) P*A*Z*
  90 *
  91P* Parameters:   none
  92P*
  93P* Returnvalue:  int
  94P*                - 0 is always returned.
  95 *
  96Z* Intention:    This function is the board_postclk_init() method implementation
  97Z*               for the lwmon board.
  98 *
  99 ***********************************************************************/
 100int board_postclk_init (void)
 101{
 102        kbd_init();
 103
 104        return (0);
 105}
 106
 107static void kbd_init (void)
 108{
 109        uchar kbd_data[KEYBD_DATALEN];
 110        uchar tmp_data[KEYBD_DATALEN];
 111        uchar val, errcd;
 112        int i;
 113
 114        i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
 115
 116        gd->arch.kbd_status = 0;
 117
 118        /* Forced by PIC. Delays <= 175us loose */
 119        udelay(1000);
 120
 121        /* Read initial keyboard error code */
 122        val = KEYBD_CMD_READ_STATUS;
 123        i2c_write (kbd_addr, 0, 0, &val, 1);
 124        i2c_read (kbd_addr, 0, 0, &errcd, 1);
 125        /* clear unused bits */
 126        errcd &= KEYBD_STATUS_MASK;
 127        /* clear "irrelevant" bits. Recommended by Martin Rajek, LWN */
 128        errcd &= ~(KEYBD_STATUS_H_RESET|KEYBD_STATUS_BROWNOUT);
 129        if (errcd) {
 130                gd->arch.kbd_status |= errcd << 8;
 131        }
 132        /* Reset error code and verify */
 133        val = KEYBD_CMD_RESET_ERRORS;
 134        i2c_write (kbd_addr, 0, 0, &val, 1);
 135        udelay(1000);   /* delay NEEDED by keyboard PIC !!! */
 136
 137        val = KEYBD_CMD_READ_STATUS;
 138        i2c_write (kbd_addr, 0, 0, &val, 1);
 139        i2c_read (kbd_addr, 0, 0, &val, 1);
 140
 141        val &= KEYBD_STATUS_MASK;       /* clear unused bits */
 142        if (val) {                      /* permanent error, report it */
 143                gd->arch.kbd_status |= val;
 144                return;
 145        }
 146
 147        /*
 148         * Read current keyboard state.
 149         *
 150         * After the error reset it may take some time before the
 151         * keyboard PIC picks up a valid keyboard scan - the total
 152         * scan time is approx. 1.6 ms (information by Martin Rajek,
 153         * 28 Sep 2002). We read a couple of times for the keyboard
 154         * to stabilize, using a big enough delay.
 155         * 10 times should be enough. If the data is still changing,
 156         * we use what we get :-(
 157         */
 158
 159        memset (tmp_data, 0xFF, KEYBD_DATALEN); /* impossible value */
 160        for (i=0; i<10; ++i) {
 161                val = KEYBD_CMD_READ_KEYS;
 162                i2c_write (kbd_addr, 0, 0, &val, 1);
 163                i2c_read (kbd_addr, 0, 0, kbd_data, KEYBD_DATALEN);
 164
 165                if (memcmp(kbd_data, tmp_data, KEYBD_DATALEN) == 0) {
 166                        /* consistent state, done */
 167                        break;
 168                }
 169                /* remeber last state, delay, and retry */
 170                memcpy (tmp_data, kbd_data, KEYBD_DATALEN);
 171                udelay (5000);
 172        }
 173}
 174
 175
 176/* Read a register from the dsPIC. */
 177int _dspic_read(ushort reg, ushort *data)
 178{
 179        uchar buf[sizeof(*data)];
 180        int rval;
 181
 182        if (i2c_read(dspic_addr, reg, 2, buf, 2))
 183                return -1;
 184
 185        rval = i2c_read(dspic_addr, reg, sizeof(reg), buf, sizeof(*data));
 186        *data = (buf[0] << 8) | buf[1];
 187
 188        return rval;
 189}
 190
 191
 192/***********************************************************************
 193F* Function:     int misc_init_r (void) P*A*Z*
 194 *
 195P* Parameters:   none
 196P*
 197P* Returnvalue:  int
 198P*                - 0 is always returned, even in the case of a keyboard
 199P*                    error.
 200 *
 201Z* Intention:    This function is the misc_init_r() method implementation
 202Z*               for the lwmon board.
 203Z*               The keyboard controller is initialized and the result
 204Z*               of a read copied to the environment variable "keybd".
 205Z*               If KEYBD_SET_DEBUGMODE is defined, a check is made for
 206Z*               this key, and if found display to the LCD will be enabled.
 207Z*               The keys in "keybd" are checked against the magic
 208Z*               keycommands defined in the environment.
 209Z*               See also key_match().
 210 *
 211D* Design:       wd@denx.de
 212C* Coding:       wd@denx.de
 213V* Verification: dzu@denx.de
 214 ***********************************************************************/
 215int misc_init_r_kbd (void)
 216{
 217        uchar kbd_data[KEYBD_DATALEN];
 218        char keybd_env[2 * KEYBD_DATALEN + 1];
 219        uchar kbd_init_status = gd->arch.kbd_status >> 8;
 220        uchar kbd_status = gd->arch.kbd_status;
 221        uchar val;
 222        ushort data, inv_data;
 223        char *str;
 224        int i;
 225
 226        if (kbd_init_status) {
 227                printf ("KEYBD: Error %02X\n", kbd_init_status);
 228        }
 229        if (kbd_status) {               /* permanent error, report it */
 230                printf ("*** Keyboard error code %02X ***\n", kbd_status);
 231                sprintf (keybd_env, "%02X", kbd_status);
 232                setenv ("keybd", keybd_env);
 233                return 0;
 234        }
 235
 236        /*
 237         * Now we know that we have a working  keyboard,  so  disable
 238         * all output to the LCD except when a key press is detected.
 239         */
 240
 241        if ((console_assign (stdout, "serial") < 0) ||
 242                (console_assign (stderr, "serial") < 0)) {
 243                printf ("Can't assign serial port as output device\n");
 244        }
 245
 246        /* Read Version */
 247        val = KEYBD_CMD_READ_VERSION;
 248        i2c_write (kbd_addr, 0, 0, &val, 1);
 249        i2c_read (kbd_addr, 0, 0, kbd_data, KEYBD_VERSIONLEN);
 250        printf ("KEYBD: Version %d.%d\n", kbd_data[0], kbd_data[1]);
 251
 252        /* Read current keyboard state */
 253        val = KEYBD_CMD_READ_KEYS;
 254        i2c_write (kbd_addr, 0, 0, &val, 1);
 255        i2c_read (kbd_addr, 0, 0, kbd_data, KEYBD_DATALEN);
 256
 257        /* read out start key from bse01 received via can */
 258        _dspic_read(DSPIC_PON_STATUS_REG, &data);
 259        /* check highbyte from status register */
 260        if (data > 0xFF) {
 261                _dspic_read(DSPIC_PON_INV_STATUS_REG, &inv_data);
 262
 263                /* check inverse data */
 264                if ((data+inv_data) == 0xFFFF) {
 265                        /* don't overwrite local key */
 266                        if (kbd_data[1] == 0) {
 267                                /* read key value */
 268                                _dspic_read(DSPIC_PON_KEY_REG, &data);
 269                                str = (char *)&data;
 270                                /* swap bytes */
 271                                kbd_data[1] = str[1];
 272                                kbd_data[2] = str[0];
 273                                printf("CAN received startkey: 0x%X\n", data);
 274                        }
 275                }
 276        }
 277
 278        for (i = 0; i < KEYBD_DATALEN; ++i) {
 279                sprintf (keybd_env + i + i, "%02X", kbd_data[i]);
 280        }
 281
 282        setenv ("keybd", keybd_env);
 283
 284        str = strdup ((char *)key_match (kbd_data));    /* decode keys */
 285#ifdef KEYBD_SET_DEBUGMODE
 286        if (kbd_data[0] == KEYBD_SET_DEBUGMODE) {       /* set debug mode */
 287                if ((console_assign (stdout, "lcd") < 0) ||
 288                        (console_assign (stderr, "lcd") < 0)) {
 289                        printf ("Can't assign LCD display as output device\n");
 290                }
 291        }
 292#endif /* KEYBD_SET_DEBUGMODE */
 293#ifdef CONFIG_PREBOOT   /* automatically configure "preboot" command on key match */
 294        setenv ("preboot", str);        /* set or delete definition */
 295#endif /* CONFIG_PREBOOT */
 296        if (str != NULL) {
 297                free (str);
 298        }
 299        return (0);
 300}
 301
 302#ifdef CONFIG_PREBOOT
 303
 304static uchar kbd_magic_prefix[] = "key_magic";
 305static uchar kbd_command_prefix[] = "key_cmd";
 306
 307static int compare_magic (uchar *kbd_data, uchar *str)
 308{
 309        uchar compare[KEYBD_DATALEN-1];
 310        char *nxt;
 311        int i;
 312
 313        /* Don't include modifier byte */
 314        memcpy (compare, kbd_data+1, KEYBD_DATALEN-1);
 315
 316        for (; str != NULL; str = (*nxt) ? (uchar *)(nxt+1) : (uchar *)nxt) {
 317                uchar c;
 318                int k;
 319
 320                c = (uchar) simple_strtoul ((char *)str, (char **) (&nxt), 16);
 321
 322                if (str == (uchar *)nxt) {      /* invalid character */
 323                        break;
 324                }
 325
 326                /*
 327                 * Check if this key matches the input.
 328                 * Set matches to zero, so they match only once
 329                 * and we can find duplicates or extra keys
 330                 */
 331                for (k = 0; k < sizeof(compare); ++k) {
 332                        if (compare[k] == '\0') /* only non-zero entries */
 333                                continue;
 334                        if (c == compare[k]) {  /* found matching key */
 335                                compare[k] = '\0';
 336                                break;
 337                        }
 338                }
 339                if (k == sizeof(compare)) {
 340                        return -1;              /* unmatched key */
 341                }
 342        }
 343
 344        /*
 345         * A full match leaves no keys in the `compare' array,
 346         */
 347        for (i = 0; i < sizeof(compare); ++i) {
 348                if (compare[i])
 349                {
 350                        return -1;
 351                }
 352        }
 353
 354        return 0;
 355}
 356
 357/***********************************************************************
 358F* Function:     static uchar *key_match (uchar *kbd_data) P*A*Z*
 359 *
 360P* Parameters:   uchar *kbd_data
 361P*                - The keys to match against our magic definitions
 362P*
 363P* Returnvalue:  uchar *
 364P*                - != NULL: Pointer to the corresponding command(s)
 365P*                     NULL: No magic is about to happen
 366 *
 367Z* Intention:    Check if pressed key(s) match magic sequence,
 368Z*               and return the command string associated with that key(s).
 369Z*
 370Z*               If no key press was decoded, NULL is returned.
 371Z*
 372Z*               Note: the first character of the argument will be
 373Z*                     overwritten with the "magic charcter code" of the
 374Z*                     decoded key(s), or '\0'.
 375Z*
 376Z*               Note: the string points to static environment data
 377Z*                     and must be saved before you call any function that
 378Z*                     modifies the environment.
 379 *
 380D* Design:       wd@denx.de
 381C* Coding:       wd@denx.de
 382V* Verification: dzu@denx.de
 383 ***********************************************************************/
 384static uchar *key_match (uchar *kbd_data)
 385{
 386        char magic[sizeof (kbd_magic_prefix) + 1];
 387        uchar *suffix;
 388        char *kbd_magic_keys;
 389
 390        /*
 391         * The following string defines the characters that can pe appended
 392         * to "key_magic" to form the names of environment variables that
 393         * hold "magic" key codes, i. e. such key codes that can cause
 394         * pre-boot actions. If the string is empty (""), then only
 395         * "key_magic" is checked (old behaviour); the string "125" causes
 396         * checks for "key_magic1", "key_magic2" and "key_magic5", etc.
 397         */
 398        if ((kbd_magic_keys = getenv ("magic_keys")) == NULL)
 399                kbd_magic_keys = "";
 400
 401        /* loop over all magic keys;
 402         * use '\0' suffix in case of empty string
 403         */
 404        for (suffix=(uchar *)kbd_magic_keys; *suffix || suffix==(uchar *)kbd_magic_keys; ++suffix) {
 405                sprintf (magic, "%s%c", kbd_magic_prefix, *suffix);
 406                debug ("### Check magic \"%s\"\n", magic);
 407                if (compare_magic(kbd_data, (uchar *)getenv(magic)) == 0) {
 408                        char cmd_name[sizeof (kbd_command_prefix) + 1];
 409                        char *cmd;
 410
 411                        sprintf (cmd_name, "%s%c", kbd_command_prefix, *suffix);
 412
 413                        cmd = getenv (cmd_name);
 414                        debug ("### Set PREBOOT to $(%s): \"%s\"\n",
 415                                        cmd_name, cmd ? cmd : "<<NULL>>");
 416                        *kbd_data = *suffix;
 417                        return ((uchar *)cmd);
 418                }
 419        }
 420        debug ("### Delete PREBOOT\n");
 421        *kbd_data = '\0';
 422        return (NULL);
 423}
 424#endif /* CONFIG_PREBOOT */
 425
 426/***********************************************************************
 427F* Function:     int do_kbd (cmd_tbl_t *cmdtp, int flag,
 428F*                           int argc, char * const argv[]) P*A*Z*
 429 *
 430P* Parameters:   cmd_tbl_t *cmdtp
 431P*                - Pointer to our command table entry
 432P*               int flag
 433P*                - If the CMD_FLAG_REPEAT bit is set, then this call is
 434P*                  a repetition
 435P*               int argc
 436P*                - Argument count
 437P*               char * const argv[]
 438P*                - Array of the actual arguments
 439P*
 440P* Returnvalue:  int
 441P*                - 0 is always returned.
 442 *
 443Z* Intention:    Implement the "kbd" command.
 444Z*               The keyboard status is read.  The result is printed on
 445Z*               the console and written into the "keybd" environment
 446Z*               variable.
 447 *
 448D* Design:       wd@denx.de
 449C* Coding:       wd@denx.de
 450V* Verification: dzu@denx.de
 451 ***********************************************************************/
 452int do_kbd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 453{
 454        uchar kbd_data[KEYBD_DATALEN];
 455        char keybd_env[2 * KEYBD_DATALEN + 1];
 456        uchar val;
 457        int i;
 458
 459#if 0 /* Done in kbd_init */
 460        i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
 461#endif
 462
 463        /* Read keys */
 464        val = KEYBD_CMD_READ_KEYS;
 465        i2c_write (kbd_addr, 0, 0, &val, 1);
 466        i2c_read (kbd_addr, 0, 0, kbd_data, KEYBD_DATALEN);
 467
 468        puts ("Keys:");
 469        for (i = 0; i < KEYBD_DATALEN; ++i) {
 470                sprintf (keybd_env + i + i, "%02X", kbd_data[i]);
 471                printf (" %02x", kbd_data[i]);
 472        }
 473        putc ('\n');
 474        setenv ("keybd", keybd_env);
 475        return 0;
 476}
 477
 478U_BOOT_CMD(
 479        kbd,    1,      1,      do_kbd,
 480        "read keyboard status",
 481        ""
 482);
 483
 484/*----------------------------- Utilities -----------------------------*/
 485
 486#ifdef CONFIG_POST
 487/*
 488 * Returns 1 if keys pressed to start the power-on long-running tests
 489 * Called from board_init_f().
 490 */
 491int post_hotkeys_pressed(void)
 492{
 493        uchar kbd_data[KEYBD_DATALEN];
 494        uchar val;
 495
 496        /* Read keys */
 497        val = KEYBD_CMD_READ_KEYS;
 498        i2c_write (kbd_addr, 0, 0, &val, 1);
 499        i2c_read (kbd_addr, 0, 0, kbd_data, KEYBD_DATALEN);
 500
 501        return (compare_magic(kbd_data, (uchar *)CONFIG_POST_KEY_MAGIC) == 0);
 502}
 503#endif
 504