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