wskbd.c revision 1.20 1 /* $NetBSD: wskbd.c,v 1.20 1999/03/27 11:22:23 drochner 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 static const char _copyright[] __attribute__ ((unused)) =
37 "Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.";
38 static const char _rcsid[] __attribute__ ((unused)) =
39 "$NetBSD: wskbd.c,v 1.20 1999/03/27 11:22:23 drochner Exp $";
40
41 /*
42 * Copyright (c) 1992, 1993
43 * The Regents of the University of California. All rights reserved.
44 *
45 * This software was developed by the Computer Systems Engineering group
46 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
47 * contributed to Berkeley.
48 *
49 * All advertising materials mentioning features or use of this software
50 * must display the following acknowledgement:
51 * This product includes software developed by the University of
52 * California, Lawrence Berkeley Laboratory.
53 *
54 * Redistribution and use in source and binary forms, with or without
55 * modification, are permitted provided that the following conditions
56 * are met:
57 * 1. Redistributions of source code must retain the above copyright
58 * notice, this list of conditions and the following disclaimer.
59 * 2. Redistributions in binary form must reproduce the above copyright
60 * notice, this list of conditions and the following disclaimer in the
61 * documentation and/or other materials provided with the distribution.
62 * 3. All advertising materials mentioning features or use of this software
63 * must display the following acknowledgement:
64 * This product includes software developed by the University of
65 * California, Berkeley and its contributors.
66 * 4. Neither the name of the University nor the names of its contributors
67 * may be used to endorse or promote products derived from this software
68 * without specific prior written permission.
69 *
70 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
71 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
72 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
73 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
74 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
75 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
76 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
77 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
78 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
79 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
80 * SUCH DAMAGE.
81 *
82 * @(#)kbd.c 8.2 (Berkeley) 10/30/93
83 */
84
85 /*
86 * Keyboard driver (/dev/wskbd*). Translates incoming bytes to ASCII or
87 * to `wscons_events' and passes them up to the appropriate reader.
88 */
89
90 #include "opt_ddb.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/kernel.h>
97 #include <sys/proc.h>
98 #include <sys/syslog.h>
99 #include <sys/systm.h>
100 #include <sys/malloc.h>
101 #include <sys/tty.h>
102 #include <sys/signalvar.h>
103 #include <sys/errno.h>
104 #include <sys/fcntl.h>
105
106 #include <dev/wscons/wsconsio.h>
107 #include <dev/wscons/wskbdvar.h>
108 #include <dev/wscons/wsksymdef.h>
109 #include <dev/wscons/wsksymvar.h>
110 #include <dev/wscons/wseventvar.h>
111 #include <dev/wscons/wscons_callbacks.h>
112
113 #include "opt_wsdisplay_compat.h"
114
115 #include "wskbd.h"
116
117 struct wskbd_internal {
118 const struct wskbd_mapdata *t_keymap;
119
120 const struct wskbd_consops *t_consops;
121 void *t_consaccesscookie;
122
123 int t_modifiers;
124 int t_composelen; /* remaining entries in t_composebuf */
125 keysym_t t_composebuf[2];
126
127 struct wskbd_softc *t_sc; /* back pointer */
128 };
129
130 struct wskbd_softc {
131 struct device sc_dv;
132
133 struct wskbd_internal *id;
134
135 const struct wskbd_accessops *sc_accessops;
136 void *sc_accesscookie;
137
138 int sc_ledstate;
139
140 int sc_ready; /* accepting events */
141 struct wseventvar sc_events; /* event queue state */
142
143 int sc_isconsole;
144 struct device *sc_displaydv;
145
146 struct wskbd_bell_data sc_bell_data;
147 struct wskbd_keyrepeat_data sc_keyrepeat_data;
148
149 int sc_repeating; /* we've called timeout() */
150 keysym_t sc_repeatsym; /* repeated symbol */
151
152 int sc_translating; /* xlate to chars for emulation */
153
154 int sc_maplen; /* number of entries in sc_map */
155 struct wscons_keymap *sc_map; /* current translation map */
156 kbd_t sc_layout; /* current layout */
157 };
158
159 #define MOD_SHIFT_L (1 << 0)
160 #define MOD_SHIFT_R (1 << 1)
161 #define MOD_SHIFTLOCK (1 << 2)
162 #define MOD_CAPSLOCK (1 << 3)
163 #define MOD_CONTROL_L (1 << 4)
164 #define MOD_CONTROL_R (1 << 5)
165 #define MOD_META_L (1 << 6)
166 #define MOD_META_R (1 << 7)
167 #define MOD_MODESHIFT (1 << 8)
168 #define MOD_NUMLOCK (1 << 9)
169 #define MOD_COMPOSE (1 << 10)
170 #define MOD_HOLDSCREEN (1 << 11)
171 #define MOD_COMMAND (1 << 12)
172 #define MOD_COMMAND1 (1 << 13)
173 #define MOD_COMMAND2 (1 << 14)
174
175 #define MOD_ANYSHIFT (MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK)
176 #define MOD_ANYCONTROL (MOD_CONTROL_L | MOD_CONTROL_R)
177 #define MOD_ANYMETA (MOD_META_L | MOD_META_R)
178
179 #define MOD_ONESET(id, mask) (((id)->t_modifiers & (mask)) != 0)
180 #define MOD_ALLSET(id, mask) (((id)->t_modifiers & (mask)) == (mask))
181
182 int wskbd_match __P((struct device *, struct cfdata *, void *));
183 void wskbd_attach __P((struct device *, struct device *, void *));
184 static inline void update_leds __P((struct wskbd_internal *));
185 static inline void update_modifier __P((struct wskbd_internal *, u_int, int, int));
186 static int internal_command __P((struct wskbd_softc *, u_int *, keysym_t));
187 static keysym_t wskbd_translate __P((struct wskbd_internal *, u_int, int));
188 static void wskbd_holdscreen __P((struct wskbd_softc *, int));
189
190
191 struct cfattach wskbd_ca = {
192 sizeof (struct wskbd_softc), wskbd_match, wskbd_attach,
193 };
194
195 #if NWSKBD > 0
196 extern struct cfdriver wskbd_cd;
197 #endif
198
199 #ifndef WSKBD_DEFAULT_BELL_PITCH
200 #define WSKBD_DEFAULT_BELL_PITCH 1500 /* 1500Hz */
201 #endif
202 #ifndef WSKBD_DEFAULT_BELL_PERIOD
203 #define WSKBD_DEFAULT_BELL_PERIOD 100 /* 100ms */
204 #endif
205 #ifndef WSKBD_DEFAULT_BELL_VOLUME
206 #define WSKBD_DEFAULT_BELL_VOLUME 50 /* 50% volume */
207 #endif
208
209 struct wskbd_bell_data wskbd_default_bell_data = {
210 WSKBD_BELL_DOALL,
211 WSKBD_DEFAULT_BELL_PITCH,
212 WSKBD_DEFAULT_BELL_PERIOD,
213 WSKBD_DEFAULT_BELL_VOLUME,
214 };
215
216 #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1
217 #define WSKBD_DEFAULT_KEYREPEAT_DEL1 400 /* 400ms to start repeating */
218 #endif
219 #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN
220 #define WSKBD_DEFAULT_KEYREPEAT_DELN 100 /* 100ms to between repeats */
221 #endif
222
223 struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = {
224 WSKBD_KEYREPEAT_DOALL,
225 WSKBD_DEFAULT_KEYREPEAT_DEL1,
226 WSKBD_DEFAULT_KEYREPEAT_DELN,
227 };
228
229 cdev_decl(wskbd);
230 static void wskbd_repeat __P((void *v));
231
232 static int wskbd_console_initted;
233 static struct wskbd_softc *wskbd_console_device;
234 static struct wskbd_internal wskbd_console_data;
235
236 /*
237 * Print function (for parent devices).
238 */
239 int
240 wskbddevprint(aux, pnp)
241 void *aux;
242 const char *pnp;
243 {
244 #if 0
245 struct wskbddev_attach_args *ap = aux;
246 #endif
247
248 if (pnp)
249 printf("wskbd at %s", pnp);
250 #if 0
251 printf(" console %d", ap->console);
252 #endif
253
254 return (UNCONF);
255 }
256
257 int
258 wskbd_match(parent, match, aux)
259 struct device *parent;
260 struct cfdata *match;
261 void *aux;
262 {
263 struct wskbddev_attach_args *ap = aux;
264
265 if (match->wskbddevcf_console != WSKBDDEVCF_CONSOLE_UNK) {
266 /*
267 * If console-ness of device specified, either match
268 * exactly (at high priority), or fail.
269 */
270 if (match->wskbddevcf_console != 0 && ap->console != 0)
271 return (10);
272 else
273 return (0);
274 }
275
276 /* If console-ness unspecified, it wins. */
277 return (1);
278 }
279
280 void
281 wskbd_attach(parent, self, aux)
282 struct device *parent, *self;
283 void *aux;
284 {
285 struct wskbd_softc *sc = (struct wskbd_softc *)self;
286 struct wskbddev_attach_args *ap = aux;
287
288 if (ap->console)
289 printf(": console keyboard");
290 printf("\n");
291
292 if (ap->console) {
293 sc->id = &wskbd_console_data;
294 } else {
295 sc->id = malloc(sizeof(struct wskbd_internal),
296 M_DEVBUF, M_WAITOK);
297 sc->id->t_keymap = ap->keymap;
298 sc->id->t_modifiers = 0;
299 }
300
301 sc->id->t_sc = sc;
302
303 sc->sc_accessops = ap->accessops;
304 sc->sc_accesscookie = ap->accesscookie;
305 sc->sc_ready = 0; /* sanity */
306 sc->sc_repeating = 0;
307 sc->sc_translating = 1;
308 sc->sc_ledstate = -1; /* force update */
309
310 if (wskbd_load_keymap(sc->id->t_keymap,
311 &sc->sc_map, &sc->sc_maplen) != 0)
312 panic("cannot load keymap");
313
314 sc->sc_layout = sc->id->t_keymap->layout;
315
316 if (ap->console) {
317 KASSERT(wskbd_console_initted);
318 KASSERT(wskbd_console_device == NULL);
319 wskbd_console_device = sc;
320 }
321 sc->sc_isconsole = ap->console;
322 sc->sc_displaydv = NULL;
323
324 /* set default bell and key repeat data */
325 sc->sc_bell_data = wskbd_default_bell_data;
326 sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data;
327 }
328
329 void
330 wskbd_cnattach(consops, conscookie, mapdata)
331 const struct wskbd_consops *consops;
332 void *conscookie;
333 const struct wskbd_mapdata *mapdata;
334 {
335
336 KASSERT(!wskbd_console_initted);
337
338 wskbd_console_data.t_keymap = mapdata;
339
340 wskbd_console_data.t_consops = consops;
341 wskbd_console_data.t_consaccesscookie = conscookie;
342
343 wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc);
344
345 wskbd_console_initted = 1;
346 }
347
348 static void
349 wskbd_repeat(v)
350 void *v;
351 {
352 struct wskbd_softc *sc = (struct wskbd_softc *)v;
353 int s = spltty();
354
355 if (!sc->sc_repeating) {
356 /*
357 * race condition: a "key up" event came in when wskbd_repeat()
358 * was already called but not yet spltty()'d
359 */
360 splx(s);
361 return;
362 }
363 if (sc->sc_displaydv != NULL)
364 wsdisplay_kbdinput(sc->sc_displaydv, sc->sc_repeatsym);
365 timeout(wskbd_repeat, sc,
366 (hz * sc->sc_keyrepeat_data.delN) / 1000);
367 splx(s);
368 }
369
370 void
371 wskbd_input(dev, type, value)
372 struct device *dev;
373 u_int type;
374 int value;
375 {
376 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
377 struct wscons_event *ev;
378 struct timeval xxxtime;
379 keysym_t ks;
380 int put;
381
382 if (sc->sc_repeating) {
383 sc->sc_repeating = 0;
384 untimeout(wskbd_repeat, sc);
385 }
386
387 /*
388 * If /dev/kbd is not connected in event mode translate and
389 * send upstream.
390 */
391 if (sc->sc_translating) {
392 ks = wskbd_translate(sc->id, type, value);
393 if (ks != KS_voidSymbol) {
394 sc->sc_repeatsym = ks;
395 if (sc->sc_displaydv != NULL)
396 wsdisplay_kbdinput(sc->sc_displaydv,
397 sc->sc_repeatsym);
398
399 sc->sc_repeating = 1;
400 timeout(wskbd_repeat, sc,
401 (hz * sc->sc_keyrepeat_data.del1) / 1000);
402 }
403 return;
404 }
405
406 /*
407 * Keyboard is generating events. Turn this keystroke into an
408 * event and put it in the queue. If the queue is full, the
409 * keystroke is lost (sorry!).
410 */
411
412 /* no one to receive; punt!*/
413 if (!sc->sc_ready)
414 return;
415
416 put = sc->sc_events.put;
417 ev = &sc->sc_events.q[put];
418 put = (put + 1) % WSEVENT_QSIZE;
419 if (put == sc->sc_events.get) {
420 log(LOG_WARNING, "%s: event queue overflow\n",
421 sc->sc_dv.dv_xname);
422 return;
423 }
424 ev->type = type;
425 ev->value = value;
426 microtime(&xxxtime);
427 TIMEVAL_TO_TIMESPEC(&xxxtime, &ev->time);
428 sc->sc_events.put = put;
429 WSEVENT_WAKEUP(&sc->sc_events);
430 }
431
432 #ifdef WSDISPLAY_COMPAT_RAWKBD
433 void
434 wskbd_rawinput(dev, buf, len)
435 struct device *dev;
436 char *buf;
437 int len;
438 {
439 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
440 int i;
441
442 for (i = 0; i < len; i++)
443 wsdisplay_kbdinput(sc->sc_displaydv, buf[i]);
444 /* this is KS_GROUP_Ascii */
445 }
446 #endif
447
448 static void
449 wskbd_holdscreen(sc, hold)
450 struct wskbd_softc *sc;
451 int hold;
452 {
453 int new_state;
454
455 if (sc->sc_displaydv != NULL) {
456 wsdisplay_kbdholdscreen(sc->sc_displaydv, hold);
457 new_state = sc->sc_ledstate;
458 if (hold)
459 new_state |= WSKBD_LED_SCROLL;
460 else
461 new_state &= ~WSKBD_LED_SCROLL;
462 if (new_state != sc->sc_ledstate) {
463 (*sc->sc_accessops->set_leds)(sc->sc_accesscookie,
464 new_state);
465 sc->sc_ledstate = new_state;
466 }
467 }
468 }
469
470 int
471 wskbd_enable(dev, on)
472 struct device *dev;
473 int on;
474 {
475 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
476 int res;
477
478 /* XXX reference count? */
479 if (!on && (!sc->sc_translating || sc->sc_displaydv))
480 return (EBUSY);
481
482 res = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on);
483 return (res);
484 }
485
486 int
487 wskbdopen(dev, flags, mode, p)
488 dev_t dev;
489 int flags, mode;
490 struct proc *p;
491 {
492 #if NWSKBD > 0
493 struct wskbd_softc *sc;
494 int unit;
495
496 unit = minor(dev);
497 if (unit >= wskbd_cd.cd_ndevs || /* make sure it was attached */
498 (sc = wskbd_cd.cd_devs[unit]) == NULL)
499 return (ENXIO);
500
501 if (sc->sc_events.io) /* and that it's not in use */
502 return (EBUSY);
503
504 sc->sc_events.io = p;
505 wsevent_init(&sc->sc_events); /* may cause sleep */
506
507 sc->sc_translating = 0;
508 sc->sc_ready = 1; /* start accepting events */
509
510 wskbd_enable((struct device *)sc, 1);
511
512 return (0);
513 #else
514 return (ENXIO);
515 #endif /* NWSKBD > 0 */
516 }
517
518 int
519 wskbdclose(dev, flags, mode, p)
520 dev_t dev;
521 int flags, mode;
522 struct proc *p;
523 {
524 #if NWSKBD > 0
525 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
526
527 sc->sc_ready = 0; /* stop accepting events */
528 sc->sc_translating = 1;
529
530 wsevent_fini(&sc->sc_events);
531 sc->sc_events.io = NULL;
532
533 wskbd_enable((struct device *)sc, 0);
534 #endif /* NWSKBD > 0 */
535 return (0);
536 }
537
538 int
539 wskbdread(dev, uio, flags)
540 dev_t dev;
541 struct uio *uio;
542 int flags;
543 {
544 #if NWSKBD > 0
545 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
546
547 return (wsevent_read(&sc->sc_events, uio, flags));
548 #else
549 return (ENXIO);
550 #endif /* NWSKBD > 0 */
551 }
552
553 int
554 wskbdioctl(dev, cmd, data, flag, p)
555 dev_t dev;
556 u_long cmd;
557 caddr_t data;
558 int flag;
559 struct proc *p;
560 {
561 #if NWSKBD > 0
562 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
563 int error;
564
565 /*
566 * Try the generic ioctls that the wskbd interface supports.
567 */
568 switch (cmd) {
569 case FIONBIO: /* we will remove this someday (soon???) */
570 return (0);
571
572 case FIOASYNC:
573 sc->sc_events.async = *(int *)data != 0;
574 return (0);
575
576 case TIOCSPGRP:
577 if (*(int *)data != sc->sc_events.io->p_pgid)
578 return (EPERM);
579 return (0);
580 }
581
582 /*
583 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
584 * if it didn't recognize the request.
585 */
586 error = wskbd_displayioctl((struct device *)sc, cmd, data, flag, p);
587 return (error != -1 ? error : ENOTTY);
588 #else
589 return (ENXIO);
590 #endif /* NWSKBD > 0 */
591 }
592
593 /*
594 * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
595 * Some of these have no real effect in raw mode, however.
596 */
597 int
598 wskbd_displayioctl(dev, cmd, data, flag, p)
599 struct device *dev;
600 u_long cmd;
601 caddr_t data;
602 int flag;
603 struct proc *p;
604 {
605 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
606 struct wskbd_bell_data *ubdp, *kbdp;
607 struct wskbd_keyrepeat_data *ukdp, *kkdp;
608 struct wskbd_map_data *umdp;
609 struct wskbd_mapdata md;
610 void *buf;
611 int len, error;
612
613 switch (cmd) {
614 #define SETBELL(dstp, srcp, dfltp) \
615 do { \
616 (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ? \
617 (srcp)->pitch : (dfltp)->pitch; \
618 (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ? \
619 (srcp)->period : (dfltp)->period; \
620 (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ? \
621 (srcp)->volume : (dfltp)->volume; \
622 (dstp)->which = WSKBD_BELL_DOALL; \
623 } while (0)
624
625 case WSKBDIO_BELL:
626 if ((flag & FWRITE) == 0)
627 return (EACCES);
628 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
629 WSKBDIO_COMPLEXBELL, (caddr_t)&sc->sc_bell_data, flag, p));
630
631 case WSKBDIO_COMPLEXBELL:
632 if ((flag & FWRITE) == 0)
633 return (EACCES);
634 ubdp = (struct wskbd_bell_data *)data;
635 SETBELL(ubdp, ubdp, &sc->sc_bell_data);
636 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
637 WSKBDIO_COMPLEXBELL, (caddr_t)ubdp, flag, p));
638
639 case WSKBDIO_SETBELL:
640 if ((flag & FWRITE) == 0)
641 return (EACCES);
642 kbdp = &sc->sc_bell_data;
643 setbell:
644 ubdp = (struct wskbd_bell_data *)data;
645 SETBELL(kbdp, ubdp, kbdp);
646 return (0);
647
648 case WSKBDIO_GETBELL:
649 kbdp = &sc->sc_bell_data;
650 getbell:
651 ubdp = (struct wskbd_bell_data *)data;
652 SETBELL(ubdp, kbdp, kbdp);
653 return (0);
654
655 case WSKBDIO_SETDEFAULTBELL:
656 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
657 return (error);
658 kbdp = &wskbd_default_bell_data;
659 goto setbell;
660
661
662 case WSKBDIO_GETDEFAULTBELL:
663 kbdp = &wskbd_default_bell_data;
664 goto getbell;
665
666 #undef SETBELL
667
668 #define SETKEYREPEAT(dstp, srcp, dfltp) \
669 do { \
670 (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ? \
671 (srcp)->del1 : (dfltp)->del1; \
672 (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ? \
673 (srcp)->delN : (dfltp)->delN; \
674 (dstp)->which = WSKBD_KEYREPEAT_DOALL; \
675 } while (0)
676
677 case WSKBDIO_SETKEYREPEAT:
678 if ((flag & FWRITE) == 0)
679 return (EACCES);
680 kkdp = &sc->sc_keyrepeat_data;
681 setkeyrepeat:
682 ukdp = (struct wskbd_keyrepeat_data *)data;
683 SETKEYREPEAT(kkdp, ukdp, kkdp);
684 return (0);
685
686 case WSKBDIO_GETKEYREPEAT:
687 kkdp = &sc->sc_keyrepeat_data;
688 getkeyrepeat:
689 ukdp = (struct wskbd_keyrepeat_data *)data;
690 SETKEYREPEAT(ukdp, kkdp, kkdp);
691 return (0);
692
693 case WSKBDIO_SETDEFAULTKEYREPEAT:
694 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
695 return (error);
696 kkdp = &wskbd_default_keyrepeat_data;
697 goto setkeyrepeat;
698
699
700 case WSKBDIO_GETDEFAULTKEYREPEAT:
701 kkdp = &wskbd_default_keyrepeat_data;
702 goto getkeyrepeat;
703
704 #undef SETKEYREPEAT
705
706 case WSKBDIO_SETMAP:
707 if ((flag & FWRITE) == 0)
708 return (EACCES);
709 umdp = (struct wskbd_map_data *)data;
710 len = umdp->maplen*sizeof(struct wscons_keymap);
711 buf = malloc(len, M_TEMP, M_WAITOK);
712 error = copyin(umdp->map, buf, len);
713 if (error == 0) {
714 wskbd_init_keymap(umdp->maplen,
715 &sc->sc_map, &sc->sc_maplen);
716 memcpy(sc->sc_map, buf, len);
717 sc->sc_layout = KB_USER;
718 }
719 free(buf, M_TEMP);
720 return(error);
721
722 case WSKBDIO_GETMAP:
723 umdp = (struct wskbd_map_data *)data;
724 if (umdp->maplen > sc->sc_maplen)
725 umdp->maplen = sc->sc_maplen;
726 error = copyout(sc->sc_map, umdp->map,
727 umdp->maplen*sizeof(struct wscons_keymap));
728 return(error);
729
730 case WSKBDIO_GETENCODING:
731 *((kbd_t *) data) = sc->sc_layout;
732 return(0);
733
734 case WSKBDIO_SETENCODING:
735 if ((flag & FWRITE) == 0)
736 return (EACCES);
737 md = *(sc->id->t_keymap); /* structure assignment */
738 md.layout = *((kbd_t *)data);
739 error = wskbd_load_keymap(&md, &sc->sc_map, &sc->sc_maplen);
740 if (error == 0)
741 sc->sc_layout = *((kbd_t *)data);
742 return(error);
743 }
744
745 /*
746 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
747 * if it didn't recognize the request, and in turn we return
748 * -1 if we didn't recognize the request.
749 */
750 /* printf("kbdaccess\n"); */
751 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
752 flag, p);
753 #ifdef WSDISPLAY_COMPAT_RAWKBD
754 if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
755 int s = spltty();
756 sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
757 | MOD_CONTROL_L | MOD_CONTROL_R
758 | MOD_META_L | MOD_META_R
759 | MOD_COMMAND
760 | MOD_COMMAND1 | MOD_COMMAND2);
761 if (sc->sc_repeating) {
762 sc->sc_repeating = 0;
763 untimeout(wskbd_repeat, sc);
764 }
765 splx(s);
766 }
767 #endif
768 return (error);
769 }
770
771 int
772 wskbdpoll(dev, events, p)
773 dev_t dev;
774 int events;
775 struct proc *p;
776 {
777 #if NWSKBD > 0
778 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
779
780 return (wsevent_poll(&sc->sc_events, events, p));
781 #else
782 return (0);
783 #endif /* NWSKBD > 0 */
784 }
785
786 int
787 wskbd_is_console(dv)
788 struct device *dv;
789 {
790 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
791
792 KASSERT(sc != NULL);
793 return (sc->sc_isconsole);
794 }
795
796 struct device *
797 wskbd_display(dv)
798 struct device *dv;
799 {
800 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
801
802 KASSERT(sc != NULL);
803 return (sc->sc_displaydv);
804 }
805
806 void
807 wskbd_set_display(dv, displaydv)
808 struct device *dv, *displaydv;
809 {
810 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
811
812 KASSERT(sc != NULL);
813 sc->sc_displaydv = displaydv;
814 }
815
816 /*
817 * Console interface.
818 */
819 int
820 wskbd_cngetc(dev)
821 dev_t dev;
822 {
823 u_int type;
824 int data;
825 keysym_t ks;
826
827 if (!wskbd_console_initted)
828 return 0;
829
830 if (wskbd_console_device != NULL &&
831 !wskbd_console_device->sc_translating)
832 return 0;
833
834 for(;;) {
835 (*wskbd_console_data.t_consops->getc)
836 (wskbd_console_data.t_consaccesscookie, &type, &data);
837 ks = wskbd_translate(&wskbd_console_data, type, data);
838
839 if (KS_GROUP(ks) == KS_GROUP_Ascii)
840 return (KS_VALUE(ks));
841 }
842 }
843
844 void
845 wskbd_cnpollc(dev, poll)
846 dev_t dev;
847 int poll;
848 {
849
850 if (!wskbd_console_initted)
851 return;
852
853 if (wskbd_console_device != NULL &&
854 !wskbd_console_device->sc_translating)
855 return;
856
857 (*wskbd_console_data.t_consops->pollc)
858 (wskbd_console_data.t_consaccesscookie, poll);
859 }
860
861 static inline void
862 update_leds(id)
863 struct wskbd_internal *id;
864 {
865 int new_state;
866
867 new_state = 0;
868 if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
869 new_state |= WSKBD_LED_CAPS;
870 if (id->t_modifiers & MOD_NUMLOCK)
871 new_state |= WSKBD_LED_NUM;
872 if (id->t_modifiers & MOD_COMPOSE)
873 new_state |= WSKBD_LED_COMPOSE;
874 if (id->t_modifiers & MOD_HOLDSCREEN)
875 new_state |= WSKBD_LED_SCROLL;
876
877 if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
878 (*id->t_sc->sc_accessops->set_leds)
879 (id->t_sc->sc_accesscookie, new_state);
880 id->t_sc->sc_ledstate = new_state;
881 }
882 }
883
884 static inline void
885 update_modifier(id, type, toggle, mask)
886 struct wskbd_internal *id;
887 u_int type;
888 int toggle;
889 int mask;
890 {
891 if (toggle) {
892 if (type == WSCONS_EVENT_KEY_DOWN)
893 id->t_modifiers ^= mask;
894 } else {
895 if (type == WSCONS_EVENT_KEY_DOWN)
896 id->t_modifiers |= mask;
897 else
898 id->t_modifiers &= ~mask;
899 }
900 }
901
902 static int
903 internal_command(sc, type, ksym)
904 struct wskbd_softc *sc;
905 u_int *type;
906 keysym_t ksym;
907 {
908 switch (ksym) {
909 case KS_Cmd:
910 update_modifier(sc->id, *type, 0, MOD_COMMAND);
911 break;
912
913 case KS_Cmd1:
914 update_modifier(sc->id, *type, 0, MOD_COMMAND1);
915 break;
916
917 case KS_Cmd2:
918 update_modifier(sc->id, *type, 0, MOD_COMMAND2);
919 break;
920 }
921
922 if (*type != WSCONS_EVENT_KEY_DOWN ||
923 (! MOD_ONESET(sc->id, MOD_COMMAND) &&
924 ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)))
925 return (0);
926
927 switch (ksym) {
928 #ifdef DDB
929 case KS_Cmd_Debugger:
930 if (sc->sc_isconsole)
931 console_debugger();
932 /* discard this key (ddb discarded command modifiers) */
933 *type = WSCONS_EVENT_KEY_UP;
934 return (1);
935 #endif
936
937 case KS_Cmd_Screen0:
938 case KS_Cmd_Screen1:
939 case KS_Cmd_Screen2:
940 case KS_Cmd_Screen3:
941 case KS_Cmd_Screen4:
942 case KS_Cmd_Screen5:
943 case KS_Cmd_Screen6:
944 case KS_Cmd_Screen7:
945 case KS_Cmd_Screen8:
946 case KS_Cmd_Screen9:
947 wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0);
948 return (1);
949 case KS_Cmd_ResetEmul:
950 wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETEMUL);
951 return (1);
952 case KS_Cmd_ResetClose:
953 wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETCLOSE);
954 return (1);
955 }
956 return (0);
957 }
958
959 static keysym_t
960 wskbd_translate(id, type, value)
961 struct wskbd_internal *id;
962 u_int type;
963 int value;
964 {
965 struct wskbd_softc *sc = id->t_sc;
966 keysym_t ksym, res, *group;
967 struct wscons_keymap kpbuf, *kp;
968 int iscommand = 0;
969
970 if (type == WSCONS_EVENT_ALL_KEYS_UP) {
971 id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
972 | MOD_CONTROL_L | MOD_CONTROL_R
973 | MOD_META_L | MOD_META_R
974 | MOD_MODESHIFT
975 | MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
976 update_leds(id);
977 return (KS_voidSymbol);
978 }
979
980 if (sc != NULL) {
981 if (value < 0 || value >= sc->sc_maplen) {
982 #ifdef DEBUG
983 printf("wskbd_translate: keycode %d out of range\n",
984 value);
985 #endif
986 return (KS_voidSymbol);
987 }
988 kp = sc->sc_map + value;
989 } else {
990 kp = &kpbuf;
991 wskbd_get_mapentry(id->t_keymap, value, kp);
992 }
993
994 /* if this key has a command, process it first */
995 if (sc != NULL && kp->command != KS_voidSymbol)
996 iscommand = internal_command(sc, &type, kp->command);
997
998 /* Now update modifiers */
999 switch (kp->group1[0]) {
1000 case KS_Shift_L:
1001 update_modifier(id, type, 0, MOD_SHIFT_L);
1002 break;
1003
1004 case KS_Shift_R:
1005 update_modifier(id, type, 0, MOD_SHIFT_R);
1006 break;
1007
1008 case KS_Shift_Lock:
1009 update_modifier(id, type, 1, MOD_SHIFTLOCK);
1010 break;
1011
1012 case KS_Caps_Lock:
1013 update_modifier(id, type, 1, MOD_CAPSLOCK);
1014 break;
1015
1016 case KS_Control_L:
1017 update_modifier(id, type, 0, MOD_CONTROL_L);
1018 break;
1019
1020 case KS_Control_R:
1021 update_modifier(id, type, 0, MOD_CONTROL_R);
1022 break;
1023
1024 case KS_Alt_L:
1025 update_modifier(id, type, 0, MOD_META_L);
1026 break;
1027
1028 case KS_Alt_R:
1029 update_modifier(id, type, 0, MOD_META_R);
1030 break;
1031
1032 case KS_Mode_switch:
1033 update_modifier(id, type, 0, MOD_MODESHIFT);
1034 break;
1035
1036 case KS_Num_Lock:
1037 update_modifier(id, type, 1, MOD_NUMLOCK);
1038 break;
1039
1040 case KS_Hold_Screen:
1041 if (sc != NULL) {
1042 update_modifier(id, type, 1, MOD_HOLDSCREEN);
1043 wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN);
1044 }
1045 break;
1046 }
1047
1048 /* If this is a key release or we are in command mode, we are done */
1049 if (type != WSCONS_EVENT_KEY_DOWN || iscommand) {
1050 update_leds(id);
1051 return (KS_voidSymbol);
1052 }
1053
1054 /* Get the keysym */
1055 if (id->t_modifiers & MOD_MODESHIFT)
1056 group = & kp->group2[0];
1057 else
1058 group = & kp->group1[0];
1059
1060 if ((id->t_modifiers & MOD_NUMLOCK) != 0 &&
1061 KS_GROUP(group[1]) == KS_GROUP_Keypad) {
1062 if (MOD_ONESET(id, MOD_ANYSHIFT))
1063 ksym = group[0];
1064 else
1065 ksym = group[1];
1066 } else if (! MOD_ONESET(id, MOD_ANYSHIFT | MOD_CAPSLOCK)) {
1067 ksym = group[0];
1068 } else if (MOD_ONESET(id, MOD_CAPSLOCK)) {
1069 if (! MOD_ONESET(id, MOD_SHIFT_L | MOD_SHIFT_R))
1070 ksym = group[0];
1071 else
1072 ksym = group[1];
1073 if (ksym >= KS_a && ksym <= KS_z)
1074 ksym += KS_A - KS_a;
1075 else if (ksym >= KS_agrave && ksym <= KS_thorn &&
1076 ksym != KS_division)
1077 ksym += KS_Agrave - KS_agrave;
1078 } else if (MOD_ONESET(id, MOD_ANYSHIFT)) {
1079 ksym = group[1];
1080 } else {
1081 ksym = group[0];
1082 }
1083
1084 /* Process compose sequence and dead accents */
1085 res = KS_voidSymbol;
1086
1087 switch (KS_GROUP(ksym)) {
1088 case KS_GROUP_Ascii:
1089 case KS_GROUP_Keypad:
1090 case KS_GROUP_Function:
1091 res = ksym;
1092 break;
1093
1094 case KS_GROUP_Mod:
1095 if (ksym == KS_Multi_key) {
1096 update_modifier(id, 1, 0, MOD_COMPOSE);
1097 id->t_composelen = 2;
1098 }
1099 break;
1100
1101 case KS_GROUP_Dead:
1102 if (id->t_composelen == 0) {
1103 update_modifier(id, 1, 0, MOD_COMPOSE);
1104 id->t_composelen = 1;
1105 id->t_composebuf[0] = ksym;
1106 } else
1107 res = ksym;
1108 break;
1109 }
1110
1111 if (res == KS_voidSymbol) {
1112 update_leds(id);
1113 return (res);
1114 }
1115
1116 if (id->t_composelen > 0) {
1117 id->t_composebuf[2 - id->t_composelen] = res;
1118 if (--id->t_composelen == 0) {
1119 res = wskbd_compose_value(id->t_composebuf);
1120 update_modifier(id, 0, 0, MOD_COMPOSE);
1121 } else {
1122 return (KS_voidSymbol);
1123 }
1124 }
1125
1126 update_leds(id);
1127
1128 /* We are done, return the symbol */
1129 if (KS_GROUP(res) == KS_GROUP_Ascii) {
1130 if (MOD_ONESET(id, MOD_ANYCONTROL)) {
1131 if ((res >= KS_at && res <= KS_z) || res == KS_space)
1132 res = res & 0x1f;
1133 else if (res == KS_2)
1134 res = 0x00;
1135 else if (res >= KS_3 && res <= KS_7)
1136 res = KS_Escape + (res - KS_3);
1137 else if (res == KS_8)
1138 res = KS_Delete;
1139 }
1140 if (MOD_ONESET(id, MOD_ANYMETA))
1141 res |= 0x80;
1142 }
1143
1144 return (res);
1145 }
1146