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