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