Annotation of sys/dev/adb/akbd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: akbd.c,v 1.6 2007/03/13 20:56:56 miod Exp $ */
! 2: /* $NetBSD: akbd.c,v 1.17 2005/01/15 16:00:59 chs Exp $ */
! 3:
! 4: /*
! 5: * Copyright (C) 1998 Colin Wood
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed by Colin Wood.
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! 31: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34: #include <sys/param.h>
! 35: #include <sys/timeout.h>
! 36: #include <sys/kernel.h>
! 37: #include <sys/device.h>
! 38: #include <sys/systm.h>
! 39:
! 40: #include <dev/wscons/wsconsio.h>
! 41: #include <dev/wscons/wskbdvar.h>
! 42: #include <dev/wscons/wsksymdef.h>
! 43: #include <dev/wscons/wsksymvar.h>
! 44:
! 45: #include <machine/autoconf.h>
! 46: #include <machine/cpu.h>
! 47:
! 48: #include <dev/adb/adb.h>
! 49: #include <dev/adb/akbdmap.h>
! 50: #include <dev/adb/akbdvar.h>
! 51:
! 52: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 53: #define KEYBOARD_ARRAY
! 54: #endif
! 55: #include <dev/adb/keyboard.h>
! 56:
! 57: /*
! 58: * Function declarations.
! 59: */
! 60: int akbdmatch(struct device *, void *, void *);
! 61: void akbdattach(struct device *, struct device *, void *);
! 62:
! 63: /* Driver definition. */
! 64: struct cfattach akbd_ca = {
! 65: sizeof(struct akbd_softc), akbdmatch, akbdattach
! 66: };
! 67: struct cfdriver akbd_cd = {
! 68: NULL, "akbd", DV_DULL
! 69: };
! 70:
! 71: int akbd_enable(void *, int);
! 72: void akbd_set_leds(void *, int);
! 73: int akbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
! 74:
! 75:
! 76: struct wskbd_accessops akbd_accessops = {
! 77: akbd_enable,
! 78: akbd_set_leds,
! 79: akbd_ioctl,
! 80: };
! 81:
! 82: struct wskbd_mapdata akbd_keymapdata = {
! 83: akbd_keydesctab,
! 84: #ifdef AKBD_LAYOUT
! 85: AKBD_LAYOUT,
! 86: #else
! 87: KB_US,
! 88: #endif
! 89: };
! 90:
! 91: void akbd_adbcomplete(caddr_t, caddr_t, int);
! 92: void akbd_capslockwrapper(struct akbd_softc *, int);
! 93: void akbd_input(struct akbd_softc *, int);
! 94: void akbd_processevent(struct akbd_softc *, adb_event_t *);
! 95: void akbd_rawrepeat(void *v);
! 96: #ifdef notyet
! 97: u_char getleds(int);
! 98: int setleds(struct akbd_softc *, u_char);
! 99: void blinkleds(struct akbd_softc *);
! 100: #endif
! 101:
! 102: int
! 103: akbdmatch(struct device *parent, void *vcf, void *aux)
! 104: {
! 105: struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
! 106:
! 107: if (aa_args->origaddr == ADBADDR_KBD)
! 108: return (1);
! 109: else
! 110: return (0);
! 111: }
! 112:
! 113: void
! 114: akbdattach(struct device *parent, struct device *self, void *aux)
! 115: {
! 116: ADBSetInfoBlock adbinfo;
! 117: struct akbd_softc *sc = (struct akbd_softc *)self;
! 118: struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
! 119: int error, kbd_done;
! 120: short cmd;
! 121: u_char buffer[9];
! 122: struct wskbddev_attach_args a;
! 123: static int akbd_console_initted;
! 124: int wskbd_eligible = 1;
! 125:
! 126: sc->origaddr = aa_args->origaddr;
! 127: sc->adbaddr = aa_args->adbaddr;
! 128: sc->handler_id = aa_args->handler_id;
! 129:
! 130: sc->sc_leds = (u_int8_t)0x00; /* initially off */
! 131: sc->sc_caps = 0;
! 132:
! 133: adbinfo.siServiceRtPtr = (Ptr)akbd_adbcomplete;
! 134: adbinfo.siDataAreaAddr = (caddr_t)sc;
! 135:
! 136: printf(": ");
! 137: switch (sc->handler_id) {
! 138: case ADB_STDKBD:
! 139: printf("standard keyboard\n");
! 140: break;
! 141: case ADB_ISOKBD:
! 142: printf("standard keyboard (ISO layout)\n");
! 143: break;
! 144: case ADB_EXTKBD:
! 145: cmd = ADBTALK(sc->adbaddr, 1);
! 146: kbd_done =
! 147: (adb_op_sync((Ptr)buffer, cmd) == 0);
! 148:
! 149: /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
! 150: if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x20) {
! 151: printf("Mouseman (non-EMP) pseudo keyboard\n");
! 152: adbinfo.siServiceRtPtr = (Ptr)0;
! 153: adbinfo.siDataAreaAddr = (Ptr)0;
! 154: wskbd_eligible = 0;
! 155: } else if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x21) {
! 156: printf("Trackman (non-EMP) pseudo keyboard\n");
! 157: adbinfo.siServiceRtPtr = (Ptr)0;
! 158: adbinfo.siDataAreaAddr = (Ptr)0;
! 159: wskbd_eligible = 0;
! 160: } else {
! 161: printf("extended keyboard\n");
! 162: #ifdef notyet
! 163: blinkleds(sc);
! 164: #endif
! 165: }
! 166: break;
! 167: case ADB_EXTISOKBD:
! 168: printf("extended keyboard (ISO layout)\n");
! 169: #ifdef notyet
! 170: blinkleds(sc);
! 171: #endif
! 172: break;
! 173: case ADB_KBDII:
! 174: printf("keyboard II\n");
! 175: break;
! 176: case ADB_ISOKBDII:
! 177: printf("keyboard II (ISO layout)\n");
! 178: break;
! 179: case ADB_PBKBD:
! 180: printf("PowerBook keyboard\n");
! 181: break;
! 182: case ADB_PBISOKBD:
! 183: printf("PowerBook keyboard (ISO layout)\n");
! 184: break;
! 185: case ADB_ADJKPD:
! 186: printf("adjustable keypad\n");
! 187: wskbd_eligible = 0;
! 188: break;
! 189: case ADB_ADJKBD:
! 190: printf("adjustable keyboard\n");
! 191: break;
! 192: case ADB_ADJISOKBD:
! 193: printf("adjustable keyboard (ISO layout)\n");
! 194: break;
! 195: case ADB_ADJJAPKBD:
! 196: printf("adjustable keyboard (Japanese layout)\n");
! 197: break;
! 198: case ADB_PBEXTISOKBD:
! 199: printf("PowerBook extended keyboard (ISO layout)\n");
! 200: break;
! 201: case ADB_PBEXTJAPKBD:
! 202: printf("PowerBook extended keyboard (Japanese layout)\n");
! 203: break;
! 204: case ADB_JPKBDII:
! 205: printf("keyboard II (Japanese layout)\n");
! 206: break;
! 207: case ADB_PBEXTKBD:
! 208: printf("PowerBook extended keyboard\n");
! 209: break;
! 210: case ADB_DESIGNKBD:
! 211: printf("extended keyboard\n");
! 212: #ifdef notyet
! 213: blinkleds(sc);
! 214: #endif
! 215: break;
! 216: case ADB_PBJPKBD:
! 217: printf("PowerBook keyboard (Japanese layout)\n");
! 218: break;
! 219: case ADB_PBG3JPKBD:
! 220: printf("PowerBook G3 keyboard (Japanese layout)\n");
! 221: break;
! 222: case ADB_PBG4KBD:
! 223: printf("PowerBook G4 keyboard (Inverted T)\n");
! 224: break;
! 225: case ADB_IBITISOKBD:
! 226: printf("iBook keyboard with inverted T (ISO layout)\n");
! 227: break;
! 228: default:
! 229: printf("mapped device (%d)\n", sc->handler_id);
! 230: #if 0
! 231: wskbd_eligible = 0;
! 232: #endif
! 233: break;
! 234: }
! 235: error = set_adb_info(&adbinfo, sc->adbaddr);
! 236: #ifdef ADB_DEBUG
! 237: if (adb_debug)
! 238: printf("akbd: returned %d from set_adb_info\n", error);
! 239: #endif
! 240:
! 241: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 242: timeout_set(&sc->sc_rawrepeat_ch, akbd_rawrepeat, sc);
! 243: #endif
! 244:
! 245: if (akbd_is_console() && wskbd_eligible)
! 246: a.console = (++akbd_console_initted == 1);
! 247: else
! 248: a.console = 0;
! 249: a.keymap = &akbd_keymapdata;
! 250: a.accessops = &akbd_accessops;
! 251: a.accesscookie = sc;
! 252:
! 253: sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
! 254: }
! 255:
! 256:
! 257: /*
! 258: * Handle putting the keyboard data received from the ADB into
! 259: * an ADB event record.
! 260: */
! 261: void
! 262: akbd_adbcomplete(caddr_t buffer, caddr_t data_area, int adb_command)
! 263: {
! 264: adb_event_t event;
! 265: struct akbd_softc *sc;
! 266: int adbaddr;
! 267: #ifdef ADB_DEBUG
! 268: int i;
! 269:
! 270: if (adb_debug)
! 271: printf("adb: transaction completion\n");
! 272: #endif
! 273:
! 274: adbaddr = ADB_CMDADDR(adb_command);
! 275: sc = (struct akbd_softc *)data_area;
! 276:
! 277: event.byte_count = buffer[0];
! 278: memcpy(event.bytes, buffer + 1, event.byte_count);
! 279:
! 280: #ifdef ADB_DEBUG
! 281: if (adb_debug) {
! 282: printf("akbd: from %d at %d (org %d) %d:", adbaddr,
! 283: sc->handler_id, sc->origaddr, buffer[0]);
! 284: for (i = 1; i <= buffer[0]; i++)
! 285: printf(" %x", buffer[i]);
! 286: printf("\n");
! 287: }
! 288: #endif
! 289:
! 290: if (sc->sc_wskbddev != NULL)
! 291: akbd_processevent(sc, &event);
! 292: }
! 293:
! 294: #ifdef notyet
! 295: /*
! 296: * Get the actual hardware LED state and convert it to softc format.
! 297: */
! 298: u_char
! 299: getleds(int addr)
! 300: {
! 301: short cmd;
! 302: u_char buffer[9], leds;
! 303:
! 304: leds = 0x00; /* all off */
! 305: buffer[0] = 0;
! 306:
! 307: cmd = ADBTALK(addr, 2);
! 308: if (adb_op_sync((Ptr)buffer, cmd) == 0 &&
! 309: buffer[0] > 0)
! 310: leds = ~(buffer[2]) & 0x07;
! 311:
! 312: return (leds);
! 313: }
! 314:
! 315: /*
! 316: * Set the keyboard LED's.
! 317: *
! 318: * Automatically translates from ioctl/softc format to the
! 319: * actual keyboard register format
! 320: */
! 321: int
! 322: setleds(struct akbd_softc *sc, u_char leds)
! 323: {
! 324: int addr;
! 325: short cmd;
! 326: u_char buffer[9];
! 327:
! 328: addr = sc->adbaddr;
! 329: buffer[0] = 0;
! 330:
! 331: cmd = ADBTALK(addr, 2);
! 332: if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0)
! 333: return (EIO);
! 334:
! 335: leds = ~leds & 0x07;
! 336: buffer[2] &= 0xf8;
! 337: buffer[2] |= leds;
! 338:
! 339: cmd = ADBLISTEN(addr, 2);
! 340: adb_op_sync((Ptr)buffer, cmd);
! 341:
! 342: /* talk R2 */
! 343: cmd = ADBTALK(addr, 2);
! 344: if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0)
! 345: return (EIO);
! 346:
! 347: if ((buffer[2] & 0xf8) != leds)
! 348: return (EIO);
! 349: else
! 350: return (0);
! 351: }
! 352:
! 353: /*
! 354: * Toggle all of the LED's on and off, just for show.
! 355: */
! 356: void
! 357: blinkleds(struct akbd_softc *sc)
! 358: {
! 359: u_char origleds;
! 360:
! 361: origleds = getleds(sc->adbaddr);
! 362: setleds(sc, LED_NUMLOCK | LED_CAPSLOCK | LED_SCROLL_LOCK);
! 363: delay(400000);
! 364: setleds(sc, origleds);
! 365:
! 366: if (origleds & LED_NUMLOCK)
! 367: sc->sc_leds |= WSKBD_LED_NUM;
! 368: if (origleds & LED_CAPSLOCK)
! 369: sc->sc_leds |= WSKBD_LED_CAPS;
! 370: if (origleds & LED_SCROLL_LOCK)
! 371: sc->sc_leds |= WSKBD_LED_SCROLL;
! 372: }
! 373: #endif
! 374:
! 375: int
! 376: akbd_enable(void *v, int on)
! 377: {
! 378: return 0;
! 379: }
! 380:
! 381: void
! 382: akbd_set_leds(void *v, int on)
! 383: {
! 384: #ifdef notyet
! 385: struct akbd_softc *sc = v;
! 386: int leds;
! 387:
! 388: if (sc->sc_extended) {
! 389: if (sc->sc_leds == on)
! 390: return;
! 391:
! 392: leds = 0;
! 393: if (on & WSKBD_LED_NUM)
! 394: leds |= LED_NUMLOCK;
! 395: if (on & WSKBD_LED_CAPS)
! 396: leds |= LED_CAPSLOCK;
! 397: if (on & WSKBD_LED_SCROLL)
! 398: leds |= LED_SCROLL_LOCK;
! 399:
! 400: setleds(sc, leds);
! 401: }
! 402: #endif
! 403: }
! 404:
! 405: int
! 406: akbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
! 407: {
! 408: struct akbd_softc *sc = v;
! 409:
! 410: switch (cmd) {
! 411:
! 412: case WSKBDIO_GTYPE:
! 413: *(int *)data = WSKBD_TYPE_ADB;
! 414: return 0;
! 415: case WSKBDIO_SETLEDS:
! 416: akbd_set_leds(v, *(int *)data);
! 417: return 0;
! 418: case WSKBDIO_GETLEDS:
! 419: *(int *)data = sc->sc_leds;
! 420: return 0;
! 421: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 422: case WSKBDIO_SETMODE:
! 423: sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
! 424: timeout_del(&sc->sc_rawrepeat_ch);
! 425: return (0);
! 426: #endif
! 427:
! 428: #ifdef mac68k /* XXX not worth creating akbd_machdep_ioctl() */
! 429: case WSKBDIO_BELL:
! 430: case WSKBDIO_COMPLEXBELL:
! 431: #define d ((struct wskbd_bell_data *)data)
! 432: mac68k_ring_bell(d->pitch, d->period * hz / 1000, d->volume);
! 433: #undef d
! 434: return (0);
! 435: #endif
! 436:
! 437: default:
! 438: return (-1);
! 439: }
! 440: }
! 441:
! 442: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 443: void
! 444: akbd_rawrepeat(void *v)
! 445: {
! 446: struct akbd_softc *sc = v;
! 447: int s;
! 448:
! 449: s = spltty();
! 450: wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
! 451: splx(s);
! 452: timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000);
! 453: }
! 454: #endif
! 455:
! 456: /*
! 457: * The ``caps lock'' key is special: since on earlier keyboards, the physical
! 458: * key stays down when pressed, we will get a notification of the key press,
! 459: * but not of the key release. Then, when it is pressed again, we will not get
! 460: * a notification of the key press, but will see the key release.
! 461: *
! 462: * This is not exactly true. We see the missing release and press events both
! 463: * as the release of the power (reset) key.
! 464: *
! 465: * To avoid confusing them with real power key presses, we maintain two
! 466: * states for the caps lock key: logically down (from wscons' point of view),
! 467: * and ``physically'' down (from the adb messages point of view), to ignore
! 468: * the power key. But since one may press the power key while the caps lock
! 469: * is held down, we also have to remember the state of the power key... this
! 470: * is quite messy.
! 471: */
! 472:
! 473: /*
! 474: * Values for caps lock state machine
! 475: */
! 476: #define CL_DOWN_ADB 0x01
! 477: #define CL_DOWN_LOGICAL 0x02
! 478: #define CL_DOWN_RESET 0x04
! 479:
! 480: /*
! 481: * Given a keyboard ADB event, decode the keycodes and pass them to wskbd.
! 482: */
! 483: void
! 484: akbd_processevent(struct akbd_softc *sc, adb_event_t *event)
! 485: {
! 486: switch (event->byte_count) {
! 487: case 1:
! 488: akbd_capslockwrapper(sc, event->bytes[0]);
! 489: break;
! 490: case 2:
! 491: /*
! 492: * The reset (or power) key sends 0x7f7f on press and
! 493: * 0xffff on release, and we ignore it.
! 494: */
! 495: if (event->bytes[0] == event->bytes[1] &&
! 496: ADBK_KEYVAL(event->bytes[0]) == ADBK_RESET) {
! 497: if (event->bytes[0] == ADBK_KEYDOWN(ADBK_RESET))
! 498: SET(sc->sc_caps, CL_DOWN_RESET);
! 499: else {
! 500: if (ISSET(sc->sc_caps, CL_DOWN_RESET))
! 501: CLR(sc->sc_caps, CL_DOWN_RESET);
! 502: else if (ISSET(sc->sc_caps, CL_DOWN_ADB)) {
! 503: akbd_input(sc, ISSET(sc->sc_caps,
! 504: CL_DOWN_LOGICAL) ?
! 505: ADBK_KEYDOWN(ADBK_CAPSLOCK) :
! 506: ADBK_KEYUP(ADBK_CAPSLOCK));
! 507: sc->sc_caps ^= CL_DOWN_LOGICAL;
! 508: }
! 509: }
! 510: } else {
! 511: akbd_capslockwrapper(sc, event->bytes[0]);
! 512: akbd_capslockwrapper(sc, event->bytes[1]);
! 513: }
! 514: break;
! 515: default:
! 516: #ifdef DIAGNOSTIC
! 517: printf("%s: unexpected message length %d\n",
! 518: sc->sc_dev.dv_xname, event->byte_count);
! 519: #endif
! 520: break;
! 521: }
! 522:
! 523: }
! 524:
! 525: void
! 526: akbd_capslockwrapper(struct akbd_softc *sc, int key)
! 527: {
! 528: if (ADBK_KEYVAL(key) == ADBK_CAPSLOCK)
! 529: sc->sc_caps ^= CL_DOWN_ADB;
! 530:
! 531: if (key != 0xff)
! 532: akbd_input(sc, key);
! 533: }
! 534:
! 535: int adb_polledkey;
! 536: void
! 537: akbd_input(struct akbd_softc *sc, int key)
! 538: {
! 539: int press, val;
! 540: int type;
! 541:
! 542: press = ADBK_PRESS(key);
! 543: val = ADBK_KEYVAL(key);
! 544:
! 545: type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
! 546:
! 547: if (adb_polling) {
! 548: adb_polledkey = key;
! 549: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 550: } else if (sc->sc_rawkbd) {
! 551: char cbuf[MAXKEYS *2];
! 552: int c, j, s;
! 553: int npress;
! 554:
! 555: j = npress = 0;
! 556:
! 557: c = keyboard[val];
! 558: if (c == 0) {
! 559: return; /* XXX */
! 560: }
! 561: if (c & 0x80)
! 562: cbuf[j++] = 0xe0;
! 563: cbuf[j] = c & 0x7f;
! 564: if (type == WSCONS_EVENT_KEY_UP) {
! 565: cbuf[j] |= 0x80;
! 566: } else {
! 567: /* this only records last key pressed */
! 568: if (c & 0x80)
! 569: sc->sc_rep[npress++] = 0xe0;
! 570: sc->sc_rep[npress++] = c & 0x7f;
! 571: }
! 572: j++;
! 573: s = spltty();
! 574: wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
! 575: splx(s);
! 576: timeout_del(&sc->sc_rawrepeat_ch);
! 577: sc->sc_nrep = npress;
! 578: if (npress != 0)
! 579: timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAY1/1000);
! 580: #endif
! 581: } else {
! 582: wskbd_input(sc->sc_wskbddev, type, val);
! 583: }
! 584: }
CVSweb