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