xref: /netbsd/sys/dev/tc/zskbd.c (revision c4a72b64)
1 /*	$NetBSD: zskbd.c,v 1.8 2002/10/02 16:53:11 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.8 2002/10/02 16:53:11 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