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