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