1 /* $NetBSD: zskbd.c,v 1.19 2019/11/10 21:16:37 chs Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratory. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)kbd.c 8.2 (Berkeley) 10/30/93 41 */ 42 43 /* 44 * LK200/LK400 keyboard attached with channel A of the 2nd SCC 45 */ 46 47 #include <sys/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: zskbd.c,v 1.19 2019/11/10 21:16:37 chs Exp $"); 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/device.h> 53 #include <sys/ioctl.h> 54 #include <sys/syslog.h> 55 #include <sys/malloc.h> 56 57 #include <dev/wscons/wsconsio.h> 58 #include <dev/wscons/wskbdvar.h> 59 #include <dev/wscons/wsksymdef.h> 60 #include <dev/wscons/wsksymvar.h> 61 #include <dev/dec/wskbdmap_lk201.h> 62 63 #include <dev/ic/z8530reg.h> 64 #include <machine/z8530var.h> 65 66 #include <dev/tc/tcvar.h> 67 #include <dev/tc/zs_ioasicvar.h> 68 #include <dev/dec/lk201reg.h> 69 #include <dev/dec/lk201var.h> 70 71 #include "locators.h" 72 73 /* 74 * How many input characters we can buffer. 75 * The port-specific var.h may override this. 76 * Note: must be a power of two! 77 */ 78 #define ZSKBD_RX_RING_SIZE 256 79 #define ZSKBD_RX_RING_MASK (ZSKBD_RX_RING_SIZE-1) 80 /* 81 * Output buffer. Only need a few chars. 82 */ 83 #define ZSKBD_TX_RING_SIZE 16 84 #define ZSKBD_TX_RING_MASK (ZSKBD_TX_RING_SIZE-1) 85 86 #define ZSKBD_BPS 4800 87 88 struct zskbd_internal { 89 struct zs_chanstate *zsi_cs; 90 struct lk201_state zsi_ks; 91 }; 92 93 static struct zskbd_internal zskbd_console_internal; 94 95 struct zskbd_softc { 96 device_t zskbd_dev; /* required first: base device */ 97 98 struct zskbd_internal *sc_itl; 99 100 /* Flags to communicate with zskbd_softintr() */ 101 volatile int zskbd_intr_flags; 102 #define INTR_RX_OVERRUN 1 103 #define INTR_TX_EMPTY 2 104 #define INTR_ST_CHECK 4 105 106 /* 107 * The receive ring buffer. 108 */ 109 u_int zskbd_rbget; /* ring buffer `get' index */ 110 volatile u_int zskbd_rbput; /* ring buffer `put' index */ 111 u_short zskbd_rbuf[ZSKBD_RX_RING_SIZE]; /* rr1, data pairs */ 112 113 int sc_enabled; 114 int kbd_type; 115 116 device_t sc_wskbddev; 117 }; 118 119 static struct zsops zsops_zskbd; 120 121 static void zskbd_input(struct zskbd_softc *, int); 122 123 static int zskbd_match(device_t, cfdata_t, void *); 124 static void zskbd_attach(device_t, device_t, void *); 125 126 CFATTACH_DECL_NEW(zskbd, sizeof(struct zskbd_softc), 127 zskbd_match, zskbd_attach, NULL, NULL); 128 129 static int zskbd_enable(void *, int); 130 static void zskbd_set_leds(void *, int); 131 static int zskbd_ioctl(void *, u_long, void *, int, struct lwp *); 132 133 static const struct wskbd_accessops zskbd_accessops = { 134 zskbd_enable, 135 zskbd_set_leds, 136 zskbd_ioctl, 137 }; 138 139 static void zskbd_cngetc(void *, u_int *, int *); 140 static void zskbd_cnpollc(void *, int); 141 142 static const struct wskbd_consops zskbd_consops = { 143 zskbd_cngetc, 144 zskbd_cnpollc, 145 }; 146 147 static int zskbd_sendchar(void *, u_char); 148 149 static const struct wskbd_mapdata zskbd_keymapdata = { 150 lkkbd_keydesctab, 151 #ifdef ZSKBD_LAYOUT 152 ZSKBD_LAYOUT, 153 #else 154 KB_US | KB_LK401, 155 #endif 156 }; 157 158 int zskbd_cnattach(struct zs_chanstate *); /* EXPORTED */ 159 160 /* 161 * kbd_match: how is this zs channel configured? 162 */ 163 static int 164 zskbd_match(device_t parent, cfdata_t cf, void *aux) 165 { 166 struct zsc_attach_args *args = aux; 167 168 /* Exact match is better than wildcard. */ 169 if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel) 170 return 2; 171 172 /* This driver accepts wildcard. */ 173 if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT) 174 return 1; 175 176 return 0; 177 } 178 179 static void 180 zskbd_attach(device_t parent, device_t self, void *aux) 181 { 182 struct zsc_softc *zsc = device_private(parent); 183 struct zskbd_softc *zskbd = device_private(self); 184 struct zsc_attach_args *args = aux; 185 struct zs_chanstate *cs; 186 struct zskbd_internal *zsi; 187 struct wskbddev_attach_args a; 188 int s, isconsole; 189 190 zskbd->zskbd_dev = self; 191 192 cs = zsc->zsc_cs[args->channel]; 193 cs->cs_private = zskbd; 194 cs->cs_ops = &zsops_zskbd; 195 196 isconsole = (args->hwflags & ZS_HWFLAG_CONSOLE); 197 198 if (isconsole) { 199 zsi = &zskbd_console_internal; 200 } else { 201 zsi = malloc(sizeof(struct zskbd_internal), 202 M_DEVBUF, M_WAITOK); 203 zsi->zsi_ks.attmt.sendchar = zskbd_sendchar; 204 zsi->zsi_ks.attmt.cookie = cs; 205 zsi->zsi_cs = cs; 206 } 207 zskbd->sc_itl = zsi; 208 209 aprint_normal("\n"); 210 211 /* Initialize the speed, etc. */ 212 s = splzs(); 213 /* May need reset... */ 214 zs_write_reg(cs, 9, ZSWR9_A_RESET); 215 /* These are OK as set by zscc: WR3, WR4, WR5 */ 216 /* We don't care about status or tx interrupts. */ 217 cs->cs_preg[1] = ZSWR1_RIE; 218 (void) zs_set_speed(cs, ZSKBD_BPS); 219 zs_loadchannelregs(cs); 220 splx(s); 221 222 if (!isconsole) 223 lk201_init(&zsi->zsi_ks); 224 225 /* XXX should identify keyboard ID here XXX */ 226 /* XXX layout and the number of LED is varying XXX */ 227 228 zskbd->kbd_type = WSKBD_TYPE_LK201; 229 230 zskbd->sc_enabled = 1; 231 232 a.console = isconsole; 233 a.keymap = &zskbd_keymapdata; 234 a.accessops = &zskbd_accessops; 235 a.accesscookie = zskbd; 236 237 zskbd->sc_wskbddev = config_found(self, &a, wskbddevprint); 238 } 239 240 int 241 zskbd_cnattach(struct zs_chanstate *cs) 242 { 243 (void) zs_set_speed(cs, ZSKBD_BPS); 244 zs_loadchannelregs(cs); 245 246 zskbd_console_internal.zsi_ks.attmt.sendchar = zskbd_sendchar; 247 zskbd_console_internal.zsi_ks.attmt.cookie = cs; 248 lk201_init(&zskbd_console_internal.zsi_ks); 249 zskbd_console_internal.zsi_cs = cs; 250 251 wskbd_cnattach(&zskbd_consops, &zskbd_console_internal, 252 &zskbd_keymapdata); 253 254 return 0; 255 } 256 257 static int 258 zskbd_enable(void *v, int on) 259 { 260 struct zskbd_softc *sc = v; 261 262 sc->sc_enabled = on; 263 return 0; 264 } 265 266 static int 267 zskbd_sendchar(void *v, u_char c) 268 { 269 struct zs_chanstate *cs = v; 270 zs_write_data(cs, c); 271 DELAY(4000); 272 273 return (0); 274 } 275 276 static void 277 zskbd_cngetc(void *v, u_int *type, int *data) 278 { 279 struct zskbd_internal *zsi = v; 280 int c; 281 282 do { 283 c = zs_getc(zsi->zsi_cs); 284 } while (!lk201_decode(&zsi->zsi_ks, 0, c, type, data) == LKD_NODATA); 285 } 286 287 static void 288 zskbd_cnpollc(void *v, int on) 289 { 290 #if 0 291 struct zskbd_internal *zsi = v; 292 #endif 293 } 294 295 static void 296 zskbd_set_leds(void *v, int leds) 297 { 298 struct zskbd_softc *sc = v; 299 300 lk201_set_leds(&sc->sc_itl->zsi_ks, leds); 301 } 302 303 static int 304 zskbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 305 { 306 struct zskbd_softc *sc = v; 307 308 switch (cmd) { 309 case WSKBDIO_GTYPE: 310 *(int *)data = sc->kbd_type; 311 return 0; 312 case WSKBDIO_SETLEDS: 313 lk201_set_leds(&sc->sc_itl->zsi_ks, *(int *)data); 314 return 0; 315 case WSKBDIO_GETLEDS: 316 /* XXX don't dig in kbd internals */ 317 *(int *)data = sc->sc_itl->zsi_ks.leds_state; 318 return 0; 319 case WSKBDIO_COMPLEXBELL: 320 lk201_bell(&sc->sc_itl->zsi_ks, 321 (struct wskbd_bell_data *)data); 322 return 0; 323 case WSKBDIO_SETKEYCLICK: 324 lk201_set_keyclick(&sc->sc_itl->zsi_ks, *(int *)data); 325 return 0; 326 case WSKBDIO_GETKEYCLICK: 327 /* XXX don't dig in kbd internals */ 328 *(int *)data = sc->sc_itl->zsi_ks.kcvol; 329 return 0; 330 } 331 return EPASSTHROUGH; 332 } 333 334 static void 335 zskbd_input(struct zskbd_softc *sc, int data) 336 { 337 u_int type; 338 int val; 339 int decode; 340 341 do { 342 decode = lk201_decode(&sc->sc_itl->zsi_ks, 1, 343 data, &type, &val); 344 if (decode != LKD_NODATA) 345 wskbd_input(sc->sc_wskbddev, type, val); 346 } while (decode == LKD_MORE); 347 348 } 349 350 /**************************************************************** 351 * Interface to the lower layer (zscc) 352 ****************************************************************/ 353 354 static void zskbd_rxint(struct zs_chanstate *); 355 static void zskbd_stint(struct zs_chanstate *, int); 356 static void zskbd_txint(struct zs_chanstate *); 357 static void zskbd_softint(struct zs_chanstate *); 358 359 static void 360 zskbd_rxint(struct zs_chanstate *cs) 361 { 362 struct zskbd_softc *zskbd; 363 int put, put_next; 364 u_char c, rr1; 365 366 zskbd = cs->cs_private; 367 put = zskbd->zskbd_rbput; 368 369 /* 370 * First read the status, because reading the received char 371 * destroys the status of this char. 372 */ 373 rr1 = zs_read_reg(cs, 1); 374 c = zs_read_data(cs); 375 if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { 376 /* Clear the receive error. */ 377 zs_write_csr(cs, ZSWR0_RESET_ERRORS); 378 } 379 380 zskbd->zskbd_rbuf[put] = (c << 8) | rr1; 381 put_next = (put + 1) & ZSKBD_RX_RING_MASK; 382 383 /* Would overrun if increment makes (put==get). */ 384 if (put_next == zskbd->zskbd_rbget) { 385 zskbd->zskbd_intr_flags |= INTR_RX_OVERRUN; 386 } else { 387 /* OK, really increment. */ 388 put = put_next; 389 } 390 391 /* Done reading. */ 392 zskbd->zskbd_rbput = put; 393 394 /* Ask for softint() call. */ 395 cs->cs_softreq = 1; 396 } 397 398 399 static void 400 zskbd_txint(struct zs_chanstate *cs) 401 { 402 struct zskbd_softc *zskbd; 403 404 zskbd = cs->cs_private; 405 zs_write_csr(cs, ZSWR0_RESET_TXINT); 406 zskbd->zskbd_intr_flags |= INTR_TX_EMPTY; 407 /* Ask for softint() call. */ 408 cs->cs_softreq = 1; 409 } 410 411 412 static void 413 zskbd_stint(struct zs_chanstate *cs, int force) 414 { 415 struct zskbd_softc *zskbd; 416 int rr0; 417 418 zskbd = cs->cs_private; 419 420 rr0 = zs_read_csr(cs); 421 zs_write_csr(cs, ZSWR0_RESET_STATUS); 422 423 /* 424 * We have to accumulate status line changes here. 425 * Otherwise, if we get multiple status interrupts 426 * before the softint runs, we could fail to notice 427 * some status line changes in the softint routine. 428 * Fix from Bill Studenmund, October 1996. 429 */ 430 cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0); 431 cs->cs_rr0 = rr0; 432 zskbd->zskbd_intr_flags |= INTR_ST_CHECK; 433 434 /* Ask for softint() call. */ 435 cs->cs_softreq = 1; 436 } 437 438 439 static void 440 zskbd_softint(struct zs_chanstate *cs) 441 { 442 struct zskbd_softc *zskbd; 443 int get, c, s; 444 int intr_flags; 445 u_short ring_data; 446 447 zskbd = cs->cs_private; 448 449 /* Atomically get and clear flags. */ 450 s = splzs(); 451 intr_flags = zskbd->zskbd_intr_flags; 452 zskbd->zskbd_intr_flags = 0; 453 454 /* Now lower to spltty for the rest. */ 455 (void) spltty(); 456 457 /* 458 * Copy data from the receive ring to the event layer. 459 */ 460 get = zskbd->zskbd_rbget; 461 while (get != zskbd->zskbd_rbput) { 462 ring_data = zskbd->zskbd_rbuf[get]; 463 get = (get + 1) & ZSKBD_RX_RING_MASK; 464 465 /* low byte of ring_data is rr1 */ 466 c = (ring_data >> 8) & 0xff; 467 468 if (ring_data & ZSRR1_DO) 469 intr_flags |= INTR_RX_OVERRUN; 470 if (ring_data & (ZSRR1_FE | ZSRR1_PE)) { 471 #if 0 /* XXX */ 472 log(LOG_ERR, "%s: input error (0x%x)\n", 473 device_xname(zskbd->zskbd_dev), ring_data); 474 c = -1; /* signal input error */ 475 #endif 476 } 477 478 /* Pass this up to the "middle" layer. */ 479 zskbd_input(zskbd, c); 480 } 481 if (intr_flags & INTR_RX_OVERRUN) { 482 #if 0 /* XXX */ 483 log(LOG_ERR, "%s: input overrun\n", 484 device_xname(zskbd->zskbd_dev)); 485 #endif 486 } 487 zskbd->zskbd_rbget = get; 488 489 if (intr_flags & INTR_TX_EMPTY) { 490 /* 491 * Transmit done. (Not expected.) 492 */ 493 #if 0 494 log(LOG_ERR, "%s: transmit interrupt?\n", 495 device_xname(zskbd->zskbd_dev)); 496 #endif 497 } 498 499 if (intr_flags & INTR_ST_CHECK) { 500 /* 501 * Status line change. (Not expected.) 502 */ 503 log(LOG_ERR, "%s: status interrupt?\n", 504 device_xname(zskbd->zskbd_dev)); 505 cs->cs_rr0_delta = 0; 506 } 507 508 splx(s); 509 } 510 511 static struct zsops zsops_zskbd = { 512 zskbd_rxint, /* receive char available */ 513 zskbd_stint, /* external/status */ 514 zskbd_txint, /* xmit buffer empty */ 515 zskbd_softint, /* process software interrupt */ 516 }; 517