Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/drv/dev/input/pckbd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. kmc_send_cmd
  2. pckbd_set_leds
  3. pckbd_scan_key
  4. pckbd_isr
  5. pckbd_getc
  6. pckbd_set_poll
  7. pckbd_init

   1 /*-
   2  * Copyright (c) 2005-2009, Kohsuke Ohtani
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the author nor the names of any co-contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * pckbd.c - PC/AT keyboard driver
  32  */
  33 
  34 #include <driver.h>
  35 #include <sys/keycode.h>
  36 #include <wscons.h>
  37 #include <pm.h>
  38 
  39 #include "i8042.h"
  40 
  41 /* Parameters */
  42 #define KBD_IRQ         1
  43 
  44 struct pckbd_softc {
  45         device_t        dev;            /* device object */
  46         irq_t           irq;            /* irq handle */
  47         int             polling;        /* true if polling mode */
  48         u_char          led_sts;        /* keyboard LED status */
  49         int             shift;          /* shift key state */
  50         int             alt;            /* alt key state */
  51         int             ctrl;           /* control key state */
  52         int             capslk;         /* caps lock key staet */
  53 };
  54 
  55 static int      pckbd_init(struct driver *);
  56 static int      pckbd_getc(void *);
  57 static void     pckbd_set_poll(void *, int);
  58 
  59 struct driver pckbd_driver = {
  60         /* name */      "pckbd",
  61         /* devops */    NULL,
  62         /* devsz */     sizeof(struct pckbd_softc),
  63         /* flags */     0,
  64         /* probe */     NULL,
  65         /* init */      pckbd_init,
  66         /* shutdown */  NULL,
  67 };
  68 
  69 static struct wscons_kbd_ops wscons_pckbd_ops = {
  70         /* getc */      pckbd_getc,
  71         /* set_poll */  pckbd_set_poll,
  72 };
  73 
  74 /*
  75  * Key map
  76  */
  77 static const u_char key_map[] = {
  78         0,      0x1b,   '1',    '2',    '3',    '4',    '5',    '6',
  79         '7',    '8',    '9',    '0',    '-',    '=',    '\b',   '\t',
  80         'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
  81         'o',    'p',    '[',    ']',    '\n',   K_CTRL, 'a',    's',
  82         'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';',
  83         '\'',   '`',    K_SHFT, '\\',   'z',    'x',    'c',    'v',
  84         'b',    'n',    'm',    ',',    '.',    '/',    K_SHFT, '*',
  85         K_ALT,  ' ',    K_CAPS, K_F1,   K_F2,   K_F3,   K_F4,   K_F5,
  86         K_F6,   K_F7,   K_F8,   K_F9,   K_F10,  0,      0,      K_HOME,
  87         K_UP,   K_PGUP, 0,      K_LEFT, 0,      K_RGHT, 0,      K_END,
  88         K_DOWN, K_PGDN, K_INS,  0x7f,   K_F11,  K_F12
  89 };
  90 
  91 #define KEY_MAX (sizeof(key_map) / sizeof(char))
  92 
  93 static const u_char shift_map[] = {
  94         0,      0x1b,   '!',    '@',    '#',    '$',    '%',    '^',
  95         '&',    '*',    '(',    ')',    '_',    '+',    '\b',   '\t',
  96         'Q',    'W',    'E',    'R',    'T',    'Y',    'U',    'I',
  97         'O',    'P',    '{',    '}',    '\n',   K_CTRL, 'A',    'S',
  98         'D',    'F',    'G',    'H',    'J',    'K',    'L',    ':',
  99         '"',    '~',    0,      '|',    'Z',    'X',    'C',    'V',
 100         'B',    'N',    'M',    '<',    '>',    '?',    0,      '*',
 101         K_ALT,  ' ',    0,      0,      0,      0,      0,      0,
 102         0,      0,      0,      0,      0,      0,      0,      K_HOME,
 103         K_UP,   K_PGUP, 0,      K_LEFT, 0,      K_RGHT, 0,      K_END,
 104         K_DOWN, K_PGDN, K_INS,  0x7f,   0,      0
 105 };
 106 
 107 /*
 108  * Send command to keyboard controller
 109  */
 110 static void
 111 kmc_send_cmd(u_char cmd)
 112 {
 113 
 114         kmc_wait_ibe();
 115         bus_write_8(KMC_CMD, cmd);
 116 }
 117 
 118 /*
 119  * Update LEDs for current modifier state.
 120  */
 121 static void
 122 pckbd_set_leds(struct pckbd_softc *sc)
 123 {
 124         u_char val = 0;
 125 
 126         /* Update LEDs */
 127         if (sc->capslk)
 128                 val |= 0x04;
 129         if (sc->led_sts != val) {
 130                 sc->led_sts = val;
 131                 bus_write_8(KMC_DATA, 0xed);
 132                 while (bus_read_8(KMC_STS) & 2);
 133                 bus_write_8(KMC_DATA, val);
 134                 while (bus_read_8(KMC_STS) & 2);
 135         }
 136 }
 137 
 138 /*
 139  * Scan key input. Returns ascii code.
 140  */
 141 static int
 142 pckbd_scan_key(struct pckbd_softc *sc)
 143 {
 144         u_char scan, ascii, val;
 145         int press;
 146 
 147  again:
 148         /* Get scan code */
 149         kmc_wait_obf();
 150         scan = bus_read_8(KMC_DATA);
 151 
 152         /* Send ack to the controller */
 153         val = bus_read_8(KMC_PORTB);
 154         bus_write_8(KMC_PORTB, val | 0x80);
 155         bus_write_8(KMC_PORTB, val);
 156 
 157         /* Convert scan code to ascii */
 158         press = scan & 0x80 ? 0 : 1;
 159         scan = scan & 0x7f;
 160         if (scan >= KEY_MAX)
 161                 goto again;
 162         ascii = key_map[scan];
 163 
 164         /* Check meta key */
 165         switch (ascii) {
 166         case K_SHFT:
 167                 sc->shift = press;
 168                 return 0;
 169         case K_CTRL:
 170                 sc->ctrl = press;
 171                 return 0;
 172         case K_ALT:
 173                 sc->alt = press;
 174                 return 0;
 175         case K_CAPS:
 176                 sc->capslk = !sc->capslk;
 177                 pckbd_set_leds(sc);
 178                 return 0;
 179         }
 180 
 181         /* Ignore key release */
 182         if (!press)
 183                 return 0;
 184 
 185         if (ascii >= 0x80)
 186                 return ascii;
 187 
 188         /* Check Alt+Ctrl+Del */
 189         if (sc->alt && sc->ctrl && ascii == 0x7f) {
 190 #ifdef CONFIG_PM
 191                 pm_set_power(PWR_REBOOT);
 192 #else
 193                 machine_powerdown(PWR_REBOOT);
 194 #endif
 195         }
 196 
 197         /* Check ctrl & shift state */
 198         if (sc->ctrl) {
 199                 if (ascii >= 'a' && ascii <= 'z')
 200                         ascii = ascii - 'a' + 0x01;
 201                 else if (ascii == '\\')
 202                         ascii = 0x1c;
 203                 else
 204                         ascii = 0;
 205         } else if (sc->shift)
 206                 ascii = shift_map[scan];
 207 
 208         if (ascii == 0)
 209                 return 0;
 210 
 211         /* Check caps lock state */
 212         if (sc->capslk) {
 213                 if (ascii >= 'A' && ascii <= 'Z')
 214                         ascii += 'a' - 'A';
 215                 else if (ascii >= 'a' && ascii <= 'z')
 216                         ascii -= 'a' - 'A';
 217         }
 218 
 219         /* Check alt key */
 220         if (sc->alt)
 221                 ascii |= 0x80;
 222 
 223         /* Insert key to queue */
 224         return ascii;
 225 }
 226 
 227 /*
 228  * Interrupt service routine
 229  */
 230 static int
 231 pckbd_isr(void *arg)
 232 {
 233         struct pckbd_softc *sc = arg;
 234         int c;
 235 
 236         c = pckbd_scan_key(sc);
 237         if (c != 0)
 238                 wscons_kbd_input(c);
 239         return 0;
 240 }
 241 
 242 static int
 243 pckbd_getc(void *aux)
 244 {
 245         struct pckbd_softc *sc = aux;
 246         int c;
 247         int s;
 248 
 249         sc->alt = 0;
 250         sc->ctrl = 0;
 251         sc->shift = 0;
 252 
 253         s = splhigh();
 254         while ((c = pckbd_scan_key(sc)) == 0) ;
 255         splx(s);
 256         return c;
 257 }
 258 
 259 static void
 260 pckbd_set_poll(void *aux, int on)
 261 {
 262         struct pckbd_softc *sc = aux;
 263 
 264         sc->polling = on;
 265 }
 266 
 267 static int
 268 pckbd_init(struct driver *self)
 269 {
 270         struct pckbd_softc *sc;
 271         device_t dev;
 272 
 273         dev = device_create(self, "kbd", D_CHR);
 274 
 275         sc = device_private(dev);
 276         sc->dev = dev;
 277         sc->polling = 0;
 278         sc->led_sts = 0;
 279 
 280         /* Disable keyboard controller */
 281         kmc_send_cmd(CMD_KBD_DIS);
 282 
 283         sc->irq = irq_attach(KBD_IRQ, IPL_INPUT, 0, pckbd_isr, IST_NONE, sc);
 284 
 285         /* Discard garbage data */
 286         while (bus_read_8(KMC_STS) & STS_OBF)
 287                 bus_read_8(KMC_DATA);
 288 
 289         /* Enable keyboard controller */
 290         kmc_send_cmd(CMD_KBD_EN);
 291 
 292         wscons_attach_kbd(&wscons_pckbd_ops, sc);
 293         return 0;
 294 }

/* [<][>][^][v][top][bottom][index][help] */