uboot/drivers/input/keyboard.c
<<
>>
Prefs
   1/***********************************************************************
   2 *
   3 * (C) Copyright 2004
   4 * DENX Software Engineering
   5 * Wolfgang Denk, wd@denx.de
   6 *
   7 * Keyboard driver
   8 *
   9 ***********************************************************************/
  10
  11#include <common.h>
  12
  13#include <stdio_dev.h>
  14#include <keyboard.h>
  15
  16#undef KBG_DEBUG
  17
  18#ifdef KBG_DEBUG
  19#define PRINTF(fmt,args...)     printf (fmt ,##args)
  20#else
  21#define PRINTF(fmt,args...)
  22#endif
  23
  24
  25#define DEVNAME                 "kbd"
  26
  27#define LED_SCR                 0x01    /* scroll lock led */
  28#define LED_CAP                 0x04    /* caps lock led */
  29#define LED_NUM                 0x02    /* num lock led */
  30
  31#define KBD_BUFFER_LEN          0x20  /* size of the keyboardbuffer */
  32
  33#if defined(CONFIG_MPC5xxx) || defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
  34int ps2ser_check(void);
  35#endif
  36
  37static volatile char kbd_buffer[KBD_BUFFER_LEN];
  38static volatile int in_pointer = 0;
  39static volatile int out_pointer = 0;
  40
  41static unsigned char leds = 0;
  42static unsigned char num_lock = 0;
  43static unsigned char caps_lock = 0;
  44static unsigned char scroll_lock = 0;
  45static unsigned char shift = 0;
  46static unsigned char ctrl = 0;
  47static unsigned char alt = 0;
  48static unsigned char e0 = 0;
  49
  50/******************************************************************
  51 * Queue handling
  52 ******************************************************************/
  53
  54/* puts character in the queue and sets up the in and out pointer */
  55static void kbd_put_queue(char data)
  56{
  57        if((in_pointer+1)==KBD_BUFFER_LEN) {
  58                if(out_pointer==0) {
  59                        return; /* buffer full */
  60                } else{
  61                        in_pointer=0;
  62                }
  63        } else {
  64                if((in_pointer+1)==out_pointer)
  65                        return; /* buffer full */
  66                in_pointer++;
  67        }
  68        kbd_buffer[in_pointer]=data;
  69        return;
  70}
  71
  72/* test if a character is in the queue */
  73static int kbd_testc(void)
  74{
  75#if defined(CONFIG_MPC5xxx) || defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
  76        /* no ISR is used, so received chars must be polled */
  77        ps2ser_check();
  78#endif
  79        if(in_pointer==out_pointer)
  80                return(0); /* no data */
  81        else
  82                return(1);
  83}
  84
  85/* gets the character from the queue */
  86static int kbd_getc(void)
  87{
  88        char c;
  89        while(in_pointer==out_pointer) {
  90#if defined(CONFIG_MPC5xxx) || defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
  91        /* no ISR is used, so received chars must be polled */
  92        ps2ser_check();
  93#endif
  94        ;}
  95        if((out_pointer+1)==KBD_BUFFER_LEN)
  96                out_pointer=0;
  97        else
  98                out_pointer++;
  99        c=kbd_buffer[out_pointer];
 100        return (int)c;
 101
 102}
 103
 104/* Simple translation table for the keys */
 105
 106static unsigned char kbd_plain_xlate[] = {
 107        0xff,0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t',        /* 0x00 - 0x0f */
 108         'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\r',0xff, 'a', 's',        /* 0x10 - 0x1f */
 109         'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`',0xff,'\\', 'z', 'x', 'c', 'v',        /* 0x20 - 0x2f */
 110         'b', 'n', 'm', ',', '.', '/',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff,        /* 0x30 - 0x3f */
 111        0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',        /* 0x40 - 0x4f */
 112         '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,  /* 0x50 - 0x5F */
 113        '\r',0xff,0xff
 114        };
 115
 116static unsigned char kbd_shift_xlate[] = {
 117        0xff,0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t',        /* 0x00 - 0x0f */
 118         'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\r',0xff, 'A', 'S',        /* 0x10 - 0x1f */
 119         'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',0xff, '|', 'Z', 'X', 'C', 'V',        /* 0x20 - 0x2f */
 120         'B', 'N', 'M', '<', '>', '?',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff,        /* 0x30 - 0x3f */
 121        0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',        /* 0x40 - 0x4f */
 122         '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,  /* 0x50 - 0x5F */
 123        '\r',0xff,0xff
 124        };
 125
 126static unsigned char kbd_ctrl_xlate[] = {
 127        0xff,0x1b, '1',0x00, '3', '4', '5',0x1E, '7', '8', '9', '0',0x1F, '=','\b','\t',        /* 0x00 - 0x0f */
 128        0x11,0x17,0x05,0x12,0x14,0x18,0x15,0x09,0x0f,0x10,0x1b,0x1d,'\n',0xff,0x01,0x13,        /* 0x10 - 0x1f */
 129        0x04,0x06,0x08,0x09,0x0a,0x0b,0x0c, ';','\'', '~',0x00,0x1c,0x1a,0x18,0x03,0x16,        /* 0x20 - 0x2f */
 130        0x02,0x0e,0x0d, '<', '>', '?',0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff,        /* 0x30 - 0x3f */
 131        0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',        /* 0x40 - 0x4f */
 132         '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,  /* 0x50 - 0x5F */
 133        '\r',0xff,0xff
 134        };
 135
 136
 137void handle_scancode(unsigned char scancode)
 138{
 139        unsigned char keycode;
 140
 141        /*  Convert scancode to keycode */
 142        PRINTF("scancode %x\n",scancode);
 143        if(scancode==0xe0) {
 144                e0=1; /* special charakters */
 145                return;
 146        }
 147        if(e0==1) {
 148                e0=0; /* delete flag */
 149                if(!(   ((scancode&0x7F)==0x38)|| /* the right ctrl key */
 150                                        ((scancode&0x7F)==0x1D)|| /* the right alt key */
 151                                        ((scancode&0x7F)==0x35)||       /* the right '/' key */
 152                                        ((scancode&0x7F)==0x1C) ))  /* the right enter key */
 153                        /* we swallow unknown e0 codes */
 154                        return;
 155        }
 156        /* special cntrl keys */
 157        switch(scancode) {
 158        case 0x2A:
 159        case 0x36: /* shift pressed */
 160                shift=1;
 161                return; /* do nothing else */
 162        case 0xAA:
 163        case 0xB6: /* shift released */
 164                shift=0;
 165                return; /* do nothing else */
 166        case 0x38: /* alt pressed */
 167                alt=1;
 168                return; /* do nothing else */
 169        case 0xB8: /* alt released */
 170                alt=0;
 171                return; /* do nothing else */
 172        case 0x1d: /* ctrl pressed */
 173                ctrl=1;
 174                return; /* do nothing else */
 175        case 0x9d: /* ctrl released */
 176                ctrl=0;
 177                return; /* do nothing else */
 178        case 0x46: /* scrollock pressed */
 179                scroll_lock=~scroll_lock;
 180                if(scroll_lock==0)
 181                        leds&=~LED_SCR; /* switch LED off */
 182                else
 183                        leds|=LED_SCR; /* switch on LED */
 184                pckbd_leds(leds);
 185                return; /* do nothing else */
 186        case 0x3A: /* capslock pressed */
 187                caps_lock=~caps_lock;
 188                if(caps_lock==0)
 189                        leds&=~LED_CAP; /* switch caps_lock off */
 190                else
 191                        leds|=LED_CAP; /* switch on LED */
 192                pckbd_leds(leds);
 193                return;
 194        case 0x45: /* numlock pressed */
 195                num_lock=~num_lock;
 196                if(num_lock==0)
 197                        leds&=~LED_NUM; /* switch LED off */
 198                else
 199                        leds|=LED_NUM;  /* switch on LED */
 200                pckbd_leds(leds);
 201                return;
 202        case 0xC6: /* scroll lock released */
 203        case 0xC5: /* num lock released */
 204        case 0xBA: /* caps lock released */
 205                return; /* just swallow */
 206        }
 207#if 1
 208        if((scancode&0x80)==0x80) /* key released */
 209                return;
 210#else
 211        if((scancode&0x80)==0x00) /* key pressed */
 212                return;
 213        scancode &= ~0x80;
 214#endif
 215        /* now, decide which table we need */
 216        if(scancode > (sizeof(kbd_plain_xlate)/sizeof(kbd_plain_xlate[0]))) { /* scancode not in list */
 217                PRINTF("unkown scancode %X\n",scancode);
 218                return; /* swallow it */
 219        }
 220        /* setup plain code first */
 221        keycode=kbd_plain_xlate[scancode];
 222        if(caps_lock==1) { /* caps_lock is pressed, overwrite plain code */
 223                if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
 224                        PRINTF("unkown caps-locked scancode %X\n",scancode);
 225                        return; /* swallow it */
 226                }
 227                keycode=kbd_shift_xlate[scancode];
 228                if(keycode<'A') { /* we only want the alphas capital */
 229                        keycode=kbd_plain_xlate[scancode];
 230                }
 231        }
 232        if(shift==1) { /* shift overwrites caps_lock */
 233                if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
 234                        PRINTF("unkown shifted scancode %X\n",scancode);
 235                        return; /* swallow it */
 236                }
 237                keycode=kbd_shift_xlate[scancode];
 238        }
 239        if(ctrl==1) { /* ctrl overwrites caps_lock and shift */
 240                if(scancode > (sizeof(kbd_ctrl_xlate)/sizeof(kbd_ctrl_xlate[0]))) { /* scancode not in list */
 241                        PRINTF("unkown ctrl scancode %X\n",scancode);
 242                        return; /* swallow it */
 243                }
 244                keycode=kbd_ctrl_xlate[scancode];
 245        }
 246        /* check if valid keycode */
 247        if(keycode==0xff) {
 248                PRINTF("unkown scancode %X\n",scancode);
 249                return; /* swallow unknown codes */
 250        }
 251
 252        kbd_put_queue(keycode);
 253        PRINTF("%x\n",keycode);
 254}
 255
 256/******************************************************************
 257 * Init
 258 ******************************************************************/
 259
 260#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
 261extern int overwrite_console (void);
 262#define OVERWRITE_CONSOLE overwrite_console ()
 263#else
 264#define OVERWRITE_CONSOLE 0
 265#endif /* CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE */
 266
 267int kbd_init (void)
 268{
 269        int error;
 270        struct stdio_dev kbddev ;
 271        char *stdinname  = getenv ("stdin");
 272
 273        if(kbd_init_hw()==-1)
 274                return -1;
 275        memset (&kbddev, 0, sizeof(kbddev));
 276        strcpy(kbddev.name, DEVNAME);
 277        kbddev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
 278        kbddev.putc = NULL ;
 279        kbddev.puts = NULL ;
 280        kbddev.getc = kbd_getc ;
 281        kbddev.tstc = kbd_testc ;
 282
 283        error = stdio_register (&kbddev);
 284        if(error==0) {
 285                /* check if this is the standard input device */
 286                if(strcmp(stdinname,DEVNAME)==0) {
 287                        /* reassign the console */
 288                        if(OVERWRITE_CONSOLE) {
 289                                return 1;
 290                        }
 291                        error=console_assign(stdin,DEVNAME);
 292                        if(error==0)
 293                                return 1;
 294                        else
 295                                return error;
 296                }
 297                return 1;
 298        }
 299        return error;
 300}
 301