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