1 /* $NetBSD: kbdsun.c,v 1.10 2007/03/04 06:02:45 christos Exp $ */
2 /* NetBSD: kbd.c,v 1.29 2001/11/13 06:54:32 lukem Exp */
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This software was developed by the Computer Systems Engineering group
9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10 * contributed to Berkeley.
12 * All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by the University of
15 * California, Lawrence Berkeley Laboratory.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * @(#)kbd.c 8.2 (Berkeley) 10/30/93
45 * /dev/kbd middle layer for sun keyboard off a serial line
46 * This code is used by kbd_zs and sunkbd drivers (lower layer).
49 #include <sys/cdefs.h>
50 __KERNEL_RCSID(0, "$NetBSD: kbdsun.c,v 1.10 2007/03/04 06:02:45 christos Exp $");
52 #include <sys/param.h>
53 #include <sys/systm.h>
55 #include <sys/device.h>
56 #include <sys/ioctl.h>
57 #include <sys/kernel.h>
59 #include <sys/signal.h>
60 #include <sys/signalvar.h>
62 #include <sys/syslog.h>
63 #include <sys/select.h>
67 #include <dev/sun/kbd_reg.h>
68 #include <dev/sun/kbio.h>
69 #include <dev/sun/vuid_event.h>
70 #include <dev/sun/event_var.h>
71 #include <dev/sun/kbd_xlate.h>
73 #include <dev/sun/kbdvar.h>
74 #include <dev/sun/kbdsunvar.h>
77 /* callbacks for the upper /dev/kbd layer */
78 static int kbd_sun_open(struct kbd_softc
*);
79 static int kbd_sun_close(struct kbd_softc
*);
80 static int kbd_sun_do_cmd(struct kbd_softc
*, int, int);
81 static int kbd_sun_set_leds(struct kbd_softc
*, int, int);
83 static void kbd_sun_set_leds1(struct kbd_softc
*, int); /* aux */
85 const struct kbd_ops kbd_ops_sun
= {
92 /* in user context, wait for keyboard output to finish */
93 static int kbd_sun_drain_tx(struct kbd_sun_softc
*);
95 /* helper functions for kbd_sun_input */
96 static void kbd_sun_was_reset(struct kbd_sun_softc
*);
97 static void kbd_sun_new_layout(struct kbd_sun_softc
*);
100 /***********************************************************************
101 * Callbacks for upper layer.
105 * Initialization to be done at first open.
106 * This is called from kbdopen() or kd_cc_open()
107 * Called with user context.
110 kbd_sun_open(struct kbd_softc
*kbd
)
112 struct kbd_sun_softc
*k
= (struct kbd_sun_softc
*)kbd
;
113 struct kbd_state
*ks
;
114 int error
, ntries
, s
;
121 /* tolerate extra calls. */
125 /* open internal device */
127 (*k
->k_deviopen
)(k
->k_kbd
.k_dev
, FREAD
|FWRITE
);
131 /* reset the keyboard and find out its type */
132 kbd_sun_output(k
, KBD_CMD_RESET
);
136 /* the wakeup for this is in kbd_sun_was_reset(). */
137 for (ntries
= 30; ntries
; ntries
--) {
138 error
= tsleep((void *)&ks
->kbd_id
, PZERO
| PCATCH
, devopn
,
144 if (error
== EWOULDBLOCK
|| ks
->kbd_id
== 0) { /* no response */
145 log(LOG_ERR
, "%s: reset failed\n", device_xname(kbd
->k_dev
));
148 * Allow the open anyway (to keep getty happy)
149 * but assume the "least common denominator".
152 ks
->kbd_id
= KB_SUN2
;
155 /* earlier than type 4 does not know "layout" */
156 if (ks
->kbd_id
>= KB_SUN4
) {
157 ks
->kbd_layout
= 0xff;
159 /* ask for the layout */
160 kbd_sun_output(k
, KBD_CMD_GETLAYOUT
);
164 /* the wakeup for this is in kbd_sun_new_layout() */
165 for (ntries
= 200; ntries
; ntries
--) {
166 error
= tsleep((void *)&ks
->kbd_layout
, PZERO
| PCATCH
,
168 if (ks
->kbd_layout
!= 0xff || error
)
172 if (error
== EWOULDBLOCK
|| ks
->kbd_layout
== 0xff) {
173 log(LOG_ERR
, "%s: no response to get_layout\n",
174 device_xname(kbd
->k_dev
));
176 ks
->kbd_layout
= 0; /* US layout */
180 /* initialize the table pointers for this type/layout */
192 kbd_sun_close(struct kbd_softc
*kbd
)
195 return (0); /* nothing to do so far */
200 * keyboard command ioctl
201 * ``unimplemented commands are ignored'' (blech)
202 * XXX: This is also exported to the fb driver (for bell).
205 kbd_sun_do_cmd(struct kbd_softc
*kbd
, int cmd
, int isioctl
)
207 struct kbd_sun_softc
*k
= (struct kbd_sun_softc
*)kbd
;
208 struct kbd_state
*ks
;
218 /* Supported by type 2, 3, and 4 keyboards */
222 case KBD_CMD_NOCLICK
:
223 /* Unsupported by type 2 keyboards */
224 if (ks
->kbd_id
<= KB_SUN2
)
226 ks
->kbd_click
= (cmd
== KBD_CMD_CLICK
);
236 error
= kbd_sun_drain_tx(k
);
239 kbd_sun_output(k
, cmd
);
250 * KIOCSLED. Has user context.
251 * Take care about spl and call kbd_sun_set_leds.
254 kbd_sun_set_leds(struct kbd_softc
*kbd
, int leds
, int isioctl
)
256 struct kbd_sun_softc
*k
= (struct kbd_sun_softc
*)kbd
;
261 error
= kbd_sun_drain_tx(k
);
263 kbd_sun_set_leds1(kbd
, leds
);
269 kbd_sun_set_leds1(kbd
, leds
);
276 * Safe to call from intterupt handler. Called at spltty()
277 * by kbd_sun_iocsled and kbd_sun_input (via kbd_update_leds).
280 kbd_sun_set_leds1(struct kbd_softc
*kbd
, int new_leds
)
282 struct kbd_sun_softc
*k
= (struct kbd_sun_softc
*)kbd
;
283 struct kbd_state
*ks
= &kbd
->k_state
;
285 /* Don't send unless state changes. */
286 if (ks
->kbd_leds
== new_leds
)
289 ks
->kbd_leds
= new_leds
;
291 /* Only type 4 and later has LEDs anyway. */
292 if (ks
->kbd_id
< KB_SUN4
)
295 kbd_sun_output(k
, KBD_CMD_SETLED
);
296 kbd_sun_output(k
, new_leds
);
302 /***********************************************************************
303 * Methods for lower layer to call and related functions.
307 * Enqueue some output for the keyboard
308 * Called at spltty().
311 kbd_sun_output(struct kbd_sun_softc
*k
, int c
)
316 k
->k_tbuf
[put
] = (uint8_t)c
;
317 put
= (put
+ 1) & KBD_TX_RING_MASK
;
319 /* Would overrun if increment makes (put == get) */
320 if (put
== k
->k_tbget
) {
321 log(LOG_WARNING
, "%s: output overrun\n",
322 device_xname(k
->k_kbd
.k_dev
));
324 /* OK, really increment. */
331 * In user context. Called at spltty().
332 * Wait for output to keyboard to finish.
335 kbd_sun_drain_tx(struct kbd_sun_softc
*k
)
337 int error
= 0, bail
= 0;
339 while ((k
->k_txflags
& K_TXBUSY
) && (!error
) && (bail
<1000)) {
340 k
->k_txflags
|= K_TXWANT
;
341 error
= tsleep(&k
->k_txflags
, PZERO
| PCATCH
, "kbdout", 1);
350 * Start the sending data from the output queue
351 * Called at spltty().
354 kbd_sun_start_tx(struct kbd_sun_softc
*k
)
359 if (k
->k_txflags
& K_TXBUSY
)
362 /* Is there anything to send? */
364 if (get
== k
->k_tbput
) {
365 /* Nothing to send. Wake drain waiters. */
366 if (k
->k_txflags
& K_TXWANT
) {
367 k
->k_txflags
&= ~K_TXWANT
;
368 wakeup(&k
->k_txflags
);
373 /* Have something to send. */
375 get
= (get
+ 1) & KBD_TX_RING_MASK
;
377 k
->k_txflags
|= K_TXBUSY
;
379 /* Pass data down to the underlying device. */
380 (*k
->k_write_data
)(k
, c
);
385 * Called by underlying driver's softint() routine on input,
386 * which passes us the raw hardware make/break codes.
390 kbd_sun_input(struct kbd_sun_softc
*k
, int code
)
392 struct kbd_softc
*kbd
= (struct kbd_softc
*)k
;
394 /* XXX - Input errors already handled. */
396 /* Are we expecting special input? */
398 if (k
->k_expect
& KBD_EXPECT_IDCODE
) {
399 /* We read a KBD_RESET last time. */
400 kbd
->k_state
.kbd_id
= code
;
401 kbd_sun_was_reset(k
);
403 if (k
->k_expect
& KBD_EXPECT_LAYOUT
) {
404 /* We read a KBD_LAYOUT last time. */
405 kbd
->k_state
.kbd_layout
= code
;
406 kbd_sun_new_layout(k
);
412 /* Is this one of the "special" input codes? */
413 if (KBD_SPECIAL(code
)) {
416 k
->k_expect
|= KBD_EXPECT_IDCODE
;
417 /* Fake an "all-up" to resync. translation. */
422 k
->k_expect
|= KBD_EXPECT_LAYOUT
;
426 log(LOG_WARNING
, "%s: received error indicator\n",
427 device_xname(kbd
->k_dev
));
431 /* Let this go to the translator. */
436 kbd_input(kbd
, code
);
442 * Called by kbd_sun_input to handle keyboard's response to reset.
443 * Called at spltty().
446 kbd_sun_was_reset(struct kbd_sun_softc
*k
)
448 struct kbd_state
*ks
= &k
->k_kbd
.k_state
;
451 * On first identification, wake up anyone waiting for type
452 * and set up the table pointers.
454 wakeup((void *)&ks
->kbd_id
);
456 /* Restore keyclick, if necessary */
457 switch (ks
->kbd_id
) {
460 /* Type 2 keyboards don't support keyclick */
464 /* Type 3 keyboards come up with keyclick on */
465 if (!ks
->kbd_click
) {
466 /* turn off the click */
467 kbd_sun_output(k
, KBD_CMD_NOCLICK
);
473 /* Type 4 keyboards come up with keyclick off */
475 /* turn on the click */
476 kbd_sun_output(k
, KBD_CMD_CLICK
);
481 printf("%s: unknown keyboard type ID %u\n",
482 device_xname(k
->k_kbd
.k_dev
), (unsigned int)ks
->kbd_id
);
485 /* LEDs are off after reset. */
490 * Called by kbd_sun_input to handle response to layout request.
491 * Called at spltty().
494 kbd_sun_new_layout(struct kbd_sun_softc
*k
)
496 struct kbd_state
*ks
= &k
->k_kbd
.k_state
;
499 * On first identification, wake up anyone waiting for type
500 * and set up the table pointers.
502 wakeup((void *)&ks
->kbd_layout
);
504 /* XXX: switch decoding tables? */