Annotation of sys/dev/hil/hilkbd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hilkbd.c,v 1.13 2006/08/10 23:43:45 miod Exp $ */
! 2: /*
! 3: * Copyright (c) 2003, Miodrag Vallat.
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 19: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 20: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 23: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 24: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 25: * POSSIBILITY OF SUCH DAMAGE.
! 26: *
! 27: */
! 28:
! 29: #include <sys/param.h>
! 30: #include <sys/systm.h>
! 31: #include <sys/device.h>
! 32: #include <sys/ioctl.h>
! 33: #include <sys/kernel.h>
! 34: #include <sys/timeout.h>
! 35:
! 36: #include <machine/autoconf.h>
! 37: #include <machine/bus.h>
! 38: #include <machine/cpu.h>
! 39:
! 40: #include <dev/hil/hilreg.h>
! 41: #include <dev/hil/hilvar.h>
! 42: #include <dev/hil/hildevs.h>
! 43:
! 44: #include <dev/wscons/wsconsio.h>
! 45: #include <dev/wscons/wskbdvar.h>
! 46: #include <dev/wscons/wsksymdef.h>
! 47: #include <dev/wscons/wsksymvar.h>
! 48: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 49: #include <dev/wscons/wskbdraw.h>
! 50: #endif
! 51:
! 52: #include <dev/hil/hilkbdmap.h>
! 53:
! 54: struct hilkbd_softc {
! 55: struct hildev_softc sc_hildev;
! 56:
! 57: int sc_numleds;
! 58: int sc_ledstate;
! 59: int sc_enabled;
! 60: int sc_console;
! 61: int sc_lastarrow;
! 62:
! 63: struct device *sc_wskbddev;
! 64:
! 65: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 66: int sc_rawkbd;
! 67: int sc_nrep;
! 68: char sc_rep[HILBUFSIZE * 2];
! 69: struct timeout sc_rawrepeat_ch;
! 70: #define REP_DELAY1 400
! 71: #define REP_DELAYN 100
! 72: #endif
! 73: };
! 74:
! 75: int hilkbdprobe(struct device *, void *, void *);
! 76: void hilkbdattach(struct device *, struct device *, void *);
! 77: int hilkbddetach(struct device *, int);
! 78:
! 79: struct cfdriver hilkbd_cd = {
! 80: NULL, "hilkbd", DV_DULL
! 81: };
! 82:
! 83: struct cfattach hilkbd_ca = {
! 84: sizeof(struct hilkbd_softc), hilkbdprobe, hilkbdattach, hilkbddetach,
! 85: };
! 86:
! 87: int hilkbd_enable(void *, int);
! 88: void hilkbd_set_leds(void *, int);
! 89: int hilkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
! 90:
! 91: const struct wskbd_accessops hilkbd_accessops = {
! 92: hilkbd_enable,
! 93: hilkbd_set_leds,
! 94: hilkbd_ioctl,
! 95: };
! 96:
! 97: void hilkbd_cngetc(void *, u_int *, int *);
! 98: void hilkbd_cnpollc(void *, int);
! 99: void hilkbd_cnbell(void *, u_int, u_int, u_int);
! 100:
! 101: const struct wskbd_consops hilkbd_consops = {
! 102: hilkbd_cngetc,
! 103: hilkbd_cnpollc,
! 104: hilkbd_cnbell,
! 105: };
! 106:
! 107: struct wskbd_mapdata hilkbd_keymapdata = {
! 108: hilkbd_keydesctab,
! 109: #ifdef HILKBD_LAYOUT
! 110: HILKBD_LAYOUT,
! 111: #else
! 112: KB_US,
! 113: #endif
! 114: };
! 115:
! 116: struct wskbd_mapdata hilkbd_keymapdata_ps2 = {
! 117: hilkbd_keydesctab_ps2,
! 118: #ifdef HILKBD_LAYOUT
! 119: HILKBD_LAYOUT,
! 120: #else
! 121: KB_US,
! 122: #endif
! 123: };
! 124:
! 125: void hilkbd_bell(struct hil_softc *, u_int, u_int, u_int);
! 126: void hilkbd_callback(struct hildev_softc *, u_int, u_int8_t *);
! 127: void hilkbd_decode(struct hilkbd_softc *, u_int8_t, u_int *, int *, int);
! 128: int hilkbd_is_console(int);
! 129: void hilkbd_rawrepeat(void *);
! 130:
! 131: int seen_hilkbd_console;
! 132:
! 133: int
! 134: hilkbdprobe(struct device *parent, void *match, void *aux)
! 135: {
! 136: struct hil_attach_args *ha = aux;
! 137:
! 138: if (ha->ha_type != HIL_DEVICE_KEYBOARD &&
! 139: ha->ha_type != HIL_DEVICE_BUTTONBOX)
! 140: return (0);
! 141:
! 142: return (1);
! 143: }
! 144:
! 145: void
! 146: hilkbdattach(struct device *parent, struct device *self, void *aux)
! 147: {
! 148: struct hilkbd_softc *sc = (void *)self;
! 149: struct hil_attach_args *ha = aux;
! 150: struct wskbddev_attach_args a;
! 151: u_int8_t layoutcode;
! 152: int ps2;
! 153:
! 154: sc->hd_code = ha->ha_code;
! 155: sc->hd_type = ha->ha_type;
! 156: sc->hd_infolen = ha->ha_infolen;
! 157: bcopy(ha->ha_info, sc->hd_info, ha->ha_infolen);
! 158: sc->hd_fn = hilkbd_callback;
! 159:
! 160: if (ha->ha_type == HIL_DEVICE_KEYBOARD) {
! 161: /*
! 162: * Determine the keyboard language configuration, but don't
! 163: * override a user-specified setting.
! 164: */
! 165: layoutcode = ha->ha_id & (MAXHILKBDLAYOUT - 1);
! 166: #ifndef HILKBD_LAYOUT
! 167: if (layoutcode < MAXHILKBDLAYOUT &&
! 168: hilkbd_layouts[layoutcode] != -1)
! 169: hilkbd_keymapdata.layout =
! 170: hilkbd_keymapdata_ps2.layout =
! 171: hilkbd_layouts[layoutcode];
! 172: #endif
! 173:
! 174: printf(", layout %x", layoutcode);
! 175: }
! 176:
! 177: /*
! 178: * Interpret the identification bytes, if any
! 179: */
! 180: if (ha->ha_infolen > 2 && (ha->ha_info[1] & HIL_IOB) != 0) {
! 181: /* HILIOB_PROMPT is not always reported... */
! 182: sc->sc_numleds = (ha->ha_info[2] & HILIOB_PMASK) >> 4;
! 183: if (sc->sc_numleds != 0)
! 184: printf(", %d leds", sc->sc_numleds);
! 185: }
! 186:
! 187: printf("\n");
! 188:
! 189: /*
! 190: * Red lettered keyboards come in two flavours, the old one
! 191: * with only one control key, to the left of the escape key,
! 192: * and the modern one which has a PS/2 like layout, and leds.
! 193: *
! 194: * Unfortunately for us, they use the same device ID range.
! 195: * We'll differentiate them by looking at the leds property.
! 196: */
! 197: ps2 = (sc->sc_numleds != 0);
! 198:
! 199: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 200: timeout_set(&sc->sc_rawrepeat_ch, hilkbd_rawrepeat, sc);
! 201: #endif
! 202:
! 203: /* Do not consider button boxes as console devices. */
! 204: if (ha->ha_type == HIL_DEVICE_BUTTONBOX)
! 205: a.console = 0;
! 206: else
! 207: a.console = hilkbd_is_console(ha->ha_console);
! 208: a.keymap = ps2 ? &hilkbd_keymapdata_ps2 : &hilkbd_keymapdata;
! 209: a.accessops = &hilkbd_accessops;
! 210: a.accesscookie = sc;
! 211:
! 212: if (a.console) {
! 213: sc->sc_console = sc->sc_enabled = 1;
! 214: wskbd_cnattach(&hilkbd_consops, sc, a.keymap);
! 215: } else {
! 216: sc->sc_console = sc->sc_enabled = 0;
! 217: }
! 218:
! 219: sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
! 220:
! 221: /*
! 222: * If this is an old keyboard with a numeric pad but no ``num lock''
! 223: * key, simulate it being pressed so that the keyboard runs in
! 224: * numeric mode.
! 225: */
! 226: if (!ps2 && sc->sc_wskbddev != NULL) {
! 227: wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_DOWN, 80);
! 228: wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_UP, 80);
! 229: }
! 230: }
! 231:
! 232: int
! 233: hilkbddetach(struct device *self, int flags)
! 234: {
! 235: struct hilkbd_softc *sc = (void *)self;
! 236:
! 237: /*
! 238: * Handle console keyboard for the best. It should have been set
! 239: * as the first device in the loop anyways.
! 240: */
! 241: if (sc->sc_console) {
! 242: wskbd_cndetach();
! 243: seen_hilkbd_console = 0;
! 244: }
! 245:
! 246: if (sc->sc_wskbddev != NULL)
! 247: return config_detach(sc->sc_wskbddev, flags);
! 248:
! 249: return (0);
! 250: }
! 251:
! 252: int
! 253: hilkbd_enable(void *v, int on)
! 254: {
! 255: struct hilkbd_softc *sc = v;
! 256:
! 257: if (on) {
! 258: if (sc->sc_enabled)
! 259: return (EBUSY);
! 260: } else {
! 261: if (sc->sc_console)
! 262: return (EBUSY);
! 263: }
! 264:
! 265: sc->sc_enabled = on;
! 266:
! 267: return (0);
! 268: }
! 269:
! 270: void
! 271: hilkbd_set_leds(void *v, int leds)
! 272: {
! 273: struct hilkbd_softc *sc = v;
! 274: int changemask;
! 275:
! 276: if (sc->sc_numleds == 0)
! 277: return;
! 278:
! 279: changemask = leds ^ sc->sc_ledstate;
! 280: if (changemask == 0)
! 281: return;
! 282:
! 283: /* We do not handle more than 3 leds here */
! 284: if (changemask & WSKBD_LED_SCROLL)
! 285: send_hildev_cmd((struct hildev_softc *)sc,
! 286: (leds & WSKBD_LED_SCROLL) ? HIL_PROMPT1 : HIL_ACK1,
! 287: NULL, NULL);
! 288: if (changemask & WSKBD_LED_NUM)
! 289: send_hildev_cmd((struct hildev_softc *)sc,
! 290: (leds & WSKBD_LED_NUM) ? HIL_PROMPT2 : HIL_ACK2,
! 291: NULL, NULL);
! 292: if (changemask & WSKBD_LED_CAPS)
! 293: send_hildev_cmd((struct hildev_softc *)sc,
! 294: (leds & WSKBD_LED_CAPS) ? HIL_PROMPT3 : HIL_ACK3,
! 295: NULL, NULL);
! 296:
! 297: sc->sc_ledstate = leds;
! 298: }
! 299:
! 300: int
! 301: hilkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
! 302: {
! 303: struct hilkbd_softc *sc = v;
! 304:
! 305: switch (cmd) {
! 306: case WSKBDIO_GTYPE:
! 307: *(int *)data = WSKBD_TYPE_HIL;
! 308: return 0;
! 309: case WSKBDIO_SETLEDS:
! 310: hilkbd_set_leds(v, *(int *)data);
! 311: return 0;
! 312: case WSKBDIO_GETLEDS:
! 313: *(int *)data = sc->sc_ledstate;
! 314: return 0;
! 315: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 316: case WSKBDIO_SETMODE:
! 317: sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
! 318: timeout_del(&sc->sc_rawrepeat_ch);
! 319: return 0;
! 320: #endif
! 321: case WSKBDIO_COMPLEXBELL:
! 322: #define d ((struct wskbd_bell_data *)data)
! 323: hilkbd_bell((struct hil_softc *)sc->hd_parent,
! 324: d->pitch, d->period, d->volume);
! 325: #undef d
! 326: return 0;
! 327: }
! 328:
! 329: return -1;
! 330: }
! 331:
! 332: void
! 333: hilkbd_cngetc(void *v, u_int *type, int *data)
! 334: {
! 335: struct hilkbd_softc *sc = v;
! 336: u_int8_t c, stat;
! 337:
! 338: for (;;) {
! 339: while (hil_poll_data((struct hildev_softc *)sc, &stat, &c) != 0)
! 340: ;
! 341:
! 342: /*
! 343: * Disregard keyboard data packet header.
! 344: * Note that no key generates it, so we're safe.
! 345: */
! 346: if (c != HIL_KBDBUTTON)
! 347: break;
! 348: }
! 349:
! 350: hilkbd_decode(sc, c, type, data, HIL_KBDBUTTON);
! 351: }
! 352:
! 353: void
! 354: hilkbd_cnpollc(void *v, int on)
! 355: {
! 356: struct hilkbd_softc *sc = v;
! 357:
! 358: hil_set_poll((struct hil_softc *)sc->hd_parent, on);
! 359: }
! 360:
! 361: void
! 362: hilkbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
! 363: {
! 364: struct hilkbd_softc *sc = v;
! 365:
! 366: hilkbd_bell((struct hil_softc *)sc->hd_parent,
! 367: pitch, period, volume);
! 368: }
! 369:
! 370: void
! 371: hilkbd_bell(struct hil_softc *sc, u_int pitch, u_int period, u_int volume)
! 372: {
! 373: u_int8_t buf[2];
! 374:
! 375: /* XXX there could be at least a pitch -> HIL pitch conversion here */
! 376: #define BELLDUR 80 /* tone duration in msec (10-2560) */
! 377: #define BELLFREQ 8 /* tone frequency (0-63) */
! 378: buf[0] = ar_format(period - 10);
! 379: buf[1] = BELLFREQ;
! 380: send_hil_cmd(sc, HIL_SETTONE, buf, 2, NULL);
! 381: }
! 382:
! 383: void
! 384: hilkbd_callback(struct hildev_softc *dev, u_int buflen, u_int8_t *buf)
! 385: {
! 386: struct hilkbd_softc *sc = (struct hilkbd_softc *)dev;
! 387: u_int type;
! 388: int kbdtype, key;
! 389: int i, s;
! 390:
! 391: /*
! 392: * Ignore packet if we don't need it
! 393: */
! 394: if (sc->sc_enabled == 0)
! 395: return;
! 396:
! 397: if (buflen == 0)
! 398: return;
! 399: switch ((kbdtype = *buf & HIL_KBDDATA)) {
! 400: case HIL_BUTTONBOX:
! 401: case HIL_KBDBUTTON:
! 402: break;
! 403: default:
! 404: return;
! 405: }
! 406:
! 407: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 408: if (sc->sc_rawkbd) {
! 409: u_char cbuf[HILBUFSIZE * 2];
! 410: int c, j, npress;
! 411:
! 412: npress = j = 0;
! 413: for (i = 1, buf++; i < buflen; i++) {
! 414: hilkbd_decode(sc, *buf++, &type, &key, kbdtype);
! 415: c = hilkbd_raw[key];
! 416: if (c == RAWKEY_Null)
! 417: continue;
! 418: /* fake extended scancode if necessary */
! 419: if (c & 0x80)
! 420: cbuf[j++] = 0xe0;
! 421: cbuf[j] = c & 0x7f;
! 422: if (type == WSCONS_EVENT_KEY_UP)
! 423: cbuf[j] |= 0x80;
! 424: else {
! 425: /* remember pressed keys for autorepeat */
! 426: if (c & 0x80)
! 427: sc->sc_rep[npress++] = 0xe0;
! 428: sc->sc_rep[npress++] = c & 0x7f;
! 429: }
! 430: j++;
! 431: }
! 432:
! 433: s = spltty();
! 434: wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
! 435: splx(s);
! 436: timeout_del(&sc->sc_rawrepeat_ch);
! 437: sc->sc_nrep = npress;
! 438: if (npress != 0) {
! 439: timeout_add(&sc->sc_rawrepeat_ch,
! 440: (hz * REP_DELAY1) / 1000);
! 441: }
! 442: } else
! 443: #endif
! 444: {
! 445: s = spltty();
! 446: for (i = 1, buf++; i < buflen; i++) {
! 447: hilkbd_decode(sc, *buf++, &type, &key, kbdtype);
! 448: if (sc->sc_wskbddev != NULL)
! 449: wskbd_input(sc->sc_wskbddev, type, key);
! 450: }
! 451: splx(s);
! 452: }
! 453: }
! 454:
! 455: void
! 456: hilkbd_decode(struct hilkbd_softc *sc, u_int8_t data, u_int *type, int *key,
! 457: int kbdtype)
! 458: {
! 459: if (kbdtype == HIL_BUTTONBOX) {
! 460: if (data == 0x02) /* repeat arrow */
! 461: data = sc->sc_lastarrow;
! 462: else if (data >= 0xf8)
! 463: sc->sc_lastarrow = data;
! 464: }
! 465:
! 466: *type = (data & 1) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
! 467: *key = data >> 1;
! 468: }
! 469:
! 470: int
! 471: hilkbd_is_console(int hil_is_console)
! 472: {
! 473: /* if not first hil keyboard, then not the console */
! 474: if (seen_hilkbd_console)
! 475: return (0);
! 476:
! 477: /* if PDC console does not match hil bus path, then not the console */
! 478: if (hil_is_console == 0)
! 479: return (0);
! 480:
! 481: seen_hilkbd_console = 1;
! 482: return (1);
! 483: }
! 484:
! 485: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 486: void
! 487: hilkbd_rawrepeat(void *v)
! 488: {
! 489: struct hilkbd_softc *sc = v;
! 490: int s;
! 491:
! 492: s = spltty();
! 493: wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
! 494: splx(s);
! 495: timeout_add(&sc->sc_rawrepeat_ch, (hz * REP_DELAYN) / 1000);
! 496: }
! 497: #endif
CVSweb