wskbd.c revision 1.29 1 /* $NetBSD: wskbd.c,v 1.29 1999/08/07 15:04:35 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.29 1999/08/07 15:04:35 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
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
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 (!(flags & FREAD)) {
662 /* Not opening for read, only ioctl is available. */
663 return (0);
664 }
665
666 #if NWSMUX > 0 || NWSDISPLAY > 0
667 if (sc->sc_mux)
668 return (EBUSY);
669 #endif
670
671 if (sc->sc_events.io) /* and that it's not in use */
672 return (EBUSY);
673
674 sc->sc_events.io = p;
675 wsevent_init(&sc->sc_events); /* may cause sleep */
676
677 sc->sc_translating = 0;
678 sc->sc_ready = 1; /* start accepting events */
679
680 wskbd_enable(sc, 1);
681 return (0);
682 }
683
684 int
685 wskbdclose(dev, flags, mode, p)
686 dev_t dev;
687 int flags, mode;
688 struct proc *p;
689 {
690 return (wskbddoclose(wskbd_cd.cd_devs[minor(dev)], flags, mode, p));
691 }
692
693 int
694 wskbddoclose(dv, flags, mode, p)
695 struct device *dv;
696 int flags, mode;
697 struct proc *p;
698 {
699 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
700
701 if (!(flags & FREAD)) {
702 /* Nothing to do, because open didn't do anything. */
703 return (0);
704 }
705
706 sc->sc_ready = 0; /* stop accepting events */
707 sc->sc_translating = 1;
708
709 wsevent_fini(&sc->sc_events);
710 sc->sc_events.io = NULL;
711
712 wskbd_enable(sc, 0);
713 return (0);
714 }
715
716 int
717 wskbdread(dev, uio, flags)
718 dev_t dev;
719 struct uio *uio;
720 int flags;
721 {
722 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
723 int error;
724
725 if (sc->sc_dying)
726 return (EIO);
727
728 sc->sc_refcnt++;
729 error = wsevent_read(&sc->sc_events, uio, flags);
730 if (--sc->sc_refcnt < 0) {
731 wakeup(sc);
732 error = EIO;
733 }
734 return (error);
735 }
736
737 int
738 wskbdioctl(dev, cmd, data, flag, p)
739 dev_t dev;
740 u_long cmd;
741 caddr_t data;
742 int flag;
743 struct proc *p;
744 {
745 return (wskbddoioctl(wskbd_cd.cd_devs[minor(dev)], cmd, data, flag,p));
746 }
747
748 /* A wrapper around the ioctl() workhorse to make reference counting easy. */
749 int
750 wskbddoioctl(dv, cmd, data, flag, p)
751 struct device *dv;
752 u_long cmd;
753 caddr_t data;
754 int flag;
755 struct proc *p;
756 {
757 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
758 int error;
759
760 sc->sc_refcnt++;
761 error = wskbd_do_ioctl(sc, cmd, data, flag, p);
762 if (--sc->sc_refcnt < 0)
763 wakeup(sc);
764 return (error);
765 }
766
767 int
768 wskbd_do_ioctl(sc, cmd, data, flag, p)
769 struct wskbd_softc *sc;
770 u_long cmd;
771 caddr_t data;
772 int flag;
773 struct proc *p;
774 {
775 int error;
776
777 /*
778 * Try the generic ioctls that the wskbd interface supports.
779 */
780 switch (cmd) {
781 case FIONBIO: /* we will remove this someday (soon???) */
782 return (0);
783
784 case FIOASYNC:
785 sc->sc_events.async = *(int *)data != 0;
786 return (0);
787
788 case TIOCSPGRP:
789 if (*(int *)data != sc->sc_events.io->p_pgid)
790 return (EPERM);
791 return (0);
792 }
793
794 /*
795 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
796 * if it didn't recognize the request.
797 */
798 error = wskbd_displayioctl((struct device *)sc, cmd, data, flag, p);
799 return (error != -1 ? error : ENOTTY);
800 }
801
802 /*
803 * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
804 * Some of these have no real effect in raw mode, however.
805 */
806 static int
807 wskbd_displayioctl(dev, cmd, data, flag, p)
808 struct device *dev;
809 u_long cmd;
810 caddr_t data;
811 int flag;
812 struct proc *p;
813 {
814 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
815 struct wskbd_bell_data *ubdp, *kbdp;
816 struct wskbd_keyrepeat_data *ukdp, *kkdp;
817 struct wskbd_map_data *umdp;
818 struct wskbd_mapdata md;
819 void *buf;
820 int len, error;
821
822 switch (cmd) {
823 #define SETBELL(dstp, srcp, dfltp) \
824 do { \
825 (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ? \
826 (srcp)->pitch : (dfltp)->pitch; \
827 (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ? \
828 (srcp)->period : (dfltp)->period; \
829 (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ? \
830 (srcp)->volume : (dfltp)->volume; \
831 (dstp)->which = WSKBD_BELL_DOALL; \
832 } while (0)
833
834 case WSKBDIO_BELL:
835 if ((flag & FWRITE) == 0)
836 return (EACCES);
837 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
838 WSKBDIO_COMPLEXBELL, (caddr_t)&sc->sc_bell_data, flag, p));
839
840 case WSKBDIO_COMPLEXBELL:
841 if ((flag & FWRITE) == 0)
842 return (EACCES);
843 ubdp = (struct wskbd_bell_data *)data;
844 SETBELL(ubdp, ubdp, &sc->sc_bell_data);
845 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
846 WSKBDIO_COMPLEXBELL, (caddr_t)ubdp, flag, p));
847
848 case WSKBDIO_SETBELL:
849 if ((flag & FWRITE) == 0)
850 return (EACCES);
851 kbdp = &sc->sc_bell_data;
852 setbell:
853 ubdp = (struct wskbd_bell_data *)data;
854 SETBELL(kbdp, ubdp, kbdp);
855 return (0);
856
857 case WSKBDIO_GETBELL:
858 kbdp = &sc->sc_bell_data;
859 getbell:
860 ubdp = (struct wskbd_bell_data *)data;
861 SETBELL(ubdp, kbdp, kbdp);
862 return (0);
863
864 case WSKBDIO_SETDEFAULTBELL:
865 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
866 return (error);
867 kbdp = &wskbd_default_bell_data;
868 goto setbell;
869
870
871 case WSKBDIO_GETDEFAULTBELL:
872 kbdp = &wskbd_default_bell_data;
873 goto getbell;
874
875 #undef SETBELL
876
877 #define SETKEYREPEAT(dstp, srcp, dfltp) \
878 do { \
879 (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ? \
880 (srcp)->del1 : (dfltp)->del1; \
881 (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ? \
882 (srcp)->delN : (dfltp)->delN; \
883 (dstp)->which = WSKBD_KEYREPEAT_DOALL; \
884 } while (0)
885
886 case WSKBDIO_SETKEYREPEAT:
887 if ((flag & FWRITE) == 0)
888 return (EACCES);
889 kkdp = &sc->sc_keyrepeat_data;
890 setkeyrepeat:
891 ukdp = (struct wskbd_keyrepeat_data *)data;
892 SETKEYREPEAT(kkdp, ukdp, kkdp);
893 return (0);
894
895 case WSKBDIO_GETKEYREPEAT:
896 kkdp = &sc->sc_keyrepeat_data;
897 getkeyrepeat:
898 ukdp = (struct wskbd_keyrepeat_data *)data;
899 SETKEYREPEAT(ukdp, kkdp, kkdp);
900 return (0);
901
902 case WSKBDIO_SETDEFAULTKEYREPEAT:
903 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
904 return (error);
905 kkdp = &wskbd_default_keyrepeat_data;
906 goto setkeyrepeat;
907
908
909 case WSKBDIO_GETDEFAULTKEYREPEAT:
910 kkdp = &wskbd_default_keyrepeat_data;
911 goto getkeyrepeat;
912
913 #undef SETKEYREPEAT
914
915 case WSKBDIO_SETMAP:
916 if ((flag & FWRITE) == 0)
917 return (EACCES);
918 umdp = (struct wskbd_map_data *)data;
919 len = umdp->maplen*sizeof(struct wscons_keymap);
920 buf = malloc(len, M_TEMP, M_WAITOK);
921 error = copyin(umdp->map, buf, len);
922 if (error == 0) {
923 wskbd_init_keymap(umdp->maplen,
924 &sc->sc_map, &sc->sc_maplen);
925 memcpy(sc->sc_map, buf, len);
926 sc->sc_layout = KB_USER;
927 }
928 free(buf, M_TEMP);
929 return(error);
930
931 case WSKBDIO_GETMAP:
932 umdp = (struct wskbd_map_data *)data;
933 if (umdp->maplen > sc->sc_maplen)
934 umdp->maplen = sc->sc_maplen;
935 error = copyout(sc->sc_map, umdp->map,
936 umdp->maplen*sizeof(struct wscons_keymap));
937 return(error);
938
939 case WSKBDIO_GETENCODING:
940 *((kbd_t *) data) = sc->sc_layout;
941 return(0);
942
943 case WSKBDIO_SETENCODING:
944 if ((flag & FWRITE) == 0)
945 return (EACCES);
946 md = *(sc->id->t_keymap); /* structure assignment */
947 md.layout = *((kbd_t *)data);
948 error = wskbd_load_keymap(&md, &sc->sc_map, &sc->sc_maplen);
949 if (error == 0)
950 sc->sc_layout = *((kbd_t *)data);
951 return(error);
952 }
953
954 /*
955 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
956 * if it didn't recognize the request, and in turn we return
957 * -1 if we didn't recognize the request.
958 */
959 /* printf("kbdaccess\n"); */
960 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
961 flag, p);
962 #ifdef WSDISPLAY_COMPAT_RAWKBD
963 if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
964 int s = spltty();
965 sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
966 | MOD_CONTROL_L | MOD_CONTROL_R
967 | MOD_META_L | MOD_META_R
968 | MOD_COMMAND
969 | MOD_COMMAND1 | MOD_COMMAND2);
970 #if NWSDISPLAY > 0
971 if (sc->sc_repeating) {
972 sc->sc_repeating = 0;
973 untimeout(wskbd_repeat, sc);
974 }
975 #endif
976 splx(s);
977 }
978 #endif
979 return (error);
980 }
981
982 int
983 wskbdpoll(dev, events, p)
984 dev_t dev;
985 int events;
986 struct proc *p;
987 {
988 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
989
990 return (wsevent_poll(&sc->sc_events, events, p));
991 }
992
993 #if NWSDISPLAY > 0
994
995 int
996 wskbd_pickfree()
997 {
998 int i;
999 struct wskbd_softc *sc;
1000
1001 for (i = 0; i < wskbd_cd.cd_ndevs; i++) {
1002 if ((sc = wskbd_cd.cd_devs[i]) == NULL)
1003 continue;
1004 if (sc->sc_displaydv == NULL)
1005 return (i);
1006 }
1007 return (-1);
1008 }
1009
1010 struct device *
1011 wskbd_set_console_display(displaydv, muxsc)
1012 struct device *displaydv;
1013 struct wsmux_softc *muxsc;
1014 {
1015 struct wskbd_softc *sc = wskbd_console_device;
1016
1017 if (!sc)
1018 return (0);
1019 sc->sc_displaydv = displaydv;
1020 (void)wsmux_attach_sc(muxsc, WSMUX_KBD, &sc->sc_dv, &sc->sc_events,
1021 &sc->sc_mux, &wskbd_muxops);
1022 return (&sc->sc_dv);
1023 }
1024
1025 int
1026 wskbd_set_display(dv, muxsc)
1027 struct device *dv;
1028 struct wsmux_softc *muxsc;
1029 {
1030 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
1031 struct device *displaydv = muxsc ? muxsc->sc_displaydv : 0;
1032 struct device *odisplaydv;
1033 int error;
1034
1035 DPRINTF(("wskbd_set_display: %s mux=%p disp=%p odisp=%p cons=%d\n",
1036 dv->dv_xname, muxsc, sc->sc_displaydv, displaydv,
1037 sc->sc_isconsole));
1038
1039 if (sc->sc_isconsole)
1040 return (EBUSY);
1041
1042 if (displaydv) {
1043 if (sc->sc_displaydv)
1044 return (EBUSY);
1045 } else {
1046 if (sc->sc_displaydv == NULL)
1047 return (ENXIO);
1048 }
1049
1050 odisplaydv = sc->sc_displaydv;
1051 sc->sc_displaydv = displaydv;
1052
1053 error = wskbd_enable(sc, displaydv != NULL);
1054 if (error) {
1055 sc->sc_displaydv = odisplaydv;
1056 return (error);
1057 }
1058
1059 if (displaydv)
1060 printf("%s: connecting to %s\n",
1061 sc->sc_dv.dv_xname, displaydv->dv_xname);
1062 else
1063 printf("%s: disconnecting from %s\n",
1064 sc->sc_dv.dv_xname, odisplaydv->dv_xname);
1065
1066 return (0);
1067 }
1068
1069 int
1070 wskbd_add_mux(unit, muxsc)
1071 int unit;
1072 struct wsmux_softc *muxsc;
1073 {
1074 struct wskbd_softc *sc;
1075
1076 DPRINTF(("wskbd_add_mux: %d %s %p\n", unit, muxsc->sc_dv.dv_xname,
1077 muxsc->sc_displaydv));
1078 if (unit < 0 || unit >= wskbd_cd.cd_ndevs ||
1079 (sc = wskbd_cd.cd_devs[unit]) == NULL)
1080 return (ENXIO);
1081
1082 if (sc->sc_mux || sc->sc_events.io)
1083 return (EBUSY);
1084
1085 return (wsmux_attach_sc(muxsc, WSMUX_KBD, &sc->sc_dv, &sc->sc_events,
1086 &sc->sc_mux, &wskbd_muxops));
1087 }
1088
1089 int
1090 wskbd_rem_mux(unit, muxsc)
1091 int unit;
1092 struct wsmux_softc *muxsc;
1093 {
1094 struct wskbd_softc *sc;
1095
1096 DPRINTF(("wskbd_rem_mux: %d %s\n", unit, muxsc->sc_dv.dv_xname));
1097 if (unit < 0 || unit >= wskbd_cd.cd_ndevs ||
1098 (sc = wskbd_cd.cd_devs[unit]) == NULL)
1099 return (ENXIO);
1100
1101 return (wsmux_detach_sc(muxsc, &sc->sc_dv));
1102 }
1103
1104 #endif /* NWSDISPLAY > 0 */
1105
1106 /*
1107 * Console interface.
1108 */
1109 int
1110 wskbd_cngetc(dev)
1111 dev_t dev;
1112 {
1113 u_int type;
1114 int data;
1115 keysym_t ks;
1116
1117 if (!wskbd_console_initted)
1118 return 0;
1119
1120 if (wskbd_console_device != NULL &&
1121 !wskbd_console_device->sc_translating)
1122 return 0;
1123
1124 for(;;) {
1125 (*wskbd_console_data.t_consops->getc)
1126 (wskbd_console_data.t_consaccesscookie, &type, &data);
1127 ks = wskbd_translate(&wskbd_console_data, type, data);
1128
1129 if (KS_GROUP(ks) == KS_GROUP_Ascii)
1130 return (KS_VALUE(ks));
1131 }
1132 }
1133
1134 void
1135 wskbd_cnpollc(dev, poll)
1136 dev_t dev;
1137 int poll;
1138 {
1139
1140 if (!wskbd_console_initted)
1141 return;
1142
1143 if (wskbd_console_device != NULL &&
1144 !wskbd_console_device->sc_translating)
1145 return;
1146
1147 (*wskbd_console_data.t_consops->pollc)
1148 (wskbd_console_data.t_consaccesscookie, poll);
1149 }
1150
1151 static inline void
1152 update_leds(id)
1153 struct wskbd_internal *id;
1154 {
1155 int new_state;
1156
1157 new_state = 0;
1158 if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
1159 new_state |= WSKBD_LED_CAPS;
1160 if (id->t_modifiers & MOD_NUMLOCK)
1161 new_state |= WSKBD_LED_NUM;
1162 if (id->t_modifiers & MOD_COMPOSE)
1163 new_state |= WSKBD_LED_COMPOSE;
1164 if (id->t_modifiers & MOD_HOLDSCREEN)
1165 new_state |= WSKBD_LED_SCROLL;
1166
1167 if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
1168 (*id->t_sc->sc_accessops->set_leds)
1169 (id->t_sc->sc_accesscookie, new_state);
1170 id->t_sc->sc_ledstate = new_state;
1171 }
1172 }
1173
1174 static inline void
1175 update_modifier(id, type, toggle, mask)
1176 struct wskbd_internal *id;
1177 u_int type;
1178 int toggle;
1179 int mask;
1180 {
1181 if (toggle) {
1182 if (type == WSCONS_EVENT_KEY_DOWN)
1183 id->t_modifiers ^= mask;
1184 } else {
1185 if (type == WSCONS_EVENT_KEY_DOWN)
1186 id->t_modifiers |= mask;
1187 else
1188 id->t_modifiers &= ~mask;
1189 }
1190 }
1191
1192 static int
1193 internal_command(sc, type, ksym)
1194 struct wskbd_softc *sc;
1195 u_int *type;
1196 keysym_t ksym;
1197 {
1198 switch (ksym) {
1199 case KS_Cmd:
1200 update_modifier(sc->id, *type, 0, MOD_COMMAND);
1201 break;
1202
1203 case KS_Cmd1:
1204 update_modifier(sc->id, *type, 0, MOD_COMMAND1);
1205 break;
1206
1207 case KS_Cmd2:
1208 update_modifier(sc->id, *type, 0, MOD_COMMAND2);
1209 break;
1210 }
1211
1212 if (*type != WSCONS_EVENT_KEY_DOWN ||
1213 (! MOD_ONESET(sc->id, MOD_COMMAND) &&
1214 ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)))
1215 return (0);
1216
1217 switch (ksym) {
1218 #ifdef DDB
1219 case KS_Cmd_Debugger:
1220 if (sc->sc_isconsole)
1221 console_debugger();
1222 /* discard this key (ddb discarded command modifiers) */
1223 *type = WSCONS_EVENT_KEY_UP;
1224 return (1);
1225 #endif
1226
1227 #if NWSDISPLAY > 0
1228 case KS_Cmd_Screen0:
1229 case KS_Cmd_Screen1:
1230 case KS_Cmd_Screen2:
1231 case KS_Cmd_Screen3:
1232 case KS_Cmd_Screen4:
1233 case KS_Cmd_Screen5:
1234 case KS_Cmd_Screen6:
1235 case KS_Cmd_Screen7:
1236 case KS_Cmd_Screen8:
1237 case KS_Cmd_Screen9:
1238 wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0);
1239 return (1);
1240 case KS_Cmd_ResetEmul:
1241 wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETEMUL);
1242 return (1);
1243 case KS_Cmd_ResetClose:
1244 wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETCLOSE);
1245 return (1);
1246 #endif
1247 }
1248 return (0);
1249 }
1250
1251 static keysym_t
1252 wskbd_translate(id, type, value)
1253 struct wskbd_internal *id;
1254 u_int type;
1255 int value;
1256 {
1257 struct wskbd_softc *sc = id->t_sc;
1258 keysym_t ksym, res, *group;
1259 struct wscons_keymap kpbuf, *kp;
1260 int iscommand = 0;
1261
1262 if (type == WSCONS_EVENT_ALL_KEYS_UP) {
1263 id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
1264 | MOD_CONTROL_L | MOD_CONTROL_R
1265 | MOD_META_L | MOD_META_R
1266 | MOD_MODESHIFT
1267 | MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
1268 update_leds(id);
1269 return (KS_voidSymbol);
1270 }
1271
1272 if (sc != NULL) {
1273 if (value < 0 || value >= sc->sc_maplen) {
1274 #ifdef DEBUG
1275 printf("wskbd_translate: keycode %d out of range\n",
1276 value);
1277 #endif
1278 return (KS_voidSymbol);
1279 }
1280 kp = sc->sc_map + value;
1281 } else {
1282 kp = &kpbuf;
1283 wskbd_get_mapentry(id->t_keymap, value, kp);
1284 }
1285
1286 /* if this key has a command, process it first */
1287 if (sc != NULL && kp->command != KS_voidSymbol)
1288 iscommand = internal_command(sc, &type, kp->command);
1289
1290 /* Now update modifiers */
1291 switch (kp->group1[0]) {
1292 case KS_Shift_L:
1293 update_modifier(id, type, 0, MOD_SHIFT_L);
1294 break;
1295
1296 case KS_Shift_R:
1297 update_modifier(id, type, 0, MOD_SHIFT_R);
1298 break;
1299
1300 case KS_Shift_Lock:
1301 update_modifier(id, type, 1, MOD_SHIFTLOCK);
1302 break;
1303
1304 case KS_Caps_Lock:
1305 update_modifier(id, type, 1, MOD_CAPSLOCK);
1306 break;
1307
1308 case KS_Control_L:
1309 update_modifier(id, type, 0, MOD_CONTROL_L);
1310 break;
1311
1312 case KS_Control_R:
1313 update_modifier(id, type, 0, MOD_CONTROL_R);
1314 break;
1315
1316 case KS_Alt_L:
1317 update_modifier(id, type, 0, MOD_META_L);
1318 break;
1319
1320 case KS_Alt_R:
1321 update_modifier(id, type, 0, MOD_META_R);
1322 break;
1323
1324 case KS_Mode_switch:
1325 update_modifier(id, type, 0, MOD_MODESHIFT);
1326 break;
1327
1328 case KS_Num_Lock:
1329 update_modifier(id, type, 1, MOD_NUMLOCK);
1330 break;
1331
1332 #if NWSDISPLAY > 0
1333 case KS_Hold_Screen:
1334 if (sc != NULL) {
1335 update_modifier(id, type, 1, MOD_HOLDSCREEN);
1336 wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN);
1337 }
1338 break;
1339 #endif
1340 }
1341
1342 /* If this is a key release or we are in command mode, we are done */
1343 if (type != WSCONS_EVENT_KEY_DOWN || iscommand) {
1344 update_leds(id);
1345 return (KS_voidSymbol);
1346 }
1347
1348 /* Get the keysym */
1349 if (id->t_modifiers & MOD_MODESHIFT)
1350 group = & kp->group2[0];
1351 else
1352 group = & kp->group1[0];
1353
1354 if ((id->t_modifiers & MOD_NUMLOCK) != 0 &&
1355 KS_GROUP(group[1]) == KS_GROUP_Keypad) {
1356 if (MOD_ONESET(id, MOD_ANYSHIFT))
1357 ksym = group[0];
1358 else
1359 ksym = group[1];
1360 } else if (! MOD_ONESET(id, MOD_ANYSHIFT | MOD_CAPSLOCK)) {
1361 ksym = group[0];
1362 } else if (MOD_ONESET(id, MOD_CAPSLOCK)) {
1363 if (! MOD_ONESET(id, MOD_SHIFT_L | MOD_SHIFT_R))
1364 ksym = group[0];
1365 else
1366 ksym = group[1];
1367 if (ksym >= KS_a && ksym <= KS_z)
1368 ksym += KS_A - KS_a;
1369 else if (ksym >= KS_agrave && ksym <= KS_thorn &&
1370 ksym != KS_division)
1371 ksym += KS_Agrave - KS_agrave;
1372 } else if (MOD_ONESET(id, MOD_ANYSHIFT)) {
1373 ksym = group[1];
1374 } else {
1375 ksym = group[0];
1376 }
1377
1378 /* Process compose sequence and dead accents */
1379 res = KS_voidSymbol;
1380
1381 switch (KS_GROUP(ksym)) {
1382 case KS_GROUP_Ascii:
1383 case KS_GROUP_Keypad:
1384 case KS_GROUP_Function:
1385 res = ksym;
1386 break;
1387
1388 case KS_GROUP_Mod:
1389 if (ksym == KS_Multi_key) {
1390 update_modifier(id, 1, 0, MOD_COMPOSE);
1391 id->t_composelen = 2;
1392 }
1393 break;
1394
1395 case KS_GROUP_Dead:
1396 if (id->t_composelen == 0) {
1397 update_modifier(id, 1, 0, MOD_COMPOSE);
1398 id->t_composelen = 1;
1399 id->t_composebuf[0] = ksym;
1400 } else
1401 res = ksym;
1402 break;
1403 }
1404
1405 if (res == KS_voidSymbol) {
1406 update_leds(id);
1407 return (res);
1408 }
1409
1410 if (id->t_composelen > 0) {
1411 id->t_composebuf[2 - id->t_composelen] = res;
1412 if (--id->t_composelen == 0) {
1413 res = wskbd_compose_value(id->t_composebuf);
1414 update_modifier(id, 0, 0, MOD_COMPOSE);
1415 } else {
1416 return (KS_voidSymbol);
1417 }
1418 }
1419
1420 update_leds(id);
1421
1422 /* We are done, return the symbol */
1423 if (KS_GROUP(res) == KS_GROUP_Ascii) {
1424 if (MOD_ONESET(id, MOD_ANYCONTROL)) {
1425 if ((res >= KS_at && res <= KS_z) || res == KS_space)
1426 res = res & 0x1f;
1427 else if (res == KS_2)
1428 res = 0x00;
1429 else if (res >= KS_3 && res <= KS_7)
1430 res = KS_Escape + (res - KS_3);
1431 else if (res == KS_8)
1432 res = KS_Delete;
1433 }
1434 if (MOD_ONESET(id, MOD_ANYMETA))
1435 res |= 0x80;
1436 }
1437
1438 return (res);
1439 }
1440