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