wskbd.c revision 1.121 1 /* $NetBSD: wskbd.c,v 1.121 2009/01/13 18:05:55 christos 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.121 2009/01/13 18:05:55 christos Exp $");
109
110 #include "opt_ddb.h"
111 #include "opt_kgdb.h"
112 #include "opt_wsdisplay_compat.h"
113 #include "opt_compat_netbsd.h"
114
115 #include "wsdisplay.h"
116 #include "wskbd.h"
117 #include "wsmux.h"
118
119 #include <sys/param.h>
120 #include <sys/conf.h>
121 #include <sys/device.h>
122 #include <sys/ioctl.h>
123 #include <sys/poll.h>
124 #include <sys/kernel.h>
125 #include <sys/proc.h>
126 #include <sys/syslog.h>
127 #include <sys/systm.h>
128 #include <sys/callout.h>
129 #include <sys/malloc.h>
130 #include <sys/tty.h>
131 #include <sys/signalvar.h>
132 #include <sys/errno.h>
133 #include <sys/fcntl.h>
134 #include <sys/vnode.h>
135 #include <sys/kauth.h>
136
137 #include <dev/wscons/wsconsio.h>
138 #include <dev/wscons/wskbdvar.h>
139 #include <dev/wscons/wsksymdef.h>
140 #include <dev/wscons/wsksymvar.h>
141 #include <dev/wscons/wsdisplayvar.h>
142 #include <dev/wscons/wseventvar.h>
143 #include <dev/wscons/wscons_callbacks.h>
144
145 #ifdef KGDB
146 #include <sys/kgdb.h>
147 #endif
148
149 #ifdef WSKBD_DEBUG
150 #define DPRINTF(x) if (wskbddebug) printf x
151 int wskbddebug = 0;
152 #else
153 #define DPRINTF(x)
154 #endif
155
156 #include <dev/wscons/wsmuxvar.h>
157
158 struct wskbd_internal {
159 const struct wskbd_mapdata *t_keymap;
160
161 const struct wskbd_consops *t_consops;
162 void *t_consaccesscookie;
163
164 int t_modifiers;
165 int t_composelen; /* remaining entries in t_composebuf */
166 keysym_t t_composebuf[2];
167
168 int t_flags;
169 #define WSKFL_METAESC 1
170
171 #define MAXKEYSYMSPERKEY 2 /* ESC <key> at max */
172 keysym_t t_symbols[MAXKEYSYMSPERKEY];
173
174 struct wskbd_softc *t_sc; /* back pointer */
175 };
176
177 struct wskbd_softc {
178 struct wsevsrc sc_base;
179
180 struct wskbd_internal *id;
181
182 const struct wskbd_accessops *sc_accessops;
183 void *sc_accesscookie;
184
185 int sc_ledstate;
186
187 int sc_isconsole;
188
189 struct wskbd_bell_data sc_bell_data;
190 struct wskbd_keyrepeat_data sc_keyrepeat_data;
191 #ifdef WSDISPLAY_SCROLLSUPPORT
192 struct wskbd_scroll_data sc_scroll_data;
193 #endif
194
195 int sc_repeating; /* we've called timeout() */
196 callout_t sc_repeat_ch;
197 u_int sc_repeat_type;
198 int sc_repeat_value;
199
200 int sc_translating; /* xlate to chars for emulation */
201
202 int sc_maplen; /* number of entries in sc_map */
203 struct wscons_keymap *sc_map; /* current translation map */
204 kbd_t sc_layout; /* current layout */
205
206 int sc_refcnt;
207 u_char sc_dying; /* device is being detached */
208
209 wskbd_hotkey_plugin *sc_hotkey;
210 void *sc_hotkeycookie;
211 };
212
213 #define MOD_SHIFT_L (1 << 0)
214 #define MOD_SHIFT_R (1 << 1)
215 #define MOD_SHIFTLOCK (1 << 2)
216 #define MOD_CAPSLOCK (1 << 3)
217 #define MOD_CONTROL_L (1 << 4)
218 #define MOD_CONTROL_R (1 << 5)
219 #define MOD_META_L (1 << 6)
220 #define MOD_META_R (1 << 7)
221 #define MOD_MODESHIFT (1 << 8)
222 #define MOD_NUMLOCK (1 << 9)
223 #define MOD_COMPOSE (1 << 10)
224 #define MOD_HOLDSCREEN (1 << 11)
225 #define MOD_COMMAND (1 << 12)
226 #define MOD_COMMAND1 (1 << 13)
227 #define MOD_COMMAND2 (1 << 14)
228
229 #define MOD_ANYSHIFT (MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK)
230 #define MOD_ANYCONTROL (MOD_CONTROL_L | MOD_CONTROL_R)
231 #define MOD_ANYMETA (MOD_META_L | MOD_META_R)
232
233 #define MOD_ONESET(id, mask) (((id)->t_modifiers & (mask)) != 0)
234 #define MOD_ALLSET(id, mask) (((id)->t_modifiers & (mask)) == (mask))
235
236 #define GETMODSTATE(src, dst) \
237 do { \
238 dst |= (src & MOD_SHIFT_L) ? MOD_SHIFT_L : 0; \
239 dst |= (src & MOD_SHIFT_R) ? MOD_SHIFT_R : 0; \
240 dst |= (src & MOD_CONTROL_L) ? MOD_CONTROL_L : 0; \
241 dst |= (src & MOD_CONTROL_R) ? MOD_CONTROL_R : 0; \
242 dst |= (src & MOD_META_L) ? MOD_META_L : 0; \
243 dst |= (src & MOD_META_R) ? MOD_META_R : 0; \
244 } while (0)
245
246 static int wskbd_match(device_t, cfdata_t, void *);
247 static void wskbd_attach(device_t, device_t, void *);
248 static int wskbd_detach(device_t, int);
249 static int wskbd_activate(device_t, enum devact);
250
251 static int wskbd_displayioctl(device_t, u_long, void *, int,
252 struct lwp *);
253 #if NWSDISPLAY > 0
254 static int wskbd_set_display(device_t, struct wsevsrc *);
255 #else
256 #define wskbd_set_display NULL
257 #endif
258
259 static inline void update_leds(struct wskbd_internal *);
260 static inline void update_modifier(struct wskbd_internal *, u_int, int, int);
261 static int internal_command(struct wskbd_softc *, u_int *, keysym_t, keysym_t);
262 static int wskbd_translate(struct wskbd_internal *, u_int, int);
263 static int wskbd_enable(struct wskbd_softc *, int);
264 #if NWSDISPLAY > 0
265 static void change_displayparam(struct wskbd_softc *, int, int, int);
266 static void wskbd_holdscreen(struct wskbd_softc *, int);
267 #endif
268
269 static int wskbd_do_ioctl_sc(struct wskbd_softc *, u_long, void *, int,
270 struct lwp *);
271 static void wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value);
272
273 #if NWSMUX > 0
274 static int wskbd_mux_open(struct wsevsrc *, struct wseventvar *);
275 static int wskbd_mux_close(struct wsevsrc *);
276 #else
277 #define wskbd_mux_open NULL
278 #define wskbd_mux_close NULL
279 #endif
280
281 static int wskbd_do_open(struct wskbd_softc *, struct wseventvar *);
282 static int wskbd_do_ioctl(device_t, u_long, void *, int, struct lwp *);
283
284 CFATTACH_DECL_NEW(wskbd, sizeof (struct wskbd_softc),
285 wskbd_match, wskbd_attach, wskbd_detach, wskbd_activate);
286
287 extern struct cfdriver wskbd_cd;
288
289 dev_type_open(wskbdopen);
290 dev_type_close(wskbdclose);
291 dev_type_read(wskbdread);
292 dev_type_ioctl(wskbdioctl);
293 dev_type_poll(wskbdpoll);
294 dev_type_kqfilter(wskbdkqfilter);
295
296 const struct cdevsw wskbd_cdevsw = {
297 wskbdopen, wskbdclose, wskbdread, nowrite, wskbdioctl,
298 nostop, notty, wskbdpoll, nommap, wskbdkqfilter, D_OTHER
299 };
300
301 #ifndef WSKBD_DEFAULT_BELL_PITCH
302 #define WSKBD_DEFAULT_BELL_PITCH 1500 /* 1500Hz */
303 #endif
304 #ifndef WSKBD_DEFAULT_BELL_PERIOD
305 #define WSKBD_DEFAULT_BELL_PERIOD 100 /* 100ms */
306 #endif
307 #ifndef WSKBD_DEFAULT_BELL_VOLUME
308 #define WSKBD_DEFAULT_BELL_VOLUME 50 /* 50% volume */
309 #endif
310
311 struct wskbd_bell_data wskbd_default_bell_data = {
312 WSKBD_BELL_DOALL,
313 WSKBD_DEFAULT_BELL_PITCH,
314 WSKBD_DEFAULT_BELL_PERIOD,
315 WSKBD_DEFAULT_BELL_VOLUME,
316 };
317
318 #ifdef WSDISPLAY_SCROLLSUPPORT
319 struct wskbd_scroll_data wskbd_default_scroll_data = {
320 WSKBD_SCROLL_DOALL,
321 WSKBD_SCROLL_MODE_NORMAL,
322 #ifdef WSDISPLAY_SCROLLCOMBO
323 WSDISPLAY_SCROLLCOMBO,
324 #else
325 MOD_SHIFT_L,
326 #endif
327 };
328 #endif
329
330 #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1
331 #define WSKBD_DEFAULT_KEYREPEAT_DEL1 400 /* 400ms to start repeating */
332 #endif
333 #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN
334 #define WSKBD_DEFAULT_KEYREPEAT_DELN 100 /* 100ms to between repeats */
335 #endif
336
337 struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = {
338 WSKBD_KEYREPEAT_DOALL,
339 WSKBD_DEFAULT_KEYREPEAT_DEL1,
340 WSKBD_DEFAULT_KEYREPEAT_DELN,
341 };
342
343 #if NWSDISPLAY > 0 || NWSMUX > 0
344 struct wssrcops wskbd_srcops = {
345 WSMUX_KBD,
346 wskbd_mux_open, wskbd_mux_close, wskbd_do_ioctl,
347 wskbd_displayioctl, wskbd_set_display
348 };
349 #endif
350
351 static bool wskbd_suspend(device_t dv PMF_FN_PROTO);
352 static void wskbd_repeat(void *v);
353
354 static int wskbd_console_initted;
355 static struct wskbd_softc *wskbd_console_device;
356 static struct wskbd_internal wskbd_console_data;
357
358 static void wskbd_update_layout(struct wskbd_internal *, kbd_t);
359
360 static void
361 wskbd_update_layout(struct wskbd_internal *id, kbd_t enc)
362 {
363
364 if (enc & KB_METAESC)
365 id->t_flags |= WSKFL_METAESC;
366 else
367 id->t_flags &= ~WSKFL_METAESC;
368 }
369
370 /*
371 * Print function (for parent devices).
372 */
373 int
374 wskbddevprint(void *aux, const char *pnp)
375 {
376 #if 0
377 struct wskbddev_attach_args *ap = aux;
378 #endif
379
380 if (pnp)
381 aprint_normal("wskbd at %s", pnp);
382 #if 0
383 aprint_normal(" console %d", ap->console);
384 #endif
385
386 return (UNCONF);
387 }
388
389 int
390 wskbd_match(device_t parent, cfdata_t match, void *aux)
391 {
392 struct wskbddev_attach_args *ap = aux;
393
394 if (match->wskbddevcf_console != WSKBDDEVCF_CONSOLE_UNK) {
395 /*
396 * If console-ness of device specified, either match
397 * exactly (at high priority), or fail.
398 */
399 if (match->wskbddevcf_console != 0 && ap->console != 0)
400 return (10);
401 else
402 return (0);
403 }
404
405 /* If console-ness unspecified, it wins. */
406 return (1);
407 }
408
409 void
410 wskbd_attach(device_t parent, device_t self, void *aux)
411 {
412 struct wskbd_softc *sc = device_private(self);
413 struct wskbddev_attach_args *ap = aux;
414 #if NWSMUX > 0
415 int mux, error;
416 #endif
417
418 sc->sc_base.me_dv = self;
419 sc->sc_isconsole = ap->console;
420 sc->sc_hotkey = NULL;
421 sc->sc_hotkeycookie = 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 PMF_FN_ARGS)
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_stop(&sc->sc_repeat_ch);
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) {
736 DPRINTF(("wskbd_input: not open\n"));
737 return;
738 }
739
740 #ifdef DIAGNOSTIC
741 if (evar->q == NULL) {
742 printf("wskbd_input: evar->q=NULL\n");
743 return;
744 }
745 #endif
746
747 event.type = type;
748 event.value = value;
749 if (wsevent_inject(evar, &event, 1) != 0)
750 log(LOG_WARNING, "%s: event queue overflow\n",
751 device_xname(sc->sc_base.me_dv));
752 }
753
754 #ifdef WSDISPLAY_COMPAT_RAWKBD
755 void
756 wskbd_rawinput(device_t dev, u_char *tbuf, int len)
757 {
758 #if NWSDISPLAY > 0
759 struct wskbd_softc *sc = device_private(dev);
760 int i;
761
762 if (sc->sc_base.me_dispdv != NULL)
763 for (i = 0; i < len; i++)
764 wsdisplay_kbdinput(sc->sc_base.me_dispdv, tbuf[i]);
765 /* this is KS_GROUP_Ascii */
766 #endif
767 }
768 #endif /* WSDISPLAY_COMPAT_RAWKBD */
769
770 #if NWSDISPLAY > 0
771 static void
772 wskbd_holdscreen(struct wskbd_softc *sc, int hold)
773 {
774 int new_state;
775
776 if (sc->sc_base.me_dispdv != NULL) {
777 wsdisplay_kbdholdscreen(sc->sc_base.me_dispdv, hold);
778 new_state = sc->sc_ledstate;
779 if (hold) {
780 #ifdef WSDISPLAY_SCROLLSUPPORT
781 sc->sc_scroll_data.mode = WSKBD_SCROLL_MODE_HOLD;
782 #endif
783 new_state |= WSKBD_LED_SCROLL;
784 } else {
785 #ifdef WSDISPLAY_SCROLLSUPPORT
786 sc->sc_scroll_data.mode = WSKBD_SCROLL_MODE_NORMAL;
787 #endif
788 new_state &= ~WSKBD_LED_SCROLL;
789 }
790 if (new_state != sc->sc_ledstate) {
791 (*sc->sc_accessops->set_leds)(sc->sc_accesscookie,
792 new_state);
793 sc->sc_ledstate = new_state;
794 #ifdef WSDISPLAY_SCROLLSUPPORT
795 if (!hold)
796 wsdisplay_scroll(sc->sc_base.me_dispdv,
797 WSDISPLAY_SCROLL_RESET);
798 #endif
799 }
800 }
801 }
802 #endif
803
804 static int
805 wskbd_enable(struct wskbd_softc *sc, int on)
806 {
807 int error;
808
809 #if 0
810 /* I don't understand the purpose of this code. And it seems to
811 * break things, so it's out. -- Lennart
812 */
813 if (!on && (!sc->sc_translating
814 #if NWSDISPLAY > 0
815 || sc->sc_base.me_dispdv
816 #endif
817 ))
818 return (EBUSY);
819 #endif
820 #if NWSDISPLAY > 0
821 if (sc->sc_base.me_dispdv != NULL)
822 return (0);
823 #endif
824
825 /* Always cancel auto repeat when fiddling with the kbd. */
826 if (sc->sc_repeating) {
827 sc->sc_repeating = 0;
828 callout_stop(&sc->sc_repeat_ch);
829 }
830
831 error = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on);
832 DPRINTF(("wskbd_enable: sc=%p on=%d res=%d\n", sc, on, error));
833 return (error);
834 }
835
836 #if NWSMUX > 0
837 int
838 wskbd_mux_open(struct wsevsrc *me, struct wseventvar *evp)
839 {
840 struct wskbd_softc *sc = (struct wskbd_softc *)me;
841
842 if (sc->sc_dying)
843 return (EIO);
844
845 if (sc->sc_base.me_evp != NULL)
846 return (EBUSY);
847
848 return (wskbd_do_open(sc, evp));
849 }
850 #endif
851
852 int
853 wskbdopen(dev_t dev, int flags, int mode, struct lwp *l)
854 {
855 struct wskbd_softc *sc = device_lookup_private(&wskbd_cd, minor(dev));
856 struct wseventvar *evar;
857 int error;
858
859 if (sc == NULL)
860 return (ENXIO);
861
862 #if NWSMUX > 0
863 DPRINTF(("wskbdopen: %s mux=%p l=%p\n",
864 device_xname(sc->sc_base.me_dv), sc->sc_base.me_parent, l));
865 #endif
866
867 if (sc->sc_dying)
868 return (EIO);
869
870 if ((flags & (FREAD | FWRITE)) == FWRITE)
871 /* Not opening for read, only ioctl is available. */
872 return (0);
873
874 #if NWSMUX > 0
875 if (sc->sc_base.me_parent != NULL) {
876 /* Grab the keyboard out of the greedy hands of the mux. */
877 DPRINTF(("wskbdopen: detach\n"));
878 wsmux_detach_sc(&sc->sc_base);
879 }
880 #endif
881
882 if (sc->sc_base.me_evp != NULL)
883 return (EBUSY);
884
885 evar = &sc->sc_base.me_evar;
886 #ifndef COMPAT_50
887 evar->version = WSEVENT_VERSION;
888 #endif
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 (evar == NULL)
919 /* not open for read */
920 return (0);
921
922 sc->sc_base.me_evp = NULL;
923 sc->sc_translating = 1;
924 (void)wskbd_enable(sc, 0);
925 wsevent_fini(evar);
926
927 return (0);
928 }
929
930 #if NWSMUX > 0
931 int
932 wskbd_mux_close(struct wsevsrc *me)
933 {
934 struct wskbd_softc *sc = (struct wskbd_softc *)me;
935
936 sc->sc_base.me_evp = NULL;
937 sc->sc_translating = 1;
938 (void)wskbd_enable(sc, 0);
939
940 return (0);
941 }
942 #endif
943
944 int
945 wskbdread(dev_t dev, struct uio *uio, int flags)
946 {
947 struct wskbd_softc *sc =
948 device_lookup_private(&wskbd_cd, minor(dev));
949 int error;
950
951 if (sc->sc_dying)
952 return (EIO);
953
954 #ifdef DIAGNOSTIC
955 if (sc->sc_base.me_evp == NULL) {
956 printf("wskbdread: evp == NULL\n");
957 return (EINVAL);
958 }
959 #endif
960
961 sc->sc_refcnt++;
962 error = wsevent_read(sc->sc_base.me_evp, uio, flags);
963 if (--sc->sc_refcnt < 0) {
964 wakeup(sc);
965 error = EIO;
966 }
967 return (error);
968 }
969
970 int
971 wskbdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
972 {
973 return (wskbd_do_ioctl(device_lookup(&wskbd_cd, minor(dev)),
974 cmd, data, flag,l));
975 }
976
977 /* A wrapper around the ioctl() workhorse to make reference counting easy. */
978 int
979 wskbd_do_ioctl(device_t dv, u_long cmd, void *data, int flag,
980 struct lwp *l)
981 {
982 struct wskbd_softc *sc = device_private(dv);
983 int error;
984
985 sc->sc_refcnt++;
986 error = wskbd_do_ioctl_sc(sc, cmd, data, flag, l);
987 if (--sc->sc_refcnt < 0)
988 wakeup(sc);
989 return (error);
990 }
991
992 int
993 wskbd_do_ioctl_sc(struct wskbd_softc *sc, u_long cmd, void *data, int flag,
994 struct lwp *l)
995 {
996
997 /*
998 * Try the generic ioctls that the wskbd interface supports.
999 */
1000 switch (cmd) {
1001 case FIONBIO: /* we will remove this someday (soon???) */
1002 return (0);
1003
1004 case FIOASYNC:
1005 if (sc->sc_base.me_evp == NULL)
1006 return (EINVAL);
1007 sc->sc_base.me_evp->async = *(int *)data != 0;
1008 return (0);
1009
1010 case FIOSETOWN:
1011 if (sc->sc_base.me_evp == NULL)
1012 return (EINVAL);
1013 if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid
1014 && *(int *)data != sc->sc_base.me_evp->io->p_pid)
1015 return (EPERM);
1016 return (0);
1017
1018 case TIOCSPGRP:
1019 if (sc->sc_base.me_evp == NULL)
1020 return (EINVAL);
1021 if (*(int *)data != sc->sc_base.me_evp->io->p_pgid)
1022 return (EPERM);
1023 return (0);
1024 }
1025
1026 /*
1027 * Try the keyboard driver for WSKBDIO ioctls. It returns EPASSTHROUGH
1028 * if it didn't recognize the request.
1029 */
1030 return (wskbd_displayioctl(sc->sc_base.me_dv, cmd, data, flag, l));
1031 }
1032
1033 /*
1034 * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
1035 * Some of these have no real effect in raw mode, however.
1036 */
1037 static int
1038 wskbd_displayioctl(device_t dev, u_long cmd, void *data, int flag,
1039 struct lwp *l)
1040 {
1041 #ifdef WSDISPLAY_SCROLLSUPPORT
1042 struct wskbd_scroll_data *usdp, *ksdp;
1043 #endif
1044 struct wskbd_softc *sc = device_private(dev);
1045 struct wskbd_bell_data *ubdp, *kbdp;
1046 struct wskbd_keyrepeat_data *ukdp, *kkdp;
1047 struct wskbd_map_data *umdp;
1048 struct wskbd_mapdata md;
1049 struct proc *p = l ? l->l_proc : NULL;
1050 kbd_t enc;
1051 void *tbuf;
1052 int len, error;
1053
1054 switch (cmd) {
1055 #define SETBELL(dstp, srcp, dfltp) \
1056 do { \
1057 (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ? \
1058 (srcp)->pitch : (dfltp)->pitch; \
1059 (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ? \
1060 (srcp)->period : (dfltp)->period; \
1061 (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ? \
1062 (srcp)->volume : (dfltp)->volume; \
1063 (dstp)->which = WSKBD_BELL_DOALL; \
1064 } while (0)
1065
1066 case WSKBDIO_BELL:
1067 if ((flag & FWRITE) == 0)
1068 return (EACCES);
1069 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1070 WSKBDIO_COMPLEXBELL, (void *)&sc->sc_bell_data, flag, l));
1071
1072 case WSKBDIO_COMPLEXBELL:
1073 if ((flag & FWRITE) == 0)
1074 return (EACCES);
1075 ubdp = (struct wskbd_bell_data *)data;
1076 SETBELL(ubdp, ubdp, &sc->sc_bell_data);
1077 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1078 WSKBDIO_COMPLEXBELL, (void *)ubdp, flag, l));
1079
1080 case WSKBDIO_SETBELL:
1081 if ((flag & FWRITE) == 0)
1082 return (EACCES);
1083 kbdp = &sc->sc_bell_data;
1084 setbell:
1085 ubdp = (struct wskbd_bell_data *)data;
1086 SETBELL(kbdp, ubdp, kbdp);
1087 return (0);
1088
1089 case WSKBDIO_GETBELL:
1090 kbdp = &sc->sc_bell_data;
1091 getbell:
1092 ubdp = (struct wskbd_bell_data *)data;
1093 SETBELL(ubdp, kbdp, kbdp);
1094 return (0);
1095
1096 case WSKBDIO_SETDEFAULTBELL:
1097 if (p && (error = kauth_authorize_generic(l->l_cred,
1098 KAUTH_GENERIC_ISSUSER, NULL)) != 0)
1099 return (error);
1100 kbdp = &wskbd_default_bell_data;
1101 goto setbell;
1102
1103
1104 case WSKBDIO_GETDEFAULTBELL:
1105 kbdp = &wskbd_default_bell_data;
1106 goto getbell;
1107
1108 #undef SETBELL
1109
1110 #define SETKEYREPEAT(dstp, srcp, dfltp) \
1111 do { \
1112 (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ? \
1113 (srcp)->del1 : (dfltp)->del1; \
1114 (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ? \
1115 (srcp)->delN : (dfltp)->delN; \
1116 (dstp)->which = WSKBD_KEYREPEAT_DOALL; \
1117 } while (0)
1118
1119 case WSKBDIO_SETKEYREPEAT:
1120 if ((flag & FWRITE) == 0)
1121 return (EACCES);
1122 kkdp = &sc->sc_keyrepeat_data;
1123 setkeyrepeat:
1124 ukdp = (struct wskbd_keyrepeat_data *)data;
1125 SETKEYREPEAT(kkdp, ukdp, kkdp);
1126 return (0);
1127
1128 case WSKBDIO_GETKEYREPEAT:
1129 kkdp = &sc->sc_keyrepeat_data;
1130 getkeyrepeat:
1131 ukdp = (struct wskbd_keyrepeat_data *)data;
1132 SETKEYREPEAT(ukdp, kkdp, kkdp);
1133 return (0);
1134
1135 case WSKBDIO_SETDEFAULTKEYREPEAT:
1136 if ((error = kauth_authorize_generic(l->l_cred,
1137 KAUTH_GENERIC_ISSUSER, NULL)) != 0)
1138 return (error);
1139 kkdp = &wskbd_default_keyrepeat_data;
1140 goto setkeyrepeat;
1141
1142
1143 case WSKBDIO_GETDEFAULTKEYREPEAT:
1144 kkdp = &wskbd_default_keyrepeat_data;
1145 goto getkeyrepeat;
1146
1147 #ifdef WSDISPLAY_SCROLLSUPPORT
1148 #define SETSCROLLMOD(dstp, srcp, dfltp) \
1149 do { \
1150 (dstp)->mode = ((srcp)->which & WSKBD_SCROLL_DOMODE) ? \
1151 (srcp)->mode : (dfltp)->mode; \
1152 (dstp)->modifier = ((srcp)->which & WSKBD_SCROLL_DOMODIFIER) ? \
1153 (srcp)->modifier : (dfltp)->modifier; \
1154 (dstp)->which = WSKBD_SCROLL_DOALL; \
1155 } while (0)
1156
1157 case WSKBDIO_SETSCROLL:
1158 usdp = (struct wskbd_scroll_data *)data;
1159 ksdp = &sc->sc_scroll_data;
1160 SETSCROLLMOD(ksdp, usdp, ksdp);
1161 return (0);
1162
1163 case WSKBDIO_GETSCROLL:
1164 usdp = (struct wskbd_scroll_data *)data;
1165 ksdp = &sc->sc_scroll_data;
1166 SETSCROLLMOD(usdp, ksdp, ksdp);
1167 return (0);
1168 #else
1169 case WSKBDIO_GETSCROLL:
1170 case WSKBDIO_SETSCROLL:
1171 return ENODEV;
1172 #endif
1173
1174 #undef SETKEYREPEAT
1175
1176 case WSKBDIO_SETMAP:
1177 if ((flag & FWRITE) == 0)
1178 return (EACCES);
1179 umdp = (struct wskbd_map_data *)data;
1180 if (umdp->maplen > WSKBDIO_MAXMAPLEN)
1181 return (EINVAL);
1182
1183 len = umdp->maplen*sizeof(struct wscons_keymap);
1184 tbuf = malloc(len, M_TEMP, M_WAITOK);
1185 error = copyin(umdp->map, tbuf, len);
1186 if (error == 0) {
1187 wskbd_init_keymap(umdp->maplen,
1188 &sc->sc_map, &sc->sc_maplen);
1189 memcpy(sc->sc_map, tbuf, len);
1190 /* drop the variant bits handled by the map */
1191 sc->sc_layout = KB_USER |
1192 (KB_VARIANT(sc->sc_layout) & KB_HANDLEDBYWSKBD);
1193 wskbd_update_layout(sc->id, sc->sc_layout);
1194 }
1195 free(tbuf, M_TEMP);
1196 return(error);
1197
1198 case WSKBDIO_GETMAP:
1199 umdp = (struct wskbd_map_data *)data;
1200 if (umdp->maplen > sc->sc_maplen)
1201 umdp->maplen = sc->sc_maplen;
1202 error = copyout(sc->sc_map, umdp->map,
1203 umdp->maplen*sizeof(struct wscons_keymap));
1204 return(error);
1205
1206 case WSKBDIO_GETENCODING:
1207 *((kbd_t *) data) = sc->sc_layout;
1208 return(0);
1209
1210 case WSKBDIO_SETENCODING:
1211 if ((flag & FWRITE) == 0)
1212 return (EACCES);
1213 enc = *((kbd_t *)data);
1214 if (KB_ENCODING(enc) == KB_USER) {
1215 /* user map must already be loaded */
1216 if (KB_ENCODING(sc->sc_layout) != KB_USER)
1217 return (EINVAL);
1218 /* map variants make no sense */
1219 if (KB_VARIANT(enc) & ~KB_HANDLEDBYWSKBD)
1220 return (EINVAL);
1221 } else {
1222 md = *(sc->id->t_keymap); /* structure assignment */
1223 md.layout = enc;
1224 error = wskbd_load_keymap(&md, &sc->sc_map,
1225 &sc->sc_maplen);
1226 if (error)
1227 return (error);
1228 }
1229 sc->sc_layout = enc;
1230 wskbd_update_layout(sc->id, enc);
1231 return (0);
1232
1233 case WSKBDIO_SETVERSION:
1234 return wsevent_setversion(sc->sc_base.me_evp, *(int *)data);
1235 }
1236
1237 /*
1238 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
1239 * if it didn't recognize the request, and in turn we return
1240 * -1 if we didn't recognize the request.
1241 */
1242 /* printf("kbdaccess\n"); */
1243 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
1244 flag, l);
1245 #ifdef WSDISPLAY_COMPAT_RAWKBD
1246 if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
1247 int s = spltty();
1248 sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
1249 | MOD_CONTROL_L | MOD_CONTROL_R
1250 | MOD_META_L | MOD_META_R
1251 | MOD_COMMAND
1252 | MOD_COMMAND1 | MOD_COMMAND2);
1253 if (sc->sc_repeating) {
1254 sc->sc_repeating = 0;
1255 callout_stop(&sc->sc_repeat_ch);
1256 }
1257 splx(s);
1258 }
1259 #endif
1260 return (error);
1261 }
1262
1263 int
1264 wskbdpoll(dev_t dev, int events, struct lwp *l)
1265 {
1266 struct wskbd_softc *sc =
1267 device_lookup_private(&wskbd_cd, minor(dev));
1268
1269 if (sc->sc_base.me_evp == NULL)
1270 return (POLLERR);
1271 return (wsevent_poll(sc->sc_base.me_evp, events, l));
1272 }
1273
1274 int
1275 wskbdkqfilter(dev_t dev, struct knote *kn)
1276 {
1277 struct wskbd_softc *sc =
1278 device_lookup_private(&wskbd_cd, minor(dev));
1279
1280 if (sc->sc_base.me_evp == NULL)
1281 return (1);
1282 return (wsevent_kqfilter(sc->sc_base.me_evp, kn));
1283 }
1284
1285 #if NWSDISPLAY > 0
1286
1287 int
1288 wskbd_pickfree(void)
1289 {
1290 int i;
1291 struct wskbd_softc *sc;
1292
1293 for (i = 0; i < wskbd_cd.cd_ndevs; i++) {
1294 sc = device_lookup_private(&wskbd_cd, i);
1295 if (sc == NULL)
1296 continue;
1297 if (sc->sc_base.me_dispdv == NULL)
1298 return (i);
1299 }
1300 return (-1);
1301 }
1302
1303 struct wsevsrc *
1304 wskbd_set_console_display(device_t displaydv, struct wsevsrc *me)
1305 {
1306 struct wskbd_softc *sc = wskbd_console_device;
1307
1308 if (sc == NULL)
1309 return (NULL);
1310 sc->sc_base.me_dispdv = displaydv;
1311 #if NWSMUX > 0
1312 (void)wsmux_attach_sc((struct wsmux_softc *)me, &sc->sc_base);
1313 #endif
1314 return (&sc->sc_base);
1315 }
1316
1317 int
1318 wskbd_set_display(device_t dv, struct wsevsrc *me)
1319 {
1320 struct wskbd_softc *sc = device_private(dv);
1321 device_t displaydv = me != NULL ? me->me_dispdv : NULL;
1322 device_t odisplaydv;
1323 int error;
1324
1325 DPRINTF(("wskbd_set_display: %s me=%p odisp=%p disp=%p cons=%d\n",
1326 device_xname(dv), me, sc->sc_base.me_dispdv, displaydv,
1327 sc->sc_isconsole));
1328
1329 if (sc->sc_isconsole)
1330 return (EBUSY);
1331
1332 if (displaydv != NULL) {
1333 if (sc->sc_base.me_dispdv != NULL)
1334 return (EBUSY);
1335 } else {
1336 if (sc->sc_base.me_dispdv == NULL)
1337 return (ENXIO);
1338 }
1339
1340 odisplaydv = sc->sc_base.me_dispdv;
1341 sc->sc_base.me_dispdv = NULL;
1342 error = wskbd_enable(sc, displaydv != NULL);
1343 sc->sc_base.me_dispdv = displaydv;
1344 if (error) {
1345 sc->sc_base.me_dispdv = odisplaydv;
1346 return (error);
1347 }
1348
1349 if (displaydv)
1350 aprint_verbose_dev(sc->sc_base.me_dv, "connecting to %s\n",
1351 device_xname(displaydv));
1352 else
1353 aprint_verbose_dev(sc->sc_base.me_dv, "disconnecting from %s\n",
1354 device_xname(odisplaydv));
1355
1356 return (0);
1357 }
1358
1359 #endif /* NWSDISPLAY > 0 */
1360
1361 #if NWSMUX > 0
1362 int
1363 wskbd_add_mux(int unit, struct wsmux_softc *muxsc)
1364 {
1365 struct wskbd_softc *sc = device_lookup_private(&wskbd_cd, unit);
1366
1367 if (sc == NULL)
1368 return (ENXIO);
1369
1370 if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL)
1371 return (EBUSY);
1372
1373 return (wsmux_attach_sc(muxsc, &sc->sc_base));
1374 }
1375 #endif
1376
1377 /*
1378 * Console interface.
1379 */
1380 int
1381 wskbd_cngetc(dev_t dev)
1382 {
1383 static int num = 0;
1384 static int pos;
1385 u_int type;
1386 int data;
1387 keysym_t ks;
1388
1389 if (!wskbd_console_initted)
1390 return 0;
1391
1392 if (wskbd_console_device != NULL &&
1393 !wskbd_console_device->sc_translating)
1394 return 0;
1395
1396 for(;;) {
1397 if (num-- > 0) {
1398 ks = wskbd_console_data.t_symbols[pos++];
1399 if (KS_GROUP(ks) == KS_GROUP_Ascii)
1400 return (KS_VALUE(ks));
1401 } else {
1402 (*wskbd_console_data.t_consops->getc)
1403 (wskbd_console_data.t_consaccesscookie,
1404 &type, &data);
1405 if (type == WSCONS_EVENT_ASCII) {
1406 /*
1407 * We assume that when the driver falls back
1408 * to deliver pure ASCII it is in a state that
1409 * it can not track press/release events
1410 * reliable - so we clear all previously
1411 * accumulated modifier state.
1412 */
1413 wskbd_console_data.t_modifiers = 0;
1414 return(data);
1415 }
1416 num = wskbd_translate(&wskbd_console_data, type, data);
1417 pos = 0;
1418 }
1419 }
1420 }
1421
1422 void
1423 wskbd_cnpollc(dev_t dev, int poll)
1424 {
1425
1426 if (!wskbd_console_initted)
1427 return;
1428
1429 if (wskbd_console_device != NULL &&
1430 !wskbd_console_device->sc_translating)
1431 return;
1432
1433 (*wskbd_console_data.t_consops->pollc)
1434 (wskbd_console_data.t_consaccesscookie, poll);
1435 }
1436
1437 void
1438 wskbd_cnbell(dev_t dev, u_int pitch, u_int period, u_int volume)
1439 {
1440
1441 if (!wskbd_console_initted)
1442 return;
1443
1444 if (wskbd_console_data.t_consops->bell != NULL)
1445 (*wskbd_console_data.t_consops->bell)
1446 (wskbd_console_data.t_consaccesscookie, pitch, period,
1447 volume);
1448 }
1449
1450 static inline void
1451 update_leds(struct wskbd_internal *id)
1452 {
1453 int new_state;
1454
1455 new_state = 0;
1456 if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
1457 new_state |= WSKBD_LED_CAPS;
1458 if (id->t_modifiers & MOD_NUMLOCK)
1459 new_state |= WSKBD_LED_NUM;
1460 if (id->t_modifiers & MOD_COMPOSE)
1461 new_state |= WSKBD_LED_COMPOSE;
1462 if (id->t_modifiers & MOD_HOLDSCREEN)
1463 new_state |= WSKBD_LED_SCROLL;
1464
1465 if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
1466 (*id->t_sc->sc_accessops->set_leds)
1467 (id->t_sc->sc_accesscookie, new_state);
1468 id->t_sc->sc_ledstate = new_state;
1469 }
1470 }
1471
1472 static inline void
1473 update_modifier(struct wskbd_internal *id, u_int type, int toggle, int mask)
1474 {
1475 if (toggle) {
1476 if (type == WSCONS_EVENT_KEY_DOWN)
1477 id->t_modifiers ^= mask;
1478 } else {
1479 if (type == WSCONS_EVENT_KEY_DOWN)
1480 id->t_modifiers |= mask;
1481 else
1482 id->t_modifiers &= ~mask;
1483 }
1484 }
1485
1486 #if NWSDISPLAY > 0
1487 static void
1488 change_displayparam(struct wskbd_softc *sc, int param, int updown,
1489 int wraparound)
1490 {
1491 int res;
1492 struct wsdisplay_param dp;
1493
1494 dp.param = param;
1495 res = wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_GETPARAM, &dp);
1496
1497 if (res == EINVAL)
1498 return; /* no such parameter */
1499
1500 dp.curval += updown;
1501 if (dp.max < dp.curval)
1502 dp.curval = wraparound ? dp.min : dp.max;
1503 else
1504 if (dp.curval < dp.min)
1505 dp.curval = wraparound ? dp.max : dp.min;
1506 wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_SETPARAM, &dp);
1507 }
1508 #endif
1509
1510 static int
1511 internal_command(struct wskbd_softc *sc, u_int *type, keysym_t ksym,
1512 keysym_t ksym2)
1513 {
1514 #ifdef WSDISPLAY_SCROLLSUPPORT
1515 u_int state = 0;
1516 #endif
1517 switch (ksym) {
1518 case KS_Cmd_VolumeToggle:
1519 if (*type == WSCONS_EVENT_KEY_DOWN)
1520 pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_TOGGLE);
1521 break;
1522 case KS_Cmd_VolumeUp:
1523 if (*type == WSCONS_EVENT_KEY_DOWN)
1524 pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_UP);
1525 break;
1526 case KS_Cmd_VolumeDown:
1527 if (*type == WSCONS_EVENT_KEY_DOWN)
1528 pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_DOWN);
1529 break;
1530 #ifdef WSDISPLAY_SCROLLSUPPORT
1531 case KS_Cmd_ScrollFastUp:
1532 case KS_Cmd_ScrollFastDown:
1533 if (*type == WSCONS_EVENT_KEY_DOWN) {
1534 GETMODSTATE(sc->id->t_modifiers, state);
1535 if ((sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_HOLD
1536 && MOD_ONESET(sc->id, MOD_HOLDSCREEN))
1537 || (sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_NORMAL
1538 && sc->sc_scroll_data.modifier == state)) {
1539 update_modifier(sc->id, *type, 0, MOD_COMMAND);
1540 wsdisplay_scroll(sc->sc_base.me_dispdv,
1541 (ksym == KS_Cmd_ScrollFastUp) ?
1542 WSDISPLAY_SCROLL_BACKWARD :
1543 WSDISPLAY_SCROLL_FORWARD);
1544 return (1);
1545 } else {
1546 return (0);
1547 }
1548 }
1549
1550 case KS_Cmd_ScrollSlowUp:
1551 case KS_Cmd_ScrollSlowDown:
1552 if (*type == WSCONS_EVENT_KEY_DOWN) {
1553 GETMODSTATE(sc->id->t_modifiers, state);
1554 if ((sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_HOLD
1555 && MOD_ONESET(sc->id, MOD_HOLDSCREEN))
1556 || (sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_NORMAL
1557 && sc->sc_scroll_data.modifier == state)) {
1558 update_modifier(sc->id, *type, 0, MOD_COMMAND);
1559 wsdisplay_scroll(sc->sc_base.me_dispdv,
1560 (ksym == KS_Cmd_ScrollSlowUp) ?
1561 WSDISPLAY_SCROLL_BACKWARD | WSDISPLAY_SCROLL_LOW:
1562 WSDISPLAY_SCROLL_FORWARD | WSDISPLAY_SCROLL_LOW);
1563 return (1);
1564 } else {
1565 return (0);
1566 }
1567 }
1568 #endif
1569
1570 case KS_Cmd:
1571 update_modifier(sc->id, *type, 0, MOD_COMMAND);
1572 ksym = ksym2;
1573 break;
1574
1575 case KS_Cmd1:
1576 update_modifier(sc->id, *type, 0, MOD_COMMAND1);
1577 break;
1578
1579 case KS_Cmd2:
1580 update_modifier(sc->id, *type, 0, MOD_COMMAND2);
1581 break;
1582 }
1583
1584 if (*type != WSCONS_EVENT_KEY_DOWN ||
1585 (! MOD_ONESET(sc->id, MOD_COMMAND) &&
1586 ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)))
1587 return (0);
1588
1589 #if defined(DDB) || defined(KGDB)
1590 if (ksym == KS_Cmd_Debugger) {
1591 if (sc->sc_isconsole) {
1592 #ifdef DDB
1593 console_debugger();
1594 #endif
1595 #ifdef KGDB
1596 kgdb_connect(1);
1597 #endif
1598 }
1599 /* discard this key (ddb discarded command modifiers) */
1600 *type = WSCONS_EVENT_KEY_UP;
1601 return (1);
1602 }
1603 #endif
1604
1605 #if NWSDISPLAY > 0
1606 if (sc->sc_base.me_dispdv == NULL)
1607 return (0);
1608
1609 switch (ksym) {
1610 case KS_Cmd_Screen0:
1611 case KS_Cmd_Screen1:
1612 case KS_Cmd_Screen2:
1613 case KS_Cmd_Screen3:
1614 case KS_Cmd_Screen4:
1615 case KS_Cmd_Screen5:
1616 case KS_Cmd_Screen6:
1617 case KS_Cmd_Screen7:
1618 case KS_Cmd_Screen8:
1619 case KS_Cmd_Screen9:
1620 wsdisplay_switch(sc->sc_base.me_dispdv, ksym - KS_Cmd_Screen0, 0);
1621 return (1);
1622 case KS_Cmd_ResetEmul:
1623 wsdisplay_reset(sc->sc_base.me_dispdv, WSDISPLAY_RESETEMUL);
1624 return (1);
1625 case KS_Cmd_ResetClose:
1626 wsdisplay_reset(sc->sc_base.me_dispdv, WSDISPLAY_RESETCLOSE);
1627 return (1);
1628 case KS_Cmd_BacklightOn:
1629 case KS_Cmd_BacklightOff:
1630 case KS_Cmd_BacklightToggle:
1631 change_displayparam(sc, WSDISPLAYIO_PARAM_BACKLIGHT,
1632 ksym == KS_Cmd_BacklightOff ? -1 : 1,
1633 ksym == KS_Cmd_BacklightToggle ? 1 : 0);
1634 return (1);
1635 case KS_Cmd_BrightnessUp:
1636 case KS_Cmd_BrightnessDown:
1637 case KS_Cmd_BrightnessRotate:
1638 change_displayparam(sc, WSDISPLAYIO_PARAM_BRIGHTNESS,
1639 ksym == KS_Cmd_BrightnessDown ? -1 : 1,
1640 ksym == KS_Cmd_BrightnessRotate ? 1 : 0);
1641 return (1);
1642 case KS_Cmd_ContrastUp:
1643 case KS_Cmd_ContrastDown:
1644 case KS_Cmd_ContrastRotate:
1645 change_displayparam(sc, WSDISPLAYIO_PARAM_CONTRAST,
1646 ksym == KS_Cmd_ContrastDown ? -1 : 1,
1647 ksym == KS_Cmd_ContrastRotate ? 1 : 0);
1648 return (1);
1649 }
1650 #endif
1651
1652 return (0);
1653 }
1654
1655 device_t
1656 wskbd_hotkey_register(device_t self, void *cookie, wskbd_hotkey_plugin *hotkey)
1657 {
1658 struct wskbd_softc *sc = device_private(self);
1659
1660 sc->sc_hotkey = hotkey;
1661 sc->sc_hotkeycookie = cookie;
1662 return sc->sc_base.me_dv;
1663 }
1664
1665 static int
1666 wskbd_translate(struct wskbd_internal *id, u_int type, int value)
1667 {
1668 struct wskbd_softc *sc = id->t_sc;
1669 keysym_t ksym, res, *group;
1670 struct wscons_keymap kpbuf, *kp;
1671 int iscommand = 0;
1672 int ishotkey = 0;
1673
1674 if (type == WSCONS_EVENT_ALL_KEYS_UP) {
1675 id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
1676 | MOD_CONTROL_L | MOD_CONTROL_R
1677 | MOD_META_L | MOD_META_R
1678 | MOD_MODESHIFT
1679 | MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
1680 update_leds(id);
1681 return (0);
1682 }
1683
1684 if (sc != NULL) {
1685 if (sc->sc_hotkey != NULL)
1686 ishotkey = sc->sc_hotkey(sc, sc->sc_hotkeycookie,
1687 type, value);
1688 if (ishotkey)
1689 return 0;
1690
1691 if (value < 0 || value >= sc->sc_maplen) {
1692 #ifdef DEBUG
1693 printf("%s: keycode %d out of range\n",
1694 __func__, value);
1695 #endif
1696 return (0);
1697 }
1698 kp = sc->sc_map + value;
1699 } else {
1700 kp = &kpbuf;
1701 wskbd_get_mapentry(id->t_keymap, value, kp);
1702 }
1703
1704 /* if this key has a command, process it first */
1705 if (sc != NULL && kp->command != KS_voidSymbol)
1706 iscommand = internal_command(sc, &type, kp->command,
1707 kp->group1[0]);
1708
1709 /* Now update modifiers */
1710 switch (kp->group1[0]) {
1711 case KS_Shift_L:
1712 update_modifier(id, type, 0, MOD_SHIFT_L);
1713 break;
1714
1715 case KS_Shift_R:
1716 update_modifier(id, type, 0, MOD_SHIFT_R);
1717 break;
1718
1719 case KS_Shift_Lock:
1720 update_modifier(id, type, 1, MOD_SHIFTLOCK);
1721 break;
1722
1723 case KS_Caps_Lock:
1724 update_modifier(id, type, 1, MOD_CAPSLOCK);
1725 break;
1726
1727 case KS_Control_L:
1728 update_modifier(id, type, 0, MOD_CONTROL_L);
1729 break;
1730
1731 case KS_Control_R:
1732 update_modifier(id, type, 0, MOD_CONTROL_R);
1733 break;
1734
1735 case KS_Alt_L:
1736 update_modifier(id, type, 0, MOD_META_L);
1737 break;
1738
1739 case KS_Alt_R:
1740 update_modifier(id, type, 0, MOD_META_R);
1741 break;
1742
1743 case KS_Mode_switch:
1744 update_modifier(id, type, 0, MOD_MODESHIFT);
1745 break;
1746
1747 case KS_Num_Lock:
1748 update_modifier(id, type, 1, MOD_NUMLOCK);
1749 break;
1750
1751 #if NWSDISPLAY > 0
1752 case KS_Hold_Screen:
1753 if (sc != NULL) {
1754 update_modifier(id, type, 1, MOD_HOLDSCREEN);
1755 wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN);
1756 }
1757 break;
1758 #endif
1759 }
1760
1761 /* If this is a key release or we are in command mode, we are done */
1762 if (type != WSCONS_EVENT_KEY_DOWN || iscommand) {
1763 update_leds(id);
1764 return (0);
1765 }
1766
1767 /* Get the keysym */
1768 if (id->t_modifiers & MOD_MODESHIFT)
1769 group = & kp->group2[0];
1770 else
1771 group = & kp->group1[0];
1772
1773 if ((id->t_modifiers & MOD_NUMLOCK) != 0 &&
1774 KS_GROUP(group[1]) == KS_GROUP_Keypad) {
1775 if (MOD_ONESET(id, MOD_ANYSHIFT))
1776 ksym = group[0];
1777 else
1778 ksym = group[1];
1779 } else if (! MOD_ONESET(id, MOD_ANYSHIFT | MOD_CAPSLOCK)) {
1780 ksym = group[0];
1781 } else if (MOD_ONESET(id, MOD_CAPSLOCK)) {
1782 if (! MOD_ONESET(id, MOD_SHIFT_L | MOD_SHIFT_R))
1783 ksym = group[0];
1784 else
1785 ksym = group[1];
1786 if (ksym >= KS_a && ksym <= KS_z)
1787 ksym += KS_A - KS_a;
1788 else if (ksym >= KS_agrave && ksym <= KS_thorn &&
1789 ksym != KS_division)
1790 ksym += KS_Agrave - KS_agrave;
1791 } else if (MOD_ONESET(id, MOD_ANYSHIFT)) {
1792 ksym = group[1];
1793 } else {
1794 ksym = group[0];
1795 }
1796
1797 /* Process compose sequence and dead accents */
1798 res = KS_voidSymbol;
1799
1800 switch (KS_GROUP(ksym)) {
1801 case KS_GROUP_Ascii:
1802 case KS_GROUP_Keypad:
1803 case KS_GROUP_Function:
1804 res = ksym;
1805 break;
1806
1807 case KS_GROUP_Mod:
1808 if (ksym == KS_Multi_key) {
1809 update_modifier(id, 1, 0, MOD_COMPOSE);
1810 id->t_composelen = 2;
1811 }
1812 break;
1813
1814 case KS_GROUP_Dead:
1815 if (id->t_composelen == 0) {
1816 update_modifier(id, 1, 0, MOD_COMPOSE);
1817 id->t_composelen = 1;
1818 id->t_composebuf[0] = ksym;
1819 } else
1820 res = ksym;
1821 break;
1822 }
1823
1824 if (res == KS_voidSymbol) {
1825 update_leds(id);
1826 return (0);
1827 }
1828
1829 if (id->t_composelen > 0) {
1830 id->t_composebuf[2 - id->t_composelen] = res;
1831 if (--id->t_composelen == 0) {
1832 res = wskbd_compose_value(id->t_composebuf);
1833 update_modifier(id, 0, 0, MOD_COMPOSE);
1834 } else {
1835 return (0);
1836 }
1837 }
1838
1839 update_leds(id);
1840
1841 /* We are done, return the symbol */
1842 if (KS_GROUP(res) == KS_GROUP_Ascii) {
1843 if (MOD_ONESET(id, MOD_ANYCONTROL)) {
1844 if ((res >= KS_at && res <= KS_z) || res == KS_space)
1845 res = res & 0x1f;
1846 else if (res == KS_2)
1847 res = 0x00;
1848 else if (res >= KS_3 && res <= KS_7)
1849 res = KS_Escape + (res - KS_3);
1850 else if (res == KS_8)
1851 res = KS_Delete;
1852 }
1853 if (MOD_ONESET(id, MOD_ANYMETA)) {
1854 if (id->t_flags & WSKFL_METAESC) {
1855 id->t_symbols[0] = KS_Escape;
1856 id->t_symbols[1] = res;
1857 return (2);
1858 } else
1859 res |= 0x80;
1860 }
1861 }
1862
1863 id->t_symbols[0] = res;
1864 return (1);
1865 }
1866