Home | History | Annotate | Line # | Download | only in wscons
wskbd.c revision 1.13
      1 /* $NetBSD: wskbd.c,v 1.13 1998/09/17 18:05:43 drochner Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
      5  *
      6  * Keysym translator:
      7  * Contributed to The NetBSD Foundation by Juergen Hannken-Illjes.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *      This product includes software developed by Christopher G. Demetriou
     20  *	for the NetBSD Project.
     21  * 4. The name of the author may not be used to endorse or promote products
     22  *    derived from this software without specific prior written permission
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34  */
     35 
     36 static const char _copyright[] __attribute__ ((unused)) =
     37     "Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.";
     38 static const char _rcsid[] __attribute__ ((unused)) =
     39     "$NetBSD: wskbd.c,v 1.13 1998/09/17 18:05:43 drochner Exp $";
     40 
     41 /*
     42  * Copyright (c) 1992, 1993
     43  *	The Regents of the University of California.  All rights reserved.
     44  *
     45  * This software was developed by the Computer Systems Engineering group
     46  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
     47  * contributed to Berkeley.
     48  *
     49  * All advertising materials mentioning features or use of this software
     50  * must display the following acknowledgement:
     51  *	This product includes software developed by the University of
     52  *	California, Lawrence Berkeley Laboratory.
     53  *
     54  * Redistribution and use in source and binary forms, with or without
     55  * modification, are permitted provided that the following conditions
     56  * are met:
     57  * 1. Redistributions of source code must retain the above copyright
     58  *    notice, this list of conditions and the following disclaimer.
     59  * 2. Redistributions in binary form must reproduce the above copyright
     60  *    notice, this list of conditions and the following disclaimer in the
     61  *    documentation and/or other materials provided with the distribution.
     62  * 3. All advertising materials mentioning features or use of this software
     63  *    must display the following acknowledgement:
     64  *	This product includes software developed by the University of
     65  *	California, Berkeley and its contributors.
     66  * 4. Neither the name of the University nor the names of its contributors
     67  *    may be used to endorse or promote products derived from this software
     68  *    without specific prior written permission.
     69  *
     70  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     71  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     72  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     73  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     74  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     75  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     76  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     77  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     78  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     79  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     80  * SUCH DAMAGE.
     81  *
     82  *	@(#)kbd.c	8.2 (Berkeley) 10/30/93
     83  */
     84 
     85 /*
     86  * Keyboard driver (/dev/wskbd*).  Translates incoming bytes to ASCII or
     87  * to `wscons_events' and passes them up to the appropriate reader.
     88  */
     89 
     90 #include "opt_ddb.h"
     91 
     92 #include <sys/param.h>
     93 #include <sys/conf.h>
     94 #include <sys/device.h>
     95 #include <sys/ioctl.h>
     96 #include <sys/kernel.h>
     97 #include <sys/proc.h>
     98 #include <sys/syslog.h>
     99 #include <sys/systm.h>
    100 #include <sys/malloc.h>
    101 #include <sys/tty.h>
    102 #include <sys/signalvar.h>
    103 #include <sys/errno.h>
    104 #include <sys/fcntl.h>
    105 
    106 #include <dev/wscons/wsconsio.h>
    107 #include <dev/wscons/wskbdvar.h>
    108 #include <dev/wscons/wsksymdef.h>
    109 #include <dev/wscons/wsksymvar.h>
    110 #include <dev/wscons/wseventvar.h>
    111 #include <dev/wscons/wscons_callbacks.h>
    112 
    113 #include "opt_wsdisplay_compat.h"
    114 
    115 #include "wskbd.h"
    116 
    117 struct wskbd_internal {
    118 	const struct wskbd_mapdata *t_keymap;
    119 
    120 	const struct wskbd_consops *t_consops;
    121 	void	*t_consaccesscookie;
    122 
    123 	int	t_modifiers;
    124 	int	t_composelen;		/* remaining entries in t_composebuf */
    125 	keysym_t t_composebuf[2];
    126 
    127 	struct wskbd_softc *t_sc;	/* back pointer */
    128 };
    129 
    130 struct wskbd_softc {
    131 	struct device	sc_dv;
    132 
    133 	struct wskbd_internal *id;
    134 
    135 	const struct wskbd_accessops *sc_accessops;
    136 	void *sc_accesscookie;
    137 
    138 	int	sc_ledstate;
    139 
    140 	int	sc_ready;		/* accepting events */
    141 	struct wseventvar sc_events;	/* event queue state */
    142 
    143 	int	sc_isconsole;
    144 	struct device	*sc_displaydv;
    145 
    146 	struct wskbd_bell_data sc_bell_data;
    147 	struct wskbd_keyrepeat_data sc_keyrepeat_data;
    148 
    149 	int	sc_repeating;		/* we've called timeout() */
    150 	keysym_t sc_repeatsym;		/* repeated symbol */
    151 
    152 	int	sc_translating;		/* xlate to chars for emulation */
    153 
    154 	int	sc_maplen;		/* number of entries in sc_map */
    155 	struct wscons_keymap *sc_map;	/* current translation map */
    156 	kbd_t sc_layout; /* current layout */
    157 };
    158 
    159 #define MOD_SHIFT_L		(1 << 0)
    160 #define MOD_SHIFT_R		(1 << 1)
    161 #define MOD_SHIFTLOCK		(1 << 2)
    162 #define MOD_CAPSLOCK		(1 << 3)
    163 #define MOD_CONTROL_L		(1 << 4)
    164 #define MOD_CONTROL_R		(1 << 5)
    165 #define MOD_META_L		(1 << 6)
    166 #define MOD_META_R		(1 << 7)
    167 #define MOD_MODESHIFT		(1 << 8)
    168 #define MOD_NUMLOCK		(1 << 9)
    169 #define MOD_COMPOSE		(1 << 10)
    170 #define MOD_HOLDSCREEN		(1 << 11)
    171 #define MOD_COMMAND		(1 << 12)
    172 #define MOD_COMMAND1		(1 << 13)
    173 #define MOD_COMMAND2		(1 << 14)
    174 
    175 #define MOD_ANYSHIFT		(MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK)
    176 #define MOD_ANYCONTROL		(MOD_CONTROL_L | MOD_CONTROL_R)
    177 #define MOD_ANYMETA		(MOD_META_L | MOD_META_R)
    178 
    179 #define MOD_ONESET(id, mask)	(((id)->t_modifiers & (mask)) != 0)
    180 #define MOD_ALLSET(id, mask)	(((id)->t_modifiers & (mask)) == (mask))
    181 
    182 int	wskbd_match __P((struct device *, struct cfdata *, void *));
    183 void	wskbd_attach __P((struct device *, struct device *, void *));
    184 static inline void update_leds __P((struct wskbd_internal *));
    185 static inline void update_modifier __P((struct wskbd_internal *, u_int, int, int));
    186 static int internal_command __P((struct wskbd_softc *, u_int *, keysym_t));
    187 static keysym_t wskbd_translate __P((struct wskbd_internal *, u_int, int));
    188 static void wskbd_holdscreen __P((struct wskbd_softc *, int));
    189 
    190 
    191 struct cfattach wskbd_ca = {
    192 	sizeof (struct wskbd_softc), wskbd_match, wskbd_attach,
    193 };
    194 
    195 #if NWSKBD > 0
    196 extern struct cfdriver wskbd_cd;
    197 #endif
    198 
    199 #ifndef WSKBD_DEFAULT_BELL_PITCH
    200 #define	WSKBD_DEFAULT_BELL_PITCH	1500	/* 1500Hz */
    201 #endif
    202 #ifndef WSKBD_DEFAULT_BELL_PERIOD
    203 #define	WSKBD_DEFAULT_BELL_PERIOD	100	/* 100ms */
    204 #endif
    205 #ifndef WSKBD_DEFAULT_BELL_VOLUME
    206 #define	WSKBD_DEFAULT_BELL_VOLUME	50	/* 50% volume */
    207 #endif
    208 
    209 struct wskbd_bell_data wskbd_default_bell_data = {
    210 	WSKBD_BELL_DOALL,
    211 	WSKBD_DEFAULT_BELL_PITCH,
    212 	WSKBD_DEFAULT_BELL_PERIOD,
    213 	WSKBD_DEFAULT_BELL_VOLUME,
    214 };
    215 
    216 #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1
    217 #define	WSKBD_DEFAULT_KEYREPEAT_DEL1	400	/* 400ms to start repeating */
    218 #endif
    219 #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN
    220 #define	WSKBD_DEFAULT_KEYREPEAT_DELN	100	/* 100ms to between repeats */
    221 #endif
    222 
    223 struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = {
    224 	WSKBD_KEYREPEAT_DOALL,
    225 	WSKBD_DEFAULT_KEYREPEAT_DEL1,
    226 	WSKBD_DEFAULT_KEYREPEAT_DELN,
    227 };
    228 
    229 cdev_decl(wskbd);
    230 static void wskbd_repeat __P((void *v));
    231 
    232 static int wskbd_console_initted;
    233 static struct wskbd_softc *wskbd_console_device;
    234 static struct wskbd_internal wskbd_console_data;
    235 
    236 /*
    237  * Print function (for parent devices).
    238  */
    239 int
    240 wskbddevprint(aux, pnp)
    241 	void *aux;
    242 	const char *pnp;
    243 {
    244 #if 0
    245 	struct wskbddev_attach_args *ap = aux;
    246 #endif
    247 
    248 	if (pnp)
    249 		printf("wskbd at %s", pnp);
    250 #if 0
    251 	printf(" console %d", ap->console);
    252 #endif
    253 
    254 	return (UNCONF);
    255 }
    256 
    257 int
    258 wskbd_match(parent, match, aux)
    259 	struct device *parent;
    260 	struct cfdata *match;
    261 	void *aux;
    262 {
    263 	struct wskbddev_attach_args *ap = aux;
    264 
    265 	if (match->wskbddevcf_console != WSKBDDEVCF_CONSOLE_UNK) {
    266 		/*
    267 		 * If console-ness of device specified, either match
    268 		 * exactly (at high priority), or fail.
    269 		 */
    270 		if (match->wskbddevcf_console != 0 && ap->console != 0)
    271 			return (10);
    272 		else
    273 			return (0);
    274 	}
    275 
    276 	/* If console-ness unspecified, it wins. */
    277 	return (1);
    278 }
    279 
    280 void
    281 wskbd_attach(parent, self, aux)
    282 	struct device *parent, *self;
    283 	void *aux;
    284 {
    285 	struct wskbd_softc *sc = (struct wskbd_softc *)self;
    286 	struct wskbddev_attach_args *ap = aux;
    287 
    288 	if (ap->console)
    289 		printf(": console keyboard");
    290 	printf("\n");
    291 
    292 	if (ap->console) {
    293 		sc->id = &wskbd_console_data;
    294 	} else {
    295 		sc->id = malloc(sizeof(struct wskbd_internal),
    296 				M_DEVBUF, M_WAITOK);
    297 		sc->id->t_keymap = ap->keymap;
    298 		sc->id->t_modifiers = 0;
    299 	}
    300 
    301 	sc->id->t_sc = sc;
    302 
    303 	sc->sc_accessops = ap->accessops;
    304 	sc->sc_accesscookie = ap->accesscookie;
    305 	sc->sc_ready = 0;				/* sanity */
    306 	sc->sc_repeating = 0;
    307 	sc->sc_translating = 1;
    308 	sc->sc_ledstate = -1; /* force update */
    309 
    310 	if (wskbd_load_keymap(sc->id->t_keymap,
    311 			      &sc->sc_map, &sc->sc_maplen) != 0)
    312 		panic("cannot load keymap");
    313 
    314 	sc->sc_layout = sc->id->t_keymap->layout;
    315 
    316 	if (ap->console) {
    317 		KASSERT(wskbd_console_initted);
    318 		KASSERT(wskbd_console_device == NULL);
    319 		wskbd_console_device = sc;
    320 	}
    321 	sc->sc_isconsole = ap->console;
    322 	sc->sc_displaydv = NULL;
    323 
    324 	/* set default bell and key repeat data */
    325 	sc->sc_bell_data = wskbd_default_bell_data;
    326 	sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data;
    327 }
    328 
    329 void
    330 wskbd_cnattach(consops, conscookie, mapdata)
    331 	const struct wskbd_consops *consops;
    332 	void *conscookie;
    333 	const struct wskbd_mapdata *mapdata;
    334 {
    335 
    336 	KASSERT(!wskbd_console_initted);
    337 
    338 	wskbd_console_data.t_keymap = mapdata;
    339 
    340 	wskbd_console_data.t_consops = consops;
    341 	wskbd_console_data.t_consaccesscookie = conscookie;
    342 
    343 	wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc);
    344 
    345 	wskbd_console_initted = 1;
    346 }
    347 
    348 static void
    349 wskbd_repeat(v)
    350 	void *v;
    351 {
    352 	struct wskbd_softc *sc = (struct wskbd_softc *)v;
    353 	int s = spltty();
    354 
    355 	KASSERT(sc->sc_repeating);
    356 	if (sc->sc_displaydv != NULL)
    357 		wsdisplay_kbdinput(sc->sc_displaydv, sc->sc_repeatsym);
    358 	timeout(wskbd_repeat, sc,
    359 		(hz * sc->sc_keyrepeat_data.delN) / 1000);
    360 	splx(s);
    361 }
    362 
    363 void
    364 wskbd_input(dev, type, value)
    365 	struct device *dev;
    366 	u_int type;
    367 	int value;
    368 {
    369 	struct wskbd_softc *sc = (struct wskbd_softc *)dev;
    370 	struct wscons_event *ev;
    371 	struct timeval xxxtime;
    372 	keysym_t ks;
    373 	int put;
    374 
    375 	if (sc->sc_repeating) {
    376 		sc->sc_repeating = 0;
    377 		untimeout(wskbd_repeat, sc);
    378 	}
    379 
    380 	/*
    381 	 * If /dev/kbd is not connected in event mode translate and
    382 	 * send upstream.
    383 	 */
    384 	if (sc->sc_translating) {
    385 		ks = wskbd_translate(sc->id, type, value);
    386 		if (ks != KS_voidSymbol) {
    387 			sc->sc_repeatsym = ks;
    388 			if (sc->sc_displaydv != NULL)
    389 				wsdisplay_kbdinput(sc->sc_displaydv,
    390 						   sc->sc_repeatsym);
    391 
    392 			sc->sc_repeating = 1;
    393 			timeout(wskbd_repeat, sc,
    394 				(hz * sc->sc_keyrepeat_data.del1) / 1000);
    395 		}
    396 		return;
    397 	}
    398 
    399 	/*
    400 	 * Keyboard is generating events.  Turn this keystroke into an
    401 	 * event and put it in the queue.  If the queue is full, the
    402 	 * keystroke is lost (sorry!).
    403 	 */
    404 
    405 	/* no one to receive; punt!*/
    406 	if (!sc->sc_ready)
    407 		return;
    408 
    409 	put = sc->sc_events.put;
    410 	ev = &sc->sc_events.q[put];
    411 	put = (put + 1) % WSEVENT_QSIZE;
    412 	if (put == sc->sc_events.get) {
    413 		log(LOG_WARNING, "%s: event queue overflow\n",
    414 		    sc->sc_dv.dv_xname);
    415 		return;
    416 	}
    417 	ev->type = type;
    418 	ev->value = value;
    419 	microtime(&xxxtime);
    420 	TIMEVAL_TO_TIMESPEC(&xxxtime, &ev->time);
    421 	sc->sc_events.put = put;
    422 	WSEVENT_WAKEUP(&sc->sc_events);
    423 }
    424 
    425 #ifdef WSDISPLAY_COMPAT_RAWKBD
    426 void
    427 wskbd_rawinput(dev, buf, len)
    428 	struct device *dev;
    429 	char *buf;
    430 	int len;
    431 {
    432 	struct wskbd_softc *sc = (struct wskbd_softc *)dev;
    433 	int i;
    434 
    435 	for (i = 0; i < len; i++)
    436 		wsdisplay_kbdinput(sc->sc_displaydv, buf[i]);
    437 	/* this is KS_GROUP_Ascii */
    438 }
    439 #endif
    440 
    441 static void
    442 wskbd_holdscreen(sc, hold)
    443 	struct wskbd_softc *sc;
    444 	int hold;
    445 {
    446 	int new_state;
    447 
    448 	if (sc->sc_displaydv != NULL) {
    449 		wsdisplay_kbdholdscreen(sc->sc_displaydv, hold);
    450 		new_state = sc->sc_ledstate;
    451 		if (hold)
    452 			new_state |= WSKBD_LED_SCROLL;
    453 		else
    454 			new_state &= ~WSKBD_LED_SCROLL;
    455 		if (new_state != sc->sc_ledstate) {
    456 			(*sc->sc_accessops->set_leds)(sc->sc_accesscookie,
    457 						      new_state);
    458 			sc->sc_ledstate = new_state;
    459 		}
    460 	}
    461 }
    462 
    463 int
    464 wskbd_enable(dev, on)
    465 	struct device *dev;
    466 	int on;
    467 {
    468 	struct wskbd_softc *sc = (struct wskbd_softc *)dev;
    469 	int res;
    470 
    471 	/* XXX reference count? */
    472 	if (!on && (!sc->sc_translating || sc->sc_displaydv))
    473 		return (EBUSY);
    474 
    475 	res = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on);
    476 	return (res);
    477 }
    478 
    479 int
    480 wskbdopen(dev, flags, mode, p)
    481 	dev_t dev;
    482 	int flags, mode;
    483 	struct proc *p;
    484 {
    485 #if NWSKBD > 0
    486 	struct wskbd_softc *sc;
    487 	int unit;
    488 
    489 	unit = minor(dev);
    490 	if (unit >= wskbd_cd.cd_ndevs ||	/* make sure it was attached */
    491 	    (sc = wskbd_cd.cd_devs[unit]) == NULL)
    492 		return (ENXIO);
    493 
    494 	if (sc->sc_events.io)			/* and that it's not in use */
    495 		return (EBUSY);
    496 
    497 	sc->sc_events.io = p;
    498 	wsevent_init(&sc->sc_events);		/* may cause sleep */
    499 
    500 	sc->sc_translating = 0;
    501 	sc->sc_ready = 1;			/* start accepting events */
    502 
    503 	wskbd_enable((struct device *)sc, 1);
    504 
    505 	return (0);
    506 #else
    507 	return (ENXIO);
    508 #endif /* NWSKBD > 0 */
    509 }
    510 
    511 int
    512 wskbdclose(dev, flags, mode, p)
    513 	dev_t dev;
    514 	int flags, mode;
    515 	struct proc *p;
    516 {
    517 #if NWSKBD > 0
    518 	struct wskbd_softc *sc;
    519 	int unit;
    520 
    521 	unit = minor(dev);
    522 	if (unit >= wskbd_cd.cd_ndevs ||	/* make sure it was attached */
    523 	    (sc = wskbd_cd.cd_devs[unit]) == NULL)
    524 		return (ENXIO);
    525 
    526 	sc->sc_ready = 0;			/* stop accepting events */
    527 	sc->sc_translating = 1;
    528 
    529 	wsevent_fini(&sc->sc_events);
    530 	sc->sc_events.io = NULL;
    531 
    532 	wskbd_enable((struct device *)sc, 0);
    533 #endif /* NWSKBD > 0 */
    534 	return (0);
    535 }
    536 
    537 int
    538 wskbdread(dev, uio, flags)
    539 	dev_t dev;
    540 	struct uio *uio;
    541 	int flags;
    542 {
    543 #if NWSKBD > 0
    544 	struct wskbd_softc *sc;
    545 	int unit;
    546 
    547 	unit = minor(dev);
    548 	if (unit >= wskbd_cd.cd_ndevs ||	/* make sure it was attached */
    549 	    (sc = wskbd_cd.cd_devs[unit]) == NULL)
    550 		return (ENXIO);
    551 
    552 	return (wsevent_read(&sc->sc_events, uio, flags));
    553 #else
    554 	return (ENXIO);
    555 #endif /* NWSKBD > 0 */
    556 }
    557 
    558 int
    559 wskbdioctl(dev, cmd, data, flag, p)
    560 	dev_t dev;
    561 	u_long cmd;
    562 	caddr_t data;
    563 	int flag;
    564 	struct proc *p;
    565 {
    566 #if NWSKBD > 0
    567 	struct wskbd_softc *sc;
    568 	int unit, error;
    569 
    570 	unit = minor(dev);
    571 	if (unit >= wskbd_cd.cd_ndevs ||	/* make sure it was attached */
    572 	    (sc = wskbd_cd.cd_devs[unit]) == NULL)
    573 		return (ENXIO);
    574 
    575 	/*
    576 	 * Try the generic ioctls that the wskbd interface supports.
    577 	 */
    578 	switch (cmd) {
    579 	case FIONBIO:		/* we will remove this someday (soon???) */
    580 		return (0);
    581 
    582 	case FIOASYNC:
    583 		sc->sc_events.async = *(int *)data != 0;
    584 		return (0);
    585 
    586 	case TIOCSPGRP:
    587 		if (*(int *)data != sc->sc_events.io->p_pgid)
    588 			return (EPERM);
    589 		return (0);
    590 	}
    591 
    592 	/*
    593 	 * Try the keyboard driver for WSKBDIO ioctls.  It returns -1
    594 	 * if it didn't recognize the request.
    595 	 */
    596 	error = wskbd_displayioctl((struct device *)sc, cmd, data, flag, p);
    597 	return (error != -1 ? error : ENOTTY);
    598 #else
    599 	return (ENXIO);
    600 #endif /* NWSKBD > 0 */
    601 }
    602 
    603 /*
    604  * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
    605  * Some of these have no real effect in raw mode, however.
    606  */
    607 int
    608 wskbd_displayioctl(dev, cmd, data, flag, p)
    609 	struct device *dev;
    610 	u_long cmd;
    611 	caddr_t data;
    612 	int flag;
    613 	struct proc *p;
    614 {
    615 	struct wskbd_softc *sc = (struct wskbd_softc *)dev;
    616 	struct wskbd_bell_data *ubdp, *kbdp;
    617 	struct wskbd_keyrepeat_data *ukdp, *kkdp;
    618 	struct wskbd_map_data *umdp;
    619 	struct wskbd_mapdata md;
    620 	void *buf;
    621 	int len, error;
    622 
    623 	switch (cmd) {
    624 #define	SETBELL(dstp, srcp, dfltp)					\
    625     do {								\
    626 	(dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ?		\
    627 	    (srcp)->pitch : (dfltp)->pitch;				\
    628 	(dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ?	\
    629 	    (srcp)->period : (dfltp)->period;				\
    630 	(dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ?	\
    631 	    (srcp)->volume : (dfltp)->volume;				\
    632 	(dstp)->which = WSKBD_BELL_DOALL;				\
    633     } while (0)
    634 
    635 	case WSKBDIO_BELL:
    636 		if ((flag & FWRITE) == 0)
    637 			return (EACCES);
    638 		return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
    639 		    WSKBDIO_COMPLEXBELL, (caddr_t)&sc->sc_bell_data, flag, p));
    640 
    641 	case WSKBDIO_COMPLEXBELL:
    642 		if ((flag & FWRITE) == 0)
    643 			return (EACCES);
    644 		ubdp = (struct wskbd_bell_data *)data;
    645 		SETBELL(ubdp, ubdp, &sc->sc_bell_data);
    646 		return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
    647 		    WSKBDIO_COMPLEXBELL, (caddr_t)ubdp, flag, p));
    648 
    649 	case WSKBDIO_SETBELL:
    650 		if ((flag & FWRITE) == 0)
    651 			return (EACCES);
    652 		kbdp = &sc->sc_bell_data;
    653 setbell:
    654 		ubdp = (struct wskbd_bell_data *)data;
    655 		SETBELL(kbdp, ubdp, kbdp);
    656 		return (0);
    657 
    658 	case WSKBDIO_GETBELL:
    659 		kbdp = &sc->sc_bell_data;
    660 getbell:
    661 		ubdp = (struct wskbd_bell_data *)data;
    662 		SETBELL(ubdp, kbdp, kbdp);
    663 		return (0);
    664 
    665 	case WSKBDIO_SETDEFAULTBELL:
    666 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    667 			return (error);
    668 		kbdp = &wskbd_default_bell_data;
    669 		goto setbell;
    670 
    671 
    672 	case WSKBDIO_GETDEFAULTBELL:
    673 		kbdp = &wskbd_default_bell_data;
    674 		goto getbell;
    675 
    676 #undef SETBELL
    677 
    678 #define	SETKEYREPEAT(dstp, srcp, dfltp)					\
    679     do {								\
    680 	(dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ?	\
    681 	    (srcp)->del1 : (dfltp)->del1;				\
    682 	(dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ?	\
    683 	    (srcp)->delN : (dfltp)->delN;				\
    684 	(dstp)->which = WSKBD_KEYREPEAT_DOALL;				\
    685     } while (0)
    686 
    687 	case WSKBDIO_SETKEYREPEAT:
    688 		if ((flag & FWRITE) == 0)
    689 			return (EACCES);
    690 		kkdp = &sc->sc_keyrepeat_data;
    691 setkeyrepeat:
    692 		ukdp = (struct wskbd_keyrepeat_data *)data;
    693 		SETKEYREPEAT(kkdp, ukdp, kkdp);
    694 		return (0);
    695 
    696 	case WSKBDIO_GETKEYREPEAT:
    697 		kkdp = &sc->sc_keyrepeat_data;
    698 getkeyrepeat:
    699 		ukdp = (struct wskbd_keyrepeat_data *)data;
    700 		SETKEYREPEAT(ukdp, kkdp, kkdp);
    701 		return (0);
    702 
    703 	case WSKBDIO_SETDEFAULTKEYREPEAT:
    704 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    705 			return (error);
    706 		kkdp = &wskbd_default_keyrepeat_data;
    707 		goto setkeyrepeat;
    708 
    709 
    710 	case WSKBDIO_GETDEFAULTKEYREPEAT:
    711 		kkdp = &wskbd_default_keyrepeat_data;
    712 		goto getkeyrepeat;
    713 
    714 #undef SETKEYREPEAT
    715 
    716 	case WSKBDIO_SETMAP:
    717 		if ((flag & FWRITE) == 0)
    718 			return (EACCES);
    719 		umdp = (struct wskbd_map_data *)data;
    720 		len = umdp->maplen*sizeof(struct wscons_keymap);
    721 		buf = malloc(len, M_TEMP, M_WAITOK);
    722 		error = copyin(umdp->map, buf, len);
    723 		if (error == 0) {
    724 			wskbd_init_keymap(umdp->maplen,
    725 					  &sc->sc_map, &sc->sc_maplen);
    726 			bcopy(buf, sc->sc_map, len);
    727 		}
    728 		free(buf, M_TEMP);
    729 		return(error);
    730 
    731 	case WSKBDIO_GETMAP:
    732 		umdp = (struct wskbd_map_data *)data;
    733 		if (umdp->maplen > sc->sc_maplen)
    734 			umdp->maplen = sc->sc_maplen;
    735 		error = copyout(sc->sc_map, umdp->map,
    736 				umdp->maplen*sizeof(struct wscons_keymap));
    737 		return(error);
    738 
    739 	case WSKBDIO_GETENCODING:
    740 		*((kbd_t *) data) = sc->sc_layout;
    741 		return(0);
    742 
    743 	case WSKBDIO_SETENCODING:
    744 		if ((flag & FWRITE) == 0)
    745 			return (EACCES);
    746 		md = *(sc->id->t_keymap); /* structure assignment */
    747 		md.layout = *((kbd_t *)data);
    748 		error = wskbd_load_keymap(&md, &sc->sc_map, &sc->sc_maplen);
    749 		if (error == 0)
    750 			sc->sc_layout = *((kbd_t *)data);
    751 		return(error);
    752 	}
    753 
    754 	/*
    755 	 * Try the keyboard driver for WSKBDIO ioctls.  It returns -1
    756 	 * if it didn't recognize the request, and in turn we return
    757 	 * -1 if we didn't recognize the request.
    758 	 */
    759 /* printf("kbdaccess\n"); */
    760 	error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
    761 					   flag, p);
    762 #ifdef WSDISPLAY_COMPAT_RAWKBD
    763 	if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
    764 		int s = spltty();
    765 		sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
    766 					 | MOD_CONTROL_L | MOD_CONTROL_R
    767 					 | MOD_META_L | MOD_META_R
    768 					 | MOD_COMMAND
    769 					 | MOD_COMMAND1 | MOD_COMMAND2);
    770 		if (sc->sc_repeating) {
    771 			sc->sc_repeating = 0;
    772 			untimeout(wskbd_repeat, sc);
    773 		}
    774 		splx(s);
    775 	}
    776 #endif
    777 	return (error);
    778 }
    779 
    780 int
    781 wskbdpoll(dev, events, p)
    782 	dev_t dev;
    783 	int events;
    784 	struct proc *p;
    785 {
    786 #if NWSKBD > 0
    787 	struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
    788 
    789 	return (wsevent_poll(&sc->sc_events, events, p));
    790 #else
    791 	return (0);
    792 #endif /* NWSKBD > 0 */
    793 }
    794 
    795 int
    796 wskbd_is_console(dv)
    797 	struct device *dv;
    798 {
    799 	struct wskbd_softc *sc = (struct wskbd_softc *)dv;
    800 
    801 	KASSERT(sc != NULL);
    802 	return (sc->sc_isconsole);
    803 }
    804 
    805 struct device *
    806 wskbd_display(dv)
    807 	struct device *dv;
    808 {
    809 	struct wskbd_softc *sc = (struct wskbd_softc *)dv;
    810 
    811 	KASSERT(sc != NULL);
    812 	return (sc->sc_displaydv);
    813 }
    814 
    815 void
    816 wskbd_set_display(dv, displaydv)
    817 	struct device *dv, *displaydv;
    818 {
    819 	struct wskbd_softc *sc = (struct wskbd_softc *)dv;
    820 
    821 	KASSERT(sc != NULL);
    822 	sc->sc_displaydv = displaydv;
    823 }
    824 
    825 /*
    826  * Console interface.
    827  */
    828 int
    829 wskbd_cngetc(dev)
    830 	dev_t dev;
    831 {
    832 	u_int type;
    833 	int data;
    834 	keysym_t ks;
    835 
    836 	if (!wskbd_console_initted)
    837 		return 0;
    838 
    839 	if (wskbd_console_device != NULL &&
    840 	    !wskbd_console_device->sc_translating)
    841 		return 0;
    842 
    843 	for(;;) {
    844 		(*wskbd_console_data.t_consops->getc)
    845 		    (wskbd_console_data.t_consaccesscookie, &type, &data);
    846 		ks = wskbd_translate(&wskbd_console_data, type, data);
    847 
    848 		if (KS_GROUP(ks) == KS_GROUP_Ascii)
    849 			return (KS_VALUE(ks));
    850 	}
    851 }
    852 
    853 void
    854 wskbd_cnpollc(dev, poll)
    855 	dev_t dev;
    856 	int poll;
    857 {
    858 
    859 	if (!wskbd_console_initted)
    860 		return;
    861 
    862 	if (wskbd_console_device != NULL &&
    863 	    !wskbd_console_device->sc_translating)
    864 		return;
    865 
    866 	(*wskbd_console_data.t_consops->pollc)
    867 	    (wskbd_console_data.t_consaccesscookie, poll);
    868 }
    869 
    870 static inline void
    871 update_leds(id)
    872 	struct wskbd_internal *id;
    873 {
    874 	int new_state;
    875 
    876 	new_state = 0;
    877 	if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
    878 		new_state |= WSKBD_LED_CAPS;
    879 	if (id->t_modifiers & MOD_NUMLOCK)
    880 		new_state |= WSKBD_LED_NUM;
    881 	if (id->t_modifiers & MOD_COMPOSE)
    882 		new_state |= WSKBD_LED_COMPOSE;
    883 	if (id->t_modifiers & MOD_HOLDSCREEN)
    884 		new_state |= WSKBD_LED_SCROLL;
    885 
    886 	if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
    887 		(*id->t_sc->sc_accessops->set_leds)
    888 		    (id->t_sc->sc_accesscookie, new_state);
    889 		id->t_sc->sc_ledstate = new_state;
    890 	}
    891 }
    892 
    893 static inline void
    894 update_modifier(id, type, toggle, mask)
    895 	struct wskbd_internal *id;
    896 	u_int type;
    897 	int toggle;
    898 	int mask;
    899 {
    900 	if (toggle) {
    901 		if (type == WSCONS_EVENT_KEY_DOWN)
    902 			id->t_modifiers ^= mask;
    903 	} else {
    904 		if (type == WSCONS_EVENT_KEY_DOWN)
    905 			id->t_modifiers |= mask;
    906 		else
    907 			id->t_modifiers &= ~mask;
    908 	}
    909 }
    910 
    911 static int
    912 internal_command(sc, type, ksym)
    913 	struct wskbd_softc *sc;
    914 	u_int *type;
    915 	keysym_t ksym;
    916 {
    917 	switch (ksym) {
    918 	case KS_Cmd:
    919 		update_modifier(sc->id, *type, 0, MOD_COMMAND);
    920 		break;
    921 
    922 	case KS_Cmd1:
    923 		update_modifier(sc->id, *type, 0, MOD_COMMAND1);
    924 		break;
    925 
    926 	case KS_Cmd2:
    927 		update_modifier(sc->id, *type, 0, MOD_COMMAND2);
    928 		break;
    929 	}
    930 
    931 	if (*type != WSCONS_EVENT_KEY_DOWN ||
    932 	    (! MOD_ONESET(sc->id, MOD_COMMAND) &&
    933 	     ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)))
    934 		return (0);
    935 
    936 	switch (ksym) {
    937 #ifdef DDB
    938 	case KS_Cmd_Debugger:
    939 		if (sc->sc_isconsole)
    940 			Debugger();
    941 		/* discard this key (ddb discarded command modifiers) */
    942 		*type = WSCONS_EVENT_KEY_UP;
    943 		return (1);
    944 #endif
    945 
    946 	case KS_Cmd_Screen0:
    947 	case KS_Cmd_Screen1:
    948 	case KS_Cmd_Screen2:
    949 	case KS_Cmd_Screen3:
    950 	case KS_Cmd_Screen4:
    951 	case KS_Cmd_Screen5:
    952 	case KS_Cmd_Screen6:
    953 	case KS_Cmd_Screen7:
    954 	case KS_Cmd_Screen8:
    955 	case KS_Cmd_Screen9:
    956 		wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0);
    957 		return (1);
    958 	}
    959 	return (0);
    960 }
    961 
    962 static keysym_t
    963 wskbd_translate(id, type, value)
    964 	struct wskbd_internal *id;
    965 	u_int type;
    966 	int value;
    967 {
    968 	struct wskbd_softc *sc = id->t_sc;
    969 	keysym_t ksym, res, *group;
    970 	struct wscons_keymap kpbuf, *kp;
    971 	int iscommand = 0;
    972 
    973 	if (type == WSCONS_EVENT_ALL_KEYS_UP) {
    974 		id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
    975 				| MOD_CONTROL_L | MOD_CONTROL_R
    976 				| MOD_META_L | MOD_META_R
    977 				| MOD_MODESHIFT
    978 				| MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
    979 		update_leds(id);
    980 		return (KS_voidSymbol);
    981 	}
    982 
    983 	if (sc != NULL) {
    984 		if (value < 0 || value >= sc->sc_maplen) {
    985 #ifdef DEBUG
    986 			printf("wskbd_translate: keycode %d out of range\n",
    987 			       value);
    988 #endif
    989 			return (KS_voidSymbol);
    990 		}
    991 		kp = sc->sc_map + value;
    992 	} else {
    993 		kp = &kpbuf;
    994 		wskbd_get_mapentry(id->t_keymap, value, kp);
    995 	}
    996 
    997 	/* if this key has a command, process it first */
    998 	if (sc != NULL && kp->command != KS_voidSymbol)
    999 		iscommand = internal_command(sc, &type, kp->command);
   1000 
   1001 	/* Now update modifiers */
   1002 	switch (kp->group1[0]) {
   1003 	case KS_Shift_L:
   1004 		update_modifier(id, type, 0, MOD_SHIFT_L);
   1005 		break;
   1006 
   1007 	case KS_Shift_R:
   1008 		update_modifier(id, type, 0, MOD_SHIFT_R);
   1009 		break;
   1010 
   1011 	case KS_Shift_Lock:
   1012 		update_modifier(id, type, 1, MOD_SHIFTLOCK);
   1013 		break;
   1014 
   1015 	case KS_Caps_Lock:
   1016 		update_modifier(id, type, 1, MOD_CAPSLOCK);
   1017 		break;
   1018 
   1019 	case KS_Control_L:
   1020 		update_modifier(id, type, 0, MOD_CONTROL_L);
   1021 		break;
   1022 
   1023 	case KS_Control_R:
   1024 		update_modifier(id, type, 0, MOD_CONTROL_R);
   1025 		break;
   1026 
   1027 	case KS_Alt_L:
   1028 		update_modifier(id, type, 0, MOD_META_L);
   1029 		break;
   1030 
   1031 	case KS_Alt_R:
   1032 		update_modifier(id, type, 0, MOD_META_R);
   1033 		break;
   1034 
   1035 	case KS_Mode_switch:
   1036 		update_modifier(id, type, 0, MOD_MODESHIFT);
   1037 		break;
   1038 
   1039 	case KS_Num_Lock:
   1040 		update_modifier(id, type, 1, MOD_NUMLOCK);
   1041 		break;
   1042 
   1043 	case KS_Hold_Screen:
   1044 		if (sc != NULL) {
   1045 			update_modifier(id, type, 1, MOD_HOLDSCREEN);
   1046 			wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN);
   1047 		}
   1048 		break;
   1049 	}
   1050 
   1051 	/* If this is a key release or we are in command mode, we are done */
   1052 	if (type != WSCONS_EVENT_KEY_DOWN || iscommand) {
   1053 		update_leds(id);
   1054 		return (KS_voidSymbol);
   1055 	}
   1056 
   1057 	/* Get the keysym */
   1058 	if (id->t_modifiers & MOD_MODESHIFT)
   1059 		group = & kp->group2[0];
   1060 	else
   1061 		group = & kp->group1[0];
   1062 
   1063 	if ((id->t_modifiers & MOD_NUMLOCK) != 0 &&
   1064 	    KS_GROUP(group[1]) == KS_GROUP_Keypad) {
   1065 		if (MOD_ONESET(id, MOD_ANYSHIFT))
   1066 			ksym = group[0];
   1067 		else
   1068 			ksym = group[1];
   1069 	} else if (! MOD_ONESET(id, MOD_ANYSHIFT | MOD_CAPSLOCK)) {
   1070 		ksym = group[0];
   1071 	} else if (MOD_ONESET(id, MOD_CAPSLOCK)) {
   1072 		if (! MOD_ONESET(id, MOD_SHIFT_L | MOD_SHIFT_R))
   1073 			ksym = group[0];
   1074 		else
   1075 			ksym = group[1];
   1076 		if (ksym >= KS_a && ksym <= KS_z)
   1077 			ksym += KS_A - KS_a;
   1078 		else if (ksym >= KS_agrave && ksym <= KS_thorn &&
   1079 			 ksym != KS_division)
   1080 			ksym += KS_Agrave - KS_agrave;
   1081 	} else if (MOD_ONESET(id, MOD_ANYSHIFT)) {
   1082 		ksym = group[1];
   1083 	} else {
   1084 		ksym = group[0];
   1085 	}
   1086 
   1087 	/* Process compose sequence and dead accents */
   1088 	res = KS_voidSymbol;
   1089 
   1090 	switch (KS_GROUP(ksym)) {
   1091 	case KS_GROUP_Ascii:
   1092 	case KS_GROUP_Keypad:
   1093 	case KS_GROUP_Function:
   1094 		res = ksym;
   1095 		break;
   1096 
   1097 	case KS_GROUP_Mod:
   1098 		if (ksym == KS_Multi_key) {
   1099 			update_modifier(id, 1, 0, MOD_COMPOSE);
   1100 			id->t_composelen = 2;
   1101 		}
   1102 		break;
   1103 
   1104 	case KS_GROUP_Dead:
   1105 		if (id->t_composelen == 0) {
   1106 			update_modifier(id, 1, 0, MOD_COMPOSE);
   1107 			id->t_composelen = 1;
   1108 			id->t_composebuf[0] = ksym;
   1109 		} else
   1110 			res = ksym;
   1111 		break;
   1112 	}
   1113 
   1114 	if (res == KS_voidSymbol) {
   1115 		update_leds(id);
   1116 		return (res);
   1117 	}
   1118 
   1119 	if (id->t_composelen > 0) {
   1120 		id->t_composebuf[2 - id->t_composelen] = res;
   1121 		if (--id->t_composelen == 0) {
   1122 			res = wskbd_compose_value(id->t_composebuf);
   1123 			update_modifier(id, 0, 0, MOD_COMPOSE);
   1124 		} else {
   1125 			return (KS_voidSymbol);
   1126 		}
   1127 	}
   1128 
   1129 	update_leds(id);
   1130 
   1131 	/* We are done, return the symbol */
   1132 	if (KS_GROUP(res) == KS_GROUP_Ascii) {
   1133 		if (MOD_ONESET(id, MOD_ANYCONTROL)) {
   1134 			if ((res >= KS_at && res <= KS_z) || res == KS_space)
   1135 				res = res & 0x1f;
   1136 			else if (res == KS_2)
   1137 				res = 0x00;
   1138 			else if (res >= KS_3 && res <= KS_7)
   1139 				res = KS_Escape + (res - KS_3);
   1140 			else if (res == KS_8)
   1141 				res = KS_Delete;
   1142 		}
   1143 		if (MOD_ONESET(id, MOD_ANYMETA))
   1144 			res |= 0x80;
   1145 	}
   1146 
   1147 	return (res);
   1148 }
   1149