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