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