diff options
author | Uwe Stuehler <uwe@cvs.openbsd.org> | 2005-11-17 05:26:32 +0000 |
---|---|---|
committer | Uwe Stuehler <uwe@cvs.openbsd.org> | 2005-11-17 05:26:32 +0000 |
commit | aa4c7411b799ccebf28303ee57375d9267e4371d (patch) | |
tree | 8da454bb4c78c26cc6e559671cded225f7b74d78 /sys/arch/zaurus/dev | |
parent | 6d4fe888f197dfe30c3a837e6543d8ce015c6d72 (diff) |
Sharp CE-RH2 remote control driver
Diffstat (limited to 'sys/arch/zaurus/dev')
-rw-r--r-- | sys/arch/zaurus/dev/zaurus_remote.c | 374 | ||||
-rw-r--r-- | sys/arch/zaurus/dev/zaurus_scoop.c | 24 | ||||
-rw-r--r-- | sys/arch/zaurus/dev/zaurus_scoopvar.h | 3 |
3 files changed, 399 insertions, 2 deletions
diff --git a/sys/arch/zaurus/dev/zaurus_remote.c b/sys/arch/zaurus/dev/zaurus_remote.c new file mode 100644 index 00000000000..582ea8e01b8 --- /dev/null +++ b/sys/arch/zaurus/dev/zaurus_remote.c @@ -0,0 +1,374 @@ +/* $OpenBSD: zaurus_remote.c,v 1.1 2005/11/17 05:26:31 uwe Exp $ */ + +/* + * Copyright (c) 2005 Uwe Stuehler <uwe@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/limits.h> +#include <sys/timeout.h> +#include <sys/systm.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wskbdraw.h> +#include <dev/wscons/wskbdvar.h> +#include <dev/wscons/wsksymdef.h> +#include <dev/wscons/wsksymvar.h> + +#include <machine/intr.h> +#include <machine/zaurus_var.h> + +#include <arm/xscale/pxa2x0reg.h> +#include <arm/xscale/pxa2x0_gpio.h> + +#include <zaurus/dev/zaurus_scoopvar.h> +#include <zaurus/dev/zaurus_sspvar.h> + +#define RESCAN_INTERVAL (hz/100) + +#define KEY_RELEASE 0 /* button release */ +#define KEY_VOL_DOWN 1 +#define KEY_MUTE 2 +#define KEY_REWIND 3 +#define KEY_VOL_UP 4 +#define KEY_FORWARD 5 +#define KEY_PLAY 6 +#define KEY_STOP 7 +#define KEY_EARPHONE 8 + +#ifdef DEBUG +static const char *zrc_keyname[] = { + "(release)", "volume down", "mute", "rewind", "volume up", + "forward", "play", "stop", "(earphone)" +}; +#endif + +struct zrc_akey { + int min; /* minimum ADC value or INT_MIN */ + int key; /* remote control key number */ +}; + +/* Values match the resistors in the CE-RH2 remote control. */ +static const struct zrc_akey zrc_akeytab_c3000[] = { + { 238, KEY_RELEASE }, + { 202, KEY_VOL_DOWN }, + { 168, KEY_MUTE }, + { 135, KEY_REWIND }, + { 105, KEY_VOL_UP }, + { 74, KEY_FORWARD }, + { 42, KEY_PLAY }, + { 12, KEY_STOP }, + { INT_MIN, KEY_EARPHONE } +}; + +static const struct zrc_akey *zrc_akeytab = zrc_akeytab_c3000; + +struct zrc_softc { + struct device sc_dev; + struct timeout sc_to; + void *sc_ih; + int sc_key; /* being scanned */ + int sc_scans; /* rescan counter */ + int sc_noise; /* discard if too noisy? */ + int sc_keydown; /* currently pressed key */ + struct device *sc_wskbddev; +#ifdef WSDISPLAY_COMPAT_RAWKBD + int sc_rawkbd; +#endif +}; + +int zrc_match(struct device *, void *, void *); +void zrc_attach(struct device *, struct device *, void *); + +int zrc_intr(void *); +void zrc_timeout(void *); +int zrc_scan(void); +void zrc_input(struct zrc_softc *, int, int); + +struct cfattach zrc_ca = { + sizeof(struct zrc_softc), zrc_match, zrc_attach +}; + +struct cfdriver zrc_cd = { + NULL, "zrc", DV_DULL +}; + +int zrc_enable(void *, int); +void zrc_set_leds(void *, int); +int zrc_ioctl(void *, u_long, caddr_t, int, struct proc *); + +struct wskbd_accessops zrc_accessops = { + zrc_enable, + zrc_set_leds, + zrc_ioctl, +}; + +#define KC(n) KS_KEYCODE(n) + +/* XXX what keys should be generated in translated mode? */ +static const keysym_t zrc_keydesc[] = { + KC(KEY_VOL_DOWN), KS_minus, + KC(KEY_MUTE), KS_m, + KC(KEY_REWIND), KS_b, + KC(KEY_VOL_UP), KS_plus, + KC(KEY_FORWARD), KS_f, + KC(KEY_PLAY), KS_p, + KC(KEY_STOP), KS_s, +}; + +#ifdef WSDISPLAY_COMPAT_RAWKBD +#define RAWKEY_AudioRewind 0xa0 +#define RAWKEY_AudioForward 0xa1 +#define RAWKEY_AudioPlay 0xa2 +#define RAWKEY_AudioStop 0xa3 +static const keysym_t zrc_xt_keymap[] = { + /* KC(KEY_RELEASE), */ RAWKEY_Null, + /* KC(KEY_VOL_DOWN), */ RAWKEY_AudioLower, + /* KC(KEY_MUTE), */ RAWKEY_AudioMute, + /* KC(KEY_REWIND), */ RAWKEY_AudioRewind, + /* KC(KEY_VOL_UP), */ RAWKEY_AudioRaise, + /* KC(KEY_FORWARD), */ RAWKEY_AudioForward, + /* KC(KEY_PLAY), */ RAWKEY_AudioPlay, + /* KC(KEY_STOP), */ RAWKEY_AudioStop, +}; +#endif + +static const struct wscons_keydesc zrc_keydesctab[] = { + {KB_US, 0, sizeof(zrc_keydesc)/sizeof(keysym_t), zrc_keydesc}, + {0, 0, 0, 0} +}; + +struct wskbd_mapdata zrc_keymapdata = { + zrc_keydesctab, KB_US +}; + + +int +zrc_match(struct device *parent, void *match, void *aux) +{ + return (ZAURUS_ISC3000); +} + +void +zrc_attach(struct device *parent, struct device *self, void *aux) +{ + struct zrc_softc *sc = (struct zrc_softc *)self; + struct wskbddev_attach_args a; + + /* Configure remote control interrupt handling. */ + timeout_set(&sc->sc_to, zrc_timeout, sc); + pxa2x0_gpio_set_function(C3000_RC_IRQ_PIN, GPIO_IN); + sc->sc_ih = pxa2x0_gpio_intr_establish(C3000_RC_IRQ_PIN, + IST_EDGE_BOTH, IPL_BIO, zrc_intr, sc, "zrc"); + + /* Enable the pullup while waiting for an interrupt. */ + scoop_akin_pullup(1); + + sc->sc_keydown = KEY_RELEASE; + + printf(": CE-RH2 remote control\n"); + + a.console = 0; + a.keymap = &zrc_keymapdata; + a.accessops = &zrc_accessops; + a.accesscookie = sc; + + sc->sc_wskbddev = config_found(self, &a, wskbddevprint); +} + +int +zrc_intr(void *v) +{ + struct zrc_softc *sc = v; + + /* just return if remote control isn't present */ + + pxa2x0_gpio_intr_mask(sc->sc_ih); + scoop_akin_pullup(0); + sc->sc_key = zrc_scan(); + sc->sc_scans = 0; + sc->sc_noise = 0; + timeout_add(&sc->sc_to, RESCAN_INTERVAL); + return (1); +} + +void +zrc_timeout(void *v) +{ + struct zrc_softc *sc = v; + int key; + + key = zrc_scan(); + switch (sc->sc_scans) { + case 0: + case 1: + case 2: + /* wait for a stable read */ + if (sc->sc_key == key) + sc->sc_scans++; + else { + sc->sc_key = key; + sc->sc_scans = 0; + sc->sc_noise++; + } + timeout_add(&sc->sc_to, RESCAN_INTERVAL); + break; + case 3: + /* generate key press event */ + if (sc->sc_key != key) { + key = sc->sc_key; + sc->sc_noise++; + } + sc->sc_scans++; + switch (key) { + case KEY_EARPHONE: + case KEY_RELEASE: + sc->sc_scans = 6; + break; + default: +#ifdef DEBUG + printf("%s pressed (%d noise)\n", zrc_keyname[key], + sc->sc_noise); +#endif + sc->sc_keydown = key; + sc->sc_noise = 0; + zrc_input(sc, key, 1); + break; + } + timeout_add(&sc->sc_to, RESCAN_INTERVAL); + break; + case 4: + case 5: + /* wait for key release, permit noise */ + if (sc->sc_key == key) { + if (sc->sc_scans == 5) + sc->sc_noise++; + sc->sc_scans = 4; + } else + sc->sc_scans++; + timeout_add(&sc->sc_to, RESCAN_INTERVAL); + break; + case 6: + /* generate key release event */ + if (sc->sc_keydown != KEY_RELEASE) { + zrc_input(sc, sc->sc_keydown, 0); +#ifdef DEBUG + printf("%s released (%d noise)\n", + zrc_keyname[sc->sc_keydown], sc->sc_noise); +#endif + sc->sc_keydown = KEY_RELEASE; + } + /* FALLTHROUGH */ + default: + /* unmask interrupt again */ + timeout_del(&sc->sc_to); + sc->sc_scans = 7; + scoop_akin_pullup(1); + pxa2x0_gpio_intr_unmask(sc->sc_ih); + } +} + +int +zrc_scan(void) +{ + int val; + int i; + +/* XXX MAX1111 command word - also appears in zaurus_apm.c */ +#define MAXCTRL_PD0 (1<<0) +#define MAXCTRL_PD1 (1<<1) +#define MAXCTRL_SGL (1<<2) +#define MAXCTRL_UNI (1<<3) +#define MAXCTRL_SEL_SHIFT 4 +#define MAXCTRL_STR (1<<7) + +#define C3000_ADCCH_ZRC 0 + val = zssp_read_max1111(MAXCTRL_PD0 | MAXCTRL_PD1 | MAXCTRL_SGL | + MAXCTRL_UNI | (C3000_ADCCH_ZRC << MAXCTRL_SEL_SHIFT) | + MAXCTRL_STR); + for (i = 0; zrc_akeytab[i].min != INT_MIN; i++) + if (val >= zrc_akeytab[i].min) + break; + return (zrc_akeytab[i].key); +} + +void +zrc_input(struct zrc_softc *sc, int key, int down) +{ + u_int type = down ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; + int s; + + s = spltty(); + +#ifdef WSDISPLAY_COMPAT_RAWKBD + if (sc->sc_rawkbd) { + int c; + u_char cbuf[2]; + int ncbuf = 0; + + c = zrc_xt_keymap[key]; + if (c & 0x80) + cbuf[ncbuf++] = 0xe0; + cbuf[ncbuf] = c & 0x7f; + + if (!down) + cbuf[ncbuf] |= 0x80; + ncbuf++; + + wskbd_rawinput(sc->sc_wskbddev, cbuf, ncbuf); + } else +#endif + wskbd_input(sc->sc_wskbddev, type, key); + + splx(s); +} + +int +zrc_enable(void *v, int on) +{ + return (0); +} + +void +zrc_set_leds(void *v, int on) +{ +} + +int +zrc_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +{ +#ifdef WSDISPLAY_COMPAT_RAWKBD + struct zrc_softc *sc = v; +#endif + + switch (cmd) { + case WSKBDIO_GTYPE: + *(int *)data = WSKBD_TYPE_ZAURUS; + return (0); + case WSKBDIO_SETLEDS: + return (0); + case WSKBDIO_GETLEDS: + *(int *)data = 0; + return (0); +#ifdef WSDISPLAY_COMPAT_RAWKBD + case WSKBDIO_SETMODE: + sc->sc_rawkbd = *(int *)data == WSKBD_RAW; + return (0); +#endif + } + return (-1); +} diff --git a/sys/arch/zaurus/dev/zaurus_scoop.c b/sys/arch/zaurus/dev/zaurus_scoop.c index 197a74020d3..424fdea5efb 100644 --- a/sys/arch/zaurus/dev/zaurus_scoop.c +++ b/sys/arch/zaurus/dev/zaurus_scoop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: zaurus_scoop.c,v 1.11 2005/07/01 23:51:55 uwe Exp $ */ +/* $OpenBSD: zaurus_scoop.c,v 1.12 2005/11/17 05:26:31 uwe Exp $ */ /* * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de> @@ -92,6 +92,14 @@ scoopattach(struct device *parent, struct device *self, void *aux) return; } + if (ZAURUS_ISC3000 && sc->sc_dev.dv_unit == 1) { + scoop_gpio_pin_ctl(sc, SCOOP1_AKIN_PULLUP, GPIO_PIN_OUTPUT); + scoop_gpio_pin_write(sc, SCOOP1_AKIN_PULLUP, GPIO_PIN_LOW); + } else if (!ZAURUS_ISC3000) { + scoop_gpio_pin_ctl(sc, SCOOP0_AKIN_PULLUP, GPIO_PIN_OUTPUT); + scoop_gpio_pin_write(sc, SCOOP0_AKIN_PULLUP, GPIO_PIN_LOW); + } + printf(": PCMCIA/GPIO controller\n"); } @@ -214,6 +222,20 @@ scoop_set_headphone(int on) } } +/* + * Turn on pullup resistor while not reading the remote control. + */ +void +scoop_akin_pullup(int enable) +{ + if (scoop_cd.cd_ndevs > 1 && scoop_cd.cd_devs[1] != NULL) + scoop_gpio_pin_write(scoop_cd.cd_devs[1], + SCOOP1_AKIN_PULLUP, enable); + else + scoop_gpio_pin_write(scoop_cd.cd_devs[0], + SCOOP0_AKIN_PULLUP, enable); +} + void scoop_battery_temp_adc(int enable) { diff --git a/sys/arch/zaurus/dev/zaurus_scoopvar.h b/sys/arch/zaurus/dev/zaurus_scoopvar.h index bdddf7e06eb..84411efc87f 100644 --- a/sys/arch/zaurus/dev/zaurus_scoopvar.h +++ b/sys/arch/zaurus/dev/zaurus_scoopvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: zaurus_scoopvar.h,v 1.9 2005/05/23 22:44:57 pascoe Exp $ */ +/* $OpenBSD: zaurus_scoopvar.h,v 1.10 2005/11/17 05:26:31 uwe Exp $ */ /* * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de> @@ -27,5 +27,6 @@ void scoop_charge_battery(int, int); void scoop_discharge_battery(int); void scoop_check_mcr(void); void scoop_set_headphone(int); +void scoop_akin_pullup(int); void scoop_suspend(void); void scoop_resume(void); |