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