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