zskbd.c revision 1.8 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