wskbd.c revision 1.27 1 /* $NetBSD: wskbd.c,v 1.27 1999/07/29 18:20:03 augustss 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.27 1999/07/29 18:20:03 augustss 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 #include <sys/vnode.h>
106
107 #include <dev/wscons/wsconsio.h>
108 #include <dev/wscons/wskbdvar.h>
109 #include <dev/wscons/wsksymdef.h>
110 #include <dev/wscons/wsksymvar.h>
111 #include <dev/wscons/wseventvar.h>
112 #include <dev/wscons/wscons_callbacks.h>
113
114 #include "opt_wsdisplay_compat.h"
115
116 #include "wsdisplay.h"
117 #include "wsmux.h"
118
119 #ifdef WSKBD_DEBUG
120 #define DPRINTF(x) if (wskbddebug) printf x
121 int wskbddebug = 0;
122 #else
123 #define DPRINTF(x)
124 #endif
125
126 #if NWSMUX > 0 || NWSDISPLAY > 0
127 #include <dev/wscons/wsmuxvar.h>
128 #endif
129
130 struct wskbd_internal {
131 const struct wskbd_mapdata *t_keymap;
132
133 const struct wskbd_consops *t_consops;
134 void *t_consaccesscookie;
135
136 int t_modifiers;
137 int t_composelen; /* remaining entries in t_composebuf */
138 keysym_t t_composebuf[2];
139
140 struct wskbd_softc *t_sc; /* back pointer */
141 };
142
143 struct wskbd_softc {
144 struct device sc_dv;
145
146 struct wskbd_internal *id;
147
148 const struct wskbd_accessops *sc_accessops;
149 void *sc_accesscookie;
150
151 int sc_ledstate;
152
153 int sc_ready; /* accepting events */
154 struct wseventvar sc_events; /* event queue state */
155
156 int sc_isconsole;
157 #if NWSDISPLAY > 0
158 struct device *sc_displaydv;
159 #endif
160
161 struct wskbd_bell_data sc_bell_data;
162 struct wskbd_keyrepeat_data sc_keyrepeat_data;
163
164 int sc_repeating; /* we've called timeout() */
165 keysym_t sc_repeatsym; /* repeated symbol */
166
167 int sc_translating; /* xlate to chars for emulation */
168
169 int sc_maplen; /* number of entries in sc_map */
170 struct wscons_keymap *sc_map; /* current translation map */
171 kbd_t sc_layout; /* current layout */
172
173 int sc_refcnt;
174 u_char sc_dying; /* device is being detached */
175
176 #if NWSMUX > 0 || NWSDISPLAY > 0
177 struct wsmux_softc *sc_mux;
178 #endif
179 };
180
181 #define MOD_SHIFT_L (1 << 0)
182 #define MOD_SHIFT_R (1 << 1)
183 #define MOD_SHIFTLOCK (1 << 2)
184 #define MOD_CAPSLOCK (1 << 3)
185 #define MOD_CONTROL_L (1 << 4)
186 #define MOD_CONTROL_R (1 << 5)
187 #define MOD_META_L (1 << 6)
188 #define MOD_META_R (1 << 7)
189 #define MOD_MODESHIFT (1 << 8)
190 #define MOD_NUMLOCK (1 << 9)
191 #define MOD_COMPOSE (1 << 10)
192 #define MOD_HOLDSCREEN (1 << 11)
193 #define MOD_COMMAND (1 << 12)
194 #define MOD_COMMAND1 (1 << 13)
195 #define MOD_COMMAND2 (1 << 14)
196
197 #define MOD_ANYSHIFT (MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK)
198 #define MOD_ANYCONTROL (MOD_CONTROL_L | MOD_CONTROL_R)
199 #define MOD_ANYMETA (MOD_META_L | MOD_META_R)
200
201 #define MOD_ONESET(id, mask) (((id)->t_modifiers & (mask)) != 0)
202 #define MOD_ALLSET(id, mask) (((id)->t_modifiers & (mask)) == (mask))
203
204 int wskbd_match __P((struct device *, struct cfdata *, void *));
205 void wskbd_attach __P((struct device *, struct device *, void *));
206 int wskbd_detach __P((struct device *, int));
207 int wskbd_activate __P((struct device *, enum devact));
208
209 static int wskbd_displayioctl
210 __P((struct device *, u_long, caddr_t, int, struct proc *p));
211 int wskbd_set_display __P((struct device *, struct wsmux_softc *));
212
213 static inline void update_leds __P((struct wskbd_internal *));
214 static inline void update_modifier __P((struct wskbd_internal *, u_int, int, int));
215 static int internal_command __P((struct wskbd_softc *, u_int *, keysym_t));
216 static keysym_t wskbd_translate __P((struct wskbd_internal *, u_int, int));
217 static int wskbd_enable __P((struct wskbd_softc *, int));
218 #if NWSDISPLAY > 0
219 static void wskbd_holdscreen __P((struct wskbd_softc *, int));
220 #endif
221
222 int wskbd_do_ioctl __P((struct wskbd_softc *, u_long, caddr_t,
223 int, struct proc *));
224
225 int wskbddoclose __P((struct device *, int, int, struct proc *));
226 int wskbddoioctl __P((struct device *, u_long, caddr_t, int,
227 struct proc *));
228
229 struct cfattach wskbd_ca = {
230 sizeof (struct wskbd_softc), wskbd_match, wskbd_attach,
231 wskbd_detach, wskbd_activate
232 };
233
234 extern struct cfdriver wskbd_cd;
235
236 #ifndef WSKBD_DEFAULT_BELL_PITCH
237 #define WSKBD_DEFAULT_BELL_PITCH 1500 /* 1500Hz */
238 #endif
239 #ifndef WSKBD_DEFAULT_BELL_PERIOD
240 #define WSKBD_DEFAULT_BELL_PERIOD 100 /* 100ms */
241 #endif
242 #ifndef WSKBD_DEFAULT_BELL_VOLUME
243 #define WSKBD_DEFAULT_BELL_VOLUME 50 /* 50% volume */
244 #endif
245
246 struct wskbd_bell_data wskbd_default_bell_data = {
247 WSKBD_BELL_DOALL,
248 WSKBD_DEFAULT_BELL_PITCH,
249 WSKBD_DEFAULT_BELL_PERIOD,
250 WSKBD_DEFAULT_BELL_VOLUME,
251 };
252
253 #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1
254 #define WSKBD_DEFAULT_KEYREPEAT_DEL1 400 /* 400ms to start repeating */
255 #endif
256 #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN
257 #define WSKBD_DEFAULT_KEYREPEAT_DELN 100 /* 100ms to between repeats */
258 #endif
259
260 struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = {
261 WSKBD_KEYREPEAT_DOALL,
262 WSKBD_DEFAULT_KEYREPEAT_DEL1,
263 WSKBD_DEFAULT_KEYREPEAT_DELN,
264 };
265
266 cdev_decl(wskbd);
267
268 struct wsmuxops wskbd_muxops = {
269 wskbdopen, wskbddoclose, wskbddoioctl, wskbd_displayioctl,
270 wskbd_set_display
271 };
272
273 #if NWSDISPLAY > 0
274 static void wskbd_repeat __P((void *v));
275 #endif
276
277 static int wskbd_console_initted;
278 static struct wskbd_softc *wskbd_console_device;
279 static struct wskbd_internal wskbd_console_data;
280
281 /*
282 * Print function (for parent devices).
283 */
284 int
285 wskbddevprint(aux, pnp)
286 void *aux;
287 const char *pnp;
288 {
289 #if 0
290 struct wskbddev_attach_args *ap = aux;
291 #endif
292
293 if (pnp)
294 printf("wskbd at %s", pnp);
295 #if 0
296 printf(" console %d", ap->console);
297 #endif
298
299 return (UNCONF);
300 }
301
302 int
303 wskbd_match(parent, match, aux)
304 struct device *parent;
305 struct cfdata *match;
306 void *aux;
307 {
308 struct wskbddev_attach_args *ap = aux;
309
310 if (match->wskbddevcf_console != WSKBDDEVCF_CONSOLE_UNK) {
311 /*
312 * If console-ness of device specified, either match
313 * exactly (at high priority), or fail.
314 */
315 if (match->wskbddevcf_console != 0 && ap->console != 0)
316 return (10);
317 else
318 return (0);
319 }
320
321 /* If console-ness unspecified, it wins. */
322 return (1);
323 }
324
325 void
326 wskbd_attach(parent, self, aux)
327 struct device *parent, *self;
328 void *aux;
329 {
330 struct wskbd_softc *sc = (struct wskbd_softc *)self;
331 struct wskbddev_attach_args *ap = aux;
332 #if NWSMUX > 0 || NWSDISPLAY > 0
333 int mux;
334 #endif
335
336 #if NWSDISPLAY > 0
337 sc->sc_displaydv = NULL;
338 #endif
339 sc->sc_isconsole = ap->console;
340
341 #if NWSMUX > 0 || NWSDISPLAY > 0
342 mux = sc->sc_dv.dv_cfdata->wskbddevcf_mux;
343 if (sc->sc_isconsole && mux != WSKBDDEVCF_MUX_DEFAULT) {
344 printf(" (mux ignored for console)");
345 mux = WSKBDDEVCF_MUX_DEFAULT;
346 }
347 if (mux != WSKBDDEVCF_MUX_DEFAULT)
348 printf(" mux %d", mux);
349 #endif
350
351 if (ap->console) {
352 sc->id = &wskbd_console_data;
353 } else {
354 sc->id = malloc(sizeof(struct wskbd_internal),
355 M_DEVBUF, M_WAITOK);
356 sc->id->t_keymap = ap->keymap;
357 sc->id->t_modifiers = 0;
358 }
359
360 sc->id->t_sc = sc;
361
362 sc->sc_accessops = ap->accessops;
363 sc->sc_accesscookie = ap->accesscookie;
364 sc->sc_ready = 0; /* sanity */
365 sc->sc_repeating = 0;
366 sc->sc_translating = 1;
367 sc->sc_ledstate = -1; /* force update */
368
369 if (wskbd_load_keymap(sc->id->t_keymap,
370 &sc->sc_map, &sc->sc_maplen) != 0)
371 panic("cannot load keymap");
372
373 sc->sc_layout = sc->id->t_keymap->layout;
374
375 /* set default bell and key repeat data */
376 sc->sc_bell_data = wskbd_default_bell_data;
377 sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data;
378
379 if (ap->console) {
380 KASSERT(wskbd_console_initted);
381 KASSERT(wskbd_console_device == NULL);
382
383 wskbd_console_device = sc;
384
385 printf(": console keyboard");
386
387 #if NWSDISPLAY > 0
388 if ((sc->sc_displaydv = wsdisplay_set_console_kbd(self)))
389 printf(", using %s", sc->sc_displaydv->dv_xname);
390 #endif
391 }
392 printf("\n");
393
394 #if NWSMUX > 0 || NWSDISPLAY > 0
395 if (mux != WSKBDDEVCF_MUX_DEFAULT)
396 wsmux_attach(mux, WSMUX_KBD, &sc->sc_dv, &sc->sc_events,
397 &sc->sc_mux, &wskbd_muxops);
398 #endif
399
400 }
401
402 void
403 wskbd_cnattach(consops, conscookie, mapdata)
404 const struct wskbd_consops *consops;
405 void *conscookie;
406 const struct wskbd_mapdata *mapdata;
407 {
408
409 KASSERT(!wskbd_console_initted);
410
411 wskbd_console_data.t_keymap = mapdata;
412
413 wskbd_console_data.t_consops = consops;
414 wskbd_console_data.t_consaccesscookie = conscookie;
415
416 #if NWSDISPLAY > 0
417 wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc);
418 #endif
419
420 wskbd_console_initted = 1;
421 }
422
423 #if NWSDISPLAY > 0
424 static void
425 wskbd_repeat(v)
426 void *v;
427 {
428 struct wskbd_softc *sc = (struct wskbd_softc *)v;
429 int s = spltty();
430
431 if (!sc->sc_repeating) {
432 /*
433 * race condition: a "key up" event came in when wskbd_repeat()
434 * was already called but not yet spltty()'d
435 */
436 splx(s);
437 return;
438 }
439 if (sc->sc_displaydv != NULL)
440 wsdisplay_kbdinput(sc->sc_displaydv, sc->sc_repeatsym);
441 timeout(wskbd_repeat, sc,
442 (hz * sc->sc_keyrepeat_data.delN) / 1000);
443 splx(s);
444 }
445 #endif
446
447 int
448 wskbd_activate(self, act)
449 struct device *self;
450 enum devact act;
451 {
452 /* XXX should we do something more? */
453 return (0);
454 }
455
456 /*
457 * Detach a keyboard. To keep track of users of the softc we keep
458 * a reference count that's incremented while inside, e.g., read.
459 * If the keyboard is active and the reference count is > 0 (0 is the
460 * normal state) we post an event and then wait for the process
461 * that had the reference to wake us up again. Then we blow away the
462 * vnode and return (which will deallocate the softc).
463 */
464 int
465 wskbd_detach(self, flags)
466 struct device *self;
467 int flags;
468 {
469 struct wskbd_softc *sc = (struct wskbd_softc *)self;
470 struct wseventvar *evar;
471 int maj, mn;
472 int s;
473 #if NWSMUX > 0 || NWSDISPLAY > 0
474 int mux;
475
476 mux = sc->sc_dv.dv_cfdata->wskbddevcf_mux;
477 if (mux != WSMOUSEDEVCF_MUX_DEFAULT)
478 wsmux_detach(mux, &sc->sc_dv);
479 #endif
480
481 evar = &sc->sc_events;
482 if (evar->io) {
483 s = spltty();
484 if (--sc->sc_refcnt >= 0) {
485 /* Wake everyone by generating a dummy event. */
486 if (++evar->put >= WSEVENT_QSIZE)
487 evar->put = 0;
488 WSEVENT_WAKEUP(evar);
489 /* Wait for processes to go away. */
490 if (tsleep(sc, PZERO, "wskdet", hz * 60))
491 printf("wskbd_detach: %s didn't detach\n",
492 sc->sc_dv.dv_xname);
493 }
494 splx(s);
495 }
496
497 /* locate the major number */
498 for (maj = 0; maj < nchrdev; maj++)
499 if (cdevsw[maj].d_open == wskbdopen)
500 break;
501
502 /* Nuke the vnodes for any open instances. */
503 mn = self->dv_unit;
504 vdevgone(maj, mn, mn, VCHR);
505
506 return (0);
507 }
508
509 void
510 wskbd_input(dev, type, value)
511 struct device *dev;
512 u_int type;
513 int value;
514 {
515 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
516 struct wscons_event *ev;
517 struct wseventvar *evar;
518 struct timeval xxxtime;
519 #if NWSDISPLAY > 0
520 keysym_t ks;
521 #endif
522 int put;
523
524 #if NWSDISPLAY > 0
525 if (sc->sc_repeating) {
526 sc->sc_repeating = 0;
527 untimeout(wskbd_repeat, sc);
528 }
529
530 /*
531 * If /dev/wskbd is not connected in event mode translate and
532 * send upstream.
533 */
534 if (sc->sc_translating) {
535 ks = wskbd_translate(sc->id, type, value);
536 if (ks != KS_voidSymbol) {
537 sc->sc_repeatsym = ks;
538 if (sc->sc_displaydv != NULL)
539 wsdisplay_kbdinput(sc->sc_displaydv,
540 sc->sc_repeatsym);
541
542 sc->sc_repeating = 1;
543 timeout(wskbd_repeat, sc,
544 (hz * sc->sc_keyrepeat_data.del1) / 1000);
545 }
546 return;
547 }
548 #endif
549
550 /*
551 * Keyboard is generating events. Turn this keystroke into an
552 * event and put it in the queue. If the queue is full, the
553 * keystroke is lost (sorry!).
554 */
555
556 /* no one to receive; punt!*/
557 if (!sc->sc_ready)
558 return;
559
560 #if NWSMUX > 0 || NWSDISPLAY > 0
561 if (sc->sc_mux)
562 evar = &sc->sc_mux->sc_events;
563 else
564 #endif
565 evar = &sc->sc_events;
566
567 put = evar->put;
568 ev = &evar->q[put];
569 put = (put + 1) % WSEVENT_QSIZE;
570 if (put == evar->get) {
571 log(LOG_WARNING, "%s: event queue overflow\n",
572 sc->sc_dv.dv_xname);
573 return;
574 }
575 ev->type = type;
576 ev->value = value;
577 microtime(&xxxtime);
578 TIMEVAL_TO_TIMESPEC(&xxxtime, &ev->time);
579 evar->put = put;
580 WSEVENT_WAKEUP(evar);
581 }
582
583 #ifdef WSDISPLAY_COMPAT_RAWKBD
584 void
585 wskbd_rawinput(dev, buf, len)
586 struct device *dev;
587 char *buf;
588 int len;
589 {
590 #if NWSDISPLAY > 0
591 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
592 int i;
593
594 for (i = 0; i < len; i++)
595 wsdisplay_kbdinput(sc->sc_displaydv, buf[i]);
596 /* this is KS_GROUP_Ascii */
597 #endif
598 }
599 #endif /* WSDISPLAY_COMPAT_RAWKBD */
600
601 #if NWSDISPLAY > 0
602 static void
603 wskbd_holdscreen(sc, hold)
604 struct wskbd_softc *sc;
605 int hold;
606 {
607 int new_state;
608
609 if (sc->sc_displaydv != NULL) {
610 wsdisplay_kbdholdscreen(sc->sc_displaydv, hold);
611 new_state = sc->sc_ledstate;
612 if (hold)
613 new_state |= WSKBD_LED_SCROLL;
614 else
615 new_state &= ~WSKBD_LED_SCROLL;
616 if (new_state != sc->sc_ledstate) {
617 (*sc->sc_accessops->set_leds)(sc->sc_accesscookie,
618 new_state);
619 sc->sc_ledstate = new_state;
620 }
621 }
622 }
623 #endif
624
625 static int
626 wskbd_enable(sc, on)
627 struct wskbd_softc *sc;
628 int on;
629 {
630 int res;
631
632 /* XXX reference count? */
633 if (!on && (!sc->sc_translating
634 #if NWSDISPLAY > 0
635 || sc->sc_displaydv
636 #endif
637 ))
638 return (EBUSY);
639
640 res = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on);
641 return (res);
642 }
643
644 int
645 wskbdopen(dev, flags, mode, p)
646 dev_t dev;
647 int flags, mode;
648 struct proc *p;
649 {
650 struct wskbd_softc *sc;
651 int unit;
652
653 unit = minor(dev);
654 if (unit >= wskbd_cd.cd_ndevs || /* make sure it was attached */
655 (sc = wskbd_cd.cd_devs[unit]) == NULL)
656 return (ENXIO);
657
658 if (sc->sc_dying)
659 return (EIO);
660
661 #if NWSMUX > 0 || NWSDISPLAY > 0
662 if (sc->sc_mux)
663 return (EBUSY);
664 #endif
665
666 if (sc->sc_events.io) /* and that it's not in use */
667 return (EBUSY);
668
669 sc->sc_events.io = p;
670 wsevent_init(&sc->sc_events); /* may cause sleep */
671
672 sc->sc_translating = 0;
673 sc->sc_ready = 1; /* start accepting events */
674
675 wskbd_enable(sc, 1);
676 return (0);
677 }
678
679 int
680 wskbdclose(dev, flags, mode, p)
681 dev_t dev;
682 int flags, mode;
683 struct proc *p;
684 {
685 return (wskbddoclose(wskbd_cd.cd_devs[minor(dev)], flags, mode, p));
686 }
687
688 int
689 wskbddoclose(dv, flags, mode, p)
690 struct device *dv;
691 int flags, mode;
692 struct proc *p;
693 {
694 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
695
696 sc->sc_ready = 0; /* stop accepting events */
697 sc->sc_translating = 1;
698
699 wsevent_fini(&sc->sc_events);
700 sc->sc_events.io = NULL;
701
702 wskbd_enable(sc, 0);
703 return (0);
704 }
705
706 int
707 wskbdread(dev, uio, flags)
708 dev_t dev;
709 struct uio *uio;
710 int flags;
711 {
712 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
713 int error;
714
715 if (sc->sc_dying)
716 return (EIO);
717
718 sc->sc_refcnt++;
719 error = wsevent_read(&sc->sc_events, uio, flags);
720 if (--sc->sc_refcnt < 0) {
721 wakeup(sc);
722 error = EIO;
723 }
724 return (error);
725 }
726
727 int
728 wskbdioctl(dev, cmd, data, flag, p)
729 dev_t dev;
730 u_long cmd;
731 caddr_t data;
732 int flag;
733 struct proc *p;
734 {
735 return (wskbddoioctl(wskbd_cd.cd_devs[minor(dev)], cmd, data, flag,p));
736 }
737
738 /* A wrapper around the ioctl() workhorse to make reference counting easy. */
739 int
740 wskbddoioctl(dv, cmd, data, flag, p)
741 struct device *dv;
742 u_long cmd;
743 caddr_t data;
744 int flag;
745 struct proc *p;
746 {
747 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
748 int error;
749
750 sc->sc_refcnt++;
751 error = wskbd_do_ioctl(sc, cmd, data, flag, p);
752 if (--sc->sc_refcnt < 0)
753 wakeup(sc);
754 return (error);
755 }
756
757 int
758 wskbd_do_ioctl(sc, cmd, data, flag, p)
759 struct wskbd_softc *sc;
760 u_long cmd;
761 caddr_t data;
762 int flag;
763 struct proc *p;
764 {
765 int error;
766
767 /*
768 * Try the generic ioctls that the wskbd interface supports.
769 */
770 switch (cmd) {
771 case FIONBIO: /* we will remove this someday (soon???) */
772 return (0);
773
774 case FIOASYNC:
775 sc->sc_events.async = *(int *)data != 0;
776 return (0);
777
778 case TIOCSPGRP:
779 if (*(int *)data != sc->sc_events.io->p_pgid)
780 return (EPERM);
781 return (0);
782 }
783
784 /*
785 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
786 * if it didn't recognize the request.
787 */
788 error = wskbd_displayioctl((struct device *)sc, cmd, data, flag, p);
789 return (error != -1 ? error : ENOTTY);
790 }
791
792 /*
793 * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
794 * Some of these have no real effect in raw mode, however.
795 */
796 static int
797 wskbd_displayioctl(dev, cmd, data, flag, p)
798 struct device *dev;
799 u_long cmd;
800 caddr_t data;
801 int flag;
802 struct proc *p;
803 {
804 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
805 struct wskbd_bell_data *ubdp, *kbdp;
806 struct wskbd_keyrepeat_data *ukdp, *kkdp;
807 struct wskbd_map_data *umdp;
808 struct wskbd_mapdata md;
809 void *buf;
810 int len, error;
811
812 switch (cmd) {
813 #define SETBELL(dstp, srcp, dfltp) \
814 do { \
815 (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ? \
816 (srcp)->pitch : (dfltp)->pitch; \
817 (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ? \
818 (srcp)->period : (dfltp)->period; \
819 (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ? \
820 (srcp)->volume : (dfltp)->volume; \
821 (dstp)->which = WSKBD_BELL_DOALL; \
822 } while (0)
823
824 case WSKBDIO_BELL:
825 if ((flag & FWRITE) == 0)
826 return (EACCES);
827 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
828 WSKBDIO_COMPLEXBELL, (caddr_t)&sc->sc_bell_data, flag, p));
829
830 case WSKBDIO_COMPLEXBELL:
831 if ((flag & FWRITE) == 0)
832 return (EACCES);
833 ubdp = (struct wskbd_bell_data *)data;
834 SETBELL(ubdp, ubdp, &sc->sc_bell_data);
835 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
836 WSKBDIO_COMPLEXBELL, (caddr_t)ubdp, flag, p));
837
838 case WSKBDIO_SETBELL:
839 if ((flag & FWRITE) == 0)
840 return (EACCES);
841 kbdp = &sc->sc_bell_data;
842 setbell:
843 ubdp = (struct wskbd_bell_data *)data;
844 SETBELL(kbdp, ubdp, kbdp);
845 return (0);
846
847 case WSKBDIO_GETBELL:
848 kbdp = &sc->sc_bell_data;
849 getbell:
850 ubdp = (struct wskbd_bell_data *)data;
851 SETBELL(ubdp, kbdp, kbdp);
852 return (0);
853
854 case WSKBDIO_SETDEFAULTBELL:
855 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
856 return (error);
857 kbdp = &wskbd_default_bell_data;
858 goto setbell;
859
860
861 case WSKBDIO_GETDEFAULTBELL:
862 kbdp = &wskbd_default_bell_data;
863 goto getbell;
864
865 #undef SETBELL
866
867 #define SETKEYREPEAT(dstp, srcp, dfltp) \
868 do { \
869 (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ? \
870 (srcp)->del1 : (dfltp)->del1; \
871 (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ? \
872 (srcp)->delN : (dfltp)->delN; \
873 (dstp)->which = WSKBD_KEYREPEAT_DOALL; \
874 } while (0)
875
876 case WSKBDIO_SETKEYREPEAT:
877 if ((flag & FWRITE) == 0)
878 return (EACCES);
879 kkdp = &sc->sc_keyrepeat_data;
880 setkeyrepeat:
881 ukdp = (struct wskbd_keyrepeat_data *)data;
882 SETKEYREPEAT(kkdp, ukdp, kkdp);
883 return (0);
884
885 case WSKBDIO_GETKEYREPEAT:
886 kkdp = &sc->sc_keyrepeat_data;
887 getkeyrepeat:
888 ukdp = (struct wskbd_keyrepeat_data *)data;
889 SETKEYREPEAT(ukdp, kkdp, kkdp);
890 return (0);
891
892 case WSKBDIO_SETDEFAULTKEYREPEAT:
893 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
894 return (error);
895 kkdp = &wskbd_default_keyrepeat_data;
896 goto setkeyrepeat;
897
898
899 case WSKBDIO_GETDEFAULTKEYREPEAT:
900 kkdp = &wskbd_default_keyrepeat_data;
901 goto getkeyrepeat;
902
903 #undef SETKEYREPEAT
904
905 case WSKBDIO_SETMAP:
906 if ((flag & FWRITE) == 0)
907 return (EACCES);
908 umdp = (struct wskbd_map_data *)data;
909 len = umdp->maplen*sizeof(struct wscons_keymap);
910 buf = malloc(len, M_TEMP, M_WAITOK);
911 error = copyin(umdp->map, buf, len);
912 if (error == 0) {
913 wskbd_init_keymap(umdp->maplen,
914 &sc->sc_map, &sc->sc_maplen);
915 memcpy(sc->sc_map, buf, len);
916 sc->sc_layout = KB_USER;
917 }
918 free(buf, M_TEMP);
919 return(error);
920
921 case WSKBDIO_GETMAP:
922 umdp = (struct wskbd_map_data *)data;
923 if (umdp->maplen > sc->sc_maplen)
924 umdp->maplen = sc->sc_maplen;
925 error = copyout(sc->sc_map, umdp->map,
926 umdp->maplen*sizeof(struct wscons_keymap));
927 return(error);
928
929 case WSKBDIO_GETENCODING:
930 *((kbd_t *) data) = sc->sc_layout;
931 return(0);
932
933 case WSKBDIO_SETENCODING:
934 if ((flag & FWRITE) == 0)
935 return (EACCES);
936 md = *(sc->id->t_keymap); /* structure assignment */
937 md.layout = *((kbd_t *)data);
938 error = wskbd_load_keymap(&md, &sc->sc_map, &sc->sc_maplen);
939 if (error == 0)
940 sc->sc_layout = *((kbd_t *)data);
941 return(error);
942 }
943
944 /*
945 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
946 * if it didn't recognize the request, and in turn we return
947 * -1 if we didn't recognize the request.
948 */
949 /* printf("kbdaccess\n"); */
950 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
951 flag, p);
952 #ifdef WSDISPLAY_COMPAT_RAWKBD
953 if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
954 int s = spltty();
955 sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
956 | MOD_CONTROL_L | MOD_CONTROL_R
957 | MOD_META_L | MOD_META_R
958 | MOD_COMMAND
959 | MOD_COMMAND1 | MOD_COMMAND2);
960 #if NWSDISPLAY > 0
961 if (sc->sc_repeating) {
962 sc->sc_repeating = 0;
963 untimeout(wskbd_repeat, sc);
964 }
965 #endif
966 splx(s);
967 }
968 #endif
969 return (error);
970 }
971
972 int
973 wskbdpoll(dev, events, p)
974 dev_t dev;
975 int events;
976 struct proc *p;
977 {
978 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
979
980 return (wsevent_poll(&sc->sc_events, events, p));
981 }
982
983 #if NWSDISPLAY > 0
984
985 int
986 wskbd_pickfree()
987 {
988 int i;
989 struct wskbd_softc *sc;
990
991 for (i = 0; i < wskbd_cd.cd_ndevs; i++) {
992 if ((sc = wskbd_cd.cd_devs[i]) == NULL)
993 continue;
994 if (sc->sc_displaydv == NULL)
995 return (i);
996 }
997 return (-1);
998 }
999
1000 struct device *
1001 wskbd_set_console_display(displaydv, muxsc)
1002 struct device *displaydv;
1003 struct wsmux_softc *muxsc;
1004 {
1005 struct wskbd_softc *sc = wskbd_console_device;
1006
1007 if (!sc)
1008 return (0);
1009 sc->sc_displaydv = displaydv;
1010 (void)wsmux_attach_sc(muxsc, WSMUX_KBD, &sc->sc_dv, &sc->sc_events,
1011 &sc->sc_mux, &wskbd_muxops);
1012 return (&sc->sc_dv);
1013 }
1014
1015 int
1016 wskbd_set_display(dv, muxsc)
1017 struct device *dv;
1018 struct wsmux_softc *muxsc;
1019 {
1020 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
1021 struct device *displaydv = muxsc ? muxsc->sc_displaydv : 0;
1022 struct device *odisplaydv;
1023 int error;
1024
1025 DPRINTF(("wskbd_set_display: %s mux=%p disp=%p odisp=%p cons=%d\n",
1026 dv->dv_xname, muxsc, sc->sc_displaydv, displaydv,
1027 sc->sc_isconsole));
1028
1029 if (sc->sc_isconsole)
1030 return (EBUSY);
1031
1032 if (displaydv) {
1033 if (sc->sc_displaydv)
1034 return (EBUSY);
1035 } else {
1036 if (sc->sc_displaydv == NULL)
1037 return (ENXIO);
1038 }
1039
1040 odisplaydv = sc->sc_displaydv;
1041 sc->sc_displaydv = displaydv;
1042
1043 error = wskbd_enable(sc, displaydv != NULL);
1044 if (error) {
1045 sc->sc_displaydv = odisplaydv;
1046 return (error);
1047 }
1048
1049 if (displaydv)
1050 printf("%s: connecting to %s\n",
1051 sc->sc_dv.dv_xname, displaydv->dv_xname);
1052 else
1053 printf("%s: disconnecting from %s\n",
1054 sc->sc_dv.dv_xname, odisplaydv->dv_xname);
1055
1056 return (0);
1057 }
1058
1059 int
1060 wskbd_add_mux(unit, muxsc)
1061 int unit;
1062 struct wsmux_softc *muxsc;
1063 {
1064 struct wskbd_softc *sc;
1065
1066 DPRINTF(("wskbd_add_mux: %d %s %p\n", unit, muxsc->sc_dv.dv_xname,
1067 muxsc->sc_displaydv));
1068 if (unit < 0 || unit >= wskbd_cd.cd_ndevs ||
1069 (sc = wskbd_cd.cd_devs[unit]) == NULL)
1070 return (ENXIO);
1071
1072 if (sc->sc_mux || sc->sc_events.io)
1073 return (EBUSY);
1074
1075 return (wsmux_attach_sc(muxsc, WSMUX_KBD, &sc->sc_dv, &sc->sc_events,
1076 &sc->sc_mux, &wskbd_muxops));
1077 }
1078
1079 int
1080 wskbd_rem_mux(unit, muxsc)
1081 int unit;
1082 struct wsmux_softc *muxsc;
1083 {
1084 struct wskbd_softc *sc;
1085
1086 DPRINTF(("wskbd_rem_mux: %d %s\n", unit, muxsc->sc_dv.dv_xname));
1087 if (unit < 0 || unit >= wskbd_cd.cd_ndevs ||
1088 (sc = wskbd_cd.cd_devs[unit]) == NULL)
1089 return (ENXIO);
1090
1091 return (wsmux_detach_sc(muxsc, &sc->sc_dv));
1092 }
1093
1094 #endif /* NWSDISPLAY > 0 */
1095
1096 /*
1097 * Console interface.
1098 */
1099 int
1100 wskbd_cngetc(dev)
1101 dev_t dev;
1102 {
1103 u_int type;
1104 int data;
1105 keysym_t ks;
1106
1107 if (!wskbd_console_initted)
1108 return 0;
1109
1110 if (wskbd_console_device != NULL &&
1111 !wskbd_console_device->sc_translating)
1112 return 0;
1113
1114 for(;;) {
1115 (*wskbd_console_data.t_consops->getc)
1116 (wskbd_console_data.t_consaccesscookie, &type, &data);
1117 ks = wskbd_translate(&wskbd_console_data, type, data);
1118
1119 if (KS_GROUP(ks) == KS_GROUP_Ascii)
1120 return (KS_VALUE(ks));
1121 }
1122 }
1123
1124 void
1125 wskbd_cnpollc(dev, poll)
1126 dev_t dev;
1127 int poll;
1128 {
1129
1130 if (!wskbd_console_initted)
1131 return;
1132
1133 if (wskbd_console_device != NULL &&
1134 !wskbd_console_device->sc_translating)
1135 return;
1136
1137 (*wskbd_console_data.t_consops->pollc)
1138 (wskbd_console_data.t_consaccesscookie, poll);
1139 }
1140
1141 static inline void
1142 update_leds(id)
1143 struct wskbd_internal *id;
1144 {
1145 int new_state;
1146
1147 new_state = 0;
1148 if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
1149 new_state |= WSKBD_LED_CAPS;
1150 if (id->t_modifiers & MOD_NUMLOCK)
1151 new_state |= WSKBD_LED_NUM;
1152 if (id->t_modifiers & MOD_COMPOSE)
1153 new_state |= WSKBD_LED_COMPOSE;
1154 if (id->t_modifiers & MOD_HOLDSCREEN)
1155 new_state |= WSKBD_LED_SCROLL;
1156
1157 if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
1158 (*id->t_sc->sc_accessops->set_leds)
1159 (id->t_sc->sc_accesscookie, new_state);
1160 id->t_sc->sc_ledstate = new_state;
1161 }
1162 }
1163
1164 static inline void
1165 update_modifier(id, type, toggle, mask)
1166 struct wskbd_internal *id;
1167 u_int type;
1168 int toggle;
1169 int mask;
1170 {
1171 if (toggle) {
1172 if (type == WSCONS_EVENT_KEY_DOWN)
1173 id->t_modifiers ^= mask;
1174 } else {
1175 if (type == WSCONS_EVENT_KEY_DOWN)
1176 id->t_modifiers |= mask;
1177 else
1178 id->t_modifiers &= ~mask;
1179 }
1180 }
1181
1182 static int
1183 internal_command(sc, type, ksym)
1184 struct wskbd_softc *sc;
1185 u_int *type;
1186 keysym_t ksym;
1187 {
1188 switch (ksym) {
1189 case KS_Cmd:
1190 update_modifier(sc->id, *type, 0, MOD_COMMAND);
1191 break;
1192
1193 case KS_Cmd1:
1194 update_modifier(sc->id, *type, 0, MOD_COMMAND1);
1195 break;
1196
1197 case KS_Cmd2:
1198 update_modifier(sc->id, *type, 0, MOD_COMMAND2);
1199 break;
1200 }
1201
1202 if (*type != WSCONS_EVENT_KEY_DOWN ||
1203 (! MOD_ONESET(sc->id, MOD_COMMAND) &&
1204 ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)))
1205 return (0);
1206
1207 switch (ksym) {
1208 #ifdef DDB
1209 case KS_Cmd_Debugger:
1210 if (sc->sc_isconsole)
1211 console_debugger();
1212 /* discard this key (ddb discarded command modifiers) */
1213 *type = WSCONS_EVENT_KEY_UP;
1214 return (1);
1215 #endif
1216
1217 #if NWSDISPLAY > 0
1218 case KS_Cmd_Screen0:
1219 case KS_Cmd_Screen1:
1220 case KS_Cmd_Screen2:
1221 case KS_Cmd_Screen3:
1222 case KS_Cmd_Screen4:
1223 case KS_Cmd_Screen5:
1224 case KS_Cmd_Screen6:
1225 case KS_Cmd_Screen7:
1226 case KS_Cmd_Screen8:
1227 case KS_Cmd_Screen9:
1228 wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0);
1229 return (1);
1230 case KS_Cmd_ResetEmul:
1231 wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETEMUL);
1232 return (1);
1233 case KS_Cmd_ResetClose:
1234 wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETCLOSE);
1235 return (1);
1236 #endif
1237 }
1238 return (0);
1239 }
1240
1241 static keysym_t
1242 wskbd_translate(id, type, value)
1243 struct wskbd_internal *id;
1244 u_int type;
1245 int value;
1246 {
1247 struct wskbd_softc *sc = id->t_sc;
1248 keysym_t ksym, res, *group;
1249 struct wscons_keymap kpbuf, *kp;
1250 int iscommand = 0;
1251
1252 if (type == WSCONS_EVENT_ALL_KEYS_UP) {
1253 id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
1254 | MOD_CONTROL_L | MOD_CONTROL_R
1255 | MOD_META_L | MOD_META_R
1256 | MOD_MODESHIFT
1257 | MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
1258 update_leds(id);
1259 return (KS_voidSymbol);
1260 }
1261
1262 if (sc != NULL) {
1263 if (value < 0 || value >= sc->sc_maplen) {
1264 #ifdef DEBUG
1265 printf("wskbd_translate: keycode %d out of range\n",
1266 value);
1267 #endif
1268 return (KS_voidSymbol);
1269 }
1270 kp = sc->sc_map + value;
1271 } else {
1272 kp = &kpbuf;
1273 wskbd_get_mapentry(id->t_keymap, value, kp);
1274 }
1275
1276 /* if this key has a command, process it first */
1277 if (sc != NULL && kp->command != KS_voidSymbol)
1278 iscommand = internal_command(sc, &type, kp->command);
1279
1280 /* Now update modifiers */
1281 switch (kp->group1[0]) {
1282 case KS_Shift_L:
1283 update_modifier(id, type, 0, MOD_SHIFT_L);
1284 break;
1285
1286 case KS_Shift_R:
1287 update_modifier(id, type, 0, MOD_SHIFT_R);
1288 break;
1289
1290 case KS_Shift_Lock:
1291 update_modifier(id, type, 1, MOD_SHIFTLOCK);
1292 break;
1293
1294 case KS_Caps_Lock:
1295 update_modifier(id, type, 1, MOD_CAPSLOCK);
1296 break;
1297
1298 case KS_Control_L:
1299 update_modifier(id, type, 0, MOD_CONTROL_L);
1300 break;
1301
1302 case KS_Control_R:
1303 update_modifier(id, type, 0, MOD_CONTROL_R);
1304 break;
1305
1306 case KS_Alt_L:
1307 update_modifier(id, type, 0, MOD_META_L);
1308 break;
1309
1310 case KS_Alt_R:
1311 update_modifier(id, type, 0, MOD_META_R);
1312 break;
1313
1314 case KS_Mode_switch:
1315 update_modifier(id, type, 0, MOD_MODESHIFT);
1316 break;
1317
1318 case KS_Num_Lock:
1319 update_modifier(id, type, 1, MOD_NUMLOCK);
1320 break;
1321
1322 #if NWSDISPLAY > 0
1323 case KS_Hold_Screen:
1324 if (sc != NULL) {
1325 update_modifier(id, type, 1, MOD_HOLDSCREEN);
1326 wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN);
1327 }
1328 break;
1329 #endif
1330 }
1331
1332 /* If this is a key release or we are in command mode, we are done */
1333 if (type != WSCONS_EVENT_KEY_DOWN || iscommand) {
1334 update_leds(id);
1335 return (KS_voidSymbol);
1336 }
1337
1338 /* Get the keysym */
1339 if (id->t_modifiers & MOD_MODESHIFT)
1340 group = & kp->group2[0];
1341 else
1342 group = & kp->group1[0];
1343
1344 if ((id->t_modifiers & MOD_NUMLOCK) != 0 &&
1345 KS_GROUP(group[1]) == KS_GROUP_Keypad) {
1346 if (MOD_ONESET(id, MOD_ANYSHIFT))
1347 ksym = group[0];
1348 else
1349 ksym = group[1];
1350 } else if (! MOD_ONESET(id, MOD_ANYSHIFT | MOD_CAPSLOCK)) {
1351 ksym = group[0];
1352 } else if (MOD_ONESET(id, MOD_CAPSLOCK)) {
1353 if (! MOD_ONESET(id, MOD_SHIFT_L | MOD_SHIFT_R))
1354 ksym = group[0];
1355 else
1356 ksym = group[1];
1357 if (ksym >= KS_a && ksym <= KS_z)
1358 ksym += KS_A - KS_a;
1359 else if (ksym >= KS_agrave && ksym <= KS_thorn &&
1360 ksym != KS_division)
1361 ksym += KS_Agrave - KS_agrave;
1362 } else if (MOD_ONESET(id, MOD_ANYSHIFT)) {
1363 ksym = group[1];
1364 } else {
1365 ksym = group[0];
1366 }
1367
1368 /* Process compose sequence and dead accents */
1369 res = KS_voidSymbol;
1370
1371 switch (KS_GROUP(ksym)) {
1372 case KS_GROUP_Ascii:
1373 case KS_GROUP_Keypad:
1374 case KS_GROUP_Function:
1375 res = ksym;
1376 break;
1377
1378 case KS_GROUP_Mod:
1379 if (ksym == KS_Multi_key) {
1380 update_modifier(id, 1, 0, MOD_COMPOSE);
1381 id->t_composelen = 2;
1382 }
1383 break;
1384
1385 case KS_GROUP_Dead:
1386 if (id->t_composelen == 0) {
1387 update_modifier(id, 1, 0, MOD_COMPOSE);
1388 id->t_composelen = 1;
1389 id->t_composebuf[0] = ksym;
1390 } else
1391 res = ksym;
1392 break;
1393 }
1394
1395 if (res == KS_voidSymbol) {
1396 update_leds(id);
1397 return (res);
1398 }
1399
1400 if (id->t_composelen > 0) {
1401 id->t_composebuf[2 - id->t_composelen] = res;
1402 if (--id->t_composelen == 0) {
1403 res = wskbd_compose_value(id->t_composebuf);
1404 update_modifier(id, 0, 0, MOD_COMPOSE);
1405 } else {
1406 return (KS_voidSymbol);
1407 }
1408 }
1409
1410 update_leds(id);
1411
1412 /* We are done, return the symbol */
1413 if (KS_GROUP(res) == KS_GROUP_Ascii) {
1414 if (MOD_ONESET(id, MOD_ANYCONTROL)) {
1415 if ((res >= KS_at && res <= KS_z) || res == KS_space)
1416 res = res & 0x1f;
1417 else if (res == KS_2)
1418 res = 0x00;
1419 else if (res >= KS_3 && res <= KS_7)
1420 res = KS_Escape + (res - KS_3);
1421 else if (res == KS_8)
1422 res = KS_Delete;
1423 }
1424 if (MOD_ONESET(id, MOD_ANYMETA))
1425 res |= 0x80;
1426 }
1427
1428 return (res);
1429 }
1430