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