1 /* $NetBSD: lunaws.c,v 1.31 2015/08/21 10:48:06 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tohru Nishimura. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 33 34 __KERNEL_RCSID(0, "$NetBSD: lunaws.c,v 1.31 2015/08/21 10:48:06 christos Exp $"); 35 36 #include "opt_wsdisplay_compat.h" 37 #include "wsmouse.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/conf.h> 42 #include <sys/device.h> 43 44 #include <dev/wscons/wsconsio.h> 45 #include <dev/wscons/wskbdvar.h> 46 #include <dev/wscons/wsksymdef.h> 47 #include <dev/wscons/wsksymvar.h> 48 #include <dev/wscons/wsmousevar.h> 49 50 #include <luna68k/dev/omkbdmap.h> 51 #include <luna68k/dev/sioreg.h> 52 #include <luna68k/dev/siovar.h> 53 #include <luna68k/dev/syscn.h> 54 55 #include "ioconf.h" 56 57 #define OMKBD_RXQ_LEN 64 58 #define OMKBD_RXQ_LEN_MASK (OMKBD_RXQ_LEN - 1) 59 #define OMKBD_NEXTRXQ(x) (((x) + 1) & OMKBD_RXQ_LEN_MASK) 60 61 static const uint8_t ch1_regs[6] = { 62 WR0_RSTINT, /* Reset E/S Interrupt */ 63 WR1_RXALLS, /* Rx per char, No Tx */ 64 0, /* */ 65 WR3_RX8BIT | WR3_RXENBL, /* Rx */ 66 WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY, /* Tx/Rx */ 67 WR5_TX8BIT | WR5_TXENBL, /* Tx */ 68 }; 69 70 struct ws_softc { 71 device_t sc_dev; 72 struct sioreg *sc_ctl; 73 uint8_t sc_wr[6]; 74 device_t sc_wskbddev; 75 uint8_t sc_rxq[OMKBD_RXQ_LEN]; 76 u_int sc_rxqhead; 77 u_int sc_rxqtail; 78 #if NWSMOUSE > 0 79 device_t sc_wsmousedev; 80 int sc_msreport; 81 int sc_msbuttons, sc_msdx, sc_msdy; 82 #endif 83 void *sc_si; 84 int sc_rawkbd; 85 }; 86 87 static void omkbd_input(void *, int); 88 static void omkbd_decode(void *, int, u_int *, int *); 89 static int omkbd_enable(void *, int); 90 static void omkbd_set_leds(void *, int); 91 static int omkbd_ioctl(void *, u_long, void *, int, struct lwp *); 92 93 static const struct wskbd_mapdata omkbd_keymapdata = { 94 omkbd_keydesctab, 95 KB_JP, 96 }; 97 static const struct wskbd_accessops omkbd_accessops = { 98 omkbd_enable, 99 omkbd_set_leds, 100 omkbd_ioctl, 101 }; 102 103 void ws_cnattach(void); 104 static void ws_cngetc(void *, u_int *, int *); 105 static void ws_cnpollc(void *, int); 106 static const struct wskbd_consops ws_consops = { 107 ws_cngetc, 108 ws_cnpollc, 109 }; 110 111 #if NWSMOUSE > 0 112 static int omms_enable(void *); 113 static int omms_ioctl(void *, u_long, void *, int, struct lwp *); 114 static void omms_disable(void *); 115 116 static const struct wsmouse_accessops omms_accessops = { 117 omms_enable, 118 omms_ioctl, 119 omms_disable, 120 }; 121 #endif 122 123 static void wsintr(void *); 124 static void wssoftintr(void *); 125 126 static int wsmatch(device_t, cfdata_t, void *); 127 static void wsattach(device_t, device_t, void *); 128 129 CFATTACH_DECL_NEW(ws, sizeof(struct ws_softc), 130 wsmatch, wsattach, NULL, NULL); 131 132 static int 133 wsmatch(device_t parent, cfdata_t cf, void *aux) 134 { 135 struct sio_attach_args *args = aux; 136 137 if (args->channel != 1) 138 return 0; 139 return 1; 140 } 141 142 static void 143 wsattach(device_t parent, device_t self, void *aux) 144 { 145 struct ws_softc *sc = device_private(self); 146 struct sio_softc *siosc = device_private(parent); 147 struct sio_attach_args *args = aux; 148 int channel = args->channel; 149 struct wskbddev_attach_args a; 150 151 sc->sc_dev = self; 152 sc->sc_ctl = &siosc->sc_ctl[channel]; 153 memcpy(sc->sc_wr, ch1_regs, sizeof(ch1_regs)); 154 siosc->sc_intrhand[channel].ih_func = wsintr; 155 siosc->sc_intrhand[channel].ih_arg = sc; 156 157 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]); 158 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]); 159 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]); 160 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]); 161 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]); 162 setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); 163 164 syscnputc((dev_t)1, 0x20); /* keep quiet mouse */ 165 166 sc->sc_rxqhead = 0; 167 sc->sc_rxqtail = 0; 168 169 sc->sc_si = softint_establish(SOFTINT_SERIAL, wssoftintr, sc); 170 171 aprint_normal("\n"); 172 173 a.console = (args->hwflags == 1); 174 a.keymap = &omkbd_keymapdata; 175 a.accessops = &omkbd_accessops; 176 a.accesscookie = (void *)sc; 177 sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint); 178 179 #if NWSMOUSE > 0 180 { 181 struct wsmousedev_attach_args b; 182 b.accessops = &omms_accessops; 183 b.accesscookie = (void *)sc; 184 sc->sc_wsmousedev = 185 config_found_ia(self, "wsmousedev", &b, wsmousedevprint); 186 sc->sc_msreport = 0; 187 } 188 #endif 189 } 190 191 /*ARGSUSED*/ 192 static void 193 wsintr(void *arg) 194 { 195 struct ws_softc *sc = arg; 196 struct sioreg *sio = sc->sc_ctl; 197 uint8_t code; 198 int rr; 199 200 rr = getsiocsr(sio); 201 if ((rr & RR_RXRDY) != 0) { 202 do { 203 code = sio->sio_data; 204 if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) { 205 sio->sio_cmd = WR0_ERRRST; 206 continue; 207 } 208 sc->sc_rxq[sc->sc_rxqtail] = code; 209 sc->sc_rxqtail = OMKBD_NEXTRXQ(sc->sc_rxqtail); 210 } while (((rr = getsiocsr(sio)) & RR_RXRDY) != 0); 211 softint_schedule(sc->sc_si); 212 } 213 if ((rr & RR_TXRDY) != 0) 214 sio->sio_cmd = WR0_RSTPEND; 215 /* not capable of transmit, yet */ 216 } 217 218 static void 219 wssoftintr(void *arg) 220 { 221 struct ws_softc *sc = arg; 222 uint8_t code; 223 224 while (sc->sc_rxqhead != sc->sc_rxqtail) { 225 code = sc->sc_rxq[sc->sc_rxqhead]; 226 sc->sc_rxqhead = OMKBD_NEXTRXQ(sc->sc_rxqhead); 227 #if NWSMOUSE > 0 228 /* 229 * if (code >= 0x80 && code <= 0x87), then 230 * it's the first byte of 3 byte long mouse report 231 * code[0] & 07 -> LMR button condition 232 * code[1], [2] -> x,y delta 233 * otherwise, key press or release event. 234 */ 235 if (sc->sc_msreport == 0) { 236 if (code < 0x80 || code > 0x87) { 237 omkbd_input(sc, code); 238 continue; 239 } 240 code = (code & 07) ^ 07; 241 /* LMR->RML: wsevent counts 0 for leftmost */ 242 sc->sc_msbuttons = (code & 02); 243 if ((code & 01) != 0) 244 sc->sc_msbuttons |= 04; 245 if ((code & 04) != 0) 246 sc->sc_msbuttons |= 01; 247 sc->sc_msreport = 1; 248 } else if (sc->sc_msreport == 1) { 249 sc->sc_msdx = (int8_t)code; 250 sc->sc_msreport = 2; 251 } else if (sc->sc_msreport == 2) { 252 sc->sc_msdy = (int8_t)code; 253 wsmouse_input(sc->sc_wsmousedev, 254 sc->sc_msbuttons, sc->sc_msdx, sc->sc_msdy, 0, 0, 255 WSMOUSE_INPUT_DELTA); 256 257 sc->sc_msreport = 0; 258 } 259 #else 260 omkbd_input(sc, code); 261 #endif 262 } 263 } 264 265 static void 266 omkbd_input(void *v, int data) 267 { 268 struct ws_softc *sc = v; 269 u_int type; 270 int key; 271 272 omkbd_decode(v, data, &type, &key); 273 274 #ifdef WSDISPLAY_COMPAT_RAWKBD 275 if (sc->sc_rawkbd) { 276 uint8_t cbuf[2]; 277 int c, j = 0; 278 279 c = omkbd_raw[key]; 280 if (c != 0x00) { 281 /* fake extended scancode if necessary */ 282 if (c & 0x80) 283 cbuf[j++] = 0xe0; 284 cbuf[j] = c & 0x7f; 285 if (type == WSCONS_EVENT_KEY_UP) 286 cbuf[j] |= 0x80; 287 j++; 288 289 wskbd_rawinput(sc->sc_wskbddev, cbuf, j); 290 } 291 } else 292 #endif 293 { 294 if (sc->sc_wskbddev != NULL) 295 wskbd_input(sc->sc_wskbddev, type, key); 296 } 297 } 298 299 static void 300 omkbd_decode(void *v, int datain, u_int *type, int *dataout) 301 { 302 303 *type = (datain & 0x80) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 304 *dataout = datain & 0x7f; 305 } 306 307 static void 308 ws_cngetc(void *v, u_int *type, int *data) 309 { 310 int code; 311 312 code = syscngetc((dev_t)1); 313 omkbd_decode(v, code, type, data); 314 } 315 316 static void 317 ws_cnpollc(void *v, int on) 318 { 319 } 320 321 /* EXPORT */ void 322 ws_cnattach(void) 323 { 324 static int voidfill; 325 326 /* XXX need CH.B initialization XXX */ 327 328 wskbd_cnattach(&ws_consops, &voidfill, &omkbd_keymapdata); 329 } 330 331 static int 332 omkbd_enable(void *v, int on) 333 { 334 335 return 0; 336 } 337 338 static void 339 omkbd_set_leds(void *v, int leds) 340 { 341 342 #if 0 343 syscnputc((dev_t)1, 0x10); /* kana LED on */ 344 syscnputc((dev_t)1, 0x00); /* kana LED off */ 345 syscnputc((dev_t)1, 0x11); /* caps LED on */ 346 syscnputc((dev_t)1, 0x01); /* caps LED off */ 347 #endif 348 } 349 350 static int 351 omkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 352 { 353 #ifdef WSDISPLAY_COMPAT_RAWKBD 354 struct ws_softc *sc = v; 355 #endif 356 357 switch (cmd) { 358 case WSKBDIO_GTYPE: 359 *(int *)data = WSKBD_TYPE_LUNA; 360 return 0; 361 case WSKBDIO_SETLEDS: 362 case WSKBDIO_GETLEDS: 363 case WSKBDIO_COMPLEXBELL: /* XXX capable of complex bell */ 364 return 0; 365 #ifdef WSDISPLAY_COMPAT_RAWKBD 366 case WSKBDIO_SETMODE: 367 sc->sc_rawkbd = *(int *)data == WSKBD_RAW; 368 return 0; 369 case WSKBDIO_GETMODE: 370 *(int *)data = sc->sc_rawkbd; 371 return 0; 372 #endif 373 } 374 return EPASSTHROUGH; 375 } 376 377 #if NWSMOUSE > 0 378 379 static int 380 omms_enable(void *v) 381 { 382 struct ws_softc *sc = v; 383 384 syscnputc((dev_t)1, 0x60); /* enable 3 byte long mouse reporting */ 385 sc->sc_msreport = 0; 386 return 0; 387 } 388 389 /*ARGUSED*/ 390 static int 391 omms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 392 { 393 394 if (cmd == WSMOUSEIO_GTYPE) { 395 *(u_int *)data = 0x19991005; /* XXX */ 396 return 0; 397 } 398 return EPASSTHROUGH; 399 } 400 401 static void 402 omms_disable(void *v) 403 { 404 struct ws_softc *sc = v; 405 406 syscnputc((dev_t)1, 0x20); /* quiet mouse */ 407 sc->sc_msreport = 0; 408 } 409 #endif 410