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