wskbd.c revision 1.13 1 /* $NetBSD: wskbd.c,v 1.13 1998/09/17 18:05:43 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.13 1998/09/17 18:05:43 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;
519 int unit;
520
521 unit = minor(dev);
522 if (unit >= wskbd_cd.cd_ndevs || /* make sure it was attached */
523 (sc = wskbd_cd.cd_devs[unit]) == NULL)
524 return (ENXIO);
525
526 sc->sc_ready = 0; /* stop accepting events */
527 sc->sc_translating = 1;
528
529 wsevent_fini(&sc->sc_events);
530 sc->sc_events.io = NULL;
531
532 wskbd_enable((struct device *)sc, 0);
533 #endif /* NWSKBD > 0 */
534 return (0);
535 }
536
537 int
538 wskbdread(dev, uio, flags)
539 dev_t dev;
540 struct uio *uio;
541 int flags;
542 {
543 #if NWSKBD > 0
544 struct wskbd_softc *sc;
545 int unit;
546
547 unit = minor(dev);
548 if (unit >= wskbd_cd.cd_ndevs || /* make sure it was attached */
549 (sc = wskbd_cd.cd_devs[unit]) == NULL)
550 return (ENXIO);
551
552 return (wsevent_read(&sc->sc_events, uio, flags));
553 #else
554 return (ENXIO);
555 #endif /* NWSKBD > 0 */
556 }
557
558 int
559 wskbdioctl(dev, cmd, data, flag, p)
560 dev_t dev;
561 u_long cmd;
562 caddr_t data;
563 int flag;
564 struct proc *p;
565 {
566 #if NWSKBD > 0
567 struct wskbd_softc *sc;
568 int unit, error;
569
570 unit = minor(dev);
571 if (unit >= wskbd_cd.cd_ndevs || /* make sure it was attached */
572 (sc = wskbd_cd.cd_devs[unit]) == NULL)
573 return (ENXIO);
574
575 /*
576 * Try the generic ioctls that the wskbd interface supports.
577 */
578 switch (cmd) {
579 case FIONBIO: /* we will remove this someday (soon???) */
580 return (0);
581
582 case FIOASYNC:
583 sc->sc_events.async = *(int *)data != 0;
584 return (0);
585
586 case TIOCSPGRP:
587 if (*(int *)data != sc->sc_events.io->p_pgid)
588 return (EPERM);
589 return (0);
590 }
591
592 /*
593 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
594 * if it didn't recognize the request.
595 */
596 error = wskbd_displayioctl((struct device *)sc, cmd, data, flag, p);
597 return (error != -1 ? error : ENOTTY);
598 #else
599 return (ENXIO);
600 #endif /* NWSKBD > 0 */
601 }
602
603 /*
604 * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
605 * Some of these have no real effect in raw mode, however.
606 */
607 int
608 wskbd_displayioctl(dev, cmd, data, flag, p)
609 struct device *dev;
610 u_long cmd;
611 caddr_t data;
612 int flag;
613 struct proc *p;
614 {
615 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
616 struct wskbd_bell_data *ubdp, *kbdp;
617 struct wskbd_keyrepeat_data *ukdp, *kkdp;
618 struct wskbd_map_data *umdp;
619 struct wskbd_mapdata md;
620 void *buf;
621 int len, error;
622
623 switch (cmd) {
624 #define SETBELL(dstp, srcp, dfltp) \
625 do { \
626 (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ? \
627 (srcp)->pitch : (dfltp)->pitch; \
628 (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ? \
629 (srcp)->period : (dfltp)->period; \
630 (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ? \
631 (srcp)->volume : (dfltp)->volume; \
632 (dstp)->which = WSKBD_BELL_DOALL; \
633 } while (0)
634
635 case WSKBDIO_BELL:
636 if ((flag & FWRITE) == 0)
637 return (EACCES);
638 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
639 WSKBDIO_COMPLEXBELL, (caddr_t)&sc->sc_bell_data, flag, p));
640
641 case WSKBDIO_COMPLEXBELL:
642 if ((flag & FWRITE) == 0)
643 return (EACCES);
644 ubdp = (struct wskbd_bell_data *)data;
645 SETBELL(ubdp, ubdp, &sc->sc_bell_data);
646 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
647 WSKBDIO_COMPLEXBELL, (caddr_t)ubdp, flag, p));
648
649 case WSKBDIO_SETBELL:
650 if ((flag & FWRITE) == 0)
651 return (EACCES);
652 kbdp = &sc->sc_bell_data;
653 setbell:
654 ubdp = (struct wskbd_bell_data *)data;
655 SETBELL(kbdp, ubdp, kbdp);
656 return (0);
657
658 case WSKBDIO_GETBELL:
659 kbdp = &sc->sc_bell_data;
660 getbell:
661 ubdp = (struct wskbd_bell_data *)data;
662 SETBELL(ubdp, kbdp, kbdp);
663 return (0);
664
665 case WSKBDIO_SETDEFAULTBELL:
666 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
667 return (error);
668 kbdp = &wskbd_default_bell_data;
669 goto setbell;
670
671
672 case WSKBDIO_GETDEFAULTBELL:
673 kbdp = &wskbd_default_bell_data;
674 goto getbell;
675
676 #undef SETBELL
677
678 #define SETKEYREPEAT(dstp, srcp, dfltp) \
679 do { \
680 (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ? \
681 (srcp)->del1 : (dfltp)->del1; \
682 (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ? \
683 (srcp)->delN : (dfltp)->delN; \
684 (dstp)->which = WSKBD_KEYREPEAT_DOALL; \
685 } while (0)
686
687 case WSKBDIO_SETKEYREPEAT:
688 if ((flag & FWRITE) == 0)
689 return (EACCES);
690 kkdp = &sc->sc_keyrepeat_data;
691 setkeyrepeat:
692 ukdp = (struct wskbd_keyrepeat_data *)data;
693 SETKEYREPEAT(kkdp, ukdp, kkdp);
694 return (0);
695
696 case WSKBDIO_GETKEYREPEAT:
697 kkdp = &sc->sc_keyrepeat_data;
698 getkeyrepeat:
699 ukdp = (struct wskbd_keyrepeat_data *)data;
700 SETKEYREPEAT(ukdp, kkdp, kkdp);
701 return (0);
702
703 case WSKBDIO_SETDEFAULTKEYREPEAT:
704 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
705 return (error);
706 kkdp = &wskbd_default_keyrepeat_data;
707 goto setkeyrepeat;
708
709
710 case WSKBDIO_GETDEFAULTKEYREPEAT:
711 kkdp = &wskbd_default_keyrepeat_data;
712 goto getkeyrepeat;
713
714 #undef SETKEYREPEAT
715
716 case WSKBDIO_SETMAP:
717 if ((flag & FWRITE) == 0)
718 return (EACCES);
719 umdp = (struct wskbd_map_data *)data;
720 len = umdp->maplen*sizeof(struct wscons_keymap);
721 buf = malloc(len, M_TEMP, M_WAITOK);
722 error = copyin(umdp->map, buf, len);
723 if (error == 0) {
724 wskbd_init_keymap(umdp->maplen,
725 &sc->sc_map, &sc->sc_maplen);
726 bcopy(buf, sc->sc_map, len);
727 }
728 free(buf, M_TEMP);
729 return(error);
730
731 case WSKBDIO_GETMAP:
732 umdp = (struct wskbd_map_data *)data;
733 if (umdp->maplen > sc->sc_maplen)
734 umdp->maplen = sc->sc_maplen;
735 error = copyout(sc->sc_map, umdp->map,
736 umdp->maplen*sizeof(struct wscons_keymap));
737 return(error);
738
739 case WSKBDIO_GETENCODING:
740 *((kbd_t *) data) = sc->sc_layout;
741 return(0);
742
743 case WSKBDIO_SETENCODING:
744 if ((flag & FWRITE) == 0)
745 return (EACCES);
746 md = *(sc->id->t_keymap); /* structure assignment */
747 md.layout = *((kbd_t *)data);
748 error = wskbd_load_keymap(&md, &sc->sc_map, &sc->sc_maplen);
749 if (error == 0)
750 sc->sc_layout = *((kbd_t *)data);
751 return(error);
752 }
753
754 /*
755 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
756 * if it didn't recognize the request, and in turn we return
757 * -1 if we didn't recognize the request.
758 */
759 /* printf("kbdaccess\n"); */
760 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
761 flag, p);
762 #ifdef WSDISPLAY_COMPAT_RAWKBD
763 if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
764 int s = spltty();
765 sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
766 | MOD_CONTROL_L | MOD_CONTROL_R
767 | MOD_META_L | MOD_META_R
768 | MOD_COMMAND
769 | MOD_COMMAND1 | MOD_COMMAND2);
770 if (sc->sc_repeating) {
771 sc->sc_repeating = 0;
772 untimeout(wskbd_repeat, sc);
773 }
774 splx(s);
775 }
776 #endif
777 return (error);
778 }
779
780 int
781 wskbdpoll(dev, events, p)
782 dev_t dev;
783 int events;
784 struct proc *p;
785 {
786 #if NWSKBD > 0
787 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
788
789 return (wsevent_poll(&sc->sc_events, events, p));
790 #else
791 return (0);
792 #endif /* NWSKBD > 0 */
793 }
794
795 int
796 wskbd_is_console(dv)
797 struct device *dv;
798 {
799 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
800
801 KASSERT(sc != NULL);
802 return (sc->sc_isconsole);
803 }
804
805 struct device *
806 wskbd_display(dv)
807 struct device *dv;
808 {
809 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
810
811 KASSERT(sc != NULL);
812 return (sc->sc_displaydv);
813 }
814
815 void
816 wskbd_set_display(dv, displaydv)
817 struct device *dv, *displaydv;
818 {
819 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
820
821 KASSERT(sc != NULL);
822 sc->sc_displaydv = displaydv;
823 }
824
825 /*
826 * Console interface.
827 */
828 int
829 wskbd_cngetc(dev)
830 dev_t dev;
831 {
832 u_int type;
833 int data;
834 keysym_t ks;
835
836 if (!wskbd_console_initted)
837 return 0;
838
839 if (wskbd_console_device != NULL &&
840 !wskbd_console_device->sc_translating)
841 return 0;
842
843 for(;;) {
844 (*wskbd_console_data.t_consops->getc)
845 (wskbd_console_data.t_consaccesscookie, &type, &data);
846 ks = wskbd_translate(&wskbd_console_data, type, data);
847
848 if (KS_GROUP(ks) == KS_GROUP_Ascii)
849 return (KS_VALUE(ks));
850 }
851 }
852
853 void
854 wskbd_cnpollc(dev, poll)
855 dev_t dev;
856 int poll;
857 {
858
859 if (!wskbd_console_initted)
860 return;
861
862 if (wskbd_console_device != NULL &&
863 !wskbd_console_device->sc_translating)
864 return;
865
866 (*wskbd_console_data.t_consops->pollc)
867 (wskbd_console_data.t_consaccesscookie, poll);
868 }
869
870 static inline void
871 update_leds(id)
872 struct wskbd_internal *id;
873 {
874 int new_state;
875
876 new_state = 0;
877 if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
878 new_state |= WSKBD_LED_CAPS;
879 if (id->t_modifiers & MOD_NUMLOCK)
880 new_state |= WSKBD_LED_NUM;
881 if (id->t_modifiers & MOD_COMPOSE)
882 new_state |= WSKBD_LED_COMPOSE;
883 if (id->t_modifiers & MOD_HOLDSCREEN)
884 new_state |= WSKBD_LED_SCROLL;
885
886 if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
887 (*id->t_sc->sc_accessops->set_leds)
888 (id->t_sc->sc_accesscookie, new_state);
889 id->t_sc->sc_ledstate = new_state;
890 }
891 }
892
893 static inline void
894 update_modifier(id, type, toggle, mask)
895 struct wskbd_internal *id;
896 u_int type;
897 int toggle;
898 int mask;
899 {
900 if (toggle) {
901 if (type == WSCONS_EVENT_KEY_DOWN)
902 id->t_modifiers ^= mask;
903 } else {
904 if (type == WSCONS_EVENT_KEY_DOWN)
905 id->t_modifiers |= mask;
906 else
907 id->t_modifiers &= ~mask;
908 }
909 }
910
911 static int
912 internal_command(sc, type, ksym)
913 struct wskbd_softc *sc;
914 u_int *type;
915 keysym_t ksym;
916 {
917 switch (ksym) {
918 case KS_Cmd:
919 update_modifier(sc->id, *type, 0, MOD_COMMAND);
920 break;
921
922 case KS_Cmd1:
923 update_modifier(sc->id, *type, 0, MOD_COMMAND1);
924 break;
925
926 case KS_Cmd2:
927 update_modifier(sc->id, *type, 0, MOD_COMMAND2);
928 break;
929 }
930
931 if (*type != WSCONS_EVENT_KEY_DOWN ||
932 (! MOD_ONESET(sc->id, MOD_COMMAND) &&
933 ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)))
934 return (0);
935
936 switch (ksym) {
937 #ifdef DDB
938 case KS_Cmd_Debugger:
939 if (sc->sc_isconsole)
940 Debugger();
941 /* discard this key (ddb discarded command modifiers) */
942 *type = WSCONS_EVENT_KEY_UP;
943 return (1);
944 #endif
945
946 case KS_Cmd_Screen0:
947 case KS_Cmd_Screen1:
948 case KS_Cmd_Screen2:
949 case KS_Cmd_Screen3:
950 case KS_Cmd_Screen4:
951 case KS_Cmd_Screen5:
952 case KS_Cmd_Screen6:
953 case KS_Cmd_Screen7:
954 case KS_Cmd_Screen8:
955 case KS_Cmd_Screen9:
956 wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0);
957 return (1);
958 }
959 return (0);
960 }
961
962 static keysym_t
963 wskbd_translate(id, type, value)
964 struct wskbd_internal *id;
965 u_int type;
966 int value;
967 {
968 struct wskbd_softc *sc = id->t_sc;
969 keysym_t ksym, res, *group;
970 struct wscons_keymap kpbuf, *kp;
971 int iscommand = 0;
972
973 if (type == WSCONS_EVENT_ALL_KEYS_UP) {
974 id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
975 | MOD_CONTROL_L | MOD_CONTROL_R
976 | MOD_META_L | MOD_META_R
977 | MOD_MODESHIFT
978 | MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
979 update_leds(id);
980 return (KS_voidSymbol);
981 }
982
983 if (sc != NULL) {
984 if (value < 0 || value >= sc->sc_maplen) {
985 #ifdef DEBUG
986 printf("wskbd_translate: keycode %d out of range\n",
987 value);
988 #endif
989 return (KS_voidSymbol);
990 }
991 kp = sc->sc_map + value;
992 } else {
993 kp = &kpbuf;
994 wskbd_get_mapentry(id->t_keymap, value, kp);
995 }
996
997 /* if this key has a command, process it first */
998 if (sc != NULL && kp->command != KS_voidSymbol)
999 iscommand = internal_command(sc, &type, kp->command);
1000
1001 /* Now update modifiers */
1002 switch (kp->group1[0]) {
1003 case KS_Shift_L:
1004 update_modifier(id, type, 0, MOD_SHIFT_L);
1005 break;
1006
1007 case KS_Shift_R:
1008 update_modifier(id, type, 0, MOD_SHIFT_R);
1009 break;
1010
1011 case KS_Shift_Lock:
1012 update_modifier(id, type, 1, MOD_SHIFTLOCK);
1013 break;
1014
1015 case KS_Caps_Lock:
1016 update_modifier(id, type, 1, MOD_CAPSLOCK);
1017 break;
1018
1019 case KS_Control_L:
1020 update_modifier(id, type, 0, MOD_CONTROL_L);
1021 break;
1022
1023 case KS_Control_R:
1024 update_modifier(id, type, 0, MOD_CONTROL_R);
1025 break;
1026
1027 case KS_Alt_L:
1028 update_modifier(id, type, 0, MOD_META_L);
1029 break;
1030
1031 case KS_Alt_R:
1032 update_modifier(id, type, 0, MOD_META_R);
1033 break;
1034
1035 case KS_Mode_switch:
1036 update_modifier(id, type, 0, MOD_MODESHIFT);
1037 break;
1038
1039 case KS_Num_Lock:
1040 update_modifier(id, type, 1, MOD_NUMLOCK);
1041 break;
1042
1043 case KS_Hold_Screen:
1044 if (sc != NULL) {
1045 update_modifier(id, type, 1, MOD_HOLDSCREEN);
1046 wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN);
1047 }
1048 break;
1049 }
1050
1051 /* If this is a key release or we are in command mode, we are done */
1052 if (type != WSCONS_EVENT_KEY_DOWN || iscommand) {
1053 update_leds(id);
1054 return (KS_voidSymbol);
1055 }
1056
1057 /* Get the keysym */
1058 if (id->t_modifiers & MOD_MODESHIFT)
1059 group = & kp->group2[0];
1060 else
1061 group = & kp->group1[0];
1062
1063 if ((id->t_modifiers & MOD_NUMLOCK) != 0 &&
1064 KS_GROUP(group[1]) == KS_GROUP_Keypad) {
1065 if (MOD_ONESET(id, MOD_ANYSHIFT))
1066 ksym = group[0];
1067 else
1068 ksym = group[1];
1069 } else if (! MOD_ONESET(id, MOD_ANYSHIFT | MOD_CAPSLOCK)) {
1070 ksym = group[0];
1071 } else if (MOD_ONESET(id, MOD_CAPSLOCK)) {
1072 if (! MOD_ONESET(id, MOD_SHIFT_L | MOD_SHIFT_R))
1073 ksym = group[0];
1074 else
1075 ksym = group[1];
1076 if (ksym >= KS_a && ksym <= KS_z)
1077 ksym += KS_A - KS_a;
1078 else if (ksym >= KS_agrave && ksym <= KS_thorn &&
1079 ksym != KS_division)
1080 ksym += KS_Agrave - KS_agrave;
1081 } else if (MOD_ONESET(id, MOD_ANYSHIFT)) {
1082 ksym = group[1];
1083 } else {
1084 ksym = group[0];
1085 }
1086
1087 /* Process compose sequence and dead accents */
1088 res = KS_voidSymbol;
1089
1090 switch (KS_GROUP(ksym)) {
1091 case KS_GROUP_Ascii:
1092 case KS_GROUP_Keypad:
1093 case KS_GROUP_Function:
1094 res = ksym;
1095 break;
1096
1097 case KS_GROUP_Mod:
1098 if (ksym == KS_Multi_key) {
1099 update_modifier(id, 1, 0, MOD_COMPOSE);
1100 id->t_composelen = 2;
1101 }
1102 break;
1103
1104 case KS_GROUP_Dead:
1105 if (id->t_composelen == 0) {
1106 update_modifier(id, 1, 0, MOD_COMPOSE);
1107 id->t_composelen = 1;
1108 id->t_composebuf[0] = ksym;
1109 } else
1110 res = ksym;
1111 break;
1112 }
1113
1114 if (res == KS_voidSymbol) {
1115 update_leds(id);
1116 return (res);
1117 }
1118
1119 if (id->t_composelen > 0) {
1120 id->t_composebuf[2 - id->t_composelen] = res;
1121 if (--id->t_composelen == 0) {
1122 res = wskbd_compose_value(id->t_composebuf);
1123 update_modifier(id, 0, 0, MOD_COMPOSE);
1124 } else {
1125 return (KS_voidSymbol);
1126 }
1127 }
1128
1129 update_leds(id);
1130
1131 /* We are done, return the symbol */
1132 if (KS_GROUP(res) == KS_GROUP_Ascii) {
1133 if (MOD_ONESET(id, MOD_ANYCONTROL)) {
1134 if ((res >= KS_at && res <= KS_z) || res == KS_space)
1135 res = res & 0x1f;
1136 else if (res == KS_2)
1137 res = 0x00;
1138 else if (res >= KS_3 && res <= KS_7)
1139 res = KS_Escape + (res - KS_3);
1140 else if (res == KS_8)
1141 res = KS_Delete;
1142 }
1143 if (MOD_ONESET(id, MOD_ANYMETA))
1144 res |= 0x80;
1145 }
1146
1147 return (res);
1148 }
1149