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