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