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