zskbd.c revision 1.3 1 /* $NetBSD: zskbd.c,v 1.3 2001/11/13 06:26:10 lukem 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.3 2001/11/13 06:26:10 lukem 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 zskbd_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 -1;
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