xref: /openbsd/sys/dev/wscons/wskbd.c (revision eecdf764)
1 /* $OpenBSD: wskbd.c,v 1.122 2025/01/26 08:50:02 jsg 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
wskbd_update_layout(struct wskbd_internal * id,kbd_t enc)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
wskbddevprint(void * aux,const char * pnp)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
wskbd_match(struct device * parent,void * match,void * aux)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
wskbd_attach(struct device * parent,struct device * self,void * aux)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
wskbd_cnattach(const struct wskbd_consops * consops,void * conscookie,const struct wskbd_mapdata * mapdata)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
wskbd_cndetach(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
wskbd_repeat(void * v)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
wskbd_activate(struct device * self,int act)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
wskbd_detach(struct device * self,int flags)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 
629 #if NWSMUX > 0
630 	/* Tell parent mux we're leaving. */
631 	if (sc->sc_base.me_parent != NULL)
632 		wsmux_detach_sc(&sc->sc_base);
633 #endif
634 
635 #if NWSDISPLAY > 0
636 	if (sc->sc_repeating) {
637 		sc->sc_repeating = 0;
638 		timeout_del(&sc->sc_repeat_ch);
639 	}
640 #endif
641 
642 	if (sc->sc_isconsole) {
643 		KASSERT(wskbd_console_device == sc);
644 		wskbd_cndetach();
645 	}
646 
647 	evar = sc->sc_base.me_evp;
648 	if (evar != NULL) {
649 		if (--sc->sc_refcnt >= 0) {
650 			/* Wake everyone by generating a dummy event. */
651 
652 			mtx_enter(&evar->ws_mtx);
653 			if (++evar->ws_put >= WSEVENT_QSIZE)
654 				evar->ws_put = 0;
655 			mtx_leave(&evar->ws_mtx);
656 			wsevent_wakeup(evar);
657 			/* Wait for processes to go away. */
658 			if (tsleep_nsec(sc, PZERO, "wskdet", SEC_TO_NSEC(60)))
659 				printf("wskbd_detach: %s didn't detach\n",
660 				       sc->sc_base.me_dv.dv_xname);
661 		}
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
wskbd_input(struct device * dev,u_int type,int value)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
wskbd_deliver_event(struct wskbd_softc * sc,u_int type,int value)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 	mtx_enter(&evar->ws_mtx);
767 	put = evar->ws_put;
768 	ev = &evar->ws_q[put];
769 	put = (put + 1) % WSEVENT_QSIZE;
770 	if (put == evar->ws_get) {
771 		mtx_leave(&evar->ws_mtx);
772 		log(LOG_WARNING, "%s: event queue overflow\n",
773 		    sc->sc_base.me_dv.dv_xname);
774 		return;
775 	}
776 	ev->type = type;
777 	ev->value = value;
778 	nanotime(&ev->time);
779 	evar->ws_put = put;
780 	mtx_leave(&evar->ws_mtx);
781 	wsevent_wakeup(evar);
782 }
783 
784 #ifdef WSDISPLAY_COMPAT_RAWKBD
785 void
wskbd_rawinput(struct device * dev,u_char * buf,int len)786 wskbd_rawinput(struct device *dev, u_char *buf, int len)
787 {
788 #if NWSDISPLAY > 0
789 	struct wskbd_softc *sc = (struct wskbd_softc *)dev;
790 
791 	if (sc->sc_displaydv != NULL)
792 		wsdisplay_rawkbdinput(sc->sc_displaydv, buf, len);
793 #endif
794 }
795 #endif /* WSDISPLAY_COMPAT_RAWKBD */
796 
797 int
wskbd_enable(struct wskbd_softc * sc,int on)798 wskbd_enable(struct wskbd_softc *sc, int on)
799 {
800 	int error;
801 
802 #if NWSDISPLAY > 0
803 	if (sc->sc_displaydv != NULL)
804 		return (0);
805 
806 	/* Always cancel auto repeat when fiddling with the kbd. */
807 	if (sc->sc_repeating) {
808 		sc->sc_repeating = 0;
809 		timeout_del(&sc->sc_repeat_ch);
810 	}
811 #endif
812 
813 	error = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on);
814 	DPRINTF(("%s: sc=%p on=%d res=%d\n", __func__, sc, on, error));
815 	return (error);
816 }
817 
818 #if NWSMUX > 0
819 int
wskbd_mux_open(struct wsevsrc * me,struct wseventvar * evp)820 wskbd_mux_open(struct wsevsrc *me, struct wseventvar *evp)
821 {
822 	struct wskbd_softc *sc = (struct wskbd_softc *)me;
823 
824 	if (sc->sc_dying)
825 		return (EIO);
826 
827 	return (wskbd_do_open(sc, evp));
828 }
829 #endif
830 
831 int
wskbdopen(dev_t dev,int flags,int mode,struct proc * p)832 wskbdopen(dev_t dev, int flags, int mode, struct proc *p)
833 {
834 	struct wskbd_softc *sc;
835 	struct wseventvar *evar;
836 	int unit, error;
837 
838 	unit = minor(dev);
839 	if (unit >= wskbd_cd.cd_ndevs ||	/* make sure it was attached */
840 	    (sc = wskbd_cd.cd_devs[unit]) == NULL)
841 		return (ENXIO);
842 
843 #if NWSMUX > 0
844 	DPRINTF(("%s: %s mux=%p\n", __func__, sc->sc_base.me_dv.dv_xname,
845 		 sc->sc_base.me_parent));
846 #endif
847 
848 	if (sc->sc_dying)
849 		return (EIO);
850 
851 	if ((flags & (FREAD | FWRITE)) == FWRITE) {
852 		/* Not opening for read, only ioctl is available. */
853 		return (0);
854 	}
855 
856 #if NWSMUX > 0
857 	if (sc->sc_base.me_parent != NULL) {
858 		/* Grab the keyboard out of the greedy hands of the mux. */
859 		DPRINTF(("%s: detach\n", __func__));
860 		wsmux_detach_sc(&sc->sc_base);
861 	}
862 #endif
863 
864 	if (sc->sc_base.me_evp != NULL)
865 		return (EBUSY);
866 
867 	evar = &sc->sc_base.me_evar;
868 	if (wsevent_init_flags(evar, WSEVENT_MPSAFE))
869 		return (EBUSY);
870 
871 	error = wskbd_do_open(sc, evar);
872 	if (error)
873 		wsevent_fini(evar);
874 	return (error);
875 }
876 
877 int
wskbd_do_open(struct wskbd_softc * sc,struct wseventvar * evp)878 wskbd_do_open(struct wskbd_softc *sc, struct wseventvar *evp)
879 {
880 	int error;
881 
882 	/* The device could already be attached to a mux. */
883 	if (sc->sc_base.me_evp != NULL)
884 		return (EBUSY);
885 
886 	sc->sc_base.me_evp = evp;
887 	sc->sc_translating = 0;
888 
889 	error = wskbd_enable(sc, 1);
890 	if (error)
891 		sc->sc_base.me_evp = NULL;
892 	return (error);
893 }
894 
895 int
wskbdclose(dev_t dev,int flags,int mode,struct proc * p)896 wskbdclose(dev_t dev, int flags, int mode, struct proc *p)
897 {
898 	struct wskbd_softc *sc =
899 	    (struct wskbd_softc *)wskbd_cd.cd_devs[minor(dev)];
900 	struct wseventvar *evar = sc->sc_base.me_evp;
901 
902 	if ((flags & (FREAD | FWRITE)) == FWRITE) {
903 		/* not open for read */
904 		return (0);
905 	}
906 
907 	sc->sc_base.me_evp = NULL;
908 	sc->sc_translating = 1;
909 	(void)wskbd_enable(sc, 0);
910 	wsevent_fini(evar);
911 
912 #if NWSMUX > 0
913 	if (sc->sc_base.me_parent == NULL) {
914 		int mux, error;
915 
916 		DPRINTF(("%s: attach\n", __func__));
917 		mux = sc->sc_base.me_dv.dv_cfdata->wskbddevcf_mux;
918 		if (mux >= 0) {
919 			error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base);
920 			if (error)
921 				printf("%s: can't attach mux (error=%d)\n",
922 				    sc->sc_base.me_dv.dv_xname, error);
923 		}
924 	}
925 #endif
926 
927 	return (0);
928 }
929 
930 #if NWSMUX > 0
931 int
wskbd_mux_close(struct wsevsrc * me)932 wskbd_mux_close(struct wsevsrc *me)
933 {
934 	struct wskbd_softc *sc = (struct wskbd_softc *)me;
935 
936 	(void)wskbd_enable(sc, 0);
937 	sc->sc_translating = 1;
938 	sc->sc_base.me_evp = NULL;
939 
940 	return (0);
941 }
942 #endif
943 
944 int
wskbdread(dev_t dev,struct uio * uio,int flags)945 wskbdread(dev_t dev, struct uio *uio, int flags)
946 {
947 	struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
948 	int error;
949 
950 	if (sc->sc_dying)
951 		return (EIO);
952 
953 #ifdef DIAGNOSTIC
954 	if (sc->sc_base.me_evp == NULL) {
955 		printf("wskbdread: evp == NULL\n");
956 		return (EINVAL);
957 	}
958 #endif
959 
960 	sc->sc_refcnt++;
961 	error = wsevent_read(&sc->sc_base.me_evar, uio, flags);
962 	if (--sc->sc_refcnt < 0) {
963 		wakeup(sc);
964 		error = EIO;
965 	}
966 	return (error);
967 }
968 
969 int
wskbdioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)970 wskbdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
971 {
972 	struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
973 	int error;
974 
975 	sc->sc_refcnt++;
976 	error = wskbd_do_ioctl_sc(sc, cmd, data, flag, p, 0);
977 	if (--sc->sc_refcnt < 0)
978 		wakeup(sc);
979 	return (error);
980 }
981 
982 /* A wrapper around the ioctl() workhorse to make reference counting easy. */
983 int
wskbd_do_ioctl(struct device * dv,u_long cmd,caddr_t data,int flag,struct proc * p)984 wskbd_do_ioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
985     struct proc *p)
986 {
987 	struct wskbd_softc *sc = (struct wskbd_softc *)dv;
988 	int error;
989 
990 	sc->sc_refcnt++;
991 	error = wskbd_do_ioctl_sc(sc, cmd, data, flag, p, 1);
992 	if (--sc->sc_refcnt < 0)
993 		wakeup(sc);
994 	return (error);
995 }
996 
997 int
wskbd_do_ioctl_sc(struct wskbd_softc * sc,u_long cmd,caddr_t data,int flag,struct proc * p,int evsrc)998 wskbd_do_ioctl_sc(struct wskbd_softc *sc, u_long cmd, caddr_t data, int flag,
999     struct proc *p, int evsrc)
1000 {
1001 	struct wseventvar *evar;
1002 	int error;
1003 
1004 	/*
1005 	 * Try the generic ioctls that the wskbd interface supports.
1006 	 */
1007 	switch (cmd) {
1008 	case FIOASYNC:
1009 		if (sc->sc_base.me_evp == NULL)
1010 			return (EINVAL);
1011 		mtx_enter(&sc->sc_base.me_evp->ws_mtx);
1012 		sc->sc_base.me_evp->ws_async = *(int *)data != 0;
1013 		mtx_leave(&sc->sc_base.me_evp->ws_mtx);
1014 		return (0);
1015 
1016 	case FIOGETOWN:
1017 	case TIOCGPGRP:
1018 		evar = sc->sc_base.me_evp;
1019 		if (evar == NULL)
1020 			return (EINVAL);
1021 		sigio_getown(&evar->ws_sigio, cmd, data);
1022 		return (0);
1023 
1024 	case FIOSETOWN:
1025 	case TIOCSPGRP:
1026 		evar = sc->sc_base.me_evp;
1027 		if (evar == NULL)
1028 			return (EINVAL);
1029 		return (sigio_setown(&evar->ws_sigio, cmd, data));
1030 	}
1031 
1032 	/*
1033 	 * Try the keyboard driver for WSKBDIO ioctls.  It returns -1
1034 	 * if it didn't recognize the request.
1035 	 */
1036 	error = wskbd_displayioctl_sc(sc, cmd, data, flag, p, evsrc);
1037 	return (error != -1 ? error : ENOTTY);
1038 }
1039 
1040 /*
1041  * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
1042  * Some of these have no real effect in raw mode, however.
1043  */
1044 int
wskbd_displayioctl(struct device * dv,u_long cmd,caddr_t data,int flag,struct proc * p)1045 wskbd_displayioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
1046     struct proc *p)
1047 {
1048 	struct wskbd_softc *sc = (struct wskbd_softc *)dv;
1049 
1050 	return (wskbd_displayioctl_sc(sc, cmd, data, flag, p, 1));
1051 }
1052 
1053 int
wskbd_displayioctl_sc(struct wskbd_softc * sc,u_long cmd,caddr_t data,int flag,struct proc * p,int evsrc)1054 wskbd_displayioctl_sc(struct wskbd_softc *sc, u_long cmd, caddr_t data,
1055     int flag, struct proc *p, int evsrc)
1056 {
1057 	struct wskbd_bell_data *ubdp, *kbdp;
1058 	struct wskbd_keyrepeat_data *ukdp, *kkdp;
1059 	struct wskbd_map_data *umdp;
1060 	struct wskbd_encoding_data *uedp;
1061 	kbd_t enc;
1062 	void *buf;
1063 	int len, error;
1064 	int count, i;
1065 
1066 	switch (cmd) {
1067 	case WSKBDIO_BELL:
1068 	case WSKBDIO_COMPLEXBELL:
1069 	case WSKBDIO_SETBELL:
1070 	case WSKBDIO_SETKEYREPEAT:
1071 	case WSKBDIO_SETDEFAULTKEYREPEAT:
1072 	case WSKBDIO_SETMAP:
1073 	case WSKBDIO_SETENCODING:
1074 	case WSKBDIO_SETBACKLIGHT:
1075 		if ((flag & FWRITE) == 0)
1076 			return (EACCES);
1077 	}
1078 
1079 	switch (cmd) {
1080 #define	SETBELL(dstp, srcp, dfltp)					\
1081     do {								\
1082 	(dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ?		\
1083 	    (srcp)->pitch : (dfltp)->pitch;				\
1084 	(dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ?	\
1085 	    (srcp)->period : (dfltp)->period;				\
1086 	(dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ?	\
1087 	    (srcp)->volume : (dfltp)->volume;				\
1088 	(dstp)->which = WSKBD_BELL_DOALL;				\
1089     } while (0)
1090 
1091 	case WSKBDIO_BELL:
1092 		return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1093 		    WSKBDIO_COMPLEXBELL, (caddr_t)&sc->sc_bell_data, flag, p));
1094 
1095 	case WSKBDIO_COMPLEXBELL:
1096 		ubdp = (struct wskbd_bell_data *)data;
1097 		SETBELL(ubdp, ubdp, &sc->sc_bell_data);
1098 		return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1099 		    WSKBDIO_COMPLEXBELL, (caddr_t)ubdp, flag, p));
1100 
1101 	case WSKBDIO_SETBELL:
1102 		kbdp = &sc->sc_bell_data;
1103 setbell:
1104 		ubdp = (struct wskbd_bell_data *)data;
1105 		SETBELL(kbdp, ubdp, kbdp);
1106 		return (0);
1107 
1108 	case WSKBDIO_GETBELL:
1109 		kbdp = &sc->sc_bell_data;
1110 getbell:
1111 		ubdp = (struct wskbd_bell_data *)data;
1112 		SETBELL(ubdp, kbdp, kbdp);
1113 		return (0);
1114 
1115 	case WSKBDIO_SETDEFAULTBELL:
1116 		if ((error = suser(p)) != 0)
1117 			return (error);
1118 		kbdp = &wskbd_default_bell_data;
1119 		goto setbell;
1120 
1121 
1122 	case WSKBDIO_GETDEFAULTBELL:
1123 		kbdp = &wskbd_default_bell_data;
1124 		goto getbell;
1125 
1126 #undef SETBELL
1127 
1128 #define	SETKEYREPEAT(dstp, srcp, dfltp)					\
1129     do {								\
1130 	(dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ?	\
1131 	    (srcp)->del1 : (dfltp)->del1;				\
1132 	(dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ?	\
1133 	    (srcp)->delN : (dfltp)->delN;				\
1134 	(dstp)->which = WSKBD_KEYREPEAT_DOALL;				\
1135     } while (0)
1136 
1137 	case WSKBDIO_SETKEYREPEAT:
1138 		kkdp = &sc->sc_keyrepeat_data;
1139 setkeyrepeat:
1140 		ukdp = (struct wskbd_keyrepeat_data *)data;
1141 		SETKEYREPEAT(kkdp, ukdp, kkdp);
1142 		return (0);
1143 
1144 	case WSKBDIO_GETKEYREPEAT:
1145 		kkdp = &sc->sc_keyrepeat_data;
1146 getkeyrepeat:
1147 		ukdp = (struct wskbd_keyrepeat_data *)data;
1148 		SETKEYREPEAT(ukdp, kkdp, kkdp);
1149 		return (0);
1150 
1151 	case WSKBDIO_SETDEFAULTKEYREPEAT:
1152 		if ((error = suser(p)) != 0)
1153 			return (error);
1154 		kkdp = &wskbd_default_keyrepeat_data;
1155 		goto setkeyrepeat;
1156 
1157 
1158 	case WSKBDIO_GETDEFAULTKEYREPEAT:
1159 		kkdp = &wskbd_default_keyrepeat_data;
1160 		goto getkeyrepeat;
1161 
1162 #undef SETKEYREPEAT
1163 
1164 	case WSKBDIO_SETMAP:
1165 		umdp = (struct wskbd_map_data *)data;
1166 		if (umdp->maplen > WSKBDIO_MAXMAPLEN)
1167 			return (EINVAL);
1168 
1169 		buf = mallocarray(umdp->maplen, sizeof(struct wscons_keymap),
1170 		    M_TEMP, M_WAITOK);
1171 		len = umdp->maplen * sizeof(struct wscons_keymap);
1172 
1173 		error = copyin(umdp->map, buf, len);
1174 		if (error == 0) {
1175 			struct wscons_keymap *map;
1176 
1177 			map = wskbd_init_keymap(umdp->maplen);
1178 			memcpy(map, buf, len);
1179 			wskbd_set_keymap(sc, map, umdp->maplen);
1180 			/* drop the variant bits handled by the map */
1181 			enc = KB_USER | (KB_VARIANT(sc->id->t_keymap.layout) &
1182 			    KB_HANDLEDBYWSKBD);
1183 			wskbd_update_layout(sc->id, enc);
1184 		}
1185 		free(buf, M_TEMP, len);
1186 		return(error);
1187 
1188 	case WSKBDIO_GETMAP:
1189 		umdp = (struct wskbd_map_data *)data;
1190 		if (umdp->maplen > sc->sc_maplen)
1191 			umdp->maplen = sc->sc_maplen;
1192 		error = copyout(sc->sc_map, umdp->map,
1193 				umdp->maplen*sizeof(struct wscons_keymap));
1194 		return(error);
1195 
1196 	case WSKBDIO_GETENCODING:
1197 		/* Do not advertise encoding to the parent mux. */
1198 		if (evsrc && (sc->id->t_keymap.layout & KB_NOENCODING))
1199 			return (ENOTTY);
1200 		*((kbd_t *)data) = sc->id->t_keymap.layout & ~KB_DEFAULT;
1201 		return(0);
1202 
1203 	case WSKBDIO_SETENCODING:
1204 		enc = *((kbd_t *)data);
1205 		if (KB_ENCODING(enc) == KB_USER) {
1206 			/* user map must already be loaded */
1207 			if (KB_ENCODING(sc->id->t_keymap.layout) != KB_USER)
1208 				return (EINVAL);
1209 			/* map variants make no sense */
1210 			if (KB_VARIANT(enc) & ~KB_HANDLEDBYWSKBD)
1211 				return (EINVAL);
1212 		} else if (sc->id->t_keymap.layout & KB_NOENCODING) {
1213 			return (0);
1214 		} else {
1215 			struct wscons_keymap *map;
1216 			int maplen;
1217 
1218 			error = wskbd_load_keymap(&sc->id->t_keymap, enc,
1219 			    &map, &maplen);
1220 			if (error)
1221 				return (error);
1222 			wskbd_set_keymap(sc, map, maplen);
1223 		}
1224 		wskbd_update_layout(sc->id, enc);
1225 #if NWSMUX > 0
1226 		/* Update mux default layout */
1227 		if (sc->sc_base.me_parent != NULL)
1228 			wsmux_set_layout(sc->sc_base.me_parent, enc);
1229 #endif
1230 		return (0);
1231 
1232 	case WSKBDIO_GETENCODINGS:
1233 		uedp = (struct wskbd_encoding_data *)data;
1234 		count = 0;
1235 		if (sc->id->t_keymap.keydesc != NULL) {
1236 			while (sc->id->t_keymap.keydesc[count].name)
1237 				count++;
1238 		}
1239 		if (uedp->nencodings > count)
1240 			uedp->nencodings = count;
1241 		for (i = 0; i < uedp->nencodings; i++) {
1242 			error = copyout(&sc->id->t_keymap.keydesc[i].name,
1243 			    &uedp->encodings[i], sizeof(kbd_t));
1244 			if (error)
1245 				return (error);
1246 		}
1247 		return (0);
1248 
1249 	case WSKBDIO_GETBACKLIGHT:
1250 		if (wskbd_get_backlight != NULL)
1251 			return (*wskbd_get_backlight)((struct wskbd_backlight *)data);
1252 		break;
1253 
1254 	case WSKBDIO_SETBACKLIGHT:
1255 		if (wskbd_set_backlight != NULL)
1256 			return (*wskbd_set_backlight)((struct wskbd_backlight *)data);
1257 		break;
1258 	}
1259 
1260 	/*
1261 	 * Try the keyboard driver for WSKBDIO ioctls.  It returns -1
1262 	 * if it didn't recognize the request, and in turn we return
1263 	 * -1 if we didn't recognize the request.
1264 	 */
1265 /* printf("kbdaccess\n"); */
1266 	error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
1267 					   flag, p);
1268 #ifdef WSDISPLAY_COMPAT_RAWKBD
1269 	if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
1270 		int s = spltty();
1271 		sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
1272 					 | MOD_CONTROL_L | MOD_CONTROL_R
1273 					 | MOD_META_L | MOD_META_R
1274 					 | MOD_COMMAND
1275 					 | MOD_COMMAND1 | MOD_COMMAND2);
1276 #if NWSDISPLAY > 0
1277 		if (sc->sc_repeating) {
1278 			sc->sc_repeating = 0;
1279 			timeout_del(&sc->sc_repeat_ch);
1280 		}
1281 #endif
1282 		splx(s);
1283 	}
1284 #endif
1285 	return (error);
1286 }
1287 
1288 int
wskbdkqfilter(dev_t dev,struct knote * kn)1289 wskbdkqfilter(dev_t dev, struct knote *kn)
1290 {
1291 	struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
1292 
1293 	if (sc->sc_base.me_evp == NULL)
1294 		return (ENXIO);
1295 	return (wsevent_kqfilter(sc->sc_base.me_evp, kn));
1296 }
1297 
1298 #if NWSDISPLAY > 0
1299 
1300 int
wskbd_pickfree(void)1301 wskbd_pickfree(void)
1302 {
1303 	int i;
1304 	struct wskbd_softc *sc;
1305 
1306 	for (i = 0; i < wskbd_cd.cd_ndevs; i++) {
1307 		if ((sc = wskbd_cd.cd_devs[i]) == NULL)
1308 			continue;
1309 		if (sc->sc_displaydv == NULL)
1310 			return (i);
1311 	}
1312 	return (-1);
1313 }
1314 
1315 struct wsevsrc *
wskbd_set_console_display(struct device * displaydv,struct wsevsrc * me)1316 wskbd_set_console_display(struct device *displaydv, struct wsevsrc *me)
1317 {
1318 	struct wskbd_softc *sc = wskbd_console_device;
1319 
1320 	if (sc == NULL)
1321 		return (NULL);
1322 	sc->sc_displaydv = displaydv;
1323 #if NWSMUX > 0
1324 	(void)wsmux_attach_sc((struct wsmux_softc *)me, &sc->sc_base);
1325 #endif
1326 	return (&sc->sc_base);
1327 }
1328 
1329 int
wskbd_set_display(struct device * dv,struct device * displaydv)1330 wskbd_set_display(struct device *dv, struct device *displaydv)
1331 {
1332 	struct wskbd_softc *sc = (struct wskbd_softc *)dv;
1333 	struct device *odisplaydv;
1334 	int error;
1335 
1336 	DPRINTF(("%s: %s odisp=%p disp=%p cons=%d\n", __func__,
1337 		 dv->dv_xname, sc->sc_displaydv, displaydv,
1338 		 sc->sc_isconsole));
1339 
1340 	if (sc->sc_isconsole)
1341 		return (EBUSY);
1342 
1343 	if (displaydv != NULL) {
1344 		if (sc->sc_displaydv != NULL)
1345 			return (EBUSY);
1346 	} else {
1347 		if (sc->sc_displaydv == NULL)
1348 			return (ENXIO);
1349 	}
1350 
1351 	odisplaydv = sc->sc_displaydv;
1352 	sc->sc_displaydv = NULL;
1353 	error = wskbd_enable(sc, displaydv != NULL);
1354 	sc->sc_displaydv = displaydv;
1355 	if (error) {
1356 		sc->sc_displaydv = odisplaydv;
1357 		return (error);
1358 	}
1359 
1360 	if (displaydv)
1361 		printf("%s: connecting to %s\n",
1362 		       sc->sc_base.me_dv.dv_xname, displaydv->dv_xname);
1363 	else
1364 		printf("%s: disconnecting from %s\n",
1365 		       sc->sc_base.me_dv.dv_xname, odisplaydv->dv_xname);
1366 
1367 	return (0);
1368 }
1369 
1370 #endif	/* NWSDISPLAY > 0 */
1371 
1372 #if NWSMUX > 0
1373 int
wskbd_add_mux(int unit,struct wsmux_softc * muxsc)1374 wskbd_add_mux(int unit, struct wsmux_softc *muxsc)
1375 {
1376 	struct wskbd_softc *sc;
1377 
1378 	if (unit < 0 || unit >= wskbd_cd.cd_ndevs ||
1379 	    (sc = wskbd_cd.cd_devs[unit]) == NULL)
1380 		return (ENXIO);
1381 
1382 	if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL)
1383 		return (EBUSY);
1384 
1385 	return (wsmux_attach_sc(muxsc, &sc->sc_base));
1386 }
1387 #endif
1388 
1389 /*
1390  * Console interface.
1391  */
1392 int
wskbd_cngetc(dev_t dev)1393 wskbd_cngetc(dev_t dev)
1394 {
1395 	static int num = 0;
1396 	static int pos;
1397 	u_int type;
1398 	int data;
1399 	keysym_t ks;
1400 
1401 	if (!wskbd_console_initted)
1402 		return 0;
1403 
1404 	if (wskbd_console_device != NULL &&
1405 	    !wskbd_console_device->sc_translating)
1406 		return 0;
1407 
1408 	for(;;) {
1409 		if (num-- > 0) {
1410 			ks = wskbd_console_data.t_symbols[pos++];
1411 			if (KS_GROUP(ks) == KS_GROUP_Ascii)
1412 				return (KS_VALUE(ks));
1413 		} else {
1414 			(*wskbd_console_data.t_consops->getc)
1415 				(wskbd_console_data.t_consaccesscookie,
1416 				 &type, &data);
1417 			num = wskbd_translate(&wskbd_console_data, type, data);
1418 			pos = 0;
1419 		}
1420 	}
1421 }
1422 
1423 void
wskbd_cnpollc(dev_t dev,int poll)1424 wskbd_cnpollc(dev_t dev, int poll)
1425 {
1426 	if (!wskbd_console_initted)
1427 		return;
1428 
1429 	if (wskbd_console_device != NULL &&
1430 	    !wskbd_console_device->sc_translating)
1431 		return;
1432 
1433 	(*wskbd_console_data.t_consops->pollc)
1434 	    (wskbd_console_data.t_consaccesscookie, poll);
1435 }
1436 
1437 void
wskbd_cnbell(dev_t dev,u_int pitch,u_int period,u_int volume)1438 wskbd_cnbell(dev_t dev, u_int pitch, u_int period, u_int volume)
1439 {
1440 	if (!wskbd_console_initted)
1441 		return;
1442 
1443 	if (wskbd_console_data.t_consops->bell != NULL)
1444 		(*wskbd_console_data.t_consops->bell)
1445 		    (wskbd_console_data.t_consaccesscookie, pitch, period,
1446 			volume);
1447 }
1448 
1449 void
update_leds(struct wskbd_internal * id)1450 update_leds(struct wskbd_internal *id)
1451 {
1452 	int new_state;
1453 
1454 	new_state = 0;
1455 	if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
1456 		new_state |= WSKBD_LED_CAPS;
1457 	if (id->t_modifiers & MOD_NUMLOCK)
1458 		new_state |= WSKBD_LED_NUM;
1459 	if (id->t_modifiers & MOD_COMPOSE)
1460 		new_state |= WSKBD_LED_COMPOSE;
1461 	if (id->t_modifiers & MOD_HOLDSCREEN)
1462 		new_state |= WSKBD_LED_SCROLL;
1463 
1464 	if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
1465 		(*id->t_sc->sc_accessops->set_leds)
1466 		    (id->t_sc->sc_accesscookie, new_state);
1467 		id->t_sc->sc_ledstate = new_state;
1468 	}
1469 }
1470 
1471 void
update_modifier(struct wskbd_internal * id,u_int type,int toggle,int mask)1472 update_modifier(struct wskbd_internal *id, u_int type, int toggle, int mask)
1473 {
1474 	if (toggle) {
1475 		if (type == WSCONS_EVENT_KEY_DOWN)
1476 			id->t_modifiers ^= mask;
1477 	} else {
1478 		if (type == WSCONS_EVENT_KEY_DOWN)
1479 			id->t_modifiers |= mask;
1480 		else
1481 			id->t_modifiers &= ~mask;
1482 	}
1483 	if (mask & MOD_ANYLED)
1484 		update_leds(id);
1485 }
1486 
1487 #if NWSDISPLAY > 0
1488 void
change_displayparam(struct wskbd_softc * sc,int param,int updown,int wraparound)1489 change_displayparam(struct wskbd_softc *sc, int param, int updown,
1490     int wraparound)
1491 {
1492 	int res;
1493 	struct wsdisplay_param dp;
1494 
1495 	dp.param = param;
1496 	res = wsdisplay_param(sc->sc_displaydv, WSDISPLAYIO_GETPARAM, &dp);
1497 
1498 	if (res == EINVAL)
1499 		return; /* no such parameter */
1500 
1501 	dp.curval += updown;
1502 	if (dp.max < dp.curval)
1503 		dp.curval = wraparound ? dp.min : dp.max;
1504 	else
1505 	if (dp.curval < dp.min)
1506 		dp.curval = wraparound ? dp.max : dp.min;
1507 	wsdisplay_param(sc->sc_displaydv, WSDISPLAYIO_SETPARAM, &dp);
1508 }
1509 #endif
1510 
1511 int
internal_command(struct wskbd_softc * sc,u_int * type,keysym_t ksym,keysym_t ksym2)1512 internal_command(struct wskbd_softc *sc, u_int *type, keysym_t ksym,
1513     keysym_t ksym2)
1514 {
1515 	switch (ksym) {
1516 	case KS_Cmd:
1517 		update_modifier(sc->id, *type, 0, MOD_COMMAND);
1518 		ksym = ksym2;
1519 		break;
1520 
1521 	case KS_Cmd1:
1522 		update_modifier(sc->id, *type, 0, MOD_COMMAND1);
1523 		break;
1524 
1525 	case KS_Cmd2:
1526 		update_modifier(sc->id, *type, 0, MOD_COMMAND2);
1527 		break;
1528 	}
1529 
1530 	if (*type != WSCONS_EVENT_KEY_DOWN)
1531 		return (0);
1532 
1533 #ifdef SUSPEND
1534 	if (ksym == KS_Cmd_Sleep) {
1535 		request_sleep(SLEEP_SUSPEND);
1536 		return (1);
1537 	}
1538 #endif
1539 
1540 #ifdef HAVE_SCROLLBACK_SUPPORT
1541 #if NWSDISPLAY > 0
1542 	switch (ksym) {
1543 	case KS_Cmd_ScrollBack:
1544 		if (MOD_ONESET(sc->id, MOD_ANYSHIFT)) {
1545 			if (sc->sc_displaydv != NULL)
1546 				wsscrollback(sc->sc_displaydv,
1547 				    WSDISPLAY_SCROLL_BACKWARD);
1548 			return (1);
1549 		}
1550 		break;
1551 
1552 	case KS_Cmd_ScrollFwd:
1553 		if (MOD_ONESET(sc->id, MOD_ANYSHIFT)) {
1554 			if (sc->sc_displaydv != NULL)
1555 				wsscrollback(sc->sc_displaydv,
1556 				    WSDISPLAY_SCROLL_FORWARD);
1557 			return (1);
1558 		}
1559 		break;
1560 	}
1561 #endif
1562 #endif
1563 
1564 	switch (ksym) {
1565 	case KS_Cmd_KbdBacklightUp:
1566 		atomic_store_int(&sc->sc_kbd_backlight_cmd, KBD_BACKLIGHT_UP);
1567 		task_add(systq, &sc->sc_kbd_backlight_task);
1568 		return (1);
1569 	case KS_Cmd_KbdBacklightDown:
1570 		atomic_store_int(&sc->sc_kbd_backlight_cmd, KBD_BACKLIGHT_DOWN);
1571 		task_add(systq, &sc->sc_kbd_backlight_task);
1572 		return (1);
1573 	case KS_Cmd_KbdBacklightToggle:
1574 		atomic_store_int(&sc->sc_kbd_backlight_cmd, KBD_BACKLIGHT_TOGGLE);
1575 		task_add(systq, &sc->sc_kbd_backlight_task);
1576 		return (1);
1577 	}
1578 
1579 #if NWSDISPLAY > 0
1580 	switch(ksym) {
1581 	case KS_Cmd_BrightnessUp:
1582 		atomic_add_int(&sc->sc_brightness_steps, 1);
1583 		task_add(systq, &sc->sc_brightness_task);
1584 		return (1);
1585 	case KS_Cmd_BrightnessDown:
1586 		atomic_sub_int(&sc->sc_brightness_steps, 1);
1587 		task_add(systq, &sc->sc_brightness_task);
1588 		return (1);
1589 	case KS_Cmd_BrightnessRotate:
1590 		wsdisplay_brightness_cycle(sc->sc_displaydv);
1591 		return (1);
1592 	}
1593 #endif
1594 
1595 	if (!MOD_ONESET(sc->id, MOD_COMMAND) &&
1596 	    !MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2))
1597 		return (0);
1598 
1599 #ifdef DDB
1600 	if (ksym == KS_Cmd_Debugger) {
1601 		wskbd_debugger(sc);
1602 		/* discard this key (ddb discarded command modifiers) */
1603 		*type = WSCONS_EVENT_KEY_UP;
1604 		return (1);
1605 	}
1606 #endif
1607 
1608 #if NWSDISPLAY > 0
1609 	if (sc->sc_displaydv == NULL)
1610 		return (0);
1611 
1612 	switch (ksym) {
1613 	case KS_Cmd_Screen0:
1614 	case KS_Cmd_Screen1:
1615 	case KS_Cmd_Screen2:
1616 	case KS_Cmd_Screen3:
1617 	case KS_Cmd_Screen4:
1618 	case KS_Cmd_Screen5:
1619 	case KS_Cmd_Screen6:
1620 	case KS_Cmd_Screen7:
1621 	case KS_Cmd_Screen8:
1622 	case KS_Cmd_Screen9:
1623 	case KS_Cmd_Screen10:
1624 	case KS_Cmd_Screen11:
1625 		wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0);
1626 		return (1);
1627 	case KS_Cmd_ResetEmul:
1628 		wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETEMUL);
1629 		return (1);
1630 	case KS_Cmd_ResetClose:
1631 		wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETCLOSE);
1632 		return (1);
1633 #if defined(__i386__) || defined(__amd64__)
1634 	case KS_Cmd_KbdReset:
1635 		switch (kbd_reset) {
1636 #ifdef DDB
1637 		case 2:
1638 			wskbd_debugger(sc);
1639 			/* discard this key (ddb discarded command modifiers) */
1640 			*type = WSCONS_EVENT_KEY_UP;
1641 			break;
1642 #endif
1643 		case 1:
1644 			kbd_reset = 0;
1645 			prsignal(initprocess, SIGUSR1);
1646 			break;
1647 		default:
1648 			break;
1649 		}
1650 		return (1);
1651 #endif
1652 	case KS_Cmd_BacklightOn:
1653 	case KS_Cmd_BacklightOff:
1654 	case KS_Cmd_BacklightToggle:
1655 		change_displayparam(sc, WSDISPLAYIO_PARAM_BACKLIGHT,
1656 		    ksym == KS_Cmd_BacklightOff ? -1 : 1,
1657 		    ksym == KS_Cmd_BacklightToggle ? 1 : 0);
1658 		return (1);
1659 	case KS_Cmd_ContrastUp:
1660 	case KS_Cmd_ContrastDown:
1661 	case KS_Cmd_ContrastRotate:
1662 		change_displayparam(sc, WSDISPLAYIO_PARAM_CONTRAST,
1663 		    ksym == KS_Cmd_ContrastDown ? -1 : 1,
1664 		    ksym == KS_Cmd_ContrastRotate ? 1 : 0);
1665 		return (1);
1666 	}
1667 #endif
1668 	return (0);
1669 }
1670 
1671 int
wskbd_translate(struct wskbd_internal * id,u_int type,int value)1672 wskbd_translate(struct wskbd_internal *id, u_int type, int value)
1673 {
1674 	struct wskbd_softc *sc = id->t_sc;
1675 	keysym_t ksym, res, *group;
1676 	struct wscons_keymap kpbuf, *kp;
1677 	int gindex, iscommand = 0;
1678 
1679 	if (type == WSCONS_EVENT_ALL_KEYS_UP) {
1680 #if NWSDISPLAY > 0
1681 		if (sc != NULL && sc->sc_repeating) {
1682 			sc->sc_repeating = 0;
1683 			timeout_del(&sc->sc_repeat_ch);
1684 		}
1685 #endif
1686 		id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R |
1687 		    MOD_CONTROL_L | MOD_CONTROL_R |
1688 		    MOD_META_L | MOD_META_R |
1689 		    MOD_MODESHIFT | MOD_MODELOCK |
1690 		    MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
1691 		return (0);
1692 	}
1693 
1694 	if (sc != NULL) {
1695 		if (value < 0 || value >= sc->sc_maplen) {
1696 #ifdef DEBUG
1697 			printf("wskbd_translate: keycode %d out of range\n",
1698 			       value);
1699 #endif
1700 			return (0);
1701 		}
1702 		kp = sc->sc_map + value;
1703 	} else {
1704 		kp = &kpbuf;
1705 		wskbd_get_mapentry(&id->t_keymap, value, kp);
1706 	}
1707 
1708 	/* if this key has a command, process it first */
1709 	if (sc != NULL && kp->command != KS_voidSymbol)
1710 		iscommand = internal_command(sc, &type, kp->command,
1711 		    kp->group1[0]);
1712 
1713 	/* Now update modifiers */
1714 	switch (kp->group1[0]) {
1715 	case KS_Shift_L:
1716 		update_modifier(id, type, 0, MOD_SHIFT_L);
1717 		break;
1718 
1719 	case KS_Shift_R:
1720 		update_modifier(id, type, 0, MOD_SHIFT_R);
1721 		break;
1722 
1723 	case KS_Shift_Lock:
1724 		update_modifier(id, type, 1, MOD_SHIFTLOCK);
1725 		break;
1726 
1727 	case KS_Caps_Lock:
1728 		update_modifier(id, type, 1, MOD_CAPSLOCK);
1729 		break;
1730 
1731 	case KS_Control_L:
1732 		update_modifier(id, type, 0, MOD_CONTROL_L);
1733 		break;
1734 
1735 	case KS_Control_R:
1736 		update_modifier(id, type, 0, MOD_CONTROL_R);
1737 		break;
1738 
1739 	case KS_Alt_L:
1740 		update_modifier(id, type, 0, MOD_META_L);
1741 		break;
1742 
1743 	case KS_Alt_R:
1744 		update_modifier(id, type, 0, MOD_META_R);
1745 		break;
1746 
1747 	case KS_Mode_switch:
1748 		update_modifier(id, type, 0, MOD_MODESHIFT);
1749 		break;
1750 
1751 	case KS_Mode_Lock:
1752 		update_modifier(id, type, 1, MOD_MODELOCK);
1753 		break;
1754 
1755 	case KS_Num_Lock:
1756 		update_modifier(id, type, 1, MOD_NUMLOCK);
1757 		break;
1758 
1759 #if NWSDISPLAY > 0
1760 	case KS_Hold_Screen:
1761 		if (sc != NULL) {
1762 			update_modifier(id, type, 1, MOD_HOLDSCREEN);
1763 			if (sc->sc_displaydv != NULL)
1764 				wsdisplay_kbdholdscreen(sc->sc_displaydv,
1765 				    id->t_modifiers & MOD_HOLDSCREEN);
1766 		}
1767 		break;
1768 
1769 	default:
1770 		if (sc != NULL && sc->sc_repeating &&
1771 		    ((type == WSCONS_EVENT_KEY_UP && value != sc->sc_repkey) ||
1772 		     (type == WSCONS_EVENT_KEY_DOWN && value == sc->sc_repkey)))
1773 			return (0);
1774 		break;
1775 #endif
1776 	}
1777 
1778 #if NWSDISPLAY > 0
1779 	if (sc != NULL) {
1780 		if (sc->sc_repeating) {
1781 			sc->sc_repeating = 0;
1782 			timeout_del(&sc->sc_repeat_ch);
1783 		}
1784 		sc->sc_repkey = value;
1785 	}
1786 #endif
1787 
1788 	/* If this is a key release or we are in command mode, we are done */
1789 	if (type != WSCONS_EVENT_KEY_DOWN || iscommand)
1790 		return (0);
1791 
1792 	/* Get the keysym */
1793 	if (id->t_modifiers & (MOD_MODESHIFT|MOD_MODELOCK) &&
1794 	    !MOD_ONESET(id, MOD_ANYCONTROL))
1795 		group = & kp->group2[0];
1796 	else
1797 		group = & kp->group1[0];
1798 
1799 	if ((id->t_modifiers & MOD_NUMLOCK) &&
1800 	    KS_GROUP(group[1]) == KS_GROUP_Keypad) {
1801 		gindex = !MOD_ONESET(id, MOD_ANYSHIFT);
1802 		ksym = group[gindex];
1803 	} else {
1804 		/* CAPS alone should only affect letter keys */
1805 		if ((id->t_modifiers & (MOD_CAPSLOCK | MOD_ANYSHIFT)) ==
1806 		    MOD_CAPSLOCK) {
1807 			gindex = 0;
1808 			ksym = ksym_upcase(group[0]);
1809 		} else {
1810 			gindex = MOD_ONESET(id, MOD_ANYSHIFT);
1811 			ksym = group[gindex];
1812 		}
1813 	}
1814 
1815 	/* Submit Audio keys for hotkey processing */
1816 	if (KS_GROUP(ksym) == KS_GROUP_Function) {
1817 		switch (ksym) {
1818 #if NAUDIO > 0
1819 		case KS_AudioMute:
1820 			wskbd_set_mixervolume_dev(sc->sc_audiocookie, 0, 1);
1821 			return (0);
1822 		case KS_AudioLower:
1823 			wskbd_set_mixervolume_dev(sc->sc_audiocookie, -1, 1);
1824 			return (0);
1825 		case KS_AudioRaise:
1826 			wskbd_set_mixervolume_dev(sc->sc_audiocookie, 1, 1);
1827 			return (0);
1828 #endif
1829 		default:
1830 			break;
1831 		}
1832 	}
1833 
1834 	/* Process compose sequence and dead accents */
1835 	res = KS_voidSymbol;
1836 
1837 	switch (KS_GROUP(ksym)) {
1838 	case KS_GROUP_Ascii:
1839 	case KS_GROUP_Keypad:
1840 	case KS_GROUP_Function:
1841 		res = ksym;
1842 		break;
1843 
1844 	case KS_GROUP_Mod:
1845 		if (ksym == KS_Multi_key) {
1846 			update_modifier(id, 1, 0, MOD_COMPOSE);
1847 			id->t_composelen = 2;
1848 		}
1849 		break;
1850 
1851 	case KS_GROUP_Dead:
1852 		if (id->t_composelen == 0) {
1853 			update_modifier(id, 1, 0, MOD_COMPOSE);
1854 			id->t_composelen = 1;
1855 			id->t_composebuf[0] = ksym;
1856 		} else
1857 			res = ksym;
1858 		break;
1859 	}
1860 
1861 	if (res == KS_voidSymbol)
1862 		return (0);
1863 
1864 	if (id->t_composelen > 0) {
1865 		/*
1866 		 * If the compose key also serves as AltGr (i.e. set to both
1867 		 * KS_Multi_key and KS_Mode_switch), and would provide a valid,
1868 		 * distinct combination as AltGr, leave compose mode.
1869 	 	 */
1870 		if (id->t_composelen == 2 && group == &kp->group2[0]) {
1871 			if (kp->group1[gindex] != kp->group2[gindex])
1872 				id->t_composelen = 0;
1873 		}
1874 
1875 		if (id->t_composelen != 0) {
1876 			id->t_composebuf[2 - id->t_composelen] = res;
1877 			if (--id->t_composelen == 0) {
1878 				res = wskbd_compose_value(id->t_composebuf);
1879 				update_modifier(id, 0, 0, MOD_COMPOSE);
1880 			} else {
1881 				return (0);
1882 			}
1883 		}
1884 	}
1885 
1886 	/* We are done, return the symbol */
1887 	if (KS_GROUP(res) == KS_GROUP_Ascii) {
1888 		if (MOD_ONESET(id, MOD_ANYCONTROL)) {
1889 			if ((res >= KS_at && res <= KS_z) || res == KS_space)
1890 				res = res & 0x1f;
1891 			else if (res == KS_2)
1892 				res = 0x00;
1893 			else if (res >= KS_3 && res <= KS_7)
1894 				res = KS_Escape + (res - KS_3);
1895 			else if (res == KS_8)
1896 				res = KS_Delete;
1897 		}
1898 		if (MOD_ONESET(id, MOD_ANYMETA)) {
1899 			if (id->t_flags & WSKFL_METAESC) {
1900 				id->t_symbols[0] = KS_Escape;
1901 				id->t_symbols[1] = res;
1902 				return (2);
1903 			} else
1904 				res |= 0x80;
1905 		}
1906 	}
1907 
1908 	id->t_symbols[0] = res;
1909 	return (1);
1910 }
1911 
1912 void
wskbd_debugger(struct wskbd_softc * sc)1913 wskbd_debugger(struct wskbd_softc *sc)
1914 {
1915 #ifdef DDB
1916 	if (sc->sc_isconsole && db_console) {
1917 		if (sc->id->t_consops->debugger != NULL) {
1918 			(*sc->id->t_consops->debugger)
1919 				(sc->id->t_consaccesscookie);
1920 		} else
1921 			db_enter();
1922 	}
1923 #endif
1924 }
1925 
1926 void
wskbd_set_keymap(struct wskbd_softc * sc,struct wscons_keymap * map,int maplen)1927 wskbd_set_keymap(struct wskbd_softc *sc, struct wscons_keymap *map, int maplen)
1928 {
1929 	free(sc->sc_map, M_DEVBUF, sc->sc_maplen * sizeof(*sc->sc_map));
1930 	sc->sc_map = map;
1931 	sc->sc_maplen = maplen;
1932 }
1933 
1934 void
wskbd_kbd_backlight_task(void * arg)1935 wskbd_kbd_backlight_task(void *arg)
1936 {
1937 	struct wskbd_softc *sc = arg;
1938 	struct wskbd_backlight data;
1939 	int step, val;
1940 	u_int cmd;
1941 
1942 	if (wskbd_get_backlight == NULL || wskbd_set_backlight == NULL)
1943 		return;
1944 
1945 	cmd  = atomic_swap_uint(&sc->sc_kbd_backlight_cmd, 0);
1946 	if (cmd != KBD_BACKLIGHT_UP &&
1947 	    cmd != KBD_BACKLIGHT_DOWN &&
1948 	    cmd != KBD_BACKLIGHT_TOGGLE)
1949 		return;
1950 
1951 	(*wskbd_get_backlight)(&data);
1952 	step = (data.max - data.min + 1) / 8;
1953 	val = (cmd == KBD_BACKLIGHT_UP) ?  data.curval + step :
1954 	    (cmd == KBD_BACKLIGHT_DOWN) ?  data.curval - step :
1955 	    (data.curval) ?  0 : (data.max - data.min + 1) / 2;
1956 	data.curval = (val > 0xff) ?  0xff : (val < 0) ? 0 : val;
1957 	(*wskbd_set_backlight)(&data);
1958 }
1959 
1960 #if NWSDISPLAY > 0
1961 void
wskbd_brightness_task(void * arg)1962 wskbd_brightness_task(void *arg)
1963 {
1964 	struct wskbd_softc *sc = arg;
1965 	int steps = atomic_swap_uint(&sc->sc_brightness_steps, 0);
1966 	int dir = 1;
1967 
1968 	if (steps < 0) {
1969 		steps = -steps;
1970 		dir = -1;
1971 	}
1972 	while (steps--)
1973 		wsdisplay_brightness_step(NULL, dir);
1974 }
1975 #endif
1976