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