Annotation of sys/arch/zaurus/dev/zaurus_remote.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: zaurus_remote.c,v 1.1 2005/11/17 05:26:31 uwe Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2005 Uwe Stuehler <uwe@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: #include <sys/param.h>
! 20: #include <sys/device.h>
! 21: #include <sys/kernel.h>
! 22: #include <sys/limits.h>
! 23: #include <sys/timeout.h>
! 24: #include <sys/systm.h>
! 25:
! 26: #include <dev/wscons/wsconsio.h>
! 27: #include <dev/wscons/wskbdraw.h>
! 28: #include <dev/wscons/wskbdvar.h>
! 29: #include <dev/wscons/wsksymdef.h>
! 30: #include <dev/wscons/wsksymvar.h>
! 31:
! 32: #include <machine/intr.h>
! 33: #include <machine/zaurus_var.h>
! 34:
! 35: #include <arm/xscale/pxa2x0reg.h>
! 36: #include <arm/xscale/pxa2x0_gpio.h>
! 37:
! 38: #include <zaurus/dev/zaurus_scoopvar.h>
! 39: #include <zaurus/dev/zaurus_sspvar.h>
! 40:
! 41: #define RESCAN_INTERVAL (hz/100)
! 42:
! 43: #define KEY_RELEASE 0 /* button release */
! 44: #define KEY_VOL_DOWN 1
! 45: #define KEY_MUTE 2
! 46: #define KEY_REWIND 3
! 47: #define KEY_VOL_UP 4
! 48: #define KEY_FORWARD 5
! 49: #define KEY_PLAY 6
! 50: #define KEY_STOP 7
! 51: #define KEY_EARPHONE 8
! 52:
! 53: #ifdef DEBUG
! 54: static const char *zrc_keyname[] = {
! 55: "(release)", "volume down", "mute", "rewind", "volume up",
! 56: "forward", "play", "stop", "(earphone)"
! 57: };
! 58: #endif
! 59:
! 60: struct zrc_akey {
! 61: int min; /* minimum ADC value or INT_MIN */
! 62: int key; /* remote control key number */
! 63: };
! 64:
! 65: /* Values match the resistors in the CE-RH2 remote control. */
! 66: static const struct zrc_akey zrc_akeytab_c3000[] = {
! 67: { 238, KEY_RELEASE },
! 68: { 202, KEY_VOL_DOWN },
! 69: { 168, KEY_MUTE },
! 70: { 135, KEY_REWIND },
! 71: { 105, KEY_VOL_UP },
! 72: { 74, KEY_FORWARD },
! 73: { 42, KEY_PLAY },
! 74: { 12, KEY_STOP },
! 75: { INT_MIN, KEY_EARPHONE }
! 76: };
! 77:
! 78: static const struct zrc_akey *zrc_akeytab = zrc_akeytab_c3000;
! 79:
! 80: struct zrc_softc {
! 81: struct device sc_dev;
! 82: struct timeout sc_to;
! 83: void *sc_ih;
! 84: int sc_key; /* being scanned */
! 85: int sc_scans; /* rescan counter */
! 86: int sc_noise; /* discard if too noisy? */
! 87: int sc_keydown; /* currently pressed key */
! 88: struct device *sc_wskbddev;
! 89: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 90: int sc_rawkbd;
! 91: #endif
! 92: };
! 93:
! 94: int zrc_match(struct device *, void *, void *);
! 95: void zrc_attach(struct device *, struct device *, void *);
! 96:
! 97: int zrc_intr(void *);
! 98: void zrc_timeout(void *);
! 99: int zrc_scan(void);
! 100: void zrc_input(struct zrc_softc *, int, int);
! 101:
! 102: struct cfattach zrc_ca = {
! 103: sizeof(struct zrc_softc), zrc_match, zrc_attach
! 104: };
! 105:
! 106: struct cfdriver zrc_cd = {
! 107: NULL, "zrc", DV_DULL
! 108: };
! 109:
! 110: int zrc_enable(void *, int);
! 111: void zrc_set_leds(void *, int);
! 112: int zrc_ioctl(void *, u_long, caddr_t, int, struct proc *);
! 113:
! 114: struct wskbd_accessops zrc_accessops = {
! 115: zrc_enable,
! 116: zrc_set_leds,
! 117: zrc_ioctl,
! 118: };
! 119:
! 120: #define KC(n) KS_KEYCODE(n)
! 121:
! 122: /* XXX what keys should be generated in translated mode? */
! 123: static const keysym_t zrc_keydesc[] = {
! 124: KC(KEY_VOL_DOWN), KS_minus,
! 125: KC(KEY_MUTE), KS_m,
! 126: KC(KEY_REWIND), KS_b,
! 127: KC(KEY_VOL_UP), KS_plus,
! 128: KC(KEY_FORWARD), KS_f,
! 129: KC(KEY_PLAY), KS_p,
! 130: KC(KEY_STOP), KS_s,
! 131: };
! 132:
! 133: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 134: #define RAWKEY_AudioRewind 0xa0
! 135: #define RAWKEY_AudioForward 0xa1
! 136: #define RAWKEY_AudioPlay 0xa2
! 137: #define RAWKEY_AudioStop 0xa3
! 138: static const keysym_t zrc_xt_keymap[] = {
! 139: /* KC(KEY_RELEASE), */ RAWKEY_Null,
! 140: /* KC(KEY_VOL_DOWN), */ RAWKEY_AudioLower,
! 141: /* KC(KEY_MUTE), */ RAWKEY_AudioMute,
! 142: /* KC(KEY_REWIND), */ RAWKEY_AudioRewind,
! 143: /* KC(KEY_VOL_UP), */ RAWKEY_AudioRaise,
! 144: /* KC(KEY_FORWARD), */ RAWKEY_AudioForward,
! 145: /* KC(KEY_PLAY), */ RAWKEY_AudioPlay,
! 146: /* KC(KEY_STOP), */ RAWKEY_AudioStop,
! 147: };
! 148: #endif
! 149:
! 150: static const struct wscons_keydesc zrc_keydesctab[] = {
! 151: {KB_US, 0, sizeof(zrc_keydesc)/sizeof(keysym_t), zrc_keydesc},
! 152: {0, 0, 0, 0}
! 153: };
! 154:
! 155: struct wskbd_mapdata zrc_keymapdata = {
! 156: zrc_keydesctab, KB_US
! 157: };
! 158:
! 159:
! 160: int
! 161: zrc_match(struct device *parent, void *match, void *aux)
! 162: {
! 163: return (ZAURUS_ISC3000);
! 164: }
! 165:
! 166: void
! 167: zrc_attach(struct device *parent, struct device *self, void *aux)
! 168: {
! 169: struct zrc_softc *sc = (struct zrc_softc *)self;
! 170: struct wskbddev_attach_args a;
! 171:
! 172: /* Configure remote control interrupt handling. */
! 173: timeout_set(&sc->sc_to, zrc_timeout, sc);
! 174: pxa2x0_gpio_set_function(C3000_RC_IRQ_PIN, GPIO_IN);
! 175: sc->sc_ih = pxa2x0_gpio_intr_establish(C3000_RC_IRQ_PIN,
! 176: IST_EDGE_BOTH, IPL_BIO, zrc_intr, sc, "zrc");
! 177:
! 178: /* Enable the pullup while waiting for an interrupt. */
! 179: scoop_akin_pullup(1);
! 180:
! 181: sc->sc_keydown = KEY_RELEASE;
! 182:
! 183: printf(": CE-RH2 remote control\n");
! 184:
! 185: a.console = 0;
! 186: a.keymap = &zrc_keymapdata;
! 187: a.accessops = &zrc_accessops;
! 188: a.accesscookie = sc;
! 189:
! 190: sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
! 191: }
! 192:
! 193: int
! 194: zrc_intr(void *v)
! 195: {
! 196: struct zrc_softc *sc = v;
! 197:
! 198: /* just return if remote control isn't present */
! 199:
! 200: pxa2x0_gpio_intr_mask(sc->sc_ih);
! 201: scoop_akin_pullup(0);
! 202: sc->sc_key = zrc_scan();
! 203: sc->sc_scans = 0;
! 204: sc->sc_noise = 0;
! 205: timeout_add(&sc->sc_to, RESCAN_INTERVAL);
! 206: return (1);
! 207: }
! 208:
! 209: void
! 210: zrc_timeout(void *v)
! 211: {
! 212: struct zrc_softc *sc = v;
! 213: int key;
! 214:
! 215: key = zrc_scan();
! 216: switch (sc->sc_scans) {
! 217: case 0:
! 218: case 1:
! 219: case 2:
! 220: /* wait for a stable read */
! 221: if (sc->sc_key == key)
! 222: sc->sc_scans++;
! 223: else {
! 224: sc->sc_key = key;
! 225: sc->sc_scans = 0;
! 226: sc->sc_noise++;
! 227: }
! 228: timeout_add(&sc->sc_to, RESCAN_INTERVAL);
! 229: break;
! 230: case 3:
! 231: /* generate key press event */
! 232: if (sc->sc_key != key) {
! 233: key = sc->sc_key;
! 234: sc->sc_noise++;
! 235: }
! 236: sc->sc_scans++;
! 237: switch (key) {
! 238: case KEY_EARPHONE:
! 239: case KEY_RELEASE:
! 240: sc->sc_scans = 6;
! 241: break;
! 242: default:
! 243: #ifdef DEBUG
! 244: printf("%s pressed (%d noise)\n", zrc_keyname[key],
! 245: sc->sc_noise);
! 246: #endif
! 247: sc->sc_keydown = key;
! 248: sc->sc_noise = 0;
! 249: zrc_input(sc, key, 1);
! 250: break;
! 251: }
! 252: timeout_add(&sc->sc_to, RESCAN_INTERVAL);
! 253: break;
! 254: case 4:
! 255: case 5:
! 256: /* wait for key release, permit noise */
! 257: if (sc->sc_key == key) {
! 258: if (sc->sc_scans == 5)
! 259: sc->sc_noise++;
! 260: sc->sc_scans = 4;
! 261: } else
! 262: sc->sc_scans++;
! 263: timeout_add(&sc->sc_to, RESCAN_INTERVAL);
! 264: break;
! 265: case 6:
! 266: /* generate key release event */
! 267: if (sc->sc_keydown != KEY_RELEASE) {
! 268: zrc_input(sc, sc->sc_keydown, 0);
! 269: #ifdef DEBUG
! 270: printf("%s released (%d noise)\n",
! 271: zrc_keyname[sc->sc_keydown], sc->sc_noise);
! 272: #endif
! 273: sc->sc_keydown = KEY_RELEASE;
! 274: }
! 275: /* FALLTHROUGH */
! 276: default:
! 277: /* unmask interrupt again */
! 278: timeout_del(&sc->sc_to);
! 279: sc->sc_scans = 7;
! 280: scoop_akin_pullup(1);
! 281: pxa2x0_gpio_intr_unmask(sc->sc_ih);
! 282: }
! 283: }
! 284:
! 285: int
! 286: zrc_scan(void)
! 287: {
! 288: int val;
! 289: int i;
! 290:
! 291: /* XXX MAX1111 command word - also appears in zaurus_apm.c */
! 292: #define MAXCTRL_PD0 (1<<0)
! 293: #define MAXCTRL_PD1 (1<<1)
! 294: #define MAXCTRL_SGL (1<<2)
! 295: #define MAXCTRL_UNI (1<<3)
! 296: #define MAXCTRL_SEL_SHIFT 4
! 297: #define MAXCTRL_STR (1<<7)
! 298:
! 299: #define C3000_ADCCH_ZRC 0
! 300: val = zssp_read_max1111(MAXCTRL_PD0 | MAXCTRL_PD1 | MAXCTRL_SGL |
! 301: MAXCTRL_UNI | (C3000_ADCCH_ZRC << MAXCTRL_SEL_SHIFT) |
! 302: MAXCTRL_STR);
! 303: for (i = 0; zrc_akeytab[i].min != INT_MIN; i++)
! 304: if (val >= zrc_akeytab[i].min)
! 305: break;
! 306: return (zrc_akeytab[i].key);
! 307: }
! 308:
! 309: void
! 310: zrc_input(struct zrc_softc *sc, int key, int down)
! 311: {
! 312: u_int type = down ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
! 313: int s;
! 314:
! 315: s = spltty();
! 316:
! 317: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 318: if (sc->sc_rawkbd) {
! 319: int c;
! 320: u_char cbuf[2];
! 321: int ncbuf = 0;
! 322:
! 323: c = zrc_xt_keymap[key];
! 324: if (c & 0x80)
! 325: cbuf[ncbuf++] = 0xe0;
! 326: cbuf[ncbuf] = c & 0x7f;
! 327:
! 328: if (!down)
! 329: cbuf[ncbuf] |= 0x80;
! 330: ncbuf++;
! 331:
! 332: wskbd_rawinput(sc->sc_wskbddev, cbuf, ncbuf);
! 333: } else
! 334: #endif
! 335: wskbd_input(sc->sc_wskbddev, type, key);
! 336:
! 337: splx(s);
! 338: }
! 339:
! 340: int
! 341: zrc_enable(void *v, int on)
! 342: {
! 343: return (0);
! 344: }
! 345:
! 346: void
! 347: zrc_set_leds(void *v, int on)
! 348: {
! 349: }
! 350:
! 351: int
! 352: zrc_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
! 353: {
! 354: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 355: struct zrc_softc *sc = v;
! 356: #endif
! 357:
! 358: switch (cmd) {
! 359: case WSKBDIO_GTYPE:
! 360: *(int *)data = WSKBD_TYPE_ZAURUS;
! 361: return (0);
! 362: case WSKBDIO_SETLEDS:
! 363: return (0);
! 364: case WSKBDIO_GETLEDS:
! 365: *(int *)data = 0;
! 366: return (0);
! 367: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 368: case WSKBDIO_SETMODE:
! 369: sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
! 370: return (0);
! 371: #endif
! 372: }
! 373: return (-1);
! 374: }
CVSweb