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