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