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