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