Home | History | Annotate | Line # | Download | only in tc
zskbd.c revision 1.7
      1 /*	$NetBSD: zskbd.c,v 1.7 2002/10/01 01:12:39 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.7 2002/10/01 01:12:39 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