1 /* $NetBSD: lunaws.c,v 1.28 2014/02/02 15:35:06 tsutsui 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.28 2014/02/02 15:35:06 tsutsui Exp $"); 35 36 #include "wsmouse.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/conf.h> 41 #include <sys/device.h> 42 43 #include <dev/wscons/wsconsio.h> 44 #include <dev/wscons/wskbdvar.h> 45 #include <dev/wscons/wsksymdef.h> 46 #include <dev/wscons/wsksymvar.h> 47 #include <dev/wscons/wsmousevar.h> 48 49 #include <luna68k/dev/sioreg.h> 50 #include <luna68k/dev/siovar.h> 51 52 #include "ioconf.h" 53 54 #define OMKBD_RXQ_LEN 64 55 #define OMKBD_RXQ_LEN_MASK (OMKBD_RXQ_LEN - 1) 56 #define OMKBD_NEXTRXQ(x) (((x) + 1) & OMKBD_RXQ_LEN_MASK) 57 58 static const uint8_t ch1_regs[6] = { 59 WR0_RSTINT, /* Reset E/S Interrupt */ 60 WR1_RXALLS, /* Rx per char, No Tx */ 61 0, /* */ 62 WR3_RX8BIT | WR3_RXENBL, /* Rx */ 63 WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY, /* Tx/Rx */ 64 WR5_TX8BIT | WR5_TXENBL, /* Tx */ 65 }; 66 67 struct ws_softc { 68 device_t sc_dev; 69 struct sioreg *sc_ctl; 70 uint8_t sc_wr[6]; 71 device_t sc_wskbddev; 72 uint8_t sc_rxq[OMKBD_RXQ_LEN]; 73 u_int sc_rxqhead; 74 u_int sc_rxqtail; 75 #if NWSMOUSE > 0 76 device_t sc_wsmousedev; 77 int sc_msreport; 78 int sc_msbuttons, sc_msdx, sc_msdy; 79 #endif 80 void *sc_si; 81 }; 82 83 static void omkbd_input(void *, int); 84 static int omkbd_decode(void *, int, u_int *, int *); 85 static int omkbd_enable(void *, int); 86 static void omkbd_set_leds(void *, int); 87 static int omkbd_ioctl(void *, u_long, void *, int, struct lwp *); 88 89 struct wscons_keydesc omkbd_keydesctab[]; 90 91 static const struct wskbd_mapdata omkbd_keymapdata = { 92 omkbd_keydesctab, 93 KB_JP, 94 }; 95 static const struct wskbd_accessops omkbd_accessops = { 96 omkbd_enable, 97 omkbd_set_leds, 98 omkbd_ioctl, 99 }; 100 101 void ws_cnattach(void); 102 static void ws_cngetc(void *, u_int *, int *); 103 static void ws_cnpollc(void *, int); 104 static const struct wskbd_consops ws_consops = { 105 ws_cngetc, 106 ws_cnpollc, 107 }; 108 109 #if NWSMOUSE > 0 110 static int omms_enable(void *); 111 static int omms_ioctl(void *, u_long, void *, int, struct lwp *); 112 static void omms_disable(void *); 113 114 static const struct wsmouse_accessops omms_accessops = { 115 omms_enable, 116 omms_ioctl, 117 omms_disable, 118 }; 119 #endif 120 121 static void wsintr(void *); 122 static void wssoftintr(void *); 123 124 static int wsmatch(device_t, cfdata_t, void *); 125 static void wsattach(device_t, device_t, void *); 126 127 CFATTACH_DECL_NEW(ws, sizeof(struct ws_softc), 128 wsmatch, wsattach, NULL, NULL); 129 130 extern int syscngetc(dev_t); 131 extern void syscnputc(dev_t, int); 132 133 static int 134 wsmatch(device_t parent, cfdata_t cf, void *aux) 135 { 136 struct sio_attach_args *args = aux; 137 138 if (args->channel != 1) 139 return 0; 140 return 1; 141 } 142 143 static void 144 wsattach(device_t parent, device_t self, void *aux) 145 { 146 struct ws_softc *sc = device_private(self); 147 struct sio_softc *siosc = device_private(parent); 148 struct sio_attach_args *args = aux; 149 int channel = args->channel; 150 struct wskbddev_attach_args a; 151 152 sc->sc_dev = self; 153 sc->sc_ctl = &siosc->sc_ctl[channel]; 154 memcpy(sc->sc_wr, ch1_regs, sizeof(ch1_regs)); 155 siosc->sc_intrhand[channel].ih_func = wsintr; 156 siosc->sc_intrhand[channel].ih_arg = sc; 157 158 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]); 159 setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]); 160 setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]); 161 setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]); 162 setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]); 163 setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); 164 165 syscnputc((dev_t)1, 0x20); /* keep quiet mouse */ 166 167 sc->sc_rxqhead = 0; 168 sc->sc_rxqtail = 0; 169 170 sc->sc_si = softint_establish(SOFTINT_SERIAL, wssoftintr, sc); 171 172 aprint_normal("\n"); 173 174 a.console = (args->hwflags == 1); 175 a.keymap = &omkbd_keymapdata; 176 a.accessops = &omkbd_accessops; 177 a.accesscookie = (void *)sc; 178 sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint); 179 180 #if NWSMOUSE > 0 181 { 182 struct wsmousedev_attach_args b; 183 b.accessops = &omms_accessops; 184 b.accesscookie = (void *)sc; 185 sc->sc_wsmousedev = 186 config_found_ia(self, "wsmousedev", &b, wsmousedevprint); 187 sc->sc_msreport = 0; 188 } 189 #endif 190 } 191 192 /*ARGSUSED*/ 193 static void 194 wsintr(void *arg) 195 { 196 struct ws_softc *sc = arg; 197 struct sioreg *sio = sc->sc_ctl; 198 uint8_t code; 199 int rr; 200 201 rr = getsiocsr(sio); 202 if (rr & RR_RXRDY) { 203 do { 204 code = sio->sio_data; 205 if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) { 206 sio->sio_cmd = WR0_ERRRST; 207 continue; 208 } 209 sc->sc_rxq[sc->sc_rxqtail] = code; 210 sc->sc_rxqtail = OMKBD_NEXTRXQ(sc->sc_rxqtail); 211 } while ((rr = getsiocsr(sio)) & RR_RXRDY); 212 softint_schedule(sc->sc_si); 213 } 214 if (rr & RR_TXRDY) 215 sio->sio_cmd = WR0_RSTPEND; 216 /* not capable of transmit, yet */ 217 } 218 219 static void 220 wssoftintr(void *arg) 221 { 222 struct ws_softc *sc = arg; 223 uint8_t code; 224 225 while (sc->sc_rxqhead != sc->sc_rxqtail) { 226 code = sc->sc_rxq[sc->sc_rxqhead]; 227 sc->sc_rxqhead = OMKBD_NEXTRXQ(sc->sc_rxqhead); 228 #if NWSMOUSE > 0 229 /* 230 * if (code >= 0x80 && code <= 0x87), then 231 * it's the first byte of 3 byte long mouse report 232 * code[0] & 07 -> LMR button condition 233 * code[1], [2] -> x,y delta 234 * otherwise, key press or release event. 235 */ 236 if (sc->sc_msreport == 0) { 237 if (code < 0x80 || code > 0x87) { 238 omkbd_input(sc, code); 239 continue; 240 } 241 code = (code & 07) ^ 07; 242 /* LMR->RML: wsevent counts 0 for leftmost */ 243 sc->sc_msbuttons = (code & 02); 244 if (code & 01) 245 sc->sc_msbuttons |= 04; 246 if (code & 04) 247 sc->sc_msbuttons |= 01; 248 sc->sc_msreport = 1; 249 } else if (sc->sc_msreport == 1) { 250 sc->sc_msdx = (int8_t)code; 251 sc->sc_msreport = 2; 252 } else if (sc->sc_msreport == 2) { 253 sc->sc_msdy = (int8_t)code; 254 wsmouse_input(sc->sc_wsmousedev, 255 sc->sc_msbuttons, sc->sc_msdx, sc->sc_msdy, 0, 0, 256 WSMOUSE_INPUT_DELTA); 257 258 sc->sc_msreport = 0; 259 } 260 #else 261 omkbd_input(sc, code); 262 #endif 263 } 264 } 265 266 static void 267 omkbd_input(void *v, int data) 268 { 269 struct ws_softc *sc = v; 270 u_int type; 271 int key; 272 273 if (omkbd_decode(v, data, &type, &key)) 274 wskbd_input(sc->sc_wskbddev, type, key); 275 } 276 277 static int 278 omkbd_decode(void *v, int datain, u_int *type, int *dataout) 279 { 280 281 *type = (datain & 0x80) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 282 *dataout = datain & 0x7f; 283 return 1; 284 } 285 286 #define KC(n) KS_KEYCODE(n) 287 288 static const keysym_t omkbd_keydesc_1[] = { 289 /* pos command normal shifted */ 290 KC(0x9), KS_Tab, 291 KC(0xa), KS_Control_L, 292 KC(0xb), KS_Mode_switch, /* Kana */ 293 KC(0xc), KS_Shift_R, 294 KC(0xd), KS_Shift_L, 295 KC(0xe), KS_Caps_Lock, 296 KC(0xf), KS_Meta_L, /* Zenmen */ 297 KC(0x10), KS_Escape, 298 KC(0x11), KS_BackSpace, 299 KC(0x12), KS_Return, 300 KC(0x14), KS_space, 301 KC(0x15), KS_Delete, 302 KC(0x16), KS_Alt_L, /* Henkan */ 303 KC(0x17), KS_Alt_R, /* Kakutei */ 304 KC(0x18), KS_f11, /* Shokyo */ 305 KC(0x19), KS_f12, /* Yobidashi */ 306 KC(0x1a), KS_f13, /* Bunsetsu L */ 307 KC(0x1b), KS_f14, /* Bunsetsu R */ 308 KC(0x1c), KS_KP_Up, 309 KC(0x1d), KS_KP_Left, 310 KC(0x1e), KS_KP_Right, 311 KC(0x1f), KS_KP_Down, 312 /* KC(0x20), KS_f11, */ 313 /* KC(0x21), KS_f12, */ 314 KC(0x22), KS_1, KS_exclam, 315 KC(0x23), KS_2, KS_quotedbl, 316 KC(0x24), KS_3, KS_numbersign, 317 KC(0x25), KS_4, KS_dollar, 318 KC(0x26), KS_5, KS_percent, 319 KC(0x27), KS_6, KS_ampersand, 320 KC(0x28), KS_7, KS_apostrophe, 321 KC(0x29), KS_8, KS_parenleft, 322 KC(0x2a), KS_9, KS_parenright, 323 KC(0x2b), KS_0, 324 KC(0x2c), KS_minus, KS_equal, 325 KC(0x2d), KS_asciicircum, KS_asciitilde, 326 KC(0x2e), KS_backslash, KS_bar, 327 /* KC(0x30), KS_f13, */ 328 /* KC(0x31), KS_f14, */ 329 KC(0x32), KS_q, 330 KC(0x33), KS_w, 331 KC(0x34), KS_e, 332 KC(0x35), KS_r, 333 KC(0x36), KS_t, 334 KC(0x37), KS_y, 335 KC(0x38), KS_u, 336 KC(0x39), KS_i, 337 KC(0x3a), KS_o, 338 KC(0x3b), KS_p, 339 KC(0x3c), KS_at, KS_grave, 340 KC(0x3d), KS_bracketleft, KS_braceleft, 341 KC(0x42), KS_a, 342 KC(0x43), KS_s, 343 KC(0x44), KS_d, 344 KC(0x45), KS_f, 345 KC(0x46), KS_g, 346 KC(0x47), KS_h, 347 KC(0x48), KS_j, 348 KC(0x49), KS_k, 349 KC(0x4a), KS_l, 350 KC(0x4b), KS_semicolon, KS_plus, 351 KC(0x4c), KS_colon, KS_asterisk, 352 KC(0x4d), KS_bracketright, KS_braceright, 353 KC(0x52), KS_z, 354 KC(0x53), KS_x, 355 KC(0x54), KS_c, 356 KC(0x55), KS_v, 357 KC(0x56), KS_b, 358 KC(0x57), KS_n, 359 KC(0x58), KS_m, 360 KC(0x59), KS_comma, KS_less, 361 KC(0x5a), KS_period, KS_greater, 362 KC(0x5b), KS_slash, KS_question, 363 KC(0x5c), KS_underscore, 364 KC(0x60), KS_KP_Delete, 365 KC(0x61), KS_KP_Add, 366 KC(0x62), KS_KP_Subtract, 367 KC(0x63), KS_KP_7, 368 KC(0x64), KS_KP_8, 369 KC(0x65), KS_KP_9, 370 KC(0x66), KS_KP_4, 371 KC(0x67), KS_KP_5, 372 KC(0x68), KS_KP_6, 373 KC(0x69), KS_KP_1, 374 KC(0x6a), KS_KP_2, 375 KC(0x6b), KS_KP_3, 376 KC(0x6c), KS_KP_0, 377 KC(0x6d), KS_KP_Decimal, 378 KC(0x6e), KS_KP_Enter, 379 KC(0x72), KS_f1, 380 KC(0x73), KS_f2, 381 KC(0x74), KS_f3, 382 KC(0x75), KS_f4, 383 KC(0x76), KS_f5, 384 KC(0x77), KS_f6, 385 KC(0x78), KS_f7, 386 KC(0x79), KS_f8, 387 KC(0x7a), KS_f9, 388 KC(0x7b), KS_f10, 389 KC(0x7c), KS_KP_Multiply, 390 KC(0x7d), KS_KP_Divide, 391 KC(0x7e), KS_KP_Equal, 392 KC(0x7f), KS_KP_Separator, 393 }; 394 395 #define SIZE(map) (sizeof(map)/sizeof(keysym_t)) 396 397 struct wscons_keydesc omkbd_keydesctab[] = { 398 { KB_JP, 0, SIZE(omkbd_keydesc_1), omkbd_keydesc_1, }, 399 { 0, 0, 0, 0 }, 400 }; 401 402 static void 403 ws_cngetc(void *v, u_int *type, int *data) 404 { 405 int code; 406 407 do { 408 code = syscngetc((dev_t)1); 409 } while (!omkbd_decode(v, code, type, data)); 410 } 411 412 static void 413 ws_cnpollc(void *v, int on) 414 { 415 } 416 417 /* EXPORT */ void 418 ws_cnattach(void) 419 { 420 static int voidfill; 421 422 /* XXX need CH.B initialization XXX */ 423 424 wskbd_cnattach(&ws_consops, &voidfill, &omkbd_keymapdata); 425 } 426 427 static int 428 omkbd_enable(void *v, int on) 429 { 430 431 return 0; 432 } 433 434 static void 435 omkbd_set_leds(void *v, int leds) 436 { 437 438 #if 0 439 syscnputc((dev_t)1, 0x10); /* kana LED on */ 440 syscnputc((dev_t)1, 0x00); /* kana LED off */ 441 syscnputc((dev_t)1, 0x11); /* caps LED on */ 442 syscnputc((dev_t)1, 0x01); /* caps LED off */ 443 #endif 444 } 445 446 static int 447 omkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 448 { 449 450 switch (cmd) { 451 case WSKBDIO_GTYPE: 452 *(int *)data = WSKBD_TYPE_LUNA; 453 return 0; 454 case WSKBDIO_SETLEDS: 455 case WSKBDIO_GETLEDS: 456 case WSKBDIO_COMPLEXBELL: /* XXX capable of complex bell */ 457 return 0; 458 } 459 return EPASSTHROUGH; 460 } 461 462 #if NWSMOUSE > 0 463 464 static int 465 omms_enable(void *v) 466 { 467 struct ws_softc *sc = v; 468 469 syscnputc((dev_t)1, 0x60); /* enable 3 byte long mouse reporting */ 470 sc->sc_msreport = 0; 471 return 0; 472 } 473 474 /*ARGUSED*/ 475 static int 476 omms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 477 { 478 479 if (cmd == WSMOUSEIO_GTYPE) { 480 *(u_int *)data = 0x19991005; /* XXX */ 481 return 0; 482 } 483 return EPASSTHROUGH; 484 } 485 486 static void 487 omms_disable(void *v) 488 { 489 struct ws_softc *sc = v; 490 491 syscnputc((dev_t)1, 0x20); /* quiet mouse */ 492 sc->sc_msreport = 0; 493 } 494 #endif 495