1 /* $NetBSD: zskbd.c,v 1.9 2003/08/07 16:31:28 agc 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.9 2003/08/07 16:31:28 agc 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 struct zskbd_internal zskbd_console_internal; 94 95 struct zskbd_softc { 96 struct device 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 struct device *sc_wskbddev; 117 }; 118 119 struct zsops zsops_zskbd; 120 121 static void zskbd_input __P((struct zskbd_softc *, int)); 122 123 static int zskbd_match __P((struct device *, struct cfdata *, void *)); 124 static void zskbd_attach __P((struct device *, struct device *, void *)); 125 126 CFATTACH_DECL(zskbd, sizeof(struct zskbd_softc), 127 zskbd_match, zskbd_attach, NULL, NULL); 128 129 static int zskbd_enable __P((void *, int)); 130 static void zskbd_set_leds __P((void *, int)); 131 static int zskbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 132 133 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 const struct wskbd_consops zskbd_consops = { 143 zskbd_cngetc, 144 zskbd_cnpollc, 145 }; 146 147 static int zskbd_sendchar __P((void *, u_char)); 148 149 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 __P((struct zs_chanstate *)); /* EXPORTED */ 159 160 /* 161 * kbd_match: how is this zs channel configured? 162 */ 163 static int 164 zskbd_match(parent, cf, aux) 165 struct device *parent; 166 struct cfdata *cf; 167 void *aux; 168 { 169 struct zsc_attach_args *args = aux; 170 171 /* Exact match is better than wildcard. */ 172 if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel) 173 return 2; 174 175 /* This driver accepts wildcard. */ 176 if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT) 177 return 1; 178 179 return 0; 180 } 181 182 static void 183 zskbd_attach(parent, self, aux) 184 struct device *parent, *self; 185 void *aux; 186 { 187 struct zsc_softc *zsc = (void *)parent; 188 struct zskbd_softc *zskbd = (void *)self; 189 struct zsc_attach_args *args = aux; 190 struct zs_chanstate *cs; 191 struct zskbd_internal *zsi; 192 struct wskbddev_attach_args a; 193 int s, isconsole; 194 195 cs = zsc->zsc_cs[args->channel]; 196 cs->cs_private = zskbd; 197 cs->cs_ops = &zsops_zskbd; 198 199 isconsole = (args->hwflags & ZS_HWFLAG_CONSOLE); 200 201 if (isconsole) { 202 zsi = &zskbd_console_internal; 203 } else { 204 zsi = malloc(sizeof(struct zskbd_internal), 205 M_DEVBUF, M_NOWAIT); 206 zsi->zsi_ks.attmt.sendchar = zskbd_sendchar; 207 zsi->zsi_ks.attmt.cookie = cs; 208 zsi->zsi_cs = cs; 209 } 210 zskbd->sc_itl = zsi; 211 212 printf("\n"); 213 214 /* Initialize the speed, etc. */ 215 s = splzs(); 216 /* May need reset... */ 217 zs_write_reg(cs, 9, ZSWR9_A_RESET); 218 /* These are OK as set by zscc: WR3, WR4, WR5 */ 219 /* We don't care about status or tx interrupts. */ 220 cs->cs_preg[1] = ZSWR1_RIE; 221 (void) zs_set_speed(cs, ZSKBD_BPS); 222 zs_loadchannelregs(cs); 223 splx(s); 224 225 if (!isconsole) 226 lk201_init(&zsi->zsi_ks); 227 228 /* XXX should identify keyboard ID here XXX */ 229 /* XXX layout and the number of LED is varying XXX */ 230 231 zskbd->kbd_type = WSKBD_TYPE_LK201; 232 233 zskbd->sc_enabled = 1; 234 235 a.console = isconsole; 236 a.keymap = &zskbd_keymapdata; 237 a.accessops = &zskbd_accessops; 238 a.accesscookie = zskbd; 239 240 zskbd->sc_wskbddev = config_found(self, &a, wskbddevprint); 241 } 242 243 int 244 zskbd_cnattach(cs) 245 struct zs_chanstate *cs; 246 { 247 (void) zs_set_speed(cs, ZSKBD_BPS); 248 zs_loadchannelregs(cs); 249 250 zskbd_console_internal.zsi_ks.attmt.sendchar = zskbd_sendchar; 251 zskbd_console_internal.zsi_ks.attmt.cookie = cs; 252 lk201_init(&zskbd_console_internal.zsi_ks); 253 zskbd_console_internal.zsi_cs = cs; 254 255 wskbd_cnattach(&zskbd_consops, &zskbd_console_internal, 256 &zskbd_keymapdata); 257 258 return 0; 259 } 260 261 static int 262 zskbd_enable(v, on) 263 void *v; 264 int on; 265 { 266 struct zskbd_softc *sc = v; 267 268 sc->sc_enabled = on; 269 return 0; 270 } 271 272 static int 273 zskbd_sendchar(v, c) 274 void *v; 275 u_char c; 276 { 277 struct zs_chanstate *cs = v; 278 zs_write_data(cs, c); 279 DELAY(4000); 280 281 return (0); 282 } 283 284 static void 285 zskbd_cngetc(v, type, data) 286 void *v; 287 u_int *type; 288 int *data; 289 { 290 struct zskbd_internal *zsi = v; 291 int c; 292 293 do { 294 c = zs_getc(zsi->zsi_cs); 295 } while (!lk201_decode(&zsi->zsi_ks, c, type, data)); 296 } 297 298 static void 299 zskbd_cnpollc(v, on) 300 void *v; 301 int on; 302 { 303 #if 0 304 struct zskbd_internal *zsi = v; 305 #endif 306 } 307 308 static void 309 zskbd_set_leds(v, leds) 310 void *v; 311 int leds; 312 { 313 struct zskbd_softc *sc = (struct zskbd_softc *)v; 314 315 lk201_set_leds(&sc->sc_itl->zsi_ks, leds); 316 } 317 318 static int 319 zskbd_ioctl(v, cmd, data, flag, p) 320 void *v; 321 u_long cmd; 322 caddr_t data; 323 int flag; 324 struct proc *p; 325 { 326 struct zskbd_softc *sc = (struct zskbd_softc *)v; 327 328 switch (cmd) { 329 case WSKBDIO_GTYPE: 330 *(int *)data = sc->kbd_type; 331 return 0; 332 case WSKBDIO_SETLEDS: 333 lk201_set_leds(&sc->sc_itl->zsi_ks, *(int *)data); 334 return 0; 335 case WSKBDIO_GETLEDS: 336 /* XXX don't dig in kbd internals */ 337 *(int *)data = sc->sc_itl->zsi_ks.leds_state; 338 return 0; 339 case WSKBDIO_COMPLEXBELL: 340 lk201_bell(&sc->sc_itl->zsi_ks, 341 (struct wskbd_bell_data *)data); 342 return 0; 343 case WSKBDIO_SETKEYCLICK: 344 lk201_set_keyclick(&sc->sc_itl->zsi_ks, *(int *)data); 345 return 0; 346 case WSKBDIO_GETKEYCLICK: 347 /* XXX don't dig in kbd internals */ 348 *(int *)data = sc->sc_itl->zsi_ks.kcvol; 349 return 0; 350 } 351 return EPASSTHROUGH; 352 } 353 354 static void 355 zskbd_input(sc, data) 356 struct zskbd_softc *sc; 357 int data; 358 { 359 u_int type; 360 int val; 361 362 if (sc->sc_enabled == 0) 363 return; 364 365 if (lk201_decode(&sc->sc_itl->zsi_ks, data, &type, &val)) 366 wskbd_input(sc->sc_wskbddev, type, val); 367 } 368 369 /**************************************************************** 370 * Interface to the lower layer (zscc) 371 ****************************************************************/ 372 373 static void zskbd_rxint __P((struct zs_chanstate *)); 374 static void zskbd_stint __P((struct zs_chanstate *, int)); 375 static void zskbd_txint __P((struct zs_chanstate *)); 376 static void zskbd_softint __P((struct zs_chanstate *)); 377 378 static void 379 zskbd_rxint(cs) 380 struct zs_chanstate *cs; 381 { 382 struct zskbd_softc *zskbd; 383 int put, put_next; 384 u_char c, rr1; 385 386 zskbd = cs->cs_private; 387 put = zskbd->zskbd_rbput; 388 389 /* 390 * First read the status, because reading the received char 391 * destroys the status of this char. 392 */ 393 rr1 = zs_read_reg(cs, 1); 394 c = zs_read_data(cs); 395 if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { 396 /* Clear the receive error. */ 397 zs_write_csr(cs, ZSWR0_RESET_ERRORS); 398 } 399 400 zskbd->zskbd_rbuf[put] = (c << 8) | rr1; 401 put_next = (put + 1) & ZSKBD_RX_RING_MASK; 402 403 /* Would overrun if increment makes (put==get). */ 404 if (put_next == zskbd->zskbd_rbget) { 405 zskbd->zskbd_intr_flags |= INTR_RX_OVERRUN; 406 } else { 407 /* OK, really increment. */ 408 put = put_next; 409 } 410 411 /* Done reading. */ 412 zskbd->zskbd_rbput = put; 413 414 /* Ask for softint() call. */ 415 cs->cs_softreq = 1; 416 } 417 418 419 static void 420 zskbd_txint(cs) 421 struct zs_chanstate *cs; 422 { 423 struct zskbd_softc *zskbd; 424 425 zskbd = cs->cs_private; 426 zs_write_csr(cs, ZSWR0_RESET_TXINT); 427 zskbd->zskbd_intr_flags |= INTR_TX_EMPTY; 428 /* Ask for softint() call. */ 429 cs->cs_softreq = 1; 430 } 431 432 433 static void 434 zskbd_stint(cs, force) 435 struct zs_chanstate *cs; 436 int force; 437 { 438 struct zskbd_softc *zskbd; 439 int rr0; 440 441 zskbd = cs->cs_private; 442 443 rr0 = zs_read_csr(cs); 444 zs_write_csr(cs, ZSWR0_RESET_STATUS); 445 446 /* 447 * We have to accumulate status line changes here. 448 * Otherwise, if we get multiple status interrupts 449 * before the softint runs, we could fail to notice 450 * some status line changes in the softint routine. 451 * Fix from Bill Studenmund, October 1996. 452 */ 453 cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0); 454 cs->cs_rr0 = rr0; 455 zskbd->zskbd_intr_flags |= INTR_ST_CHECK; 456 457 /* Ask for softint() call. */ 458 cs->cs_softreq = 1; 459 } 460 461 462 static void 463 zskbd_softint(cs) 464 struct zs_chanstate *cs; 465 { 466 struct zskbd_softc *zskbd; 467 int get, c, s; 468 int intr_flags; 469 u_short ring_data; 470 471 zskbd = cs->cs_private; 472 473 /* Atomically get and clear flags. */ 474 s = splzs(); 475 intr_flags = zskbd->zskbd_intr_flags; 476 zskbd->zskbd_intr_flags = 0; 477 478 /* Now lower to spltty for the rest. */ 479 (void) spltty(); 480 481 /* 482 * Copy data from the receive ring to the event layer. 483 */ 484 get = zskbd->zskbd_rbget; 485 while (get != zskbd->zskbd_rbput) { 486 ring_data = zskbd->zskbd_rbuf[get]; 487 get = (get + 1) & ZSKBD_RX_RING_MASK; 488 489 /* low byte of ring_data is rr1 */ 490 c = (ring_data >> 8) & 0xff; 491 492 if (ring_data & ZSRR1_DO) 493 intr_flags |= INTR_RX_OVERRUN; 494 if (ring_data & (ZSRR1_FE | ZSRR1_PE)) { 495 #if 0 /* XXX */ 496 log(LOG_ERR, "%s: input error (0x%x)\n", 497 zskbd->zskbd_dev.dv_xname, ring_data); 498 c = -1; /* signal input error */ 499 #endif 500 } 501 502 /* Pass this up to the "middle" layer. */ 503 zskbd_input(zskbd, c); 504 } 505 if (intr_flags & INTR_RX_OVERRUN) { 506 #if 0 /* XXX */ 507 log(LOG_ERR, "%s: input overrun\n", 508 zskbd->zskbd_dev.dv_xname); 509 #endif 510 } 511 zskbd->zskbd_rbget = get; 512 513 if (intr_flags & INTR_TX_EMPTY) { 514 /* 515 * Transmit done. (Not expected.) 516 */ 517 #if 0 518 log(LOG_ERR, "%s: transmit interrupt?\n", 519 zskbd->zskbd_dev.dv_xname); 520 #endif 521 } 522 523 if (intr_flags & INTR_ST_CHECK) { 524 /* 525 * Status line change. (Not expected.) 526 */ 527 log(LOG_ERR, "%s: status interrupt?\n", 528 zskbd->zskbd_dev.dv_xname); 529 cs->cs_rr0_delta = 0; 530 } 531 532 splx(s); 533 } 534 535 struct zsops zsops_zskbd = { 536 zskbd_rxint, /* receive char available */ 537 zskbd_stint, /* external/status */ 538 zskbd_txint, /* xmit buffer empty */ 539 zskbd_softint, /* process software interrupt */ 540 }; 541