1 /* $NetBSD: wskbd.c,v 1.146 2025/04/07 11:25:42 hans Exp $ */
2 
3 /*
4  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Christopher G. Demetriou
17  *        for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1998 The NetBSD Foundation, Inc.
35  *  All rights reserved.
36  *
37  * Keysym translator contributed to The NetBSD Foundation by
38  * Juergen Hannken-Illjes.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
50  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
51  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
52  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
53  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
54  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
55  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
56  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
57  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
58  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
59  * POSSIBILITY OF SUCH DAMAGE.
60  */
61 
62 /*
63  * Copyright (c) 1992, 1993
64  *        The Regents of the University of California.  All rights reserved.
65  *
66  * This software was developed by the Computer Systems Engineering group
67  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
68  * contributed to Berkeley.
69  *
70  * All advertising materials mentioning features or use of this software
71  * must display the following acknowledgement:
72  *        This product includes software developed by the University of
73  *        California, Lawrence Berkeley Laboratory.
74  *
75  * Redistribution and use in source and binary forms, with or without
76  * modification, are permitted provided that the following conditions
77  * are met:
78  * 1. Redistributions of source code must retain the above copyright
79  *    notice, this list of conditions and the following disclaimer.
80  * 2. Redistributions in binary form must reproduce the above copyright
81  *    notice, this list of conditions and the following disclaimer in the
82  *    documentation and/or other materials provided with the distribution.
83  * 3. Neither the name of the University nor the names of its contributors
84  *    may be used to endorse or promote products derived from this software
85  *    without specific prior written permission.
86  *
87  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
88  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
89  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
90  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
91  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
92  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
93  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
94  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
95  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
96  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
97  * SUCH DAMAGE.
98  *
99  *        @(#)kbd.c 8.2 (Berkeley) 10/30/93
100  */
101 
102 /*
103  * Keyboard driver (/dev/wskbd*).  Translates incoming bytes to ASCII or
104  * to `wscons_events' and passes them up to the appropriate reader.
105  */
106 
107 #include <sys/cdefs.h>
108 __KERNEL_RCSID(0, "$NetBSD: wskbd.c,v 1.146 2025/04/07 11:25:42 hans Exp $");
109 
110 #ifdef _KERNEL_OPT
111 #include "opt_ddb.h"
112 #include "opt_kgdb.h"
113 #include "opt_wsdisplay_compat.h"
114 #endif
115 
116 #include "wsdisplay.h"
117 #include "wskbd.h"
118 #include "wsmux.h"
119 
120 #include <sys/param.h>
121 #include <sys/conf.h>
122 #include <sys/device.h>
123 #include <sys/ioctl.h>
124 #include <sys/poll.h>
125 #include <sys/kernel.h>
126 #include <sys/proc.h>
127 #include <sys/syslog.h>
128 #include <sys/systm.h>
129 #include <sys/callout.h>
130 #include <sys/malloc.h>
131 #include <sys/tty.h>
132 #include <sys/signalvar.h>
133 #include <sys/errno.h>
134 #include <sys/fcntl.h>
135 #include <sys/vnode.h>
136 #include <sys/kauth.h>
137 
138 #include <dev/wscons/wsconsio.h>
139 #include <dev/wscons/wskbdvar.h>
140 #include <dev/wscons/wsksymdef.h>
141 #include <dev/wscons/wsksymvar.h>
142 #include <dev/wscons/wsdisplayvar.h>
143 #include <dev/wscons/wseventvar.h>
144 #include <dev/wscons/wscons_callbacks.h>
145 #include <dev/wscons/wsbelldata.h>
146 #include <dev/wscons/wsmuxvar.h>
147 
148 #ifdef KGDB
149 #include <sys/kgdb.h>
150 #endif
151 
152 #include "ioconf.h"
153 
154 #ifdef WSKBD_DEBUG
155 #define DPRINTF(x)  if (wskbddebug) printf x
156 int       wskbddebug = 0;
157 #else
158 #define DPRINTF(x)
159 #endif
160 
161 struct wskbd_internal {
162           const struct wskbd_mapdata *t_keymap;
163 
164           const struct wskbd_consops *t_consops;
165           void      *t_consaccesscookie;
166 
167           int       t_modifiers;
168           int       t_composelen;                 /* remaining entries in t_composebuf */
169           keysym_t t_composebuf[2];
170 
171           int t_flags;
172 #define WSKFL_METAESC 1
173 
174 #define MAXKEYSYMSPERKEY 2 /* ESC <key> at max */
175           keysym_t t_symbols[MAXKEYSYMSPERKEY];
176 
177           struct wskbd_softc *t_sc;     /* back pointer */
178 };
179 
180 struct wskbd_softc {
181           struct wsevsrc sc_base;
182 
183           struct wskbd_internal *id;
184 
185           const struct wskbd_accessops *sc_accessops;
186           void *sc_accesscookie;
187 
188           int       sc_ledstate;
189 
190           int       sc_isconsole;
191 
192           struct wskbd_bell_data sc_bell_data;
193           struct wskbd_keyrepeat_data sc_keyrepeat_data;
194 #ifdef WSDISPLAY_SCROLLSUPPORT
195           struct wskbd_scroll_data sc_scroll_data;
196 #endif
197 
198           int       sc_repeating;                 /* we've called timeout() */
199           callout_t sc_repeat_ch;
200           u_int     sc_repeat_type;
201           int       sc_repeat_value;
202 
203           int       sc_translating;               /* xlate to chars for emulation */
204 
205           int       sc_maplen;                    /* number of entries in sc_map */
206           struct wscons_keymap *sc_map; /* current translation map */
207           kbd_t sc_layout; /* current layout */
208 
209           int                 sc_refcnt;
210           u_char              sc_dying; /* device is being detached */
211 
212           wskbd_hotkey_plugin *sc_hotkey;
213           void *sc_hotkeycookie;
214 
215           /* optional table to translate scancodes in event mode */
216           int                 sc_evtrans_len;
217           keysym_t  *sc_evtrans;
218 };
219 
220 #define MOD_SHIFT_L           (1 << 0)
221 #define MOD_SHIFT_R           (1 << 1)
222 #define MOD_SHIFTLOCK                   (1 << 2)
223 #define MOD_CAPSLOCK                    (1 << 3)
224 #define MOD_CONTROL_L                   (1 << 4)
225 #define MOD_CONTROL_R                   (1 << 5)
226 #define MOD_META_L            (1 << 6)
227 #define MOD_META_R            (1 << 7)
228 #define MOD_MODESHIFT                   (1 << 8)
229 #define MOD_NUMLOCK           (1 << 9)
230 #define MOD_COMPOSE           (1 << 10)
231 #define MOD_HOLDSCREEN                  (1 << 11)
232 #define MOD_COMMAND           (1 << 12)
233 #define MOD_COMMAND1                    (1 << 13)
234 #define MOD_COMMAND2                    (1 << 14)
235 
236 #define MOD_ANYSHIFT                    (MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK)
237 #define MOD_ANYCONTROL                  (MOD_CONTROL_L | MOD_CONTROL_R)
238 #define MOD_ANYMETA           (MOD_META_L | MOD_META_R)
239 
240 #define MOD_ONESET(id, mask)  (((id)->t_modifiers & (mask)) != 0)
241 #define MOD_ALLSET(id, mask)  (((id)->t_modifiers & (mask)) == (mask))
242 
243 #define GETMODSTATE(src, dst)           \
244           do {                                                                  \
245                     dst |= (src & MOD_SHIFT_L) ? MOD_SHIFT_L : 0; \
246                     dst |= (src & MOD_SHIFT_R) ? MOD_SHIFT_R : 0; \
247                     dst |= (src & MOD_CONTROL_L) ? MOD_CONTROL_L : 0; \
248                     dst |= (src & MOD_CONTROL_R) ? MOD_CONTROL_R : 0; \
249                     dst |= (src & MOD_META_L) ? MOD_META_L : 0; \
250                     dst |= (src & MOD_META_R) ? MOD_META_R : 0; \
251           } while (0)
252 
253 static int  wskbd_match(device_t, cfdata_t, void *);
254 static void wskbd_attach(device_t, device_t, void *);
255 static int  wskbd_detach(device_t, int);
256 static int  wskbd_activate(device_t, enum devact);
257 
258 static int  wskbd_displayioctl(device_t, u_long, void *, int,
259                                     struct lwp *);
260 #if NWSDISPLAY > 0
261 static int  wskbd_set_display(device_t, struct wsevsrc *);
262 #else
263 #define wskbd_set_display NULL
264 #endif
265 
266 static inline void update_leds(struct wskbd_internal *);
267 static inline void update_modifier(struct wskbd_internal *, u_int, int, int);
268 static int internal_command(struct wskbd_softc *, u_int *, keysym_t, keysym_t);
269 static int wskbd_translate(struct wskbd_internal *, u_int, int);
270 static int wskbd_enable(struct wskbd_softc *, int);
271 #if NWSDISPLAY > 0
272 static void change_displayparam(struct wskbd_softc *, int, int, int);
273 static void wskbd_holdscreen(struct wskbd_softc *, int);
274 #endif
275 
276 static int wskbd_do_ioctl_sc(struct wskbd_softc *, u_long, void *, int,
277                                    struct lwp *);
278 static void wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value);
279 
280 #if NWSMUX > 0
281 static int wskbd_mux_open(struct wsevsrc *, struct wseventvar *);
282 static int wskbd_mux_close(struct wsevsrc *);
283 #else
284 #define wskbd_mux_open NULL
285 #define wskbd_mux_close NULL
286 #endif
287 
288 static int wskbd_do_open(struct wskbd_softc *, struct wseventvar *);
289 static int wskbd_do_ioctl(device_t, u_long, void *, int, struct lwp *);
290 
291 CFATTACH_DECL_NEW(wskbd, sizeof (struct wskbd_softc),
292     wskbd_match, wskbd_attach, wskbd_detach, wskbd_activate);
293 
294 dev_type_open(wskbdopen);
295 dev_type_close(wskbdclose);
296 dev_type_read(wskbdread);
297 dev_type_ioctl(wskbdioctl);
298 dev_type_poll(wskbdpoll);
299 dev_type_kqfilter(wskbdkqfilter);
300 
301 const struct cdevsw wskbd_cdevsw = {
302           .d_open = wskbdopen,
303           .d_close = wskbdclose,
304           .d_read = wskbdread,
305           .d_write = nowrite,
306           .d_ioctl = wskbdioctl,
307           .d_stop = nostop,
308           .d_tty = notty,
309           .d_poll = wskbdpoll,
310           .d_mmap = nommap,
311           .d_kqfilter = wskbdkqfilter,
312           .d_discard = nodiscard,
313           .d_flag = D_OTHER
314 };
315 
316 #ifdef WSDISPLAY_SCROLLSUPPORT
317 struct wskbd_scroll_data wskbd_default_scroll_data = {
318           WSKBD_SCROLL_DOALL,
319           WSKBD_SCROLL_MODE_NORMAL,
320 #ifdef WSDISPLAY_SCROLLCOMBO
321           WSDISPLAY_SCROLLCOMBO,
322 #else
323           MOD_SHIFT_L,
324 #endif
325 };
326 #endif
327 
328 #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1
329 #define   WSKBD_DEFAULT_KEYREPEAT_DEL1  400       /* 400ms to start repeating */
330 #endif
331 #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN
332 #define   WSKBD_DEFAULT_KEYREPEAT_DELN  100       /* 100ms to between repeats */
333 #endif
334 
335 struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = {
336           WSKBD_KEYREPEAT_DOALL,
337           WSKBD_DEFAULT_KEYREPEAT_DEL1,
338           WSKBD_DEFAULT_KEYREPEAT_DELN,
339 };
340 
341 #if NWSDISPLAY > 0 || NWSMUX > 0
342 struct wssrcops wskbd_srcops = {
343           WSMUX_KBD,
344           wskbd_mux_open, wskbd_mux_close, wskbd_do_ioctl,
345           wskbd_displayioctl, wskbd_set_display
346 };
347 #endif
348 
349 static bool wskbd_suspend(device_t dv, const pmf_qual_t *);
350 static void wskbd_repeat(void *v);
351 
352 static int wskbd_console_initted;
353 static struct wskbd_softc *wskbd_console_device;
354 static struct wskbd_internal wskbd_console_data;
355 
356 static void wskbd_update_layout(struct wskbd_internal *, kbd_t);
357 
358 static void
wskbd_update_layout(struct wskbd_internal * id,kbd_t enc)359 wskbd_update_layout(struct wskbd_internal *id, kbd_t enc)
360 {
361 
362           if (enc & KB_METAESC)
363                     id->t_flags |= WSKFL_METAESC;
364           else
365                     id->t_flags &= ~WSKFL_METAESC;
366 }
367 
368 /*
369  * Print function (for parent devices).
370  */
371 int
wskbddevprint(void * aux,const char * pnp)372 wskbddevprint(void *aux, const char *pnp)
373 {
374 #if 0
375           struct wskbddev_attach_args *ap = aux;
376 #endif
377 
378           if (pnp)
379                     aprint_normal("wskbd at %s", pnp);
380 #if 0
381           aprint_normal(" console %d", ap->console);
382 #endif
383 
384           return (UNCONF);
385 }
386 
387 int
wskbd_match(device_t parent,cfdata_t match,void * aux)388 wskbd_match(device_t parent, cfdata_t match, void *aux)
389 {
390           struct wskbddev_attach_args *ap = aux;
391 
392           if (match->wskbddevcf_console != WSKBDDEVCF_CONSOLE_UNK) {
393                     /*
394                      * If console-ness of device specified, either match
395                      * exactly (at high priority), or fail.
396                      */
397                     if (match->wskbddevcf_console != 0 && ap->console != 0)
398                               return (10);
399                     else
400                               return (0);
401           }
402 
403           /* If console-ness unspecified, it wins. */
404           return (1);
405 }
406 
407 void
wskbd_attach(device_t parent,device_t self,void * aux)408 wskbd_attach(device_t parent, device_t self, void *aux)
409 {
410           struct wskbd_softc *sc = device_private(self);
411           struct wskbddev_attach_args *ap = aux;
412 #if NWSMUX > 0
413           int mux, error;
414 #endif
415 
416           sc->sc_base.me_dv = self;
417           sc->sc_isconsole = ap->console;
418           sc->sc_hotkey = NULL;
419           sc->sc_hotkeycookie = NULL;
420           sc->sc_evtrans_len = 0;
421           sc->sc_evtrans = NULL;
422 
423 #if NWSMUX > 0 || NWSDISPLAY > 0
424           sc->sc_base.me_ops = &wskbd_srcops;
425 #endif
426 #if NWSMUX > 0
427           mux = device_cfdata(sc->sc_base.me_dv)->wskbddevcf_mux;
428           if (ap->console) {
429                     /* Ignore mux for console; it always goes to the console mux. */
430                     /* printf(" (mux %d ignored for console)", mux); */
431                     mux = -1;
432           }
433           if (mux >= 0)
434                     aprint_normal(" mux %d", mux);
435 #else
436           if (device_cfdata(sc->sc_base.me_dv)->wskbddevcf_mux >= 0)
437                     aprint_normal(" (mux ignored)");
438 #endif
439 
440           if (ap->console) {
441                     sc->id = &wskbd_console_data;
442           } else {
443                     sc->id = malloc(sizeof(struct wskbd_internal),
444                                         M_DEVBUF, M_WAITOK|M_ZERO);
445                     sc->id->t_keymap = ap->keymap;
446                     wskbd_update_layout(sc->id, ap->keymap->layout);
447           }
448 
449           callout_init(&sc->sc_repeat_ch, 0);
450           callout_setfunc(&sc->sc_repeat_ch, wskbd_repeat, sc);
451 
452           sc->id->t_sc = sc;
453 
454           sc->sc_accessops = ap->accessops;
455           sc->sc_accesscookie = ap->accesscookie;
456           sc->sc_repeating = 0;
457           sc->sc_translating = 1;
458           sc->sc_ledstate = -1; /* force update */
459 
460           if (wskbd_load_keymap(sc->id->t_keymap,
461                                     &sc->sc_map, &sc->sc_maplen) != 0)
462                     panic("cannot load keymap");
463 
464           sc->sc_layout = sc->id->t_keymap->layout;
465 
466           /* set default bell and key repeat data */
467           sc->sc_bell_data = wskbd_default_bell_data;
468           sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data;
469 
470 #ifdef WSDISPLAY_SCROLLSUPPORT
471           sc->sc_scroll_data = wskbd_default_scroll_data;
472 #endif
473 
474           if (ap->console) {
475                     KASSERT(wskbd_console_initted);
476                     KASSERT(wskbd_console_device == NULL);
477 
478                     wskbd_console_device = sc;
479 
480                     aprint_naive(": console keyboard");
481                     aprint_normal(": console keyboard");
482 
483 #if NWSDISPLAY > 0
484                     wsdisplay_set_console_kbd(&sc->sc_base); /* sets me_dispv */
485                     if (sc->sc_base.me_dispdv != NULL)
486                               aprint_normal(", using %s",
487                                   device_xname(sc->sc_base.me_dispdv));
488 #endif
489           }
490           aprint_naive("\n");
491           aprint_normal("\n");
492 
493 #if NWSMUX > 0
494           if (mux >= 0) {
495                     error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base);
496                     if (error)
497                               aprint_error_dev(sc->sc_base.me_dv,
498                                   "attach error=%d\n", error);
499           }
500 #endif
501 
502           if (!pmf_device_register(self, wskbd_suspend, NULL))
503                     aprint_error_dev(self, "couldn't establish power handler\n");
504           else if (!pmf_class_input_register(self))
505                     aprint_error_dev(self, "couldn't register as input device\n");
506 }
507 
508 static bool
wskbd_suspend(device_t dv,const pmf_qual_t * qual)509 wskbd_suspend(device_t dv, const pmf_qual_t *qual)
510 {
511           struct wskbd_softc *sc = device_private(dv);
512 
513           sc->sc_repeating = 0;
514           callout_stop(&sc->sc_repeat_ch);
515 
516           return true;
517 }
518 
519 void
wskbd_cnattach(const struct wskbd_consops * consops,void * conscookie,const struct wskbd_mapdata * mapdata)520 wskbd_cnattach(const struct wskbd_consops *consops, void *conscookie,
521           const struct wskbd_mapdata *mapdata)
522 {
523           KASSERT(!wskbd_console_initted);
524 
525           wskbd_console_data.t_keymap = mapdata;
526           wskbd_update_layout(&wskbd_console_data, mapdata->layout);
527 
528           wskbd_console_data.t_consops = consops;
529           wskbd_console_data.t_consaccesscookie = conscookie;
530 
531 #if NWSDISPLAY > 0
532           wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc, wskbd_cnbell);
533 #endif
534 
535           wskbd_console_initted = 1;
536 }
537 
538 void
wskbd_cndetach(void)539 wskbd_cndetach(void)
540 {
541           KASSERT(wskbd_console_initted);
542 
543           wskbd_console_data.t_keymap = 0;
544 
545           wskbd_console_data.t_consops = 0;
546           wskbd_console_data.t_consaccesscookie = 0;
547 
548 #if NWSDISPLAY > 0
549           wsdisplay_unset_cons_kbd();
550 #endif
551 
552           wskbd_console_initted = 0;
553 }
554 
555 static void
wskbd_repeat(void * v)556 wskbd_repeat(void *v)
557 {
558           struct wskbd_softc *sc = (struct wskbd_softc *)v;
559           int s = spltty();
560 
561           if (!sc->sc_repeating) {
562                     /*
563                      * race condition: a "key up" event came in when wskbd_repeat()
564                      * was already called but not yet spltty()'d
565                      */
566                     splx(s);
567                     return;
568           }
569           if (sc->sc_translating) {
570                     /* deliver keys */
571 #if NWSDISPLAY > 0
572                     if (sc->sc_base.me_dispdv != NULL) {
573                               int i;
574                               for (i = 0; i < sc->sc_repeating; i++)
575                                         wsdisplay_kbdinput(sc->sc_base.me_dispdv,
576                                                                sc->id->t_symbols[i]);
577                     }
578 #endif
579           } else {
580 #if defined(WSKBD_EVENT_AUTOREPEAT)
581                     /* queue event */
582                     wskbd_deliver_event(sc, sc->sc_repeat_type,
583                                             sc->sc_repeat_value);
584 #endif /* defined(WSKBD_EVENT_AUTOREPEAT) */
585           }
586           callout_schedule(&sc->sc_repeat_ch, mstohz(sc->sc_keyrepeat_data.delN));
587           splx(s);
588 }
589 
590 int
wskbd_activate(device_t self,enum devact act)591 wskbd_activate(device_t self, enum devact act)
592 {
593           struct wskbd_softc *sc = device_private(self);
594 
595           if (act == DVACT_DEACTIVATE)
596                     sc->sc_dying = 1;
597           return (0);
598 }
599 
600 /*
601  * Detach a keyboard.  To keep track of users of the softc we keep
602  * a reference count that's incremented while inside, e.g., read.
603  * If the keyboard is active and the reference count is > 0 (0 is the
604  * normal state) we post an event and then wait for the process
605  * that had the reference to wake us up again.  Then we blow away the
606  * vnode and return (which will deallocate the softc).
607  */
608 int
wskbd_detach(device_t self,int flags)609 wskbd_detach(device_t self, int flags)
610 {
611           struct wskbd_softc *sc = device_private(self);
612           struct wseventvar *evar;
613           int maj, mn;
614           int s;
615 
616 #if NWSMUX > 0
617           /* Tell parent mux we're leaving. */
618           if (sc->sc_base.me_parent != NULL)
619                     wsmux_detach_sc(&sc->sc_base);
620 #endif
621 
622           callout_halt(&sc->sc_repeat_ch, NULL);
623           callout_destroy(&sc->sc_repeat_ch);
624 
625           if (sc->sc_isconsole) {
626                     KASSERT(wskbd_console_device == sc);
627                     wskbd_console_device = NULL;
628           }
629 
630           pmf_device_deregister(self);
631 
632           evar = sc->sc_base.me_evp;
633           if (evar != NULL && evar->io != NULL) {
634                     s = spltty();
635                     if (--sc->sc_refcnt >= 0) {
636                               struct wscons_event event;
637 
638                               /* Wake everyone by generating a dummy event. */
639                               event.type = 0;
640                               event.value = 0;
641                               if (wsevent_inject(evar, &event, 1) != 0)
642                                         wsevent_wakeup(evar);
643 
644                               /* Wait for processes to go away. */
645                               if (tsleep(sc, PZERO, "wskdet", hz * 60))
646                                         aprint_error("wskbd_detach: %s didn't detach\n",
647                                                device_xname(self));
648                     }
649                     splx(s);
650           }
651 
652           /* locate the major number */
653           maj = cdevsw_lookup_major(&wskbd_cdevsw);
654 
655           /* Nuke the vnodes for any open instances. */
656           mn = device_unit(self);
657           vdevgone(maj, mn, mn, VCHR);
658 
659           return (0);
660 }
661 
662 void
wskbd_input(device_t dev,u_int type,int value)663 wskbd_input(device_t dev, u_int type, int value)
664 {
665           struct wskbd_softc *sc = device_private(dev);
666 #if NWSDISPLAY > 0
667           int num, i;
668 #endif
669 
670           if (sc->sc_repeating) {
671                     sc->sc_repeating = 0;
672                     callout_stop(&sc->sc_repeat_ch);
673           }
674 
675           device_active(dev, DVA_HARDWARE);
676 
677 #if NWSDISPLAY > 0
678           /*
679            * If /dev/wskbdN is not connected in event mode translate and
680            * send upstream.
681            */
682           if (sc->sc_translating) {
683                     num = wskbd_translate(sc->id, type, value);
684                     if (num > 0) {
685                               if (sc->sc_base.me_dispdv != NULL) {
686 #ifdef WSDISPLAY_SCROLLSUPPORT
687                                         if (sc->id->t_symbols [0] != KS_Print_Screen) {
688                                                   wsdisplay_scroll(sc->sc_base.
689                                                   me_dispdv, WSDISPLAY_SCROLL_RESET);
690                                         }
691 #endif
692                                         for (i = 0; i < num; i++)
693                                                   wsdisplay_kbdinput(
694                                                             sc->sc_base.me_dispdv,
695                                                             sc->id->t_symbols[i]);
696                               }
697 
698                               if (sc->sc_keyrepeat_data.del1 != 0) {
699                                         sc->sc_repeating = num;
700                                         callout_schedule(&sc->sc_repeat_ch,
701                                             mstohz(sc->sc_keyrepeat_data.del1));
702                               }
703                     }
704                     return;
705           }
706 #endif
707 
708           wskbd_deliver_event(sc, type, value);
709 
710 #if defined(WSKBD_EVENT_AUTOREPEAT)
711           /* Repeat key presses if set. */
712           if (type == WSCONS_EVENT_KEY_DOWN && sc->sc_keyrepeat_data.del1 != 0) {
713                     sc->sc_repeat_type = type;
714                     sc->sc_repeat_value = value;
715                     sc->sc_repeating = 1;
716                     callout_schedule(&sc->sc_repeat_ch,
717                         mstohz(sc->sc_keyrepeat_data.del1));
718           }
719 #endif /* defined(WSKBD_EVENT_AUTOREPEAT) */
720 }
721 
722 /*
723  * Keyboard is generating events.  Turn this keystroke into an
724  * event and put it in the queue.  If the queue is full, the
725  * keystroke is lost (sorry!).
726  */
727 static void
wskbd_deliver_event(struct wskbd_softc * sc,u_int type,int value)728 wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value)
729 {
730           struct wseventvar *evar;
731           struct wscons_event event;
732 
733           evar = sc->sc_base.me_evp;
734 
735           if (evar == NULL || evar->q == NULL) {
736                     DPRINTF(("wskbd_input: not open\n"));
737                     return;
738           }
739 
740           event.type = type;
741           event.value = 0;
742           DPRINTF(("%d ->", value));
743           if (sc->sc_evtrans_len > 0) {
744                     if (sc->sc_evtrans_len > value) {
745                               DPRINTF(("%d", sc->sc_evtrans[value]));
746                               event.value = sc->sc_evtrans[value];
747                     }
748           } else {
749                     event.value = value;
750           }
751           DPRINTF(("\n"));
752           if (wsevent_inject(evar, &event, 1) != 0)
753                     log(LOG_WARNING, "%s: event queue overflow\n",
754                         device_xname(sc->sc_base.me_dv));
755 }
756 
757 #ifdef WSDISPLAY_COMPAT_RAWKBD
758 void
wskbd_rawinput(device_t dev,u_char * tbuf,int len)759 wskbd_rawinput(device_t dev, u_char *tbuf, int len)
760 {
761 #if NWSDISPLAY > 0
762           struct wskbd_softc *sc = device_private(dev);
763           int i;
764 
765           if (sc->sc_base.me_dispdv != NULL)
766                     for (i = 0; i < len; i++)
767                               wsdisplay_kbdinput(sc->sc_base.me_dispdv, tbuf[i]);
768           /* this is KS_GROUP_Plain */
769 #endif
770 }
771 #endif /* WSDISPLAY_COMPAT_RAWKBD */
772 
773 #if NWSDISPLAY > 0
774 static void
wskbd_holdscreen(struct wskbd_softc * sc,int hold)775 wskbd_holdscreen(struct wskbd_softc *sc, int hold)
776 {
777           int new_state;
778 
779           if (sc->sc_base.me_dispdv != NULL) {
780                     wsdisplay_kbdholdscreen(sc->sc_base.me_dispdv, hold);
781                     new_state = sc->sc_ledstate;
782                     if (hold) {
783 #ifdef WSDISPLAY_SCROLLSUPPORT
784                               sc->sc_scroll_data.mode = WSKBD_SCROLL_MODE_HOLD;
785 #endif
786                               new_state |= WSKBD_LED_SCROLL;
787                     } else {
788 #ifdef WSDISPLAY_SCROLLSUPPORT
789                               sc->sc_scroll_data.mode = WSKBD_SCROLL_MODE_NORMAL;
790 #endif
791                               new_state &= ~WSKBD_LED_SCROLL;
792                     }
793                     if (new_state != sc->sc_ledstate) {
794                               (*sc->sc_accessops->set_leds)(sc->sc_accesscookie,
795                                                                   new_state);
796                               sc->sc_ledstate = new_state;
797 #ifdef WSDISPLAY_SCROLLSUPPORT
798                               if (!hold)
799                                         wsdisplay_scroll(sc->sc_base.me_dispdv,
800                                             WSDISPLAY_SCROLL_RESET);
801 #endif
802                     }
803           }
804 }
805 #endif
806 
807 static int
wskbd_enable(struct wskbd_softc * sc,int on)808 wskbd_enable(struct wskbd_softc *sc, int on)
809 {
810           int error;
811 
812 #if 0
813 /* I don't understand the purpose of this code.  And it seems to
814  * break things, so it's out.  -- Lennart
815  */
816           if (!on && (!sc->sc_translating
817 #if NWSDISPLAY > 0
818                         || sc->sc_base.me_dispdv
819 #endif
820                     ))
821                     return (EBUSY);
822 #endif
823 #if NWSDISPLAY > 0
824           if (sc->sc_base.me_dispdv != NULL)
825                     return (0);
826 #endif
827 
828           /* Always cancel auto repeat when fiddling with the kbd. */
829           if (sc->sc_repeating) {
830                     sc->sc_repeating = 0;
831                     callout_stop(&sc->sc_repeat_ch);
832           }
833 
834           error = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on);
835           DPRINTF(("wskbd_enable: sc=%p on=%d res=%d\n", sc, on, error));
836           return (error);
837 }
838 
839 #if NWSMUX > 0
840 int
wskbd_mux_open(struct wsevsrc * me,struct wseventvar * evp)841 wskbd_mux_open(struct wsevsrc *me, struct wseventvar *evp)
842 {
843           struct wskbd_softc *sc = (struct wskbd_softc *)me;
844 
845           if (sc->sc_dying)
846                     return (EIO);
847 
848           if (sc->sc_base.me_evp != NULL)
849                     return (EBUSY);
850 
851           return (wskbd_do_open(sc, evp));
852 }
853 #endif
854 
855 int
wskbdopen(dev_t dev,int flags,int mode,struct lwp * l)856 wskbdopen(dev_t dev, int flags, int mode, struct lwp *l)
857 {
858           struct wskbd_softc *sc = device_lookup_private(&wskbd_cd, minor(dev));
859           struct wseventvar *evar;
860           int error;
861 
862           if (sc == NULL)
863                     return (ENXIO);
864 
865 #if NWSMUX > 0
866           DPRINTF(("wskbdopen: %s mux=%p l=%p\n",
867               device_xname(sc->sc_base.me_dv), sc->sc_base.me_parent, l));
868 #endif
869 
870           if (sc->sc_dying)
871                     return (EIO);
872 
873           if ((flags & (FREAD | FWRITE)) == FWRITE)
874                     /* Not opening for read, only ioctl is available. */
875                     return (0);
876 
877 #if NWSMUX > 0
878           if (sc->sc_base.me_parent != NULL) {
879                     /* Grab the keyboard out of the greedy hands of the mux. */
880                     DPRINTF(("wskbdopen: detach\n"));
881                     wsmux_detach_sc(&sc->sc_base);
882           }
883 #endif
884 
885           if (sc->sc_base.me_evp != NULL)
886                     return (EBUSY);
887 
888           evar = &sc->sc_base.me_evar;
889           wsevent_init(evar, l->l_proc);
890 
891           error = wskbd_do_open(sc, evar);
892           if (error) {
893                     DPRINTF(("wskbdopen: %s open failed\n",
894                                device_xname(sc->sc_base.me_dv)));
895                     sc->sc_base.me_evp = NULL;
896                     wsevent_fini(evar);
897           }
898           return (error);
899 }
900 
901 int
wskbd_do_open(struct wskbd_softc * sc,struct wseventvar * evp)902 wskbd_do_open(struct wskbd_softc *sc, struct wseventvar *evp)
903 {
904           sc->sc_base.me_evp = evp;
905           sc->sc_translating = 0;
906 
907           return (wskbd_enable(sc, 1));
908 }
909 
910 int
wskbdclose(dev_t dev,int flags,int mode,struct lwp * l)911 wskbdclose(dev_t dev, int flags, int mode,
912     struct lwp *l)
913 {
914           struct wskbd_softc *sc =
915               device_lookup_private(&wskbd_cd, minor(dev));
916           struct wseventvar *evar = sc->sc_base.me_evp;
917 
918 #if NWSMUX > 0
919           DPRINTF(("wskbdclose: %s mux=%p p=%p\n", device_xname(sc->sc_base.me_dv),
920                      sc->sc_base.me_parent, l));
921 #endif
922 
923           if (evar == NULL) {
924                     /* not open for read */
925                     return (0);
926           }
927 
928           sc->sc_base.me_evp = NULL;
929           sc->sc_translating = 1;
930           (void)wskbd_enable(sc, 0);
931           wsevent_fini(evar);
932 
933           return (0);
934 }
935 
936 #if NWSMUX > 0
937 int
wskbd_mux_close(struct wsevsrc * me)938 wskbd_mux_close(struct wsevsrc *me)
939 {
940           struct wskbd_softc *sc = (struct wskbd_softc *)me;
941 
942           sc->sc_base.me_evp = NULL;
943           sc->sc_translating = 1;
944           (void)wskbd_enable(sc, 0);
945 
946           return (0);
947 }
948 #endif
949 
950 int
wskbdread(dev_t dev,struct uio * uio,int flags)951 wskbdread(dev_t dev, struct uio *uio, int flags)
952 {
953           struct wskbd_softc *sc =
954               device_lookup_private(&wskbd_cd, minor(dev));
955           int error;
956 
957           if (sc->sc_dying)
958                     return (EIO);
959 
960           KASSERTMSG(sc->sc_base.me_evp != NULL, "wskbdread: evp == NULL\n");
961 
962           sc->sc_refcnt++;
963           error = wsevent_read(sc->sc_base.me_evp, uio, flags);
964           if (--sc->sc_refcnt < 0) {
965                     wakeup(sc);
966                     error = EIO;
967           }
968           return (error);
969 }
970 
971 int
wskbdioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)972 wskbdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
973 {
974           return (wskbd_do_ioctl(device_lookup(&wskbd_cd, minor(dev)),
975               cmd, data, flag,l));
976 }
977 
978 /* A wrapper around the ioctl() workhorse to make reference counting easy. */
979 int
wskbd_do_ioctl(device_t dv,u_long cmd,void * data,int flag,struct lwp * l)980 wskbd_do_ioctl(device_t dv, u_long cmd, void *data, int flag,
981           struct lwp *l)
982 {
983           struct wskbd_softc *sc = device_private(dv);
984           int error;
985 
986           sc->sc_refcnt++;
987           error = wskbd_do_ioctl_sc(sc, cmd, data, flag, l);
988           if (--sc->sc_refcnt < 0)
989                     wakeup(sc);
990           return (error);
991 }
992 
993 int
wskbd_do_ioctl_sc(struct wskbd_softc * sc,u_long cmd,void * data,int flag,struct lwp * l)994 wskbd_do_ioctl_sc(struct wskbd_softc *sc, u_long cmd, void *data, int flag,
995                       struct lwp *l)
996 {
997 
998           /*
999            * Try the generic ioctls that the wskbd interface supports.
1000            */
1001           switch (cmd) {
1002           case FIONBIO:                 /* we will remove this someday (soon???) */
1003                     return (0);
1004 
1005           case FIOASYNC:
1006                     if (sc->sc_base.me_evp == NULL)
1007                               return (EINVAL);
1008                     sc->sc_base.me_evp->async = *(int *)data != 0;
1009                     return (0);
1010 
1011           case FIOSETOWN:
1012                     if (sc->sc_base.me_evp == NULL)
1013                               return (EINVAL);
1014                     if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid
1015                         && *(int *)data != sc->sc_base.me_evp->io->p_pid)
1016                               return (EPERM);
1017                     return (0);
1018 
1019           case TIOCSPGRP:
1020                     if (sc->sc_base.me_evp == NULL)
1021                               return (EINVAL);
1022                     if (*(int *)data != sc->sc_base.me_evp->io->p_pgid)
1023                               return (EPERM);
1024                     return (0);
1025           }
1026 
1027           /*
1028            * Try the keyboard driver for WSKBDIO ioctls.  It returns EPASSTHROUGH
1029            * if it didn't recognize the request.
1030            */
1031           return (wskbd_displayioctl(sc->sc_base.me_dv, cmd, data, flag, l));
1032 }
1033 
1034 /*
1035  * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
1036  * Some of these have no real effect in raw mode, however.
1037  */
1038 static int
wskbd_displayioctl(device_t dev,u_long cmd,void * data,int flag,struct lwp * l)1039 wskbd_displayioctl(device_t dev, u_long cmd, void *data, int flag,
1040           struct lwp *l)
1041 {
1042 #ifdef WSDISPLAY_SCROLLSUPPORT
1043           struct wskbd_scroll_data *usdp, *ksdp;
1044 #endif
1045           struct wskbd_softc *sc = device_private(dev);
1046           struct wskbd_bell_data *ubdp, *kbdp;
1047           struct wskbd_keyrepeat_data *ukdp, *kkdp;
1048           struct wskbd_map_data *umdp;
1049           struct wskbd_mapdata md;
1050           kbd_t enc;
1051           void *tbuf;
1052           int len, error;
1053 
1054           switch (cmd) {
1055           case WSKBDIO_BELL:
1056                     if ((flag & FWRITE) == 0)
1057                               return (EACCES);
1058                     return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1059                         WSKBDIO_COMPLEXBELL, (void *)&sc->sc_bell_data, flag, l));
1060 
1061           case WSKBDIO_COMPLEXBELL:
1062                     if ((flag & FWRITE) == 0)
1063                               return (EACCES);
1064                     ubdp = (struct wskbd_bell_data *)data;
1065                     SETBELL(ubdp, ubdp, &sc->sc_bell_data);
1066                     return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1067                         WSKBDIO_COMPLEXBELL, (void *)ubdp, flag, l));
1068 
1069           case WSKBDIO_SETBELL:
1070                     if ((flag & FWRITE) == 0)
1071                               return (EACCES);
1072                     kbdp = &sc->sc_bell_data;
1073 setbell:
1074                     ubdp = (struct wskbd_bell_data *)data;
1075                     SETBELL(kbdp, ubdp, kbdp);
1076                     return (0);
1077 
1078           case WSKBDIO_GETBELL:
1079                     kbdp = &sc->sc_bell_data;
1080 getbell:
1081                     ubdp = (struct wskbd_bell_data *)data;
1082                     SETBELL(ubdp, kbdp, kbdp);
1083                     return (0);
1084 
1085           case WSKBDIO_SETDEFAULTBELL:
1086                     if ((error = kauth_authorize_device(l->l_cred,
1087                         KAUTH_DEVICE_WSCONS_KEYBOARD_BELL, NULL, NULL,
1088                         NULL, NULL)) != 0)
1089                               return (error);
1090                     kbdp = &wskbd_default_bell_data;
1091                     goto setbell;
1092 
1093 
1094           case WSKBDIO_GETDEFAULTBELL:
1095                     kbdp = &wskbd_default_bell_data;
1096                     goto getbell;
1097 
1098 #undef SETBELL
1099 
1100 #define   SETKEYREPEAT(dstp, srcp, dfltp)                                                 \
1101     do {                                                                        \
1102           (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ?   \
1103               (srcp)->del1 : (dfltp)->del1;                                     \
1104           (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ?   \
1105               (srcp)->delN : (dfltp)->delN;                                     \
1106           (dstp)->which = WSKBD_KEYREPEAT_DOALL;                                \
1107     } while (0)
1108 
1109           case WSKBDIO_SETKEYREPEAT:
1110                     if ((flag & FWRITE) == 0)
1111                               return (EACCES);
1112                     kkdp = &sc->sc_keyrepeat_data;
1113 setkeyrepeat:
1114                     ukdp = (struct wskbd_keyrepeat_data *)data;
1115                     SETKEYREPEAT(kkdp, ukdp, kkdp);
1116                     return (0);
1117 
1118           case WSKBDIO_GETKEYREPEAT:
1119                     kkdp = &sc->sc_keyrepeat_data;
1120 getkeyrepeat:
1121                     ukdp = (struct wskbd_keyrepeat_data *)data;
1122                     SETKEYREPEAT(ukdp, kkdp, kkdp);
1123                     return (0);
1124 
1125           case WSKBDIO_SETDEFAULTKEYREPEAT:
1126                     if ((error = kauth_authorize_device(l->l_cred,
1127                         KAUTH_DEVICE_WSCONS_KEYBOARD_KEYREPEAT, NULL, NULL,
1128                         NULL, NULL)) != 0)
1129                               return (error);
1130                     kkdp = &wskbd_default_keyrepeat_data;
1131                     goto setkeyrepeat;
1132 
1133 
1134           case WSKBDIO_GETDEFAULTKEYREPEAT:
1135                     kkdp = &wskbd_default_keyrepeat_data;
1136                     goto getkeyrepeat;
1137 
1138 #ifdef WSDISPLAY_SCROLLSUPPORT
1139 #define   SETSCROLLMOD(dstp, srcp, dfltp)                                                 \
1140     do {                                                                        \
1141           (dstp)->mode = ((srcp)->which & WSKBD_SCROLL_DOMODE) ?                \
1142               (srcp)->mode : (dfltp)->mode;                                     \
1143           (dstp)->modifier = ((srcp)->which & WSKBD_SCROLL_DOMODIFIER) ?        \
1144               (srcp)->modifier : (dfltp)->modifier;                             \
1145           (dstp)->which = WSKBD_SCROLL_DOALL;                                   \
1146     } while (0)
1147 
1148           case WSKBDIO_SETSCROLL:
1149                     usdp = (struct wskbd_scroll_data *)data;
1150                     ksdp = &sc->sc_scroll_data;
1151                     SETSCROLLMOD(ksdp, usdp, ksdp);
1152                     return (0);
1153 
1154           case WSKBDIO_GETSCROLL:
1155                     usdp = (struct wskbd_scroll_data *)data;
1156                     ksdp = &sc->sc_scroll_data;
1157                     SETSCROLLMOD(usdp, ksdp, ksdp);
1158                     return (0);
1159 #else
1160           case WSKBDIO_GETSCROLL:
1161           case WSKBDIO_SETSCROLL:
1162                     return ENODEV;
1163 #endif
1164 
1165 #undef SETKEYREPEAT
1166 
1167           case WSKBDIO_SETMAP:
1168                     if ((flag & FWRITE) == 0)
1169                               return (EACCES);
1170                     umdp = (struct wskbd_map_data *)data;
1171                     if (umdp->maplen > WSKBDIO_MAXMAPLEN)
1172                               return (EINVAL);
1173 
1174                     len = umdp->maplen*sizeof(struct wscons_keymap);
1175                     tbuf = malloc(len, M_TEMP, M_WAITOK);
1176                     error = copyin(umdp->map, tbuf, len);
1177                     if (error == 0) {
1178                               wskbd_init_keymap(umdp->maplen,
1179                                                     &sc->sc_map, &sc->sc_maplen);
1180                               memcpy(sc->sc_map, tbuf, len);
1181                               /* drop the variant bits handled by the map */
1182                               sc->sc_layout = KB_USER |
1183                                     (KB_VARIANT(sc->sc_layout) & KB_HANDLEDBYWSKBD);
1184                               wskbd_update_layout(sc->id, sc->sc_layout);
1185                     }
1186                     free(tbuf, M_TEMP);
1187                     return(error);
1188 
1189           case WSKBDIO_GETMAP:
1190                     umdp = (struct wskbd_map_data *)data;
1191                     if (umdp->maplen > sc->sc_maplen)
1192                               umdp->maplen = sc->sc_maplen;
1193                     error = copyout(sc->sc_map, umdp->map,
1194                                         umdp->maplen*sizeof(struct wscons_keymap));
1195                     return(error);
1196 
1197           case WSKBDIO_GETENCODING:
1198                     *((kbd_t *) data) = sc->sc_layout;
1199                     return(0);
1200 
1201           case WSKBDIO_SETENCODING:
1202                     if ((flag & FWRITE) == 0)
1203                               return (EACCES);
1204                     enc = *((kbd_t *)data);
1205                     if (KB_ENCODING(enc) == KB_USER) {
1206                               /* user map must already be loaded */
1207                               if (KB_ENCODING(sc->sc_layout) != KB_USER)
1208                                         return (EINVAL);
1209                               /* map variants make no sense */
1210                               if (KB_VARIANT(enc) & ~KB_HANDLEDBYWSKBD)
1211                                         return (EINVAL);
1212                     } else {
1213                               md = *(sc->id->t_keymap); /* structure assignment */
1214                               md.layout = enc;
1215                               error = wskbd_load_keymap(&md, &sc->sc_map,
1216                                                               &sc->sc_maplen);
1217                               if (error)
1218                                         return (error);
1219                     }
1220                     sc->sc_layout = enc;
1221                     wskbd_update_layout(sc->id, enc);
1222                     return (0);
1223 
1224           case WSKBDIO_SETVERSION:
1225                     return wsevent_setversion(sc->sc_base.me_evp, *(int *)data);
1226           }
1227 
1228           /*
1229            * Try the keyboard driver for WSKBDIO ioctls.  It returns -1
1230            * if it didn't recognize the request, and in turn we return
1231            * -1 if we didn't recognize the request.
1232            */
1233 /* printf("kbdaccess\n"); */
1234           error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
1235                                                      flag, l);
1236 #ifdef WSDISPLAY_COMPAT_RAWKBD
1237           if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
1238                     int s = spltty();
1239                     sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
1240                                                    | MOD_CONTROL_L | MOD_CONTROL_R
1241                                                    | MOD_META_L | MOD_META_R
1242                                                    | MOD_COMMAND
1243                                                    | MOD_COMMAND1 | MOD_COMMAND2);
1244                     if (sc->sc_repeating) {
1245                               sc->sc_repeating = 0;
1246                               callout_stop(&sc->sc_repeat_ch);
1247                     }
1248                     splx(s);
1249           }
1250 #endif
1251           return (error);
1252 }
1253 
1254 int
wskbdpoll(dev_t dev,int events,struct lwp * l)1255 wskbdpoll(dev_t dev, int events, struct lwp *l)
1256 {
1257           struct wskbd_softc *sc =
1258               device_lookup_private(&wskbd_cd, minor(dev));
1259 
1260           if (sc->sc_base.me_evp == NULL)
1261                     return (POLLERR);
1262           return (wsevent_poll(sc->sc_base.me_evp, events, l));
1263 }
1264 
1265 int
wskbdkqfilter(dev_t dev,struct knote * kn)1266 wskbdkqfilter(dev_t dev, struct knote *kn)
1267 {
1268           struct wskbd_softc *sc =
1269               device_lookup_private(&wskbd_cd, minor(dev));
1270 
1271           if (sc->sc_base.me_evp == NULL)
1272                     return (1);
1273           return (wsevent_kqfilter(sc->sc_base.me_evp, kn));
1274 }
1275 
1276 #if NWSDISPLAY > 0
1277 
1278 int
wskbd_pickfree(void)1279 wskbd_pickfree(void)
1280 {
1281           int i;
1282           struct wskbd_softc *sc;
1283 
1284           for (i = 0; i < wskbd_cd.cd_ndevs; i++) {
1285                     sc = device_lookup_private(&wskbd_cd, i);
1286                     if (sc == NULL)
1287                               continue;
1288                     if (sc->sc_base.me_dispdv == NULL)
1289                               return (i);
1290           }
1291           return (-1);
1292 }
1293 
1294 struct wsevsrc *
wskbd_set_console_display(device_t displaydv,struct wsevsrc * me)1295 wskbd_set_console_display(device_t displaydv, struct wsevsrc *me)
1296 {
1297           struct wskbd_softc *sc = wskbd_console_device;
1298 
1299           if (sc == NULL)
1300                     return (NULL);
1301           sc->sc_base.me_dispdv = displaydv;
1302 #if NWSMUX > 0
1303           (void)wsmux_attach_sc((struct wsmux_softc *)me, &sc->sc_base);
1304 #endif
1305           return (&sc->sc_base);
1306 }
1307 
1308 int
wskbd_set_display(device_t dv,struct wsevsrc * me)1309 wskbd_set_display(device_t dv, struct wsevsrc *me)
1310 {
1311           struct wskbd_softc *sc = device_private(dv);
1312           device_t displaydv = me != NULL ? me->me_dispdv : NULL;
1313           device_t odisplaydv;
1314           int error;
1315 
1316           DPRINTF(("wskbd_set_display: %s me=%p odisp=%p disp=%p cons=%d\n",
1317                      device_xname(dv), me, sc->sc_base.me_dispdv, displaydv,
1318                      sc->sc_isconsole));
1319 
1320           if (sc->sc_isconsole)
1321                     return (EBUSY);
1322 
1323           if (displaydv != NULL) {
1324                     if (sc->sc_base.me_dispdv != NULL)
1325                               return (EBUSY);
1326           } else {
1327                     if (sc->sc_base.me_dispdv == NULL)
1328                               return (ENXIO);
1329           }
1330 
1331           odisplaydv = sc->sc_base.me_dispdv;
1332           sc->sc_base.me_dispdv = NULL;
1333           error = wskbd_enable(sc, displaydv != NULL);
1334           sc->sc_base.me_dispdv = displaydv;
1335           if (error) {
1336                     sc->sc_base.me_dispdv = odisplaydv;
1337                     return (error);
1338           }
1339 
1340           if (displaydv)
1341                     aprint_verbose_dev(sc->sc_base.me_dv, "connecting to %s\n",
1342                            device_xname(displaydv));
1343           else
1344                     aprint_verbose_dev(sc->sc_base.me_dv, "disconnecting from %s\n",
1345                            device_xname(odisplaydv));
1346 
1347           return (0);
1348 }
1349 
1350 #endif /* NWSDISPLAY > 0 */
1351 
1352 #if NWSMUX > 0
1353 int
wskbd_add_mux(int unit,struct wsmux_softc * muxsc)1354 wskbd_add_mux(int unit, struct wsmux_softc *muxsc)
1355 {
1356           struct wskbd_softc *sc = device_lookup_private(&wskbd_cd, unit);
1357 
1358           if (sc == NULL)
1359                     return (ENXIO);
1360 
1361           if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL)
1362                     return (EBUSY);
1363 
1364           return (wsmux_attach_sc(muxsc, &sc->sc_base));
1365 }
1366 #endif
1367 
1368 /*
1369  * Console interface.
1370  */
1371 int
wskbd_cngetc(dev_t dev)1372 wskbd_cngetc(dev_t dev)
1373 {
1374           static int num = 0;
1375           static int pos;
1376           u_int type;
1377           int data;
1378           keysym_t ks;
1379 
1380           if (!wskbd_console_initted)
1381                     return -1;
1382 
1383           if (wskbd_console_device != NULL &&
1384               !wskbd_console_device->sc_translating)
1385                     return -1;
1386 
1387           for(;;) {
1388                     if (num-- > 0) {
1389                               ks = wskbd_console_data.t_symbols[pos++];
1390                               if (KS_GROUP(ks) == KS_GROUP_Plain)
1391                                         return (KS_VALUE(ks));
1392                     } else {
1393                               (*wskbd_console_data.t_consops->getc)
1394                                         (wskbd_console_data.t_consaccesscookie,
1395                                          &type, &data);
1396                               if (type == 0) {
1397                                         /* No data returned */
1398                                         return -1;
1399                               }
1400                               if (type == WSCONS_EVENT_ASCII) {
1401                                         /*
1402                                          * We assume that when the driver falls back
1403                                          * to deliver pure ASCII it is in a state that
1404                                          * it can not track press/release events
1405                                          * reliable - so we clear all previously
1406                                          * accumulated modifier state.
1407                                          */
1408                                         wskbd_console_data.t_modifiers = 0;
1409                                         return(data);
1410                               }
1411                               num = wskbd_translate(&wskbd_console_data, type, data);
1412                               pos = 0;
1413                     }
1414           }
1415 }
1416 
1417 void
wskbd_cnpollc(dev_t dev,int poll)1418 wskbd_cnpollc(dev_t dev, int poll)
1419 {
1420 
1421           if (!wskbd_console_initted)
1422                     return;
1423 
1424           if (wskbd_console_device != NULL &&
1425               !wskbd_console_device->sc_translating)
1426                     return;
1427 
1428           (*wskbd_console_data.t_consops->pollc)
1429               (wskbd_console_data.t_consaccesscookie, poll);
1430 }
1431 
1432 void
wskbd_cnbell(dev_t dev,u_int pitch,u_int period,u_int volume)1433 wskbd_cnbell(dev_t dev, u_int pitch, u_int period, u_int volume)
1434 {
1435 
1436           if (!wskbd_console_initted)
1437                     return;
1438 
1439           if (wskbd_console_data.t_consops->bell != NULL)
1440                     (*wskbd_console_data.t_consops->bell)
1441                         (wskbd_console_data.t_consaccesscookie, pitch, period,
1442                               volume);
1443 }
1444 
1445 static inline void
update_leds(struct wskbd_internal * id)1446 update_leds(struct wskbd_internal *id)
1447 {
1448           int new_state;
1449 
1450           new_state = 0;
1451           if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
1452                     new_state |= WSKBD_LED_CAPS;
1453           if (id->t_modifiers & MOD_NUMLOCK)
1454                     new_state |= WSKBD_LED_NUM;
1455           if (id->t_modifiers & MOD_COMPOSE)
1456                     new_state |= WSKBD_LED_COMPOSE;
1457           if (id->t_modifiers & MOD_HOLDSCREEN)
1458                     new_state |= WSKBD_LED_SCROLL;
1459 
1460           if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
1461                     (*id->t_sc->sc_accessops->set_leds)
1462                         (id->t_sc->sc_accesscookie, new_state);
1463                     id->t_sc->sc_ledstate = new_state;
1464           }
1465 }
1466 
1467 static inline void
update_modifier(struct wskbd_internal * id,u_int type,int toggle,int mask)1468 update_modifier(struct wskbd_internal *id, u_int type, int toggle, int mask)
1469 {
1470           if (toggle) {
1471                     if (type == WSCONS_EVENT_KEY_DOWN)
1472                               id->t_modifiers ^= mask;
1473           } else {
1474                     if (type == WSCONS_EVENT_KEY_DOWN)
1475                               id->t_modifiers |= mask;
1476                     else
1477                               id->t_modifiers &= ~mask;
1478           }
1479 }
1480 
1481 #if NWSDISPLAY > 0
1482 static void
change_displayparam(struct wskbd_softc * sc,int param,int updown,int wraparound)1483 change_displayparam(struct wskbd_softc *sc, int param, int updown,
1484           int wraparound)
1485 {
1486           int res;
1487           struct wsdisplay_param dp;
1488 
1489           dp.param = param;
1490           res = wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_GETPARAM, &dp);
1491 
1492           if (res == EINVAL)
1493                     return; /* no such parameter */
1494 
1495           dp.curval += updown;
1496           if (dp.max < dp.curval)
1497                     dp.curval = wraparound ? dp.min : dp.max;
1498           else
1499           if (dp.curval < dp.min)
1500                     dp.curval = wraparound ? dp.max : dp.min;
1501           wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_SETPARAM, &dp);
1502 }
1503 #endif
1504 
1505 static int
internal_command(struct wskbd_softc * sc,u_int * type,keysym_t ksym,keysym_t ksym2)1506 internal_command(struct wskbd_softc *sc, u_int *type, keysym_t ksym,
1507           keysym_t ksym2)
1508 {
1509 #if NWSDISPLAY > 0 && defined(WSDISPLAY_SCROLLSUPPORT)
1510           u_int state = 0;
1511 #endif
1512           switch (ksym) {
1513           case KS_Cmd_VolumeToggle:
1514                     if (*type == WSCONS_EVENT_KEY_DOWN)
1515                               pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_TOGGLE);
1516                     break;
1517           case KS_Cmd_VolumeUp:
1518                     if (*type == WSCONS_EVENT_KEY_DOWN)
1519                               pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_UP);
1520                     break;
1521           case KS_Cmd_VolumeDown:
1522                     if (*type == WSCONS_EVENT_KEY_DOWN)
1523                               pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_DOWN);
1524                     break;
1525 #if NWSDISPLAY > 0 && defined(WSDISPLAY_SCROLLSUPPORT)
1526           case KS_Cmd_ScrollFastUp:
1527           case KS_Cmd_ScrollFastDown:
1528                     if (*type == WSCONS_EVENT_KEY_DOWN) {
1529                               GETMODSTATE(sc->id->t_modifiers, state);
1530                               if ((sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_HOLD
1531                                         && MOD_ONESET(sc->id, MOD_HOLDSCREEN))
1532                               || (sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_NORMAL
1533                                         && sc->sc_scroll_data.modifier == state)) {
1534                                                   update_modifier(sc->id, *type, 0, MOD_COMMAND);
1535                                                   wsdisplay_scroll(sc->sc_base.me_dispdv,
1536                                                             (ksym == KS_Cmd_ScrollFastUp) ?
1537                                                             WSDISPLAY_SCROLL_BACKWARD :
1538                                                             WSDISPLAY_SCROLL_FORWARD);
1539                                                   return (1);
1540                               } else {
1541                                         return (0);
1542                               }
1543                     } else
1544                               update_modifier(sc->id, *type, 0, MOD_COMMAND);
1545                     break;
1546 
1547           case KS_Cmd_ScrollSlowUp:
1548           case KS_Cmd_ScrollSlowDown:
1549                     if (*type == WSCONS_EVENT_KEY_DOWN) {
1550                               GETMODSTATE(sc->id->t_modifiers, state);
1551                               if ((sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_HOLD
1552                                         && MOD_ONESET(sc->id, MOD_HOLDSCREEN))
1553                               || (sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_NORMAL
1554                                         && sc->sc_scroll_data.modifier == state)) {
1555                                                   update_modifier(sc->id, *type, 0, MOD_COMMAND);
1556                                                   wsdisplay_scroll(sc->sc_base.me_dispdv,
1557                                                             (ksym == KS_Cmd_ScrollSlowUp) ?
1558                                                             WSDISPLAY_SCROLL_BACKWARD | WSDISPLAY_SCROLL_LOW:
1559                                                             WSDISPLAY_SCROLL_FORWARD | WSDISPLAY_SCROLL_LOW);
1560                                                   return (1);
1561                               } else {
1562                                         return (0);
1563                               }
1564                     } else
1565                               update_modifier(sc->id, *type, 0, MOD_COMMAND);
1566                     break;
1567 #endif
1568 
1569           case KS_Cmd:
1570                     update_modifier(sc->id, *type, 0, MOD_COMMAND);
1571                     ksym = ksym2;
1572                     break;
1573 
1574           case KS_Cmd1:
1575                     update_modifier(sc->id, *type, 0, MOD_COMMAND1);
1576                     break;
1577 
1578           case KS_Cmd2:
1579                     update_modifier(sc->id, *type, 0, MOD_COMMAND2);
1580                     break;
1581           }
1582 
1583           if (*type != WSCONS_EVENT_KEY_DOWN ||
1584               (! MOD_ONESET(sc->id, MOD_COMMAND) &&
1585                ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)))
1586                     return (0);
1587 
1588 #if defined(DDB) || defined(KGDB)
1589           if (ksym == KS_Cmd_Debugger) {
1590                     if (sc->sc_isconsole) {
1591 #ifdef DDB
1592                               console_debugger();
1593 #endif
1594 #ifdef KGDB
1595                               kgdb_connect(1);
1596 #endif
1597                     }
1598                     /* discard this key (ddb discarded command modifiers) */
1599                     *type = WSCONS_EVENT_KEY_UP;
1600                     return (1);
1601           }
1602 #endif
1603 
1604 #if NWSDISPLAY > 0
1605           if (sc->sc_base.me_dispdv == NULL)
1606                     return (0);
1607 
1608           switch (ksym) {
1609           case KS_Cmd_Screen0:
1610           case KS_Cmd_Screen1:
1611           case KS_Cmd_Screen2:
1612           case KS_Cmd_Screen3:
1613           case KS_Cmd_Screen4:
1614           case KS_Cmd_Screen5:
1615           case KS_Cmd_Screen6:
1616           case KS_Cmd_Screen7:
1617           case KS_Cmd_Screen8:
1618           case KS_Cmd_Screen9:
1619                     wsdisplay_switch(sc->sc_base.me_dispdv, ksym - KS_Cmd_Screen0, 0);
1620                     return (1);
1621           case KS_Cmd_ResetEmul:
1622                     wsdisplay_reset(sc->sc_base.me_dispdv, WSDISPLAY_RESETEMUL);
1623                     return (1);
1624           case KS_Cmd_ResetClose:
1625                     wsdisplay_reset(sc->sc_base.me_dispdv, WSDISPLAY_RESETCLOSE);
1626                     return (1);
1627           case KS_Cmd_BacklightOn:
1628           case KS_Cmd_BacklightOff:
1629           case KS_Cmd_BacklightToggle:
1630                     change_displayparam(sc, WSDISPLAYIO_PARAM_BACKLIGHT,
1631                                             ksym == KS_Cmd_BacklightOff ? -1 : 1,
1632                                             ksym == KS_Cmd_BacklightToggle ? 1 : 0);
1633                     return (1);
1634           case KS_Cmd_BrightnessUp:
1635           case KS_Cmd_BrightnessDown:
1636           case KS_Cmd_BrightnessRotate:
1637                     change_displayparam(sc, WSDISPLAYIO_PARAM_BRIGHTNESS,
1638                                             ksym == KS_Cmd_BrightnessDown ? -1 : 1,
1639                                             ksym == KS_Cmd_BrightnessRotate ? 1 : 0);
1640                     return (1);
1641           case KS_Cmd_ContrastUp:
1642           case KS_Cmd_ContrastDown:
1643           case KS_Cmd_ContrastRotate:
1644                     change_displayparam(sc, WSDISPLAYIO_PARAM_CONTRAST,
1645                                             ksym == KS_Cmd_ContrastDown ? -1 : 1,
1646                                             ksym == KS_Cmd_ContrastRotate ? 1 : 0);
1647                     return (1);
1648           }
1649 #endif
1650 
1651           return (0);
1652 }
1653 
1654 device_t
wskbd_hotkey_register(device_t self,void * cookie,wskbd_hotkey_plugin * hotkey)1655 wskbd_hotkey_register(device_t self, void *cookie, wskbd_hotkey_plugin *hotkey)
1656 {
1657           struct wskbd_softc *sc = device_private(self);
1658 
1659           KASSERT(sc != NULL);
1660           KASSERT(hotkey != NULL);
1661 
1662           sc->sc_hotkey = hotkey;
1663           sc->sc_hotkeycookie = cookie;
1664 
1665           return sc->sc_base.me_dv;
1666 }
1667 
1668 void
wskbd_hotkey_deregister(device_t self)1669 wskbd_hotkey_deregister(device_t self)
1670 {
1671           struct wskbd_softc *sc = device_private(self);
1672 
1673           KASSERT(sc != NULL);
1674 
1675           sc->sc_hotkey = NULL;
1676           sc->sc_hotkeycookie = NULL;
1677 }
1678 
1679 static int
wskbd_translate(struct wskbd_internal * id,u_int type,int value)1680 wskbd_translate(struct wskbd_internal *id, u_int type, int value)
1681 {
1682           struct wskbd_softc *sc = id->t_sc;
1683           keysym_t ksym, res, *group;
1684           struct wscons_keymap kpbuf, *kp;
1685           int iscommand = 0;
1686           int ishotkey = 0;
1687 
1688           if (type == WSCONS_EVENT_ALL_KEYS_UP) {
1689                     id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
1690                                         | MOD_CONTROL_L | MOD_CONTROL_R
1691                                         | MOD_META_L | MOD_META_R
1692                                         | MOD_MODESHIFT
1693                                         | MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
1694                     update_leds(id);
1695                     return (0);
1696           }
1697 
1698           if (sc != NULL) {
1699                     if (sc->sc_hotkey != NULL)
1700                               ishotkey = sc->sc_hotkey(sc, sc->sc_hotkeycookie,
1701                                                             type, value);
1702                     if (ishotkey)
1703                               return 0;
1704 
1705                     if (value < 0 || value >= sc->sc_maplen) {
1706 #ifdef DEBUG
1707                               printf("%s: keycode %d out of range\n",
1708                                      __func__, value);
1709 #endif
1710                               return (0);
1711                     }
1712                     kp = sc->sc_map + value;
1713           } else {
1714                     kp = &kpbuf;
1715                     wskbd_get_mapentry(id->t_keymap, value, kp);
1716           }
1717 
1718           /* if this key has a command, process it first */
1719           if (sc != NULL && kp->command != KS_voidSymbol)
1720                     iscommand = internal_command(sc, &type, kp->command,
1721                                                        kp->group1[0]);
1722 
1723           /* Now update modifiers */
1724           switch (kp->group1[0]) {
1725           case KS_Shift_L:
1726                     update_modifier(id, type, 0, MOD_SHIFT_L);
1727                     break;
1728 
1729           case KS_Shift_R:
1730                     update_modifier(id, type, 0, MOD_SHIFT_R);
1731                     break;
1732 
1733           case KS_Shift_Lock:
1734                     update_modifier(id, type, 1, MOD_SHIFTLOCK);
1735                     break;
1736 
1737           case KS_Caps_Lock:
1738                     update_modifier(id, type, 1, MOD_CAPSLOCK);
1739                     break;
1740 
1741           case KS_Control_L:
1742                     update_modifier(id, type, 0, MOD_CONTROL_L);
1743                     break;
1744 
1745           case KS_Control_R:
1746                     update_modifier(id, type, 0, MOD_CONTROL_R);
1747                     break;
1748 
1749           case KS_Alt_L:
1750                     update_modifier(id, type, 0, MOD_META_L);
1751                     break;
1752 
1753           case KS_Alt_R:
1754                     update_modifier(id, type, 0, MOD_META_R);
1755                     break;
1756 
1757           case KS_Mode_switch:
1758                     update_modifier(id, type, 0, MOD_MODESHIFT);
1759                     break;
1760 
1761           case KS_Num_Lock:
1762                     update_modifier(id, type, 1, MOD_NUMLOCK);
1763                     break;
1764 
1765 #if NWSDISPLAY > 0
1766           case KS_Hold_Screen:
1767                     if (sc != NULL) {
1768                               update_modifier(id, type, 1, MOD_HOLDSCREEN);
1769                               wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN);
1770                     }
1771                     break;
1772 #endif
1773           }
1774 
1775           /* If this is a key release or we are in command mode, we are done */
1776           if (type != WSCONS_EVENT_KEY_DOWN || iscommand) {
1777                     update_leds(id);
1778                     return (0);
1779           }
1780 
1781           /* Get the keysym */
1782           if (id->t_modifiers & MOD_MODESHIFT)
1783                     group = & kp->group2[0];
1784           else
1785                     group = & kp->group1[0];
1786 
1787           if ((id->t_modifiers & MOD_NUMLOCK) != 0 &&
1788               KS_GROUP(group[1]) == KS_GROUP_Keypad) {
1789                     if (MOD_ONESET(id, MOD_ANYSHIFT))
1790                               ksym = group[0];
1791                     else
1792                               ksym = group[1];
1793           } else if (! MOD_ONESET(id, MOD_ANYSHIFT | MOD_CAPSLOCK)) {
1794                     ksym = group[0];
1795           } else if (MOD_ONESET(id, MOD_CAPSLOCK)) {
1796                     if (! MOD_ONESET(id, MOD_SHIFT_L | MOD_SHIFT_R))
1797                               ksym = group[0];
1798                     else
1799                               ksym = group[1];
1800                     if (ksym >= KS_a && ksym <= KS_z)
1801                               ksym += KS_A - KS_a;
1802                     else if (ksym >= KS_agrave && ksym <= KS_thorn &&
1803                                ksym != KS_division)
1804                               ksym += KS_Agrave - KS_agrave;
1805           } else if (MOD_ONESET(id, MOD_ANYSHIFT)) {
1806                     ksym = group[1];
1807           } else {
1808                     ksym = group[0];
1809           }
1810 
1811           /* Process compose sequence and dead accents */
1812           res = KS_voidSymbol;
1813 
1814           switch (KS_GROUP(ksym)) {
1815           case KS_GROUP_Plain:
1816           case KS_GROUP_Keypad:
1817           case KS_GROUP_Function:
1818                     res = ksym;
1819                     break;
1820 
1821           case KS_GROUP_Mod:
1822                     if (ksym == KS_Multi_key) {
1823                               update_modifier(id, 1, 0, MOD_COMPOSE);
1824                               id->t_composelen = 2;
1825                     }
1826                     break;
1827 
1828           case KS_GROUP_Dead:
1829                     if (id->t_composelen == 0) {
1830                               update_modifier(id, 1, 0, MOD_COMPOSE);
1831                               id->t_composelen = 1;
1832                               id->t_composebuf[0] = ksym;
1833                     } else
1834                               res = ksym;
1835                     break;
1836           }
1837 
1838           if (res == KS_voidSymbol) {
1839                     update_leds(id);
1840                     return (0);
1841           }
1842 
1843           if (id->t_composelen > 0) {
1844                     id->t_composebuf[2 - id->t_composelen] = res;
1845                     if (--id->t_composelen == 0) {
1846                               res = wskbd_compose_value(id->t_composebuf);
1847                               update_modifier(id, 0, 0, MOD_COMPOSE);
1848                     } else {
1849                               return (0);
1850                     }
1851           }
1852 
1853           update_leds(id);
1854 
1855           /* We are done, return the symbol */
1856           if (KS_GROUP(res) == KS_GROUP_Plain) {
1857                     if (MOD_ONESET(id, MOD_ANYCONTROL)) {
1858                               if ((res >= KS_at && res <= KS_z) || res == KS_space)
1859                                         res = res & 0x1f;
1860                               else if (res == KS_2)
1861                                         res = 0x00;
1862                               else if (res >= KS_3 && res <= KS_7)
1863                                         res = KS_Escape + (res - KS_3);
1864                               else if (res == KS_8)
1865                                         res = KS_Delete;
1866                               /* convert CTL-/ to ^_ as xterm does (undo in emacs) */
1867                               else if (res == KS_slash)
1868                                         res = KS_underscore & 0x1f;
1869                     }
1870                     if (MOD_ONESET(id, MOD_ANYMETA)) {
1871                               if (id->t_flags & WSKFL_METAESC) {
1872                                         id->t_symbols[0] = KS_Escape;
1873                                         id->t_symbols[1] = res;
1874                                         return (2);
1875                               } else
1876                                         res |= 0x80;
1877                     }
1878           }
1879 
1880           id->t_symbols[0] = res;
1881           return (1);
1882 }
1883 
1884 void
wskbd_set_evtrans(device_t dev,keysym_t * tab,int len)1885 wskbd_set_evtrans(device_t dev, keysym_t *tab, int len)
1886 {
1887           struct wskbd_softc *sc = device_private(dev);
1888 
1889           sc->sc_evtrans_len = len;
1890           sc->sc_evtrans = tab;
1891 }
1892 
1893