xref: /openbsd/sys/dev/wscons/wskbd.c (revision a6445c1d)
1 /* $OpenBSD: wskbd.c,v 1.80 2014/07/12 18:48:53 tedu Exp $ */
2 /* $NetBSD: wskbd.c,v 1.80 2005/05/04 01:52:16 augustss Exp $ */
3 
4 /*
5  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
6  *
7  * Keysym translator:
8  * Contributed to The NetBSD Foundation by Juergen Hannken-Illjes.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by Christopher G. Demetriou
21  *	for the NetBSD Project.
22  * 4. The name of the author may not be used to endorse or promote products
23  *    derived from this software without specific prior written permission
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * Copyright (c) 1992, 1993
39  *	The Regents of the University of California.  All rights reserved.
40  *
41  * This software was developed by the Computer Systems Engineering group
42  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
43  * contributed to Berkeley.
44  *
45  * All advertising materials mentioning features or use of this software
46  * must display the following acknowledgement:
47  *	This product includes software developed by the University of
48  *	California, Lawrence Berkeley Laboratory.
49  *
50  * Redistribution and use in source and binary forms, with or without
51  * modification, are permitted provided that the following conditions
52  * are met:
53  * 1. Redistributions of source code must retain the above copyright
54  *    notice, this list of conditions and the following disclaimer.
55  * 2. Redistributions in binary form must reproduce the above copyright
56  *    notice, this list of conditions and the following disclaimer in the
57  *    documentation and/or other materials provided with the distribution.
58  * 3. Neither the name of the University nor the names of its contributors
59  *    may be used to endorse or promote products derived from this software
60  *    without specific prior written permission.
61  *
62  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72  * SUCH DAMAGE.
73  *
74  *	@(#)kbd.c	8.2 (Berkeley) 10/30/93
75  */
76 
77 /*
78  * Keyboard driver (/dev/wskbd*).  Translates incoming bytes to ASCII or
79  * to `wscons_events' and passes them up to the appropriate reader.
80  */
81 
82 #include <sys/param.h>
83 #include <sys/conf.h>
84 #include <sys/device.h>
85 #include <sys/ioctl.h>
86 #include <sys/kernel.h>
87 #include <sys/proc.h>
88 #include <sys/syslog.h>
89 #include <sys/systm.h>
90 #include <sys/timeout.h>
91 #include <sys/malloc.h>
92 #include <sys/tty.h>
93 #include <sys/signalvar.h>
94 #include <sys/errno.h>
95 #include <sys/fcntl.h>
96 #include <sys/vnode.h>
97 #include <sys/poll.h>
98 
99 #include <ddb/db_var.h>
100 
101 #include <dev/wscons/wscons_features.h>
102 #include <dev/wscons/wsconsio.h>
103 #include <dev/wscons/wskbdvar.h>
104 #include <dev/wscons/wsksymdef.h>
105 #include <dev/wscons/wsksymvar.h>
106 #include <dev/wscons/wsdisplayvar.h>
107 #include <dev/wscons/wseventvar.h>
108 #include <dev/wscons/wscons_callbacks.h>
109 
110 #include "audio.h"		/* NAUDIO (mixer tuning) */
111 #include "wsdisplay.h"
112 #include "wskbd.h"
113 #include "wsmux.h"
114 
115 #ifdef WSKBD_DEBUG
116 #define DPRINTF(x)	if (wskbddebug) printf x
117 int	wskbddebug = 0;
118 #else
119 #define DPRINTF(x)
120 #endif
121 
122 #include <dev/wscons/wsmuxvar.h>
123 
124 struct wskbd_internal {
125 	const struct wskbd_consops *t_consops;
126 	void	*t_consaccesscookie;
127 
128 	int	t_modifiers;
129 	int	t_composelen;		/* remaining entries in t_composebuf */
130 	keysym_t t_composebuf[2];
131 
132 	int	t_flags;
133 #define WSKFL_METAESC 1
134 
135 #define MAXKEYSYMSPERKEY 2 /* ESC <key> at max */
136 	keysym_t t_symbols[MAXKEYSYMSPERKEY];
137 
138 	struct wskbd_softc *t_sc;	/* back pointer */
139 
140 	struct wskbd_mapdata t_keymap;	/* translation map table and
141 					   current layout */
142 };
143 
144 struct wskbd_softc {
145 	struct wsevsrc	sc_base;
146 
147 	struct wskbd_internal *id;
148 
149 	const struct wskbd_accessops *sc_accessops;
150 	void *sc_accesscookie;
151 
152 	int	sc_ledstate;
153 
154 	int	sc_isconsole;
155 
156 	struct wskbd_bell_data sc_bell_data;
157 	struct wskbd_keyrepeat_data sc_keyrepeat_data;
158 
159 	int	sc_repeating;		/* we've called timeout() */
160 	int	sc_repkey;
161 	struct timeout sc_repeat_ch;
162 	u_int	sc_repeat_type;
163 	int	sc_repeat_value;
164 
165 	int	sc_translating;		/* xlate to chars for emulation */
166 
167 	int	sc_maplen;		/* number of entries in sc_map */
168 	struct wscons_keymap *sc_map;	/* current translation map */
169 
170 	int	sc_refcnt;
171 	u_char	sc_dying;		/* device is being detached */
172 };
173 
174 #define MOD_SHIFT_L		(1 << 0)
175 #define MOD_SHIFT_R		(1 << 1)
176 #define MOD_SHIFTLOCK		(1 << 2)
177 #define MOD_CAPSLOCK		(1 << 3)
178 #define MOD_CONTROL_L		(1 << 4)
179 #define MOD_CONTROL_R		(1 << 5)
180 #define MOD_META_L		(1 << 6)
181 #define MOD_META_R		(1 << 7)
182 #define MOD_MODESHIFT		(1 << 8)
183 #define MOD_NUMLOCK		(1 << 9)
184 #define MOD_COMPOSE		(1 << 10)
185 #define MOD_HOLDSCREEN		(1 << 11)
186 #define MOD_COMMAND		(1 << 12)
187 #define MOD_COMMAND1		(1 << 13)
188 #define MOD_COMMAND2		(1 << 14)
189 #define MOD_MODELOCK		(1 << 15)
190 
191 #define MOD_ANYSHIFT		(MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK)
192 #define MOD_ANYCONTROL		(MOD_CONTROL_L | MOD_CONTROL_R)
193 #define MOD_ANYMETA		(MOD_META_L | MOD_META_R)
194 #define MOD_ANYLED		(MOD_SHIFTLOCK | MOD_CAPSLOCK | MOD_NUMLOCK | \
195 				 MOD_COMPOSE | MOD_HOLDSCREEN)
196 
197 #define MOD_ONESET(id, mask)	(((id)->t_modifiers & (mask)) != 0)
198 #define MOD_ALLSET(id, mask)	(((id)->t_modifiers & (mask)) == (mask))
199 
200 keysym_t ksym_upcase(keysym_t);
201 
202 int	wskbd_match(struct device *, void *, void *);
203 void	wskbd_attach(struct device *, struct device *, void *);
204 int	wskbd_detach(struct device *, int);
205 int	wskbd_activate(struct device *, int);
206 
207 int	wskbd_displayioctl(struct device *, u_long, caddr_t, int, struct proc *);
208 
209 void	update_leds(struct wskbd_internal *);
210 void	update_modifier(struct wskbd_internal *, u_int, int, int);
211 int	internal_command(struct wskbd_softc *, u_int *, keysym_t, keysym_t);
212 int	wskbd_translate(struct wskbd_internal *, u_int, int);
213 int	wskbd_enable(struct wskbd_softc *, int);
214 #if NWSDISPLAY > 0
215 void	change_displayparam(struct wskbd_softc *, int, int, int);
216 #endif
217 
218 int	wskbd_do_ioctl_sc(struct wskbd_softc *, u_long, caddr_t, int,
219 	    struct proc *);
220 void	wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value);
221 
222 #if NWSMUX > 0
223 int	wskbd_mux_open(struct wsevsrc *, struct wseventvar *);
224 int	wskbd_mux_close(struct wsevsrc *);
225 #else
226 #define	wskbd_mux_open NULL
227 #define	wskbd_mux_close NULL
228 #endif
229 
230 int	wskbd_do_open(struct wskbd_softc *, struct wseventvar *);
231 int	wskbd_do_ioctl(struct device *, u_long, caddr_t, int, struct proc *);
232 
233 struct cfdriver wskbd_cd = {
234 	NULL, "wskbd", DV_TTY
235 };
236 
237 struct cfattach wskbd_ca = {
238 	sizeof (struct wskbd_softc), wskbd_match, wskbd_attach,
239 	wskbd_detach, wskbd_activate
240 };
241 
242 #if defined(__i386__) || defined(__amd64__)
243 extern int kbd_reset;
244 #endif
245 
246 #ifndef WSKBD_DEFAULT_BELL_PITCH
247 #define	WSKBD_DEFAULT_BELL_PITCH	400	/* 400Hz */
248 #endif
249 #ifndef WSKBD_DEFAULT_BELL_PERIOD
250 #define	WSKBD_DEFAULT_BELL_PERIOD	100	/* 100ms */
251 #endif
252 #ifndef WSKBD_DEFAULT_BELL_VOLUME
253 #define	WSKBD_DEFAULT_BELL_VOLUME	50	/* 50% volume */
254 #endif
255 
256 struct wskbd_bell_data wskbd_default_bell_data = {
257 	WSKBD_BELL_DOALL,
258 	WSKBD_DEFAULT_BELL_PITCH,
259 	WSKBD_DEFAULT_BELL_PERIOD,
260 	WSKBD_DEFAULT_BELL_VOLUME,
261 };
262 
263 #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1
264 #define	WSKBD_DEFAULT_KEYREPEAT_DEL1	400	/* 400ms to start repeating */
265 #endif
266 #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN
267 #define	WSKBD_DEFAULT_KEYREPEAT_DELN	100	/* 100ms to between repeats */
268 #endif
269 
270 struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = {
271 	WSKBD_KEYREPEAT_DOALL,
272 	WSKBD_DEFAULT_KEYREPEAT_DEL1,
273 	WSKBD_DEFAULT_KEYREPEAT_DELN,
274 };
275 
276 #if NWSMUX > 0 || NWSDISPLAY > 0
277 struct wssrcops wskbd_srcops = {
278 	WSMUX_KBD,
279 	wskbd_mux_open, wskbd_mux_close, wskbd_do_ioctl,
280 	wskbd_displayioctl,
281 #if NWSDISPLAY > 0
282 	wskbd_set_display
283 #else
284 	NULL
285 #endif
286 };
287 #endif
288 
289 #if NWSDISPLAY > 0
290 void wskbd_repeat(void *v);
291 #endif
292 
293 static int wskbd_console_initted;
294 static struct wskbd_softc *wskbd_console_device;
295 static struct wskbd_internal wskbd_console_data;
296 
297 void	wskbd_update_layout(struct wskbd_internal *, kbd_t);
298 
299 #if NAUDIO > 0
300 extern int wskbd_set_mixervolume(long, long);
301 #endif
302 
303 void
304 wskbd_update_layout(struct wskbd_internal *id, kbd_t enc)
305 {
306 	if (enc & KB_METAESC)
307 		id->t_flags |= WSKFL_METAESC;
308 	else
309 		id->t_flags &= ~WSKFL_METAESC;
310 
311 	id->t_keymap.layout = enc;
312 }
313 
314 /*
315  * Print function (for parent devices).
316  */
317 int
318 wskbddevprint(void *aux, const char *pnp)
319 {
320 #if 0
321 	struct wskbddev_attach_args *ap = aux;
322 #endif
323 
324 	if (pnp)
325 		printf("wskbd at %s", pnp);
326 #if 0
327 	printf(" console %d", ap->console);
328 #endif
329 
330 	return (UNCONF);
331 }
332 
333 int
334 wskbd_match(struct device *parent, void *match, void *aux)
335 {
336 	struct cfdata *cf = match;
337 	struct wskbddev_attach_args *ap = aux;
338 
339 	if (cf->wskbddevcf_console != WSKBDDEVCF_CONSOLE_UNK) {
340 		/*
341 		 * If console-ness of device specified, either match
342 		 * exactly (at high priority), or fail.
343 		 */
344 		if (cf->wskbddevcf_console != 0 && ap->console != 0)
345 			return (10);
346 		else
347 			return (0);
348 	}
349 
350 	/* If console-ness unspecified, it wins. */
351 	return (1);
352 }
353 
354 void
355 wskbd_attach(struct device *parent, struct device *self, void *aux)
356 {
357 	struct wskbd_softc *sc = (struct wskbd_softc *)self;
358 	struct wskbddev_attach_args *ap = aux;
359 	kbd_t layout;
360 #if NWSMUX > 0
361 	struct wsmux_softc *wsmux_sc;
362 	int mux, error;
363 #endif
364 
365 	sc->sc_isconsole = ap->console;
366 
367 #if NWSMUX > 0 || NWSDISPLAY > 0
368 	sc->sc_base.me_ops = &wskbd_srcops;
369 #endif
370 #if NWSMUX > 0
371 	mux = sc->sc_base.me_dv.dv_cfdata->wskbddevcf_mux;
372 	if (ap->console) {
373 		/* Ignore mux for console; it always goes to the console mux. */
374 		/* printf(" (mux %d ignored for console)", mux); */
375 		mux = -1;
376 	}
377 	if (mux >= 0) {
378 		printf(" mux %d", mux);
379 		wsmux_sc = wsmux_getmux(mux);
380 	} else
381 		wsmux_sc = NULL;
382 #else
383 #if 0	/* not worth keeping, especially since the default value is not -1... */
384 	if (sc->sc_base.me_dv.dv_cfdata->wskbddevcf_mux >= 0)
385 		printf(" (mux ignored)");
386 #endif
387 #endif	/* NWSMUX > 0 */
388 
389 	if (ap->console) {
390 		sc->id = &wskbd_console_data;
391 	} else {
392 		sc->id = malloc(sizeof(struct wskbd_internal),
393 		    M_DEVBUF, M_WAITOK | M_ZERO);
394 		bcopy(ap->keymap, &sc->id->t_keymap, sizeof(sc->id->t_keymap));
395 	}
396 
397 #if NWSDISPLAY > 0
398 	timeout_set(&sc->sc_repeat_ch, wskbd_repeat, sc);
399 #endif
400 
401 	sc->id->t_sc = sc;
402 
403 	sc->sc_accessops = ap->accessops;
404 	sc->sc_accesscookie = ap->accesscookie;
405 	sc->sc_repeating = 0;
406 	sc->sc_translating = 1;
407 	sc->sc_ledstate = -1; /* force update */
408 
409 	/*
410 	 * If this layout is the default choice of the driver (i.e. the
411 	 * driver doesn't know better), pick the existing layout of the
412 	 * current mux, if any.
413 	 */
414 	layout = sc->id->t_keymap.layout;
415 #if NWSMUX > 0
416 	if (layout & KB_DEFAULT) {
417 		if (wsmux_sc != NULL && wsmux_get_layout(wsmux_sc) != KB_NONE)
418 			layout = wsmux_get_layout(wsmux_sc);
419 	}
420 #endif
421 	for (;;) {
422 		if (wskbd_load_keymap(&sc->id->t_keymap, layout, &sc->sc_map,
423 		    &sc->sc_maplen) == 0)
424 			break;
425 #if NWSMUX > 0
426 		if (layout == sc->id->t_keymap.layout)
427 			panic("cannot load keymap");
428 		if (wsmux_sc != NULL && wsmux_get_layout(wsmux_sc) != KB_NONE) {
429 			printf("\n%s: cannot load keymap, "
430 			    "falling back to default\n%s",
431 			    sc->sc_base.me_dv.dv_xname,
432 			    sc->sc_base.me_dv.dv_xname);
433 			layout = wsmux_get_layout(wsmux_sc);
434 		} else
435 #endif
436 			panic("cannot load keymap");
437 	}
438 	wskbd_update_layout(sc->id, layout);
439 
440 	/* set default bell and key repeat data */
441 	sc->sc_bell_data = wskbd_default_bell_data;
442 	sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data;
443 
444 	if (ap->console) {
445 		KASSERT(wskbd_console_initted);
446 		KASSERT(wskbd_console_device == NULL);
447 
448 		wskbd_console_device = sc;
449 
450 		printf(": console keyboard");
451 
452 #if NWSDISPLAY > 0
453 		wsdisplay_set_console_kbd(&sc->sc_base); /* sets sc_displaydv */
454 		if (sc->sc_displaydv != NULL)
455 			printf(", using %s", sc->sc_displaydv->dv_xname);
456 #endif
457 	}
458 	printf("\n");
459 
460 #if NWSMUX > 0
461 	if (wsmux_sc != NULL) {
462 		error = wsmux_attach_sc(wsmux_sc, &sc->sc_base);
463 		if (error)
464 			printf("%s: attach error=%d\n",
465 			    sc->sc_base.me_dv.dv_xname, error);
466 
467 		/*
468 		 * Try and set this encoding as the mux default if it
469 		 * hasn't any yet, and if this is not a driver default
470 		 * layout (i.e. parent driver pretends to know better).
471 		 * Note that wsmux_set_layout() rejects layouts with
472 		 * KB_DEFAULT set.
473 		 */
474 		if (wsmux_get_layout(wsmux_sc) == KB_NONE)
475 			wsmux_set_layout(wsmux_sc, layout);
476 	}
477 #endif
478 
479 #if NWSDISPLAY > 0 && NWSMUX == 0
480 	if (ap->console == 0) {
481 		/*
482 		 * In the non-wsmux world, always connect wskbd0 and wsdisplay0
483 		 * together.
484 		 */
485 		extern struct cfdriver wsdisplay_cd;
486 
487 		if (wsdisplay_cd.cd_ndevs != 0 && self->dv_unit == 0) {
488 			if (wskbd_set_display(self,
489 			    wsdisplay_cd.cd_devs[0]) == 0)
490 				wsdisplay_set_kbd(wsdisplay_cd.cd_devs[0],
491 				    (struct wsevsrc *)sc);
492 		}
493 	}
494 #endif
495 }
496 
497 void
498 wskbd_cnattach(const struct wskbd_consops *consops, void *conscookie,
499     const struct wskbd_mapdata *mapdata)
500 {
501 
502 	KASSERT(!wskbd_console_initted);
503 
504 	bcopy(mapdata, &wskbd_console_data.t_keymap, sizeof(*mapdata));
505 	wskbd_update_layout(&wskbd_console_data, mapdata->layout);
506 
507 	wskbd_console_data.t_consops = consops;
508 	wskbd_console_data.t_consaccesscookie = conscookie;
509 
510 #if NWSDISPLAY > 0
511 	wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc, wskbd_cnbell);
512 #endif
513 
514 	wskbd_console_initted = 1;
515 }
516 
517 void
518 wskbd_cndetach(void)
519 {
520 	KASSERT(wskbd_console_initted);
521 
522 	wskbd_console_data.t_keymap.keydesc = NULL;
523 	wskbd_console_data.t_keymap.layout = KB_NONE;
524 
525 	wskbd_console_data.t_consops = NULL;
526 	wskbd_console_data.t_consaccesscookie = NULL;
527 
528 #if NWSDISPLAY > 0
529 	wsdisplay_unset_cons_kbd();
530 #endif
531 
532 	wskbd_console_initted = 0;
533 }
534 
535 #if NWSDISPLAY > 0
536 void
537 wskbd_repeat(void *v)
538 {
539 	struct wskbd_softc *sc = (struct wskbd_softc *)v;
540 	int s = spltty();
541 
542 	if (sc->sc_repeating == 0) {
543 		/*
544 		 * race condition: a "key up" event came in when wskbd_repeat()
545 		 * was already called but not yet spltty()'d
546 		 */
547 		splx(s);
548 		return;
549 	}
550 	if (sc->sc_translating) {
551 		/* deliver keys */
552 		if (sc->sc_displaydv != NULL)
553 			wsdisplay_kbdinput(sc->sc_displaydv,
554 			    sc->id->t_keymap.layout,
555 			    sc->id->t_symbols, sc->sc_repeating);
556 	} else {
557 		/* queue event */
558 		wskbd_deliver_event(sc, sc->sc_repeat_type,
559 		    sc->sc_repeat_value);
560 	}
561 	if (sc->sc_keyrepeat_data.delN != 0)
562 		timeout_add_msec(&sc->sc_repeat_ch, sc->sc_keyrepeat_data.delN);
563 	splx(s);
564 }
565 #endif
566 
567 int
568 wskbd_activate(struct device *self, int act)
569 {
570 	struct wskbd_softc *sc = (struct wskbd_softc *)self;
571 
572 	if (act == DVACT_DEACTIVATE)
573 		sc->sc_dying = 1;
574 	return (0);
575 }
576 
577 /*
578  * Detach a keyboard.  To keep track of users of the softc we keep
579  * a reference count that's incremented while inside, e.g., read.
580  * If the keyboard is active and the reference count is > 0 (0 is the
581  * normal state) we post an event and then wait for the process
582  * that had the reference to wake us up again.  Then we blow away the
583  * vnode and return (which will deallocate the softc).
584  */
585 int
586 wskbd_detach(struct device  *self, int flags)
587 {
588 	struct wskbd_softc *sc = (struct wskbd_softc *)self;
589 	struct wseventvar *evar;
590 	int maj, mn;
591 	int s;
592 
593 #if NWSMUX > 0
594 	/* Tell parent mux we're leaving. */
595 	if (sc->sc_base.me_parent != NULL)
596 		wsmux_detach_sc(&sc->sc_base);
597 #endif
598 
599 #if NWSDISPLAY > 0
600 	if (sc->sc_repeating) {
601 		sc->sc_repeating = 0;
602 		timeout_del(&sc->sc_repeat_ch);
603 	}
604 #endif
605 
606 	if (sc->sc_isconsole) {
607 		KASSERT(wskbd_console_device == sc);
608 		wskbd_console_device = NULL;
609 	}
610 
611 	evar = sc->sc_base.me_evp;
612 	if (evar != NULL && evar->io != NULL) {
613 		s = spltty();
614 		if (--sc->sc_refcnt >= 0) {
615 			/* Wake everyone by generating a dummy event. */
616 			if (++evar->put >= WSEVENT_QSIZE)
617 				evar->put = 0;
618 			WSEVENT_WAKEUP(evar);
619 			/* Wait for processes to go away. */
620 			if (tsleep(sc, PZERO, "wskdet", hz * 60))
621 				printf("wskbd_detach: %s didn't detach\n",
622 				       sc->sc_base.me_dv.dv_xname);
623 		}
624 		splx(s);
625 	}
626 
627 	free(sc->sc_map, M_DEVBUF, 0);
628 
629 	/* locate the major number */
630 	for (maj = 0; maj < nchrdev; maj++)
631 		if (cdevsw[maj].d_open == wskbdopen)
632 			break;
633 
634 	/* Nuke the vnodes for any open instances. */
635 	mn = self->dv_unit;
636 	vdevgone(maj, mn, mn, VCHR);
637 
638 	return (0);
639 }
640 
641 void
642 wskbd_input(struct device *dev, u_int type, int value)
643 {
644 	struct wskbd_softc *sc = (struct wskbd_softc *)dev;
645 #if NWSDISPLAY > 0
646 	int num;
647 #endif
648 
649 #if NWSDISPLAY > 0
650 	if (sc->sc_repeating) {
651 		sc->sc_repeating = 0;
652 		timeout_del(&sc->sc_repeat_ch);
653 	}
654 
655 	/*
656 	 * If /dev/wskbdN is not connected in event mode translate and
657 	 * send upstream.
658 	 */
659 	if (sc->sc_translating) {
660 #ifdef HAVE_BURNER_SUPPORT
661 		if (type == WSCONS_EVENT_KEY_DOWN && sc->sc_displaydv != NULL)
662 			wsdisplay_burn(sc->sc_displaydv, WSDISPLAY_BURN_KBD);
663 #endif
664 		num = wskbd_translate(sc->id, type, value);
665 		if (num > 0) {
666 			if (sc->sc_displaydv != NULL) {
667 #ifdef HAVE_SCROLLBACK_SUPPORT
668 				/* XXX - Shift_R+PGUP(release) emits PrtSc */
669 				if (sc->id->t_symbols[0] != KS_Print_Screen) {
670 					wsscrollback(sc->sc_displaydv,
671 					    WSDISPLAY_SCROLL_RESET);
672 				}
673 #endif
674 				wsdisplay_kbdinput(sc->sc_displaydv,
675 				    sc->id->t_keymap.layout,
676 				    sc->id->t_symbols, num);
677 			}
678 
679 			if (sc->sc_keyrepeat_data.del1 != 0) {
680 				sc->sc_repeating = num;
681 				timeout_add_msec(&sc->sc_repeat_ch,
682 				    sc->sc_keyrepeat_data.del1);
683 			}
684 		}
685 		return;
686 	}
687 #endif
688 
689 	wskbd_deliver_event(sc, type, value);
690 
691 #if NWSDISPLAY > 0
692 	/* Repeat key presses if enabled. */
693 	if (type == WSCONS_EVENT_KEY_DOWN && sc->sc_keyrepeat_data.del1 != 0) {
694 		sc->sc_repeat_type = type;
695 		sc->sc_repeat_value = value;
696 		sc->sc_repeating = 1;
697 		timeout_add_msec(&sc->sc_repeat_ch, sc->sc_keyrepeat_data.del1);
698 	}
699 #endif
700 }
701 
702 /*
703  * Keyboard is generating events.  Turn this keystroke into an
704  * event and put it in the queue.  If the queue is full, the
705  * keystroke is lost (sorry!).
706  */
707 void
708 wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value)
709 {
710 	struct wseventvar *evar;
711 	struct wscons_event *ev;
712 	int put;
713 
714 	evar = sc->sc_base.me_evp;
715 
716 	if (evar == NULL) {
717 		DPRINTF(("wskbd_input: not open\n"));
718 		return;
719 	}
720 
721 #ifdef DIAGNOSTIC
722 	if (evar->q == NULL) {
723 		printf("wskbd_input: evar->q=NULL\n");
724 		return;
725 	}
726 #endif
727 
728 	put = evar->put;
729 	ev = &evar->q[put];
730 	put = (put + 1) % WSEVENT_QSIZE;
731 	if (put == evar->get) {
732 		log(LOG_WARNING, "%s: event queue overflow\n",
733 		    sc->sc_base.me_dv.dv_xname);
734 		return;
735 	}
736 	ev->type = type;
737 	ev->value = value;
738 	nanotime(&ev->time);
739 	evar->put = put;
740 	WSEVENT_WAKEUP(evar);
741 }
742 
743 #ifdef WSDISPLAY_COMPAT_RAWKBD
744 void
745 wskbd_rawinput(struct device *dev, u_char *buf, int len)
746 {
747 #if NWSDISPLAY > 0
748 	struct wskbd_softc *sc = (struct wskbd_softc *)dev;
749 
750 	if (sc->sc_displaydv != NULL)
751 		wsdisplay_rawkbdinput(sc->sc_displaydv, buf, len);
752 #endif
753 }
754 #endif /* WSDISPLAY_COMPAT_RAWKBD */
755 
756 int
757 wskbd_enable(struct wskbd_softc *sc, int on)
758 {
759 	int error;
760 
761 #if NWSDISPLAY > 0
762 	if (sc->sc_displaydv != NULL)
763 		return (0);
764 
765 	/* Always cancel auto repeat when fiddling with the kbd. */
766 	if (sc->sc_repeating) {
767 		sc->sc_repeating = 0;
768 		timeout_del(&sc->sc_repeat_ch);
769 	}
770 #endif
771 
772 	error = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on);
773 	DPRINTF(("wskbd_enable: sc=%p on=%d res=%d\n", sc, on, error));
774 	return (error);
775 }
776 
777 #if NWSMUX > 0
778 int
779 wskbd_mux_open(struct wsevsrc *me, struct wseventvar *evp)
780 {
781 	struct wskbd_softc *sc = (struct wskbd_softc *)me;
782 
783 	if (sc->sc_dying)
784 		return (EIO);
785 
786 	if (sc->sc_base.me_evp != NULL)
787 		return (EBUSY);
788 
789 	return (wskbd_do_open(sc, evp));
790 }
791 #endif
792 
793 int
794 wskbdopen(dev_t dev, int flags, int mode, struct proc *p)
795 {
796 	struct wskbd_softc *sc;
797 	struct wseventvar *evar;
798 	int unit, error;
799 
800 	unit = minor(dev);
801 	if (unit >= wskbd_cd.cd_ndevs ||	/* make sure it was attached */
802 	    (sc = wskbd_cd.cd_devs[unit]) == NULL)
803 		return (ENXIO);
804 
805 #if NWSMUX > 0
806 	DPRINTF(("wskbdopen: %s mux=%p p=%p\n", sc->sc_base.me_dv.dv_xname,
807 		 sc->sc_base.me_parent, p));
808 #endif
809 
810 	if (sc->sc_dying)
811 		return (EIO);
812 
813 	if ((flags & (FREAD | FWRITE)) == FWRITE) {
814 		/* Not opening for read, only ioctl is available. */
815 		return (0);
816 	}
817 
818 #if NWSMUX > 0
819 	if (sc->sc_base.me_parent != NULL) {
820 		/* Grab the keyboard out of the greedy hands of the mux. */
821 		DPRINTF(("wskbdopen: detach\n"));
822 		wsmux_detach_sc(&sc->sc_base);
823 	}
824 #endif
825 
826 	if (sc->sc_base.me_evp != NULL)
827 		return (EBUSY);
828 
829 	evar = &sc->sc_base.me_evar;
830 	wsevent_init(evar);
831 	evar->io = p->p_p;
832 
833 	error = wskbd_do_open(sc, evar);
834 	if (error) {
835 		DPRINTF(("wskbdopen: %s open failed\n",
836 			 sc->sc_base.me_dv.dv_xname));
837 		sc->sc_base.me_evp = NULL;
838 		wsevent_fini(evar);
839 	}
840 	return (error);
841 }
842 
843 int
844 wskbd_do_open(struct wskbd_softc *sc, struct wseventvar *evp)
845 {
846 	sc->sc_base.me_evp = evp;
847 	sc->sc_translating = 0;
848 
849 	return (wskbd_enable(sc, 1));
850 }
851 
852 int
853 wskbdclose(dev_t dev, int flags, int mode, struct proc *p)
854 {
855 	struct wskbd_softc *sc =
856 	    (struct wskbd_softc *)wskbd_cd.cd_devs[minor(dev)];
857 	struct wseventvar *evar = sc->sc_base.me_evp;
858 
859 	if (evar == NULL)
860 		/* not open for read */
861 		return (0);
862 
863 	sc->sc_base.me_evp = NULL;
864 	sc->sc_translating = 1;
865 	(void)wskbd_enable(sc, 0);
866 	wsevent_fini(evar);
867 
868 #if NWSMUX > 0
869 	if (sc->sc_base.me_parent == NULL) {
870 		int mux, error;
871 
872 		DPRINTF(("wskbdclose: attach\n"));
873 		mux = sc->sc_base.me_dv.dv_cfdata->wskbddevcf_mux;
874 		if (mux >= 0) {
875 			error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base);
876 			if (error)
877 				printf("%s: can't attach mux (error=%d)\n",
878 				    sc->sc_base.me_dv.dv_xname, error);
879 		}
880 	}
881 #endif
882 
883 	return (0);
884 }
885 
886 #if NWSMUX > 0
887 int
888 wskbd_mux_close(struct wsevsrc *me)
889 {
890 	struct wskbd_softc *sc = (struct wskbd_softc *)me;
891 
892 	sc->sc_base.me_evp = NULL;
893 	sc->sc_translating = 1;
894 	(void)wskbd_enable(sc, 0);
895 
896 	return (0);
897 }
898 #endif
899 
900 int
901 wskbdread(dev_t dev, struct uio *uio, int flags)
902 {
903 	struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
904 	int error;
905 
906 	if (sc->sc_dying)
907 		return (EIO);
908 
909 #ifdef DIAGNOSTIC
910 	if (sc->sc_base.me_evp == NULL) {
911 		printf("wskbdread: evp == NULL\n");
912 		return (EINVAL);
913 	}
914 #endif
915 
916 	sc->sc_refcnt++;
917 	error = wsevent_read(&sc->sc_base.me_evar, uio, flags);
918 	if (--sc->sc_refcnt < 0) {
919 		wakeup(sc);
920 		error = EIO;
921 	}
922 	return (error);
923 }
924 
925 int
926 wskbdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
927 {
928 	return (wskbd_do_ioctl(wskbd_cd.cd_devs[minor(dev)], cmd, data, flag,p));
929 }
930 
931 /* A wrapper around the ioctl() workhorse to make reference counting easy. */
932 int
933 wskbd_do_ioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
934     struct proc *p)
935 {
936 	struct wskbd_softc *sc = (struct wskbd_softc *)dv;
937 	int error;
938 
939 	sc->sc_refcnt++;
940 	error = wskbd_do_ioctl_sc(sc, cmd, data, flag, p);
941 	if (--sc->sc_refcnt < 0)
942 		wakeup(sc);
943 	return (error);
944 }
945 
946 int
947 wskbd_do_ioctl_sc(struct wskbd_softc *sc, u_long cmd, caddr_t data, int flag,
948      struct proc *p)
949 {
950 	int error;
951 
952 	/*
953 	 * Try the generic ioctls that the wskbd interface supports.
954 	 */
955 	switch (cmd) {
956 	case FIONBIO:		/* we will remove this someday (soon???) */
957 		return (0);
958 
959 	case FIOASYNC:
960 		if (sc->sc_base.me_evp == NULL)
961 			return (EINVAL);
962 		sc->sc_base.me_evp->async = *(int *)data != 0;
963 		return (0);
964 
965 	case FIOSETOWN:
966 		if (sc->sc_base.me_evp == NULL)
967 			return (EINVAL);
968 		if (-*(int *)data != sc->sc_base.me_evp->io->ps_pgid &&
969 		    *(int *)data != sc->sc_base.me_evp->io->ps_pid)
970 			return (EPERM);
971 		return (0);
972 
973 	case TIOCSPGRP:
974 		if (sc->sc_base.me_evp == NULL)
975 			return (EINVAL);
976 		if (*(int *)data != sc->sc_base.me_evp->io->ps_pgid)
977 			return (EPERM);
978 		return (0);
979 	}
980 
981 	/*
982 	 * Try the keyboard driver for WSKBDIO ioctls.  It returns -1
983 	 * if it didn't recognize the request.
984 	 */
985 	error = wskbd_displayioctl(&sc->sc_base.me_dv, cmd, data, flag, p);
986 	return (error != -1 ? error : ENOTTY);
987 }
988 
989 /*
990  * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
991  * Some of these have no real effect in raw mode, however.
992  */
993 int
994 wskbd_displayioctl(struct device *dev, u_long cmd, caddr_t data, int flag,
995     struct proc *p)
996 {
997 	struct wskbd_softc *sc = (struct wskbd_softc *)dev;
998 	struct wskbd_bell_data *ubdp, *kbdp;
999 	struct wskbd_keyrepeat_data *ukdp, *kkdp;
1000 	struct wskbd_map_data *umdp;
1001 	kbd_t enc;
1002 	void *buf;
1003 	int len, error;
1004 
1005 	switch (cmd) {
1006 	case WSKBDIO_BELL:
1007 	case WSKBDIO_COMPLEXBELL:
1008 	case WSKBDIO_SETBELL:
1009 	case WSKBDIO_SETKEYREPEAT:
1010 	case WSKBDIO_SETDEFAULTKEYREPEAT:
1011 	case WSKBDIO_SETMAP:
1012 	case WSKBDIO_SETENCODING:
1013 		if ((flag & FWRITE) == 0)
1014 			return (EACCES);
1015 	}
1016 
1017 	switch (cmd) {
1018 #define	SETBELL(dstp, srcp, dfltp)					\
1019     do {								\
1020 	(dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ?		\
1021 	    (srcp)->pitch : (dfltp)->pitch;				\
1022 	(dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ?	\
1023 	    (srcp)->period : (dfltp)->period;				\
1024 	(dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ?	\
1025 	    (srcp)->volume : (dfltp)->volume;				\
1026 	(dstp)->which = WSKBD_BELL_DOALL;				\
1027     } while (0)
1028 
1029 	case WSKBDIO_BELL:
1030 		return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1031 		    WSKBDIO_COMPLEXBELL, (caddr_t)&sc->sc_bell_data, flag, p));
1032 
1033 	case WSKBDIO_COMPLEXBELL:
1034 		ubdp = (struct wskbd_bell_data *)data;
1035 		SETBELL(ubdp, ubdp, &sc->sc_bell_data);
1036 		return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1037 		    WSKBDIO_COMPLEXBELL, (caddr_t)ubdp, flag, p));
1038 
1039 	case WSKBDIO_SETBELL:
1040 		kbdp = &sc->sc_bell_data;
1041 setbell:
1042 		ubdp = (struct wskbd_bell_data *)data;
1043 		SETBELL(kbdp, ubdp, kbdp);
1044 		return (0);
1045 
1046 	case WSKBDIO_GETBELL:
1047 		kbdp = &sc->sc_bell_data;
1048 getbell:
1049 		ubdp = (struct wskbd_bell_data *)data;
1050 		SETBELL(ubdp, kbdp, kbdp);
1051 		return (0);
1052 
1053 	case WSKBDIO_SETDEFAULTBELL:
1054 		if ((error = suser(p, 0)) != 0)
1055 			return (error);
1056 		kbdp = &wskbd_default_bell_data;
1057 		goto setbell;
1058 
1059 
1060 	case WSKBDIO_GETDEFAULTBELL:
1061 		kbdp = &wskbd_default_bell_data;
1062 		goto getbell;
1063 
1064 #undef SETBELL
1065 
1066 #define	SETKEYREPEAT(dstp, srcp, dfltp)					\
1067     do {								\
1068 	(dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ?	\
1069 	    (srcp)->del1 : (dfltp)->del1;				\
1070 	(dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ?	\
1071 	    (srcp)->delN : (dfltp)->delN;				\
1072 	(dstp)->which = WSKBD_KEYREPEAT_DOALL;				\
1073     } while (0)
1074 
1075 	case WSKBDIO_SETKEYREPEAT:
1076 		kkdp = &sc->sc_keyrepeat_data;
1077 setkeyrepeat:
1078 		ukdp = (struct wskbd_keyrepeat_data *)data;
1079 		SETKEYREPEAT(kkdp, ukdp, kkdp);
1080 		return (0);
1081 
1082 	case WSKBDIO_GETKEYREPEAT:
1083 		kkdp = &sc->sc_keyrepeat_data;
1084 getkeyrepeat:
1085 		ukdp = (struct wskbd_keyrepeat_data *)data;
1086 		SETKEYREPEAT(ukdp, kkdp, kkdp);
1087 		return (0);
1088 
1089 	case WSKBDIO_SETDEFAULTKEYREPEAT:
1090 		if ((error = suser(p, 0)) != 0)
1091 			return (error);
1092 		kkdp = &wskbd_default_keyrepeat_data;
1093 		goto setkeyrepeat;
1094 
1095 
1096 	case WSKBDIO_GETDEFAULTKEYREPEAT:
1097 		kkdp = &wskbd_default_keyrepeat_data;
1098 		goto getkeyrepeat;
1099 
1100 #undef SETKEYREPEAT
1101 
1102 	case WSKBDIO_SETMAP:
1103 		umdp = (struct wskbd_map_data *)data;
1104 		if (umdp->maplen > WSKBDIO_MAXMAPLEN)
1105 			return (EINVAL);
1106 
1107 		len = umdp->maplen * sizeof(struct wscons_keymap);
1108 		buf = malloc(len, M_TEMP, M_WAITOK);
1109 		error = copyin(umdp->map, buf, len);
1110 		if (error == 0) {
1111 			wskbd_init_keymap(umdp->maplen,
1112 					  &sc->sc_map, &sc->sc_maplen);
1113 			memcpy(sc->sc_map, buf, len);
1114 			/* drop the variant bits handled by the map */
1115 			enc = KB_USER | (KB_VARIANT(sc->id->t_keymap.layout) &
1116 			    KB_HANDLEDBYWSKBD);
1117 			wskbd_update_layout(sc->id, enc);
1118 		}
1119 		free(buf, M_TEMP, 0);
1120 		return(error);
1121 
1122 	case WSKBDIO_GETMAP:
1123 		umdp = (struct wskbd_map_data *)data;
1124 		if (umdp->maplen > sc->sc_maplen)
1125 			umdp->maplen = sc->sc_maplen;
1126 		error = copyout(sc->sc_map, umdp->map,
1127 				umdp->maplen*sizeof(struct wscons_keymap));
1128 		return(error);
1129 
1130 	case WSKBDIO_GETENCODING:
1131 		*((kbd_t *)data) = sc->id->t_keymap.layout & ~KB_DEFAULT;
1132 		return(0);
1133 
1134 	case WSKBDIO_SETENCODING:
1135 		enc = *((kbd_t *)data);
1136 		if (KB_ENCODING(enc) == KB_USER) {
1137 			/* user map must already be loaded */
1138 			if (KB_ENCODING(sc->id->t_keymap.layout) != KB_USER)
1139 				return (EINVAL);
1140 			/* map variants make no sense */
1141 			if (KB_VARIANT(enc) & ~KB_HANDLEDBYWSKBD)
1142 				return (EINVAL);
1143 		} else {
1144 			error = wskbd_load_keymap(&sc->id->t_keymap, enc,
1145 			    &sc->sc_map, &sc->sc_maplen);
1146 			if (error)
1147 				return (error);
1148 		}
1149 		wskbd_update_layout(sc->id, enc);
1150 #if NWSMUX > 0
1151 		/* Update mux default layout */
1152 		if (sc->sc_base.me_parent != NULL)
1153 			wsmux_set_layout(sc->sc_base.me_parent, enc);
1154 #endif
1155 		return (0);
1156 	}
1157 
1158 	/*
1159 	 * Try the keyboard driver for WSKBDIO ioctls.  It returns -1
1160 	 * if it didn't recognize the request, and in turn we return
1161 	 * -1 if we didn't recognize the request.
1162 	 */
1163 /* printf("kbdaccess\n"); */
1164 	error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
1165 					   flag, p);
1166 #ifdef WSDISPLAY_COMPAT_RAWKBD
1167 	if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
1168 		int s = spltty();
1169 		sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
1170 					 | MOD_CONTROL_L | MOD_CONTROL_R
1171 					 | MOD_META_L | MOD_META_R
1172 					 | MOD_COMMAND
1173 					 | MOD_COMMAND1 | MOD_COMMAND2);
1174 #if NWSDISPLAY > 0
1175 		if (sc->sc_repeating) {
1176 			sc->sc_repeating = 0;
1177 			timeout_del(&sc->sc_repeat_ch);
1178 		}
1179 #endif
1180 		splx(s);
1181 	}
1182 #endif
1183 	return (error);
1184 }
1185 
1186 int
1187 wskbdpoll(dev_t dev, int events, struct proc *p)
1188 {
1189 	struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
1190 
1191 	if (sc->sc_base.me_evp == NULL)
1192 		return (POLLERR);
1193 	return (wsevent_poll(sc->sc_base.me_evp, events, p));
1194 }
1195 
1196 #if NWSDISPLAY > 0
1197 
1198 int
1199 wskbd_pickfree(void)
1200 {
1201 	int i;
1202 	struct wskbd_softc *sc;
1203 
1204 	for (i = 0; i < wskbd_cd.cd_ndevs; i++) {
1205 		if ((sc = wskbd_cd.cd_devs[i]) == NULL)
1206 			continue;
1207 		if (sc->sc_displaydv == NULL)
1208 			return (i);
1209 	}
1210 	return (-1);
1211 }
1212 
1213 struct wsevsrc *
1214 wskbd_set_console_display(struct device *displaydv, struct wsevsrc *me)
1215 {
1216 	struct wskbd_softc *sc = wskbd_console_device;
1217 
1218 	if (sc == NULL)
1219 		return (NULL);
1220 	sc->sc_displaydv = displaydv;
1221 #if NWSMUX > 0
1222 	(void)wsmux_attach_sc((struct wsmux_softc *)me, &sc->sc_base);
1223 #endif
1224 	return (&sc->sc_base);
1225 }
1226 
1227 int
1228 wskbd_set_display(struct device *dv, struct device *displaydv)
1229 {
1230 	struct wskbd_softc *sc = (struct wskbd_softc *)dv;
1231 	struct device *odisplaydv;
1232 	int error;
1233 
1234 	DPRINTF(("wskbd_set_display: %s odisp=%p disp=%p cons=%d\n",
1235 		 dv->dv_xname, sc->sc_displaydv, displaydv,
1236 		 sc->sc_isconsole));
1237 
1238 	if (sc->sc_isconsole)
1239 		return (EBUSY);
1240 
1241 	if (displaydv != NULL) {
1242 		if (sc->sc_displaydv != NULL)
1243 			return (EBUSY);
1244 	} else {
1245 		if (sc->sc_displaydv == NULL)
1246 			return (ENXIO);
1247 	}
1248 
1249 	odisplaydv = sc->sc_displaydv;
1250 	sc->sc_displaydv = NULL;
1251 	error = wskbd_enable(sc, displaydv != NULL);
1252 	sc->sc_displaydv = displaydv;
1253 	if (error) {
1254 		sc->sc_displaydv = odisplaydv;
1255 		return (error);
1256 	}
1257 
1258 	if (displaydv)
1259 		printf("%s: connecting to %s\n",
1260 		       sc->sc_base.me_dv.dv_xname, displaydv->dv_xname);
1261 	else
1262 		printf("%s: disconnecting from %s\n",
1263 		       sc->sc_base.me_dv.dv_xname, odisplaydv->dv_xname);
1264 
1265 	return (0);
1266 }
1267 
1268 #endif	/* NWSDISPLAY > 0 */
1269 
1270 #if NWSMUX > 0
1271 int
1272 wskbd_add_mux(int unit, struct wsmux_softc *muxsc)
1273 {
1274 	struct wskbd_softc *sc;
1275 
1276 	if (unit < 0 || unit >= wskbd_cd.cd_ndevs ||
1277 	    (sc = wskbd_cd.cd_devs[unit]) == NULL)
1278 		return (ENXIO);
1279 
1280 	if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL)
1281 		return (EBUSY);
1282 
1283 	return (wsmux_attach_sc(muxsc, &sc->sc_base));
1284 }
1285 #endif
1286 
1287 /*
1288  * Console interface.
1289  */
1290 int
1291 wskbd_cngetc(dev_t dev)
1292 {
1293 	static int num = 0;
1294 	static int pos;
1295 	u_int type;
1296 	int data;
1297 	keysym_t ks;
1298 
1299 	if (!wskbd_console_initted)
1300 		return 0;
1301 
1302 	if (wskbd_console_device != NULL &&
1303 	    !wskbd_console_device->sc_translating)
1304 		return 0;
1305 
1306 	for(;;) {
1307 		if (num-- > 0) {
1308 			ks = wskbd_console_data.t_symbols[pos++];
1309 			if (KS_GROUP(ks) == KS_GROUP_Ascii)
1310 				return (KS_VALUE(ks));
1311 		} else {
1312 			(*wskbd_console_data.t_consops->getc)
1313 				(wskbd_console_data.t_consaccesscookie,
1314 				 &type, &data);
1315 			num = wskbd_translate(&wskbd_console_data, type, data);
1316 			pos = 0;
1317 		}
1318 	}
1319 }
1320 
1321 void
1322 wskbd_cnpollc(dev_t dev, int poll)
1323 {
1324 
1325 	if (!wskbd_console_initted)
1326 		return;
1327 
1328 	if (wskbd_console_device != NULL &&
1329 	    !wskbd_console_device->sc_translating)
1330 		return;
1331 
1332 	(*wskbd_console_data.t_consops->pollc)
1333 	    (wskbd_console_data.t_consaccesscookie, poll);
1334 }
1335 
1336 void
1337 wskbd_cnbell(dev_t dev, u_int pitch, u_int period, u_int volume)
1338 {
1339 	if (!wskbd_console_initted)
1340 		return;
1341 
1342 	if (wskbd_console_data.t_consops->bell != NULL)
1343 		(*wskbd_console_data.t_consops->bell)
1344 		    (wskbd_console_data.t_consaccesscookie, pitch, period,
1345 			volume);
1346 }
1347 
1348 void
1349 update_leds(struct wskbd_internal *id)
1350 {
1351 	int new_state;
1352 
1353 	new_state = 0;
1354 	if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
1355 		new_state |= WSKBD_LED_CAPS;
1356 	if (id->t_modifiers & MOD_NUMLOCK)
1357 		new_state |= WSKBD_LED_NUM;
1358 	if (id->t_modifiers & MOD_COMPOSE)
1359 		new_state |= WSKBD_LED_COMPOSE;
1360 	if (id->t_modifiers & MOD_HOLDSCREEN)
1361 		new_state |= WSKBD_LED_SCROLL;
1362 
1363 	if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
1364 		(*id->t_sc->sc_accessops->set_leds)
1365 		    (id->t_sc->sc_accesscookie, new_state);
1366 		id->t_sc->sc_ledstate = new_state;
1367 	}
1368 }
1369 
1370 void
1371 update_modifier(struct wskbd_internal *id, u_int type, int toggle, int mask)
1372 {
1373 	if (toggle) {
1374 		if (type == WSCONS_EVENT_KEY_DOWN)
1375 			id->t_modifiers ^= mask;
1376 	} else {
1377 		if (type == WSCONS_EVENT_KEY_DOWN)
1378 			id->t_modifiers |= mask;
1379 		else
1380 			id->t_modifiers &= ~mask;
1381 	}
1382 	if (mask & MOD_ANYLED)
1383 		update_leds(id);
1384 }
1385 
1386 #if NWSDISPLAY > 0
1387 void
1388 change_displayparam(struct wskbd_softc *sc, int param, int updown,
1389     int wraparound)
1390 {
1391 	int res;
1392 	struct wsdisplay_param dp;
1393 
1394 	dp.param = param;
1395 	res = wsdisplay_param(sc->sc_displaydv, WSDISPLAYIO_GETPARAM, &dp);
1396 
1397 	if (res == EINVAL)
1398 		return; /* no such parameter */
1399 
1400 	dp.curval += updown;
1401 	if (dp.max < dp.curval)
1402 		dp.curval = wraparound ? dp.min : dp.max;
1403 	else
1404 	if (dp.curval < dp.min)
1405 		dp.curval = wraparound ? dp.max : dp.min;
1406 	wsdisplay_param(sc->sc_displaydv, WSDISPLAYIO_SETPARAM, &dp);
1407 }
1408 #endif
1409 
1410 int
1411 internal_command(struct wskbd_softc *sc, u_int *type, keysym_t ksym,
1412     keysym_t ksym2)
1413 {
1414 	switch (ksym) {
1415 	case KS_Cmd:
1416 		update_modifier(sc->id, *type, 0, MOD_COMMAND);
1417 		ksym = ksym2;
1418 		break;
1419 
1420 	case KS_Cmd1:
1421 		update_modifier(sc->id, *type, 0, MOD_COMMAND1);
1422 		break;
1423 
1424 	case KS_Cmd2:
1425 		update_modifier(sc->id, *type, 0, MOD_COMMAND2);
1426 		break;
1427 	}
1428 
1429 	if (*type != WSCONS_EVENT_KEY_DOWN)
1430 		return (0);
1431 
1432 #ifdef HAVE_SCROLLBACK_SUPPORT
1433 #if NWSDISPLAY > 0
1434 	switch (ksym) {
1435 	case KS_Cmd_ScrollBack:
1436 		if (MOD_ONESET(sc->id, MOD_ANYSHIFT)) {
1437 			if (sc->sc_displaydv != NULL)
1438 				wsscrollback(sc->sc_displaydv,
1439 				    WSDISPLAY_SCROLL_BACKWARD);
1440 			return (1);
1441 		}
1442 		break;
1443 
1444 	case KS_Cmd_ScrollFwd:
1445 		if (MOD_ONESET(sc->id, MOD_ANYSHIFT)) {
1446 			if (sc->sc_displaydv != NULL)
1447 				wsscrollback(sc->sc_displaydv,
1448 				    WSDISPLAY_SCROLL_FORWARD);
1449 			return (1);
1450 		}
1451 		break;
1452 	}
1453 #endif
1454 #endif
1455 
1456 	if (!MOD_ONESET(sc->id, MOD_COMMAND) &&
1457 	    !MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2))
1458 		return (0);
1459 
1460 #ifdef DDB
1461 	if (ksym == KS_Cmd_Debugger) {
1462 		if (sc->sc_isconsole && db_console)
1463 			Debugger();
1464 		/* discard this key (ddb discarded command modifiers) */
1465 		*type = WSCONS_EVENT_KEY_UP;
1466 		return (1);
1467 	}
1468 #endif
1469 
1470 #if NWSDISPLAY > 0
1471 	if (sc->sc_displaydv == NULL)
1472 		return (0);
1473 
1474 	switch (ksym) {
1475 	case KS_Cmd_Screen0:
1476 	case KS_Cmd_Screen1:
1477 	case KS_Cmd_Screen2:
1478 	case KS_Cmd_Screen3:
1479 	case KS_Cmd_Screen4:
1480 	case KS_Cmd_Screen5:
1481 	case KS_Cmd_Screen6:
1482 	case KS_Cmd_Screen7:
1483 	case KS_Cmd_Screen8:
1484 	case KS_Cmd_Screen9:
1485 	case KS_Cmd_Screen10:
1486 	case KS_Cmd_Screen11:
1487 		wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0);
1488 		return (1);
1489 	case KS_Cmd_ResetEmul:
1490 		wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETEMUL);
1491 		return (1);
1492 	case KS_Cmd_ResetClose:
1493 		wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETCLOSE);
1494 		return (1);
1495 #if defined(__i386__) || defined(__amd64__)
1496 	case KS_Cmd_KbdReset:
1497 		switch (kbd_reset) {
1498 #ifdef DDB
1499 		case 2:
1500 			if (sc->sc_isconsole && db_console)
1501 				Debugger();
1502 			/* discard this key (ddb discarded command modifiers) */
1503 			*type = WSCONS_EVENT_KEY_UP;
1504 			break;
1505 #endif
1506 		case 1:
1507 			kbd_reset = 0;
1508 			prsignal(initprocess, SIGUSR1);
1509 			break;
1510 		default:
1511 			break;
1512 		}
1513 		return (1);
1514 #endif
1515 	case KS_Cmd_BacklightOn:
1516 	case KS_Cmd_BacklightOff:
1517 	case KS_Cmd_BacklightToggle:
1518 		change_displayparam(sc, WSDISPLAYIO_PARAM_BACKLIGHT,
1519 		    ksym == KS_Cmd_BacklightOff ? -1 : 1,
1520 		    ksym == KS_Cmd_BacklightToggle ? 1 : 0);
1521 		return (1);
1522 	case KS_Cmd_BrightnessUp:
1523 	case KS_Cmd_BrightnessDown:
1524 	case KS_Cmd_BrightnessRotate:
1525 		change_displayparam(sc, WSDISPLAYIO_PARAM_BRIGHTNESS,
1526 		    ksym == KS_Cmd_BrightnessDown ? -1 : 1,
1527 		    ksym == KS_Cmd_BrightnessRotate ? 1 : 0);
1528 		return (1);
1529 	case KS_Cmd_ContrastUp:
1530 	case KS_Cmd_ContrastDown:
1531 	case KS_Cmd_ContrastRotate:
1532 		change_displayparam(sc, WSDISPLAYIO_PARAM_CONTRAST,
1533 		    ksym == KS_Cmd_ContrastDown ? -1 : 1,
1534 		    ksym == KS_Cmd_ContrastRotate ? 1 : 0);
1535 		return (1);
1536 	}
1537 #endif
1538 	return (0);
1539 }
1540 
1541 int
1542 wskbd_translate(struct wskbd_internal *id, u_int type, int value)
1543 {
1544 	struct wskbd_softc *sc = id->t_sc;
1545 	keysym_t ksym, res, *group;
1546 	struct wscons_keymap kpbuf, *kp;
1547 	int gindex, iscommand = 0;
1548 
1549 	if (type == WSCONS_EVENT_ALL_KEYS_UP) {
1550 #if NWSDISPLAY > 0
1551 		if (sc != NULL && sc->sc_repeating) {
1552 			sc->sc_repeating = 0;
1553 			timeout_del(&sc->sc_repeat_ch);
1554 		}
1555 #endif
1556 		id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R |
1557 		    MOD_CONTROL_L | MOD_CONTROL_R |
1558 		    MOD_META_L | MOD_META_R |
1559 		    MOD_MODESHIFT | MOD_MODELOCK |
1560 		    MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
1561 		return (0);
1562 	}
1563 
1564 	if (sc != NULL) {
1565 		if (value < 0 || value >= sc->sc_maplen) {
1566 #ifdef DEBUG
1567 			printf("wskbd_translate: keycode %d out of range\n",
1568 			       value);
1569 #endif
1570 			return (0);
1571 		}
1572 		kp = sc->sc_map + value;
1573 	} else {
1574 		kp = &kpbuf;
1575 		wskbd_get_mapentry(&id->t_keymap, value, kp);
1576 	}
1577 
1578 	/* if this key has a command, process it first */
1579 	if (sc != NULL && kp->command != KS_voidSymbol)
1580 		iscommand = internal_command(sc, &type, kp->command,
1581 		    kp->group1[0]);
1582 
1583 	/* Now update modifiers */
1584 	switch (kp->group1[0]) {
1585 	case KS_Shift_L:
1586 		update_modifier(id, type, 0, MOD_SHIFT_L);
1587 		break;
1588 
1589 	case KS_Shift_R:
1590 		update_modifier(id, type, 0, MOD_SHIFT_R);
1591 		break;
1592 
1593 	case KS_Shift_Lock:
1594 		update_modifier(id, type, 1, MOD_SHIFTLOCK);
1595 		break;
1596 
1597 	case KS_Caps_Lock:
1598 		update_modifier(id, type, 1, MOD_CAPSLOCK);
1599 		break;
1600 
1601 	case KS_Control_L:
1602 		update_modifier(id, type, 0, MOD_CONTROL_L);
1603 		break;
1604 
1605 	case KS_Control_R:
1606 		update_modifier(id, type, 0, MOD_CONTROL_R);
1607 		break;
1608 
1609 	case KS_Alt_L:
1610 		update_modifier(id, type, 0, MOD_META_L);
1611 		break;
1612 
1613 	case KS_Alt_R:
1614 		update_modifier(id, type, 0, MOD_META_R);
1615 		break;
1616 
1617 	case KS_Mode_switch:
1618 		update_modifier(id, type, 0, MOD_MODESHIFT);
1619 		break;
1620 
1621 	case KS_Mode_Lock:
1622 		update_modifier(id, type, 1, MOD_MODELOCK);
1623 		break;
1624 
1625 	case KS_Num_Lock:
1626 		update_modifier(id, type, 1, MOD_NUMLOCK);
1627 		break;
1628 
1629 #if NWSDISPLAY > 0
1630 	case KS_Hold_Screen:
1631 		if (sc != NULL) {
1632 			update_modifier(id, type, 1, MOD_HOLDSCREEN);
1633 			if (sc->sc_displaydv != NULL)
1634 				wsdisplay_kbdholdscreen(sc->sc_displaydv,
1635 				    id->t_modifiers & MOD_HOLDSCREEN);
1636 		}
1637 		break;
1638 
1639 	default:
1640 		if (sc != NULL && sc->sc_repeating &&
1641 		    ((type == WSCONS_EVENT_KEY_UP && value != sc->sc_repkey) ||
1642 		     (type == WSCONS_EVENT_KEY_DOWN && value == sc->sc_repkey)))
1643 			return (0);
1644 		break;
1645 #endif
1646 	}
1647 
1648 #if NWSDISPLAY > 0
1649 	if (sc != NULL) {
1650 		if (sc->sc_repeating) {
1651 			sc->sc_repeating = 0;
1652 			timeout_del(&sc->sc_repeat_ch);
1653 		}
1654 		sc->sc_repkey = value;
1655 	}
1656 #endif
1657 
1658 	/* If this is a key release or we are in command mode, we are done */
1659 	if (type != WSCONS_EVENT_KEY_DOWN || iscommand)
1660 		return (0);
1661 
1662 	/* Get the keysym */
1663 	if (id->t_modifiers & (MOD_MODESHIFT|MOD_MODELOCK) &&
1664 	    !MOD_ONESET(id, MOD_ANYCONTROL))
1665 		group = & kp->group2[0];
1666 	else
1667 		group = & kp->group1[0];
1668 
1669 	if ((id->t_modifiers & MOD_NUMLOCK) &&
1670 	    KS_GROUP(group[1]) == KS_GROUP_Keypad) {
1671 		gindex = !MOD_ONESET(id, MOD_ANYSHIFT);
1672 		ksym = group[gindex];
1673 	} else {
1674 		/* CAPS alone should only affect letter keys */
1675 		if ((id->t_modifiers & (MOD_CAPSLOCK | MOD_ANYSHIFT)) ==
1676 		    MOD_CAPSLOCK) {
1677 			gindex = 0;
1678 			ksym = ksym_upcase(group[0]);
1679 		} else {
1680 			gindex = MOD_ONESET(id, MOD_ANYSHIFT);
1681 			ksym = group[gindex];
1682 		}
1683 	}
1684 
1685 	/* Submit Audio keys for hotkey processing */
1686 	if (KS_GROUP(ksym) == KS_GROUP_Function) {
1687 		switch (ksym) {
1688 #if NAUDIO > 0
1689 		case KS_AudioMute:
1690 			wskbd_set_mixervolume(0, 1);
1691 			return (0);
1692 		case KS_AudioLower:
1693 			wskbd_set_mixervolume(-1, 1);
1694 			return (0);
1695 		case KS_AudioRaise:
1696 			wskbd_set_mixervolume(1, 1);
1697 			return (0);
1698 #endif
1699 		default:
1700 			break;
1701 		}
1702 	}
1703 
1704 	/* Process compose sequence and dead accents */
1705 	res = KS_voidSymbol;
1706 
1707 	switch (KS_GROUP(ksym)) {
1708 	case KS_GROUP_Ascii:
1709 	case KS_GROUP_Keypad:
1710 	case KS_GROUP_Function:
1711 		res = ksym;
1712 		break;
1713 
1714 	case KS_GROUP_Mod:
1715 		if (ksym == KS_Multi_key) {
1716 			update_modifier(id, 1, 0, MOD_COMPOSE);
1717 			id->t_composelen = 2;
1718 		}
1719 		break;
1720 
1721 	case KS_GROUP_Dead:
1722 		if (id->t_composelen == 0) {
1723 			update_modifier(id, 1, 0, MOD_COMPOSE);
1724 			id->t_composelen = 1;
1725 			id->t_composebuf[0] = ksym;
1726 		} else
1727 			res = ksym;
1728 		break;
1729 	}
1730 
1731 	if (res == KS_voidSymbol)
1732 		return (0);
1733 
1734 	if (id->t_composelen > 0) {
1735 		/*
1736 		 * If the compose key also serves as AltGr (i.e. set to both
1737 		 * KS_Multi_key and KS_Mode_switch), and would provide a valid,
1738 		 * distinct combination as AltGr, leave compose mode.
1739 	 	 */
1740 		if (id->t_composelen == 2 && group == &kp->group2[0]) {
1741 			if (kp->group1[gindex] != kp->group2[gindex])
1742 				id->t_composelen = 0;
1743 		}
1744 
1745 		if (id->t_composelen != 0) {
1746 			id->t_composebuf[2 - id->t_composelen] = res;
1747 			if (--id->t_composelen == 0) {
1748 				res = wskbd_compose_value(id->t_composebuf);
1749 				update_modifier(id, 0, 0, MOD_COMPOSE);
1750 			} else {
1751 				return (0);
1752 			}
1753 		}
1754 	}
1755 
1756 	/* We are done, return the symbol */
1757 	if (KS_GROUP(res) == KS_GROUP_Ascii) {
1758 		if (MOD_ONESET(id, MOD_ANYCONTROL)) {
1759 			if ((res >= KS_at && res <= KS_z) || res == KS_space)
1760 				res = res & 0x1f;
1761 			else if (res == KS_2)
1762 				res = 0x00;
1763 			else if (res >= KS_3 && res <= KS_7)
1764 				res = KS_Escape + (res - KS_3);
1765 			else if (res == KS_8)
1766 				res = KS_Delete;
1767 		}
1768 		if (MOD_ONESET(id, MOD_ANYMETA)) {
1769 			if (id->t_flags & WSKFL_METAESC) {
1770 				id->t_symbols[0] = KS_Escape;
1771 				id->t_symbols[1] = res;
1772 				return (2);
1773 			} else
1774 				res |= 0x80;
1775 		}
1776 	}
1777 
1778 	id->t_symbols[0] = res;
1779 	return (1);
1780 }
1781