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