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