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