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