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