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