|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/drv/dev/input/pckbd.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.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] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |