Annotation of prex/dev/i386/pc/kbd.c, Revision 1.1
1.1 ! nbrk 1: /*-
! 2: * Copyright (c) 2005, 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: * kbd.c - keyboard driver for PC
! 32: */
! 33:
! 34: #include <driver.h>
! 35: #include <prex/keycode.h>
! 36: #include <sys/tty.h>
! 37: #include <cpufunc.h>
! 38: #include <pm.h>
! 39: #include <console.h>
! 40: #include "kmc.h"
! 41:
! 42: /* Parameters */
! 43: #define KBD_IRQ 1
! 44:
! 45: static int kbd_init(void);
! 46:
! 47: /*
! 48: * Driver structure
! 49: */
! 50: struct driver kbd_drv = {
! 51: /* name */ "PC/AT Keyboard",
! 52: /* order */ 8,
! 53: /* init */ kbd_init,
! 54: };
! 55:
! 56: /*
! 57: * Device I/O table
! 58: */
! 59: static struct devio kbd_io = {
! 60: /* open */ NULL,
! 61: /* close */ NULL,
! 62: /* read */ NULL,
! 63: /* write */ NULL,
! 64: /* ioctl */ NULL,
! 65: /* event */ NULL,
! 66: };
! 67:
! 68: /*
! 69: * Key map
! 70: */
! 71: static const u_char key_map[] = {
! 72: 0, 0x1b, '1', '2', '3', '4', '5', '6',
! 73: '7', '8', '9', '0', '-', '=', '\b', '\t',
! 74: 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
! 75: 'o', 'p', '[', ']', '\n', K_CTRL, 'a', 's',
! 76: 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
! 77: '\'', '`', K_SHFT, '\\', 'z', 'x', 'c', 'v',
! 78: 'b', 'n', 'm', ',', '.', '/', K_SHFT, '*',
! 79: K_ALT, ' ', K_CAPS, K_F1, K_F2, K_F3, K_F4, K_F5,
! 80: K_F6, K_F7, K_F8, K_F9, K_F10, 0, 0, K_HOME,
! 81: K_UP, K_PGUP, 0, K_LEFT, 0, K_RGHT, 0, K_END,
! 82: K_DOWN, K_PGDN, K_INS, 0x7f, K_F11, K_F12
! 83: };
! 84:
! 85: #define KEY_MAX (sizeof(key_map) / sizeof(char))
! 86:
! 87: static const u_char shift_map[] = {
! 88: 0, 0x1b, '!', '@', '#', '$', '%', '^',
! 89: '&', '*', '(', ')', '_', '+', '\b', '\t',
! 90: 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
! 91: 'O', 'P', '{', '}', '\n', K_CTRL, 'A', 'S',
! 92: 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
! 93: '"', '~', 0, '|', 'Z', 'X', 'C', 'V',
! 94: 'B', 'N', 'M', '<', '>', '?', 0, '*',
! 95: K_ALT, ' ', 0, 0, 0, 0, 0, 0,
! 96: 0, 0, 0, 0, 0, 0, 0, K_HOME,
! 97: K_UP, K_PGUP, 0, K_LEFT, 0, K_RGHT, 0, K_END,
! 98: K_DOWN, K_PGDN, K_INS, 0x7f, 0, 0
! 99: };
! 100:
! 101: static device_t kbd_dev; /* Device object */
! 102: static irq_t kbd_irq; /* Handle for keyboard irq */
! 103: static struct tty *tty;
! 104:
! 105: static int shift;
! 106: static int alt;
! 107: static int ctrl;
! 108: static int capslk;
! 109:
! 110: static int led_sts;
! 111:
! 112:
! 113: /*
! 114: * Send command to keyboard controller
! 115: */
! 116: static void
! 117: kbd_cmd(u_char cmd)
! 118: {
! 119:
! 120: wait_ibe();
! 121: outb(cmd, KMC_CMD);
! 122: }
! 123:
! 124:
! 125: /*
! 126: * Update LEDs for current modifier state.
! 127: */
! 128: static void
! 129: kbd_setleds(void)
! 130: {
! 131:
! 132: outb(0xed, KMC_DATA);
! 133: while (inb(KMC_STS) & 2);
! 134: outb(led_sts, KMC_DATA);
! 135: while (inb(KMC_STS) & 2);
! 136: }
! 137:
! 138: #ifdef DEBUG
! 139: /*
! 140: * Help for keyboard debug function
! 141: */
! 142: static void
! 143: kbd_dump_help(void)
! 144: {
! 145:
! 146: printf("\nSystem dump usage:\n");
! 147: printf("F1=help F2=thread F3=task F4=mem\n");
! 148: }
! 149: #endif
! 150:
! 151:
! 152: /*
! 153: * Interrupt service routine
! 154: */
! 155: static int
! 156: kbd_isr(int irq)
! 157: {
! 158: u_char sc, ac; /* scan & ascii code */
! 159: u_char val;
! 160: int press;
! 161:
! 162: /* Get scan code */
! 163: wait_obf();
! 164: sc = inb(KMC_DATA);
! 165:
! 166: /* Send ack to the controller */
! 167: val = inb(KMC_PORTB);
! 168: outb(val | 0x80, KMC_PORTB);
! 169: outb(val, KMC_PORTB);
! 170:
! 171: /* Convert scan code to ascii */
! 172: press = sc & 0x80 ? 0 : 1;
! 173: sc = sc & 0x7f;
! 174: if (sc >= KEY_MAX)
! 175: return 0;
! 176: ac = key_map[sc];
! 177:
! 178: #ifdef CONFIG_PM
! 179: /* Reload power management timer */
! 180: if (press)
! 181: pm_active();
! 182: #endif
! 183:
! 184: /* Check meta key */
! 185: switch (ac) {
! 186: case K_SHFT:
! 187: shift = press;
! 188: return 0;
! 189: case K_CTRL:
! 190: ctrl = press;
! 191: return 0;
! 192: case K_ALT:
! 193: alt = press;
! 194: return 0;
! 195: case K_CAPS:
! 196: capslk = !capslk;
! 197: return INT_CONTINUE;
! 198: }
! 199:
! 200: /* Ignore key release */
! 201: if (!press)
! 202: return 0;
! 203:
! 204: #ifdef DEBUG
! 205: if (ac == K_F1) {
! 206: kbd_dump_help();
! 207: return 0;
! 208: }
! 209: if (ac >= K_F2 && ac <= K_F12) {
! 210: debug_dump(ac - K_F1);
! 211: return 0;
! 212: }
! 213: #endif
! 214: if (ac >= 0x80) {
! 215: tty_input(ac, tty);
! 216: return 0;
! 217: }
! 218:
! 219: /* Check Alt+Ctrl+Del */
! 220: if (alt && ctrl && ac == 0x7f) {
! 221: machine_reset();
! 222: }
! 223:
! 224: /* Check ctrl & shift state */
! 225: if (ctrl) {
! 226: if (ac >= 'a' && ac <= 'z')
! 227: ac = ac - 'a' + 0x01;
! 228: else if (ac == '\\')
! 229: ac = 0x1c;
! 230: else
! 231: ac = 0;
! 232: } else if (shift)
! 233: ac = shift_map[sc];
! 234:
! 235: if (ac == 0)
! 236: return 0;
! 237:
! 238: /* Check caps lock state */
! 239: if (capslk) {
! 240: if (ac >= 'A' && ac <= 'Z')
! 241: ac += 'a' - 'A';
! 242: else if (ac >= 'a' && ac <= 'z')
! 243: ac -= 'a' - 'A';
! 244: }
! 245:
! 246: /* Check alt key */
! 247: if (alt)
! 248: ac |= 0x80;
! 249:
! 250: /* Insert key to queue */
! 251: tty_input(ac, tty);
! 252: return 0;
! 253: }
! 254:
! 255: /*
! 256: * Interrupt service thread
! 257: */
! 258: static void
! 259: kbd_ist(int irq)
! 260: {
! 261: int val = 0;
! 262:
! 263: /* Update LEDs */
! 264: if (capslk)
! 265: val |= 0x04;
! 266: if (led_sts != val) {
! 267: led_sts = val;
! 268: kbd_setleds();
! 269: }
! 270: return;
! 271: }
! 272:
! 273: int
! 274: kbd_init(void)
! 275: {
! 276:
! 277: kbd_dev = device_create(&kbd_io, "kbd", DF_CHR);
! 278: ASSERT(kbd_dev);
! 279:
! 280: /* Disable keyboard controller */
! 281: kbd_cmd(CMD_KBD_DIS);
! 282:
! 283: led_sts = 0;
! 284: /* kbd_setleds(); */
! 285:
! 286: kbd_irq = irq_attach(KBD_IRQ, IPL_INPUT, 0, kbd_isr, kbd_ist);
! 287: ASSERT(kbd_irq != IRQ_NULL);
! 288:
! 289: /* Discard garbage data */
! 290: while (inb(KMC_STS) & STS_OBF)
! 291: inb(KMC_DATA);
! 292:
! 293: /* Enable keyboard controller */
! 294: kbd_cmd(CMD_KBD_EN);
! 295:
! 296: console_attach(&tty);
! 297: return 0;
! 298: }
CVSweb