1 /* $NetBSD: zskbd.c,v 1.16 2008/03/29 19:15:36 tsutsui Exp $ */
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
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.
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
40 * @(#)kbd.c 8.2 (Berkeley) 10/30/93
44 * LK200/LK400 keyboard attached with channel A of the 2nd SCC
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: zskbd.c,v 1.16 2008/03/29 19:15:36 tsutsui Exp $");
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>
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>
63 #include <dev/ic/z8530reg.h>
64 #include <machine/z8530var.h>
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>
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!
78 #define ZSKBD_RX_RING_SIZE 256
79 #define ZSKBD_RX_RING_MASK (ZSKBD_RX_RING_SIZE-1)
81 * Output buffer. Only need a few chars.
83 #define ZSKBD_TX_RING_SIZE 16
84 #define ZSKBD_TX_RING_MASK (ZSKBD_TX_RING_SIZE-1)
86 #define ZSKBD_BPS 4800
88 struct zskbd_internal
{
89 struct zs_chanstate
*zsi_cs
;
90 struct lk201_state zsi_ks
;
93 static struct zskbd_internal zskbd_console_internal
;
96 device_t zskbd_dev
; /* required first: base device */
98 struct zskbd_internal
*sc_itl
;
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
107 * The receive ring buffer.
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 */
116 device_t sc_wskbddev
;
119 static struct zsops zsops_zskbd
;
121 static void zskbd_input(struct zskbd_softc
*, int);
123 static int zskbd_match(device_t
, cfdata_t
, void *);
124 static void zskbd_attach(device_t
, device_t
, void *);
126 CFATTACH_DECL_NEW(zskbd
, sizeof(struct zskbd_softc
),
127 zskbd_match
, zskbd_attach
, NULL
, NULL
);
129 static int zskbd_enable(void *, int);
130 static void zskbd_set_leds(void *, int);
131 static int zskbd_ioctl(void *, u_long
, void *, int, struct lwp
*);
133 static const struct wskbd_accessops zskbd_accessops
= {
139 static void zskbd_cngetc(void *, u_int
*, int *);
140 static void zskbd_cnpollc(void *, int);
142 static const struct wskbd_consops zskbd_consops
= {
147 static int zskbd_sendchar(void *, u_char
);
149 static const struct wskbd_mapdata zskbd_keymapdata
= {
158 int zskbd_cnattach(struct zs_chanstate
*); /* EXPORTED */
161 * kbd_match: how is this zs channel configured?
164 zskbd_match(device_t parent
, cfdata_t cf
, void *aux
)
166 struct zsc_attach_args
*args
= aux
;
168 /* Exact match is better than wildcard. */
169 if (cf
->cf_loc
[ZSCCF_CHANNEL
] == args
->channel
)
172 /* This driver accepts wildcard. */
173 if (cf
->cf_loc
[ZSCCF_CHANNEL
] == ZSCCF_CHANNEL_DEFAULT
)
180 zskbd_attach(device_t parent
, device_t self
, void *aux
)
182 struct zsc_softc
*zsc
= device_private(parent
);
183 struct zskbd_softc
*zskbd
= device_private(self
);
184 struct zsc_attach_args
*args
= aux
;
185 struct zs_chanstate
*cs
;
186 struct zskbd_internal
*zsi
;
187 struct wskbddev_attach_args a
;
190 zskbd
->zskbd_dev
= self
;
192 cs
= zsc
->zsc_cs
[args
->channel
];
193 cs
->cs_private
= zskbd
;
194 cs
->cs_ops
= &zsops_zskbd
;
196 isconsole
= (args
->hwflags
& ZS_HWFLAG_CONSOLE
);
199 zsi
= &zskbd_console_internal
;
201 zsi
= malloc(sizeof(struct zskbd_internal
),
203 zsi
->zsi_ks
.attmt
.sendchar
= zskbd_sendchar
;
204 zsi
->zsi_ks
.attmt
.cookie
= cs
;
211 /* Initialize the speed, etc. */
213 /* May need reset... */
214 zs_write_reg(cs
, 9, ZSWR9_A_RESET
);
215 /* These are OK as set by zscc: WR3, WR4, WR5 */
216 /* We don't care about status or tx interrupts. */
217 cs
->cs_preg
[1] = ZSWR1_RIE
;
218 (void) zs_set_speed(cs
, ZSKBD_BPS
);
219 zs_loadchannelregs(cs
);
223 lk201_init(&zsi
->zsi_ks
);
225 /* XXX should identify keyboard ID here XXX */
226 /* XXX layout and the number of LED is varying XXX */
228 zskbd
->kbd_type
= WSKBD_TYPE_LK201
;
230 zskbd
->sc_enabled
= 1;
232 a
.console
= isconsole
;
233 a
.keymap
= &zskbd_keymapdata
;
234 a
.accessops
= &zskbd_accessops
;
235 a
.accesscookie
= zskbd
;
237 zskbd
->sc_wskbddev
= config_found(self
, &a
, wskbddevprint
);
241 zskbd_cnattach(struct zs_chanstate
*cs
)
243 (void) zs_set_speed(cs
, ZSKBD_BPS
);
244 zs_loadchannelregs(cs
);
246 zskbd_console_internal
.zsi_ks
.attmt
.sendchar
= zskbd_sendchar
;
247 zskbd_console_internal
.zsi_ks
.attmt
.cookie
= cs
;
248 lk201_init(&zskbd_console_internal
.zsi_ks
);
249 zskbd_console_internal
.zsi_cs
= cs
;
251 wskbd_cnattach(&zskbd_consops
, &zskbd_console_internal
,
258 zskbd_enable(void *v
, int on
)
260 struct zskbd_softc
*sc
= v
;
267 zskbd_sendchar(void *v
, u_char c
)
269 struct zs_chanstate
*cs
= v
;
270 zs_write_data(cs
, c
);
277 zskbd_cngetc(void *v
, u_int
*type
, int *data
)
279 struct zskbd_internal
*zsi
= v
;
283 c
= zs_getc(zsi
->zsi_cs
);
284 } while (!lk201_decode(&zsi
->zsi_ks
, c
, type
, data
));
288 zskbd_cnpollc(void *v
, int on
)
291 struct zskbd_internal
*zsi
= v
;
296 zskbd_set_leds(void *v
, int leds
)
298 struct zskbd_softc
*sc
= v
;
300 lk201_set_leds(&sc
->sc_itl
->zsi_ks
, leds
);
304 zskbd_ioctl(void *v
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
306 struct zskbd_softc
*sc
= v
;
310 *(int *)data
= sc
->kbd_type
;
312 case WSKBDIO_SETLEDS
:
313 lk201_set_leds(&sc
->sc_itl
->zsi_ks
, *(int *)data
);
315 case WSKBDIO_GETLEDS
:
316 /* XXX don't dig in kbd internals */
317 *(int *)data
= sc
->sc_itl
->zsi_ks
.leds_state
;
319 case WSKBDIO_COMPLEXBELL
:
320 lk201_bell(&sc
->sc_itl
->zsi_ks
,
321 (struct wskbd_bell_data
*)data
);
323 case WSKBDIO_SETKEYCLICK
:
324 lk201_set_keyclick(&sc
->sc_itl
->zsi_ks
, *(int *)data
);
326 case WSKBDIO_GETKEYCLICK
:
327 /* XXX don't dig in kbd internals */
328 *(int *)data
= sc
->sc_itl
->zsi_ks
.kcvol
;
335 zskbd_input(struct zskbd_softc
*sc
, int data
)
340 if (sc
->sc_enabled
== 0)
343 if (lk201_decode(&sc
->sc_itl
->zsi_ks
, data
, &type
, &val
))
344 wskbd_input(sc
->sc_wskbddev
, type
, val
);
347 /****************************************************************
348 * Interface to the lower layer (zscc)
349 ****************************************************************/
351 static void zskbd_rxint(struct zs_chanstate
*);
352 static void zskbd_stint(struct zs_chanstate
*, int);
353 static void zskbd_txint(struct zs_chanstate
*);
354 static void zskbd_softint(struct zs_chanstate
*);
357 zskbd_rxint(struct zs_chanstate
*cs
)
359 struct zskbd_softc
*zskbd
;
363 zskbd
= cs
->cs_private
;
364 put
= zskbd
->zskbd_rbput
;
367 * First read the status, because reading the received char
368 * destroys the status of this char.
370 rr1
= zs_read_reg(cs
, 1);
371 c
= zs_read_data(cs
);
372 if (rr1
& (ZSRR1_FE
| ZSRR1_DO
| ZSRR1_PE
)) {
373 /* Clear the receive error. */
374 zs_write_csr(cs
, ZSWR0_RESET_ERRORS
);
377 zskbd
->zskbd_rbuf
[put
] = (c
<< 8) | rr1
;
378 put_next
= (put
+ 1) & ZSKBD_RX_RING_MASK
;
380 /* Would overrun if increment makes (put==get). */
381 if (put_next
== zskbd
->zskbd_rbget
) {
382 zskbd
->zskbd_intr_flags
|= INTR_RX_OVERRUN
;
384 /* OK, really increment. */
389 zskbd
->zskbd_rbput
= put
;
391 /* Ask for softint() call. */
397 zskbd_txint(struct zs_chanstate
*cs
)
399 struct zskbd_softc
*zskbd
;
401 zskbd
= cs
->cs_private
;
402 zs_write_csr(cs
, ZSWR0_RESET_TXINT
);
403 zskbd
->zskbd_intr_flags
|= INTR_TX_EMPTY
;
404 /* Ask for softint() call. */
410 zskbd_stint(struct zs_chanstate
*cs
, int force
)
412 struct zskbd_softc
*zskbd
;
415 zskbd
= cs
->cs_private
;
417 rr0
= zs_read_csr(cs
);
418 zs_write_csr(cs
, ZSWR0_RESET_STATUS
);
421 * We have to accumulate status line changes here.
422 * Otherwise, if we get multiple status interrupts
423 * before the softint runs, we could fail to notice
424 * some status line changes in the softint routine.
425 * Fix from Bill Studenmund, October 1996.
427 cs
->cs_rr0_delta
|= (cs
->cs_rr0
^ rr0
);
429 zskbd
->zskbd_intr_flags
|= INTR_ST_CHECK
;
431 /* Ask for softint() call. */
437 zskbd_softint(struct zs_chanstate
*cs
)
439 struct zskbd_softc
*zskbd
;
444 zskbd
= cs
->cs_private
;
446 /* Atomically get and clear flags. */
448 intr_flags
= zskbd
->zskbd_intr_flags
;
449 zskbd
->zskbd_intr_flags
= 0;
451 /* Now lower to spltty for the rest. */
455 * Copy data from the receive ring to the event layer.
457 get
= zskbd
->zskbd_rbget
;
458 while (get
!= zskbd
->zskbd_rbput
) {
459 ring_data
= zskbd
->zskbd_rbuf
[get
];
460 get
= (get
+ 1) & ZSKBD_RX_RING_MASK
;
462 /* low byte of ring_data is rr1 */
463 c
= (ring_data
>> 8) & 0xff;
465 if (ring_data
& ZSRR1_DO
)
466 intr_flags
|= INTR_RX_OVERRUN
;
467 if (ring_data
& (ZSRR1_FE
| ZSRR1_PE
)) {
469 log(LOG_ERR
, "%s: input error (0x%x)\n",
470 device_xname(zskbd
->zskbd_dev
), ring_data
);
471 c
= -1; /* signal input error */
475 /* Pass this up to the "middle" layer. */
476 zskbd_input(zskbd
, c
);
478 if (intr_flags
& INTR_RX_OVERRUN
) {
480 log(LOG_ERR
, "%s: input overrun\n",
481 device_xname(zskbd
->zskbd_dev
));
484 zskbd
->zskbd_rbget
= get
;
486 if (intr_flags
& INTR_TX_EMPTY
) {
488 * Transmit done. (Not expected.)
491 log(LOG_ERR
, "%s: transmit interrupt?\n",
492 device_xname(zskbd
->zskbd_dev
));
496 if (intr_flags
& INTR_ST_CHECK
) {
498 * Status line change. (Not expected.)
500 log(LOG_ERR
, "%s: status interrupt?\n",
501 device_xname(zskbd
->zskbd_dev
));
502 cs
->cs_rr0_delta
= 0;
508 static struct zsops zsops_zskbd
= {
509 zskbd_rxint
, /* receive char available */
510 zskbd_stint
, /* external/status */
511 zskbd_txint
, /* xmit buffer empty */
512 zskbd_softint
, /* process software interrupt */