wskbd.c revision 1.14 1 /* $NetBSD: wskbd.c,v 1.14 1998/12/28 13:48:24 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.14 1998/12/28 13:48:24 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 "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 sc->sc_layout = KB_USER;
728 }
729 free(buf, M_TEMP);
730 return(error);
731
732 case WSKBDIO_GETMAP:
733 umdp = (struct wskbd_map_data *)data;
734 if (umdp->maplen > sc->sc_maplen)
735 umdp->maplen = sc->sc_maplen;
736 error = copyout(sc->sc_map, umdp->map,
737 umdp->maplen*sizeof(struct wscons_keymap));
738 return(error);
739
740 case WSKBDIO_GETENCODING:
741 *((kbd_t *) data) = sc->sc_layout;
742 return(0);
743
744 case WSKBDIO_SETENCODING:
745 if ((flag & FWRITE) == 0)
746 return (EACCES);
747 md = *(sc->id->t_keymap); /* structure assignment */
748 md.layout = *((kbd_t *)data);
749 error = wskbd_load_keymap(&md, &sc->sc_map, &sc->sc_maplen);
750 if (error == 0)
751 sc->sc_layout = *((kbd_t *)data);
752 return(error);
753 }
754
755 /*
756 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
757 * if it didn't recognize the request, and in turn we return
758 * -1 if we didn't recognize the request.
759 */
760 /* printf("kbdaccess\n"); */
761 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
762 flag, p);
763 #ifdef WSDISPLAY_COMPAT_RAWKBD
764 if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
765 int s = spltty();
766 sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
767 | MOD_CONTROL_L | MOD_CONTROL_R
768 | MOD_META_L | MOD_META_R
769 | MOD_COMMAND
770 | MOD_COMMAND1 | MOD_COMMAND2);
771 if (sc->sc_repeating) {
772 sc->sc_repeating = 0;
773 untimeout(wskbd_repeat, sc);
774 }
775 splx(s);
776 }
777 #endif
778 return (error);
779 }
780
781 int
782 wskbdpoll(dev, events, p)
783 dev_t dev;
784 int events;
785 struct proc *p;
786 {
787 #if NWSKBD > 0
788 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
789
790 return (wsevent_poll(&sc->sc_events, events, p));
791 #else
792 return (0);
793 #endif /* NWSKBD > 0 */
794 }
795
796 int
797 wskbd_is_console(dv)
798 struct device *dv;
799 {
800 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
801
802 KASSERT(sc != NULL);
803 return (sc->sc_isconsole);
804 }
805
806 struct device *
807 wskbd_display(dv)
808 struct device *dv;
809 {
810 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
811
812 KASSERT(sc != NULL);
813 return (sc->sc_displaydv);
814 }
815
816 void
817 wskbd_set_display(dv, displaydv)
818 struct device *dv, *displaydv;
819 {
820 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
821
822 KASSERT(sc != NULL);
823 sc->sc_displaydv = displaydv;
824 }
825
826 /*
827 * Console interface.
828 */
829 int
830 wskbd_cngetc(dev)
831 dev_t dev;
832 {
833 u_int type;
834 int data;
835 keysym_t ks;
836
837 if (!wskbd_console_initted)
838 return 0;
839
840 if (wskbd_console_device != NULL &&
841 !wskbd_console_device->sc_translating)
842 return 0;
843
844 for(;;) {
845 (*wskbd_console_data.t_consops->getc)
846 (wskbd_console_data.t_consaccesscookie, &type, &data);
847 ks = wskbd_translate(&wskbd_console_data, type, data);
848
849 if (KS_GROUP(ks) == KS_GROUP_Ascii)
850 return (KS_VALUE(ks));
851 }
852 }
853
854 void
855 wskbd_cnpollc(dev, poll)
856 dev_t dev;
857 int poll;
858 {
859
860 if (!wskbd_console_initted)
861 return;
862
863 if (wskbd_console_device != NULL &&
864 !wskbd_console_device->sc_translating)
865 return;
866
867 (*wskbd_console_data.t_consops->pollc)
868 (wskbd_console_data.t_consaccesscookie, poll);
869 }
870
871 static inline void
872 update_leds(id)
873 struct wskbd_internal *id;
874 {
875 int new_state;
876
877 new_state = 0;
878 if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
879 new_state |= WSKBD_LED_CAPS;
880 if (id->t_modifiers & MOD_NUMLOCK)
881 new_state |= WSKBD_LED_NUM;
882 if (id->t_modifiers & MOD_COMPOSE)
883 new_state |= WSKBD_LED_COMPOSE;
884 if (id->t_modifiers & MOD_HOLDSCREEN)
885 new_state |= WSKBD_LED_SCROLL;
886
887 if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
888 (*id->t_sc->sc_accessops->set_leds)
889 (id->t_sc->sc_accesscookie, new_state);
890 id->t_sc->sc_ledstate = new_state;
891 }
892 }
893
894 static inline void
895 update_modifier(id, type, toggle, mask)
896 struct wskbd_internal *id;
897 u_int type;
898 int toggle;
899 int mask;
900 {
901 if (toggle) {
902 if (type == WSCONS_EVENT_KEY_DOWN)
903 id->t_modifiers ^= mask;
904 } else {
905 if (type == WSCONS_EVENT_KEY_DOWN)
906 id->t_modifiers |= mask;
907 else
908 id->t_modifiers &= ~mask;
909 }
910 }
911
912 static int
913 internal_command(sc, type, ksym)
914 struct wskbd_softc *sc;
915 u_int *type;
916 keysym_t ksym;
917 {
918 switch (ksym) {
919 case KS_Cmd:
920 update_modifier(sc->id, *type, 0, MOD_COMMAND);
921 break;
922
923 case KS_Cmd1:
924 update_modifier(sc->id, *type, 0, MOD_COMMAND1);
925 break;
926
927 case KS_Cmd2:
928 update_modifier(sc->id, *type, 0, MOD_COMMAND2);
929 break;
930 }
931
932 if (*type != WSCONS_EVENT_KEY_DOWN ||
933 (! MOD_ONESET(sc->id, MOD_COMMAND) &&
934 ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)))
935 return (0);
936
937 switch (ksym) {
938 #ifdef DDB
939 case KS_Cmd_Debugger:
940 if (sc->sc_isconsole)
941 Debugger();
942 /* discard this key (ddb discarded command modifiers) */
943 *type = WSCONS_EVENT_KEY_UP;
944 return (1);
945 #endif
946
947 case KS_Cmd_Screen0:
948 case KS_Cmd_Screen1:
949 case KS_Cmd_Screen2:
950 case KS_Cmd_Screen3:
951 case KS_Cmd_Screen4:
952 case KS_Cmd_Screen5:
953 case KS_Cmd_Screen6:
954 case KS_Cmd_Screen7:
955 case KS_Cmd_Screen8:
956 case KS_Cmd_Screen9:
957 wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0);
958 return (1);
959 }
960 return (0);
961 }
962
963 static keysym_t
964 wskbd_translate(id, type, value)
965 struct wskbd_internal *id;
966 u_int type;
967 int value;
968 {
969 struct wskbd_softc *sc = id->t_sc;
970 keysym_t ksym, res, *group;
971 struct wscons_keymap kpbuf, *kp;
972 int iscommand = 0;
973
974 if (type == WSCONS_EVENT_ALL_KEYS_UP) {
975 id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
976 | MOD_CONTROL_L | MOD_CONTROL_R
977 | MOD_META_L | MOD_META_R
978 | MOD_MODESHIFT
979 | MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
980 update_leds(id);
981 return (KS_voidSymbol);
982 }
983
984 if (sc != NULL) {
985 if (value < 0 || value >= sc->sc_maplen) {
986 #ifdef DEBUG
987 printf("wskbd_translate: keycode %d out of range\n",
988 value);
989 #endif
990 return (KS_voidSymbol);
991 }
992 kp = sc->sc_map + value;
993 } else {
994 kp = &kpbuf;
995 wskbd_get_mapentry(id->t_keymap, value, kp);
996 }
997
998 /* if this key has a command, process it first */
999 if (sc != NULL && kp->command != KS_voidSymbol)
1000 iscommand = internal_command(sc, &type, kp->command);
1001
1002 /* Now update modifiers */
1003 switch (kp->group1[0]) {
1004 case KS_Shift_L:
1005 update_modifier(id, type, 0, MOD_SHIFT_L);
1006 break;
1007
1008 case KS_Shift_R:
1009 update_modifier(id, type, 0, MOD_SHIFT_R);
1010 break;
1011
1012 case KS_Shift_Lock:
1013 update_modifier(id, type, 1, MOD_SHIFTLOCK);
1014 break;
1015
1016 case KS_Caps_Lock:
1017 update_modifier(id, type, 1, MOD_CAPSLOCK);
1018 break;
1019
1020 case KS_Control_L:
1021 update_modifier(id, type, 0, MOD_CONTROL_L);
1022 break;
1023
1024 case KS_Control_R:
1025 update_modifier(id, type, 0, MOD_CONTROL_R);
1026 break;
1027
1028 case KS_Alt_L:
1029 update_modifier(id, type, 0, MOD_META_L);
1030 break;
1031
1032 case KS_Alt_R:
1033 update_modifier(id, type, 0, MOD_META_R);
1034 break;
1035
1036 case KS_Mode_switch:
1037 update_modifier(id, type, 0, MOD_MODESHIFT);
1038 break;
1039
1040 case KS_Num_Lock:
1041 update_modifier(id, type, 1, MOD_NUMLOCK);
1042 break;
1043
1044 case KS_Hold_Screen:
1045 if (sc != NULL) {
1046 update_modifier(id, type, 1, MOD_HOLDSCREEN);
1047 wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN);
1048 }
1049 break;
1050 }
1051
1052 /* If this is a key release or we are in command mode, we are done */
1053 if (type != WSCONS_EVENT_KEY_DOWN || iscommand) {
1054 update_leds(id);
1055 return (KS_voidSymbol);
1056 }
1057
1058 /* Get the keysym */
1059 if (id->t_modifiers & MOD_MODESHIFT)
1060 group = & kp->group2[0];
1061 else
1062 group = & kp->group1[0];
1063
1064 if ((id->t_modifiers & MOD_NUMLOCK) != 0 &&
1065 KS_GROUP(group[1]) == KS_GROUP_Keypad) {
1066 if (MOD_ONESET(id, MOD_ANYSHIFT))
1067 ksym = group[0];
1068 else
1069 ksym = group[1];
1070 } else if (! MOD_ONESET(id, MOD_ANYSHIFT | MOD_CAPSLOCK)) {
1071 ksym = group[0];
1072 } else if (MOD_ONESET(id, MOD_CAPSLOCK)) {
1073 if (! MOD_ONESET(id, MOD_SHIFT_L | MOD_SHIFT_R))
1074 ksym = group[0];
1075 else
1076 ksym = group[1];
1077 if (ksym >= KS_a && ksym <= KS_z)
1078 ksym += KS_A - KS_a;
1079 else if (ksym >= KS_agrave && ksym <= KS_thorn &&
1080 ksym != KS_division)
1081 ksym += KS_Agrave - KS_agrave;
1082 } else if (MOD_ONESET(id, MOD_ANYSHIFT)) {
1083 ksym = group[1];
1084 } else {
1085 ksym = group[0];
1086 }
1087
1088 /* Process compose sequence and dead accents */
1089 res = KS_voidSymbol;
1090
1091 switch (KS_GROUP(ksym)) {
1092 case KS_GROUP_Ascii:
1093 case KS_GROUP_Keypad:
1094 case KS_GROUP_Function:
1095 res = ksym;
1096 break;
1097
1098 case KS_GROUP_Mod:
1099 if (ksym == KS_Multi_key) {
1100 update_modifier(id, 1, 0, MOD_COMPOSE);
1101 id->t_composelen = 2;
1102 }
1103 break;
1104
1105 case KS_GROUP_Dead:
1106 if (id->t_composelen == 0) {
1107 update_modifier(id, 1, 0, MOD_COMPOSE);
1108 id->t_composelen = 1;
1109 id->t_composebuf[0] = ksym;
1110 } else
1111 res = ksym;
1112 break;
1113 }
1114
1115 if (res == KS_voidSymbol) {
1116 update_leds(id);
1117 return (res);
1118 }
1119
1120 if (id->t_composelen > 0) {
1121 id->t_composebuf[2 - id->t_composelen] = res;
1122 if (--id->t_composelen == 0) {
1123 res = wskbd_compose_value(id->t_composebuf);
1124 update_modifier(id, 0, 0, MOD_COMPOSE);
1125 } else {
1126 return (KS_voidSymbol);
1127 }
1128 }
1129
1130 update_leds(id);
1131
1132 /* We are done, return the symbol */
1133 if (KS_GROUP(res) == KS_GROUP_Ascii) {
1134 if (MOD_ONESET(id, MOD_ANYCONTROL)) {
1135 if ((res >= KS_at && res <= KS_z) || res == KS_space)
1136 res = res & 0x1f;
1137 else if (res == KS_2)
1138 res = 0x00;
1139 else if (res >= KS_3 && res <= KS_7)
1140 res = KS_Escape + (res - KS_3);
1141 else if (res == KS_8)
1142 res = KS_Delete;
1143 }
1144 if (MOD_ONESET(id, MOD_ANYMETA))
1145 res |= 0x80;
1146 }
1147
1148 return (res);
1149 }
1150