Annotation of sys/arch/zaurus/dev/zaurus_kbd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: zaurus_kbd.c,v 1.28 2005/12/21 20:36:03 deraadt Exp $ */
! 2: /*
! 3: * Copyright (c) 2005 Dale Rahn <drahn@openbsd.org>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: #include <sys/param.h>
! 19: #include <sys/systm.h>
! 20: #include <sys/device.h>
! 21: #include <sys/malloc.h>
! 22: #include <sys/timeout.h>
! 23: #include <sys/kernel.h>
! 24: #include <sys/proc.h>
! 25: #include <sys/signalvar.h>
! 26:
! 27: #include <arm/xscale/pxa2x0reg.h>
! 28: #include <arm/xscale/pxa2x0_gpio.h>
! 29:
! 30: #include <dev/wscons/wsconsio.h>
! 31: #include <dev/wscons/wskbdvar.h>
! 32: #include <dev/wscons/wsksymdef.h>
! 33: #include <dev/wscons/wsksymvar.h>
! 34:
! 35: #include <zaurus/dev/zaurus_kbdmap.h>
! 36:
! 37: #include "apm.h"
! 38:
! 39: const int
! 40: gpio_sense_pins_c3000[] = {
! 41: 12,
! 42: 17,
! 43: 91,
! 44: 34,
! 45: 36,
! 46: 38,
! 47: 39,
! 48: -1
! 49: };
! 50:
! 51: const int
! 52: gpio_strobe_pins_c3000[] = {
! 53: 88,
! 54: 23,
! 55: 24,
! 56: 25,
! 57: 26,
! 58: 27,
! 59: 52,
! 60: 103,
! 61: 107,
! 62: -1,
! 63: 108,
! 64: 114
! 65: };
! 66:
! 67: const int stuck_keys[] = {
! 68: 7,
! 69: 15,
! 70: 23,
! 71: 31
! 72: };
! 73:
! 74:
! 75: #define REP_DELAY1 400
! 76: #define REP_DELAYN 100
! 77:
! 78: struct zkbd_softc {
! 79: struct device sc_dev;
! 80:
! 81: const int *sc_sense_array;
! 82: const int *sc_strobe_array;
! 83: int sc_nsense;
! 84: int sc_nstrobe;
! 85:
! 86: short sc_onkey_pin;
! 87: short sc_sync_pin;
! 88: short sc_swa_pin;
! 89: short sc_swb_pin;
! 90: char *sc_okeystate;
! 91: char *sc_keystate;
! 92: char sc_hinge; /* 0=open, 1=nonsense, 2=backwards, 3=closed */
! 93: char sc_maxkbdcol;
! 94:
! 95: struct timeout sc_roll_to;
! 96:
! 97: /* console stuff */
! 98: int sc_polling;
! 99: int sc_pollUD;
! 100: int sc_pollkey;
! 101:
! 102: /* wskbd bits */
! 103: struct device *sc_wskbddev;
! 104: int sc_rawkbd;
! 105: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 106: const char *sc_xt_keymap;
! 107: struct timeout sc_rawrepeat_ch;
! 108: #define MAXKEYS 20
! 109: char sc_rep[MAXKEYS];
! 110: int sc_nrep;
! 111: #endif
! 112: void *sc_powerhook;
! 113: };
! 114:
! 115: struct zkbd_softc *zkbd_dev; /* XXX */
! 116:
! 117: int zkbd_match(struct device *, void *, void *);
! 118: void zkbd_attach(struct device *, struct device *, void *);
! 119:
! 120: int zkbd_irq(void *v);
! 121: void zkbd_poll(void *v);
! 122: int zkbd_on(void *v);
! 123: int zkbd_sync(void *v);
! 124: int zkbd_hinge(void *v);
! 125: void zkbd_power(int why, void *arg);
! 126:
! 127: int zkbd_modstate;
! 128:
! 129: struct cfattach zkbd_ca = {
! 130: sizeof(struct zkbd_softc), zkbd_match, zkbd_attach
! 131: };
! 132:
! 133: struct cfdriver zkbd_cd = {
! 134: NULL, "zkbd", DV_DULL
! 135: };
! 136:
! 137: int zkbd_enable(void *, int);
! 138: void zkbd_set_leds(void *, int);
! 139: int zkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
! 140: void zkbd_rawrepeat(void *v);
! 141:
! 142: struct wskbd_accessops zkbd_accessops = {
! 143: zkbd_enable,
! 144: zkbd_set_leds,
! 145: zkbd_ioctl,
! 146: };
! 147:
! 148: void zkbd_cngetc(void *, u_int *, int *);
! 149: void zkbd_cnpollc(void *, int);
! 150:
! 151: struct wskbd_consops zkbd_consops = {
! 152: zkbd_cngetc,
! 153: zkbd_cnpollc,
! 154: };
! 155:
! 156: struct wskbd_mapdata zkbd_keymapdata = {
! 157: zkbd_keydesctab,
! 158: KB_US,
! 159: };
! 160:
! 161:
! 162:
! 163: int
! 164: zkbd_match(struct device *parent, void *cf, void *aux)
! 165: {
! 166: return 1;
! 167: }
! 168:
! 169:
! 170: void
! 171: zkbd_attach(struct device *parent, struct device *self, void *aux)
! 172: {
! 173: struct zkbd_softc *sc = (struct zkbd_softc *)self;
! 174: struct wskbddev_attach_args a;
! 175: int pin, i;
! 176: extern int glass_console;
! 177:
! 178: zkbd_dev = sc;
! 179: sc->sc_polling = 0;
! 180: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 181: sc->sc_rawkbd = 0;
! 182: #endif
! 183: /* Determine which system we are - XXX */
! 184:
! 185: sc->sc_powerhook = powerhook_establish(zkbd_power, sc);
! 186: if (sc->sc_powerhook == NULL) {
! 187: printf(": unable to establish powerhook\n");
! 188: return;
! 189: }
! 190:
! 191: if (1 /* C3000 */) {
! 192: sc->sc_sense_array = gpio_sense_pins_c3000;
! 193: sc->sc_strobe_array = gpio_strobe_pins_c3000;
! 194: sc->sc_nsense = sizeof(gpio_sense_pins_c3000)/sizeof(int);
! 195: sc->sc_nstrobe = sizeof(gpio_strobe_pins_c3000)/sizeof(int);
! 196: sc->sc_maxkbdcol = 10;
! 197: sc->sc_onkey_pin = 95;
! 198: sc->sc_sync_pin = 16;
! 199: sc->sc_swa_pin = 97;
! 200: sc->sc_swb_pin = 96;
! 201: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 202: sc->sc_xt_keymap = xt_keymap;
! 203: #endif
! 204: } /* XXX */
! 205:
! 206: sc->sc_okeystate = malloc(sc->sc_nsense * sc->sc_nstrobe,
! 207: M_DEVBUF, M_NOWAIT);
! 208: bzero(sc->sc_okeystate, (sc->sc_nsense * sc->sc_nstrobe));
! 209:
! 210: sc->sc_keystate = malloc(sc->sc_nsense * sc->sc_nstrobe,
! 211: M_DEVBUF, M_NOWAIT);
! 212: bzero(sc->sc_keystate, (sc->sc_nsense * sc->sc_nstrobe));
! 213:
! 214: /* set all the strobe bits */
! 215: for (i = 0; i < sc->sc_nstrobe; i++) {
! 216: pin = sc->sc_strobe_array[i];
! 217: if (pin == -1) {
! 218: continue;
! 219: }
! 220: pxa2x0_gpio_set_function(pin, GPIO_SET|GPIO_OUT);
! 221: }
! 222: /* set all the sense bits */
! 223: for (i = 0; i < sc->sc_nsense; i++) {
! 224: pin = sc->sc_sense_array[i];
! 225: if (pin == -1) {
! 226: continue;
! 227: }
! 228: pxa2x0_gpio_set_function(pin, GPIO_IN);
! 229: pxa2x0_gpio_intr_establish(pin, IST_EDGE_BOTH, IPL_TTY,
! 230: zkbd_irq, sc, sc->sc_dev.dv_xname);
! 231: }
! 232: pxa2x0_gpio_intr_establish(sc->sc_onkey_pin, IST_EDGE_BOTH, IPL_TTY,
! 233: zkbd_on, sc, sc->sc_dev.dv_xname);
! 234: pxa2x0_gpio_intr_establish(sc->sc_sync_pin, IST_EDGE_RISING, IPL_TTY,
! 235: zkbd_sync, sc, sc->sc_dev.dv_xname);
! 236: pxa2x0_gpio_intr_establish(sc->sc_swa_pin, IST_EDGE_BOTH, IPL_TTY,
! 237: zkbd_hinge, sc, sc->sc_dev.dv_xname);
! 238: pxa2x0_gpio_intr_establish(sc->sc_swb_pin, IST_EDGE_BOTH, IPL_TTY,
! 239: zkbd_hinge, sc, sc->sc_dev.dv_xname);
! 240:
! 241: if (glass_console) {
! 242: wskbd_cnattach(&zkbd_consops, sc, &zkbd_keymapdata);
! 243: a.console = 1;
! 244: } else {
! 245: a.console = 0;
! 246: }
! 247:
! 248: a.keymap = &zkbd_keymapdata;
! 249: a.accessops = &zkbd_accessops;
! 250: a.accesscookie = sc;
! 251:
! 252: printf("\n");
! 253:
! 254: zkbd_hinge(sc); /* to initialize sc_hinge */
! 255:
! 256: sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
! 257:
! 258: timeout_set(&(sc->sc_roll_to), zkbd_poll, sc);
! 259: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 260: timeout_set(&sc->sc_rawrepeat_ch, zkbd_rawrepeat, sc);
! 261: #endif
! 262:
! 263: }
! 264:
! 265: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 266: void
! 267: zkbd_rawrepeat(void *v)
! 268: {
! 269: struct zkbd_softc *sc = v;
! 270: int s;
! 271:
! 272: s = spltty();
! 273: wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
! 274: splx(s);
! 275: timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000);
! 276: }
! 277: #endif
! 278:
! 279: /* XXX only deal with keys that can be pressed when display is open? */
! 280: /* XXX are some not in the array? */
! 281: /* handle keypress interrupt */
! 282: int
! 283: zkbd_irq(void *v)
! 284: {
! 285: zkbd_poll(v);
! 286:
! 287: return 1;
! 288: }
! 289:
! 290: void
! 291: zkbd_poll(void *v)
! 292: {
! 293: struct zkbd_softc *sc = v;
! 294: int i, j, col, pin, type, keysdown = 0, s;
! 295: int stuck;
! 296: int keystate;
! 297: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 298: int npress = 0, ncbuf = 0, c;
! 299: char cbuf[MAXKEYS *2];
! 300: #endif
! 301:
! 302: s = spltty();
! 303:
! 304: /* discharge all */
! 305: for (i = 0; i < sc->sc_nstrobe; i++) {
! 306: pin = sc->sc_strobe_array[i];
! 307: if (pin != -1) {
! 308: pxa2x0_gpio_clear_bit(pin);
! 309: pxa2x0_gpio_set_dir(pin, GPIO_IN);
! 310: }
! 311: }
! 312:
! 313: delay (10);
! 314: for(col = 0; col < sc->sc_nstrobe; col++) {
! 315: if (sc->sc_strobe_array[i] == -1)
! 316: continue;
! 317:
! 318: pin = sc->sc_strobe_array[col];
! 319:
! 320: /* activate_col */
! 321: pxa2x0_gpio_set_bit(pin);
! 322: pxa2x0_gpio_set_dir(pin, GPIO_OUT);
! 323:
! 324: /* wait activate delay */
! 325: delay(10);
! 326:
! 327: /* read row */
! 328: for (i = 0; i < sc->sc_nsense; i++) {
! 329: int bit;
! 330:
! 331: if (sc->sc_sense_array[i] == -1)
! 332: continue;
! 333:
! 334: bit = pxa2x0_gpio_get_bit(sc->sc_sense_array[i]);
! 335: if (bit && sc->sc_hinge && col < sc->sc_maxkbdcol)
! 336: continue;
! 337: sc->sc_keystate[i + (col * sc->sc_nsense)] = bit;
! 338: }
! 339:
! 340: /* reset_col */
! 341: pxa2x0_gpio_set_dir(pin, GPIO_IN);
! 342: /* wait discharge delay */
! 343: delay(10);
! 344: }
! 345: /* charge all */
! 346: for (i = 0; i < sc->sc_nstrobe; i++) {
! 347: pin = sc->sc_strobe_array[i];
! 348: if (pin != -1) {
! 349: pxa2x0_gpio_set_bit(pin);
! 350: pxa2x0_gpio_set_dir(pin, GPIO_OUT);
! 351: }
! 352: }
! 353:
! 354: /* force the irqs to clear as we have just played with them. */
! 355: for (i = 0; i < sc->sc_nsense; i++)
! 356: if (sc->sc_sense_array[i] != -1)
! 357: pxa2x0_gpio_clear_intr(sc->sc_sense_array[i]);
! 358:
! 359: /* process after resetting interrupt */
! 360:
! 361: zkbd_modstate = (
! 362: (sc->sc_keystate[84] ? (1 << 0) : 0) | /* shift */
! 363: (sc->sc_keystate[93] ? (1 << 1) : 0) | /* Fn */
! 364: (sc->sc_keystate[14] ? (1 << 2) : 0)); /* 'alt' */
! 365:
! 366: for (i = 0; i < (sc->sc_nsense * sc->sc_nstrobe); i++) {
! 367: stuck = 0;
! 368: /* extend xt_keymap to do this faster. */
! 369: /* ignore 'stuck' keys' */
! 370: for (j = 0; j < sizeof(stuck_keys)/sizeof(stuck_keys[0]); j++) {
! 371: if (stuck_keys[j] == i) {
! 372: stuck = 1 ;
! 373: break;
! 374: }
! 375: }
! 376: if (stuck)
! 377: continue;
! 378: keystate = sc->sc_keystate[i];
! 379:
! 380: keysdown |= keystate; /* if any keys held */
! 381:
! 382: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 383: if (sc->sc_polling == 0 && sc->sc_rawkbd) {
! 384: if ((keystate) || (sc->sc_okeystate[i] != keystate)) {
! 385: c = sc->sc_xt_keymap[i];
! 386: if (c & 0x80) {
! 387: cbuf[ncbuf++] = 0xe0;
! 388: }
! 389: cbuf[ncbuf] = c & 0x7f;
! 390:
! 391: if (keystate) {
! 392: if (c & 0x80) {
! 393: sc->sc_rep[npress++] = 0xe0;
! 394: }
! 395: sc->sc_rep[npress++] = c & 0x7f;
! 396: } else {
! 397: cbuf[ncbuf] |= 0x80;
! 398: }
! 399: ncbuf++;
! 400: sc->sc_okeystate[i] = keystate;
! 401: }
! 402: }
! 403: #endif
! 404:
! 405: if ((!sc->sc_rawkbd) && (sc->sc_okeystate[i] != keystate)) {
! 406:
! 407: type = keystate ? WSCONS_EVENT_KEY_DOWN :
! 408: WSCONS_EVENT_KEY_UP;
! 409:
! 410: if (sc->sc_polling) {
! 411: sc->sc_pollkey = i;
! 412: sc->sc_pollUD = type;
! 413: } else {
! 414: wskbd_input(sc->sc_wskbddev, type, i);
! 415: }
! 416:
! 417: sc->sc_okeystate[i] = keystate;
! 418: }
! 419: }
! 420:
! 421: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 422: if (sc->sc_polling == 0 && sc->sc_rawkbd) {
! 423: wskbd_rawinput(sc->sc_wskbddev, cbuf, ncbuf);
! 424: sc->sc_nrep = npress;
! 425: if (npress != 0)
! 426: timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAY1/1000);
! 427: else
! 428: timeout_del(&sc->sc_rawrepeat_ch);
! 429: }
! 430: #endif
! 431: if (keysdown)
! 432: timeout_add(&(sc->sc_roll_to), hz * REP_DELAYN / 1000 / 2);
! 433: else
! 434: timeout_del(&(sc->sc_roll_to)); /* always cancel? */
! 435:
! 436: splx(s);
! 437: }
! 438:
! 439: #if NAPM > 0
! 440: extern int kbd_reset;
! 441: extern int apm_suspends;
! 442: static int zkbdondown; /* on key is pressed */
! 443: static struct timeval zkbdontv = { 0, 0 }; /* last on key event */
! 444: const struct timeval zkbdhalttv = { 3, 0 }; /* 3s for safe shutdown */
! 445: const struct timeval zkbdsleeptv = { 0, 250000 }; /* .25s for suspend */
! 446: extern int lid_suspend;
! 447: #endif
! 448:
! 449: int
! 450: zkbd_on(void *v)
! 451: {
! 452: #if NAPM > 0
! 453: struct zkbd_softc *sc = v;
! 454: int down = pxa2x0_gpio_get_bit(sc->sc_onkey_pin) ? 1 : 0;
! 455:
! 456: /*
! 457: * Change run mode depending on how long the key is held down.
! 458: * Ignore the key if it gets pressed while the lid is closed.
! 459: *
! 460: * Keys can bounce and we have to work around missed interrupts.
! 461: * Only the second edge is detected upon exit from sleep mode.
! 462: */
! 463: if (down) {
! 464: if (sc->sc_hinge == 3) {
! 465: zkbdondown = 0;
! 466: } else {
! 467: microuptime(&zkbdontv);
! 468: zkbdondown = 1;
! 469: }
! 470: } else if (zkbdondown) {
! 471: if (ratecheck(&zkbdontv, &zkbdhalttv)) {
! 472: if (kbd_reset == 1) {
! 473: kbd_reset = 0;
! 474: psignal(initproc, SIGUSR1);
! 475: }
! 476: } else if (ratecheck(&zkbdontv, &zkbdsleeptv)) {
! 477: apm_suspends++;
! 478: }
! 479: zkbdondown = 0;
! 480: }
! 481: #endif
! 482: return 1;
! 483: }
! 484:
! 485: int
! 486: zkbd_sync(void *v)
! 487: {
! 488: return 1;
! 489: }
! 490:
! 491: int
! 492: zkbd_hinge(void *v)
! 493: {
! 494: struct zkbd_softc *sc = v;
! 495: int a = pxa2x0_gpio_get_bit(sc->sc_swa_pin) ? 1 : 0;
! 496: int b = pxa2x0_gpio_get_bit(sc->sc_swb_pin) ? 2 : 0;
! 497: extern void lcd_blank(int);
! 498:
! 499: sc->sc_hinge = a | b;
! 500:
! 501: if (sc->sc_hinge == 3) {
! 502: #if NAPM > 0
! 503: if (lid_suspend)
! 504: apm_suspends++;
! 505: #endif
! 506: lcd_blank(1);
! 507: } else
! 508: lcd_blank(0);
! 509:
! 510:
! 511: return 1;
! 512: }
! 513:
! 514: int
! 515: zkbd_enable(void *v, int on)
! 516: {
! 517: return 0;
! 518: }
! 519:
! 520: void
! 521: zkbd_set_leds(void *v, int on)
! 522: {
! 523: }
! 524:
! 525: int
! 526: zkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
! 527: {
! 528: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 529: struct zkbd_softc *sc = v;
! 530: #endif
! 531:
! 532: switch (cmd) {
! 533:
! 534: case WSKBDIO_GTYPE:
! 535: *(int *)data = WSKBD_TYPE_ZAURUS;
! 536: return 0;
! 537: case WSKBDIO_SETLEDS:
! 538: return 0;
! 539: case WSKBDIO_GETLEDS:
! 540: *(int *)data = 0;
! 541: return 0;
! 542: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 543: case WSKBDIO_SETMODE:
! 544: sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
! 545: timeout_del(&sc->sc_rawrepeat_ch);
! 546: return (0);
! 547: #endif
! 548:
! 549: }
! 550: /* kbdioctl(...); */
! 551:
! 552: return -1;
! 553: }
! 554:
! 555: /* implement polling for zaurus_kbd */
! 556: void
! 557: zkbd_cngetc(void *v, u_int *type, int *data)
! 558: {
! 559: struct zkbd_softc *sc = zkbd_dev;
! 560: sc->sc_pollkey = -1;
! 561: sc->sc_pollUD = -1;
! 562: sc->sc_polling = 1;
! 563: while (sc->sc_pollkey == -1) {
! 564: zkbd_poll(zkbd_dev);
! 565: DELAY(10000); /* XXX */
! 566: }
! 567: sc->sc_polling = 0;
! 568: *data = sc->sc_pollkey;
! 569: *type = sc->sc_pollUD;
! 570: }
! 571:
! 572: void
! 573: zkbd_cnpollc(void *v, int on)
! 574: {
! 575: }
! 576:
! 577: void
! 578: zkbd_power(int why, void *arg)
! 579: {
! 580: zkbd_hinge(arg);
! 581: }
CVSweb