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