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