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