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