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