kbd.c revision 1.36 1 /* $NetBSD: kbd.c,v 1.36 2003/06/29 09:56:31 darrenr Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratory.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the University of
27 * California, Berkeley and its contributors.
28 * 4. Neither the name of the University nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 *
44 * @(#)kbd.c 8.2 (Berkeley) 10/30/93
45 */
46
47 /*
48 * Keyboard driver (/dev/kbd -- note that we do not have minor numbers
49 * [yet?]). Translates incoming bytes to ASCII or to `firm_events' and
50 * passes them up to the appropriate reader.
51 */
52
53 #include <sys/cdefs.h>
54 __KERNEL_RCSID(0, "$NetBSD: kbd.c,v 1.36 2003/06/29 09:56:31 darrenr Exp $");
55
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/conf.h>
59 #include <sys/device.h>
60 #include <sys/ioctl.h>
61 #include <sys/kernel.h>
62 #include <sys/proc.h>
63 #include <sys/malloc.h>
64 #include <sys/signal.h>
65 #include <sys/signalvar.h>
66 #include <sys/time.h>
67 #include <sys/syslog.h>
68 #include <sys/select.h>
69 #include <sys/poll.h>
70 #include <sys/file.h>
71
72 #include <dev/wscons/wsksymdef.h>
73
74 #include <dev/sun/kbd_reg.h>
75 #include <dev/sun/kbio.h>
76 #include <dev/sun/vuid_event.h>
77 #include <dev/sun/event_var.h>
78 #include <dev/sun/kbd_xlate.h>
79 #include <dev/sun/kbdvar.h>
80
81 #include "locators.h"
82
83 extern struct cfdriver kbd_cd;
84
85 dev_type_open(kbdopen);
86 dev_type_close(kbdclose);
87 dev_type_read(kbdread);
88 dev_type_ioctl(kbdioctl);
89 dev_type_poll(kbdpoll);
90 dev_type_kqfilter(kbdkqfilter);
91
92 const struct cdevsw kbd_cdevsw = {
93 kbdopen, kbdclose, kbdread, nowrite, kbdioctl,
94 nostop, notty, kbdpoll, nommap, kbdkqfilter
95 };
96
97 #if NWSKBD > 0
98 int wssunkbd_enable __P((void *, int));
99 void wssunkbd_set_leds __P((void *, int));
100 int wssunkbd_ioctl __P((void *, u_long, caddr_t, int, struct lwp *));
101
102 void sunkbd_wskbd_cngetc __P((void *, u_int *, int *));
103 void sunkbd_wskbd_cnpollc __P((void *, int));
104 void sunkbd_wskbd_cnbell __P((void *, u_int, u_int, u_int));
105 static void sunkbd_bell_off(void *v);
106
107 const struct wskbd_accessops sunkbd_wskbd_accessops = {
108 wssunkbd_enable,
109 wssunkbd_set_leds,
110 wssunkbd_ioctl,
111 };
112
113 extern const struct wscons_keydesc wssun_keydesctab[];
114 const struct wskbd_mapdata sunkbd_wskbd_keymapdata = {
115 wssun_keydesctab,
116 #ifdef SUNKBD_LAYOUT
117 SUNKBD_LAYOUT,
118 #else
119 KB_US,
120 #endif
121 };
122
123 const struct wskbd_consops sunkbd_wskbd_consops = {
124 sunkbd_wskbd_cngetc,
125 sunkbd_wskbd_cnpollc,
126 sunkbd_wskbd_cnbell,
127 };
128
129 void kbd_wskbd_attach(struct kbd_softc *k, int isconsole);
130 #endif
131
132 /* ioctl helpers */
133 static int kbd_iockeymap(struct kbd_state *ks,
134 u_long cmd, struct kiockeymap *kio);
135 #ifdef KIOCGETKEY
136 static int kbd_oldkeymap(struct kbd_state *ks,
137 u_long cmd, struct okiockey *okio);
138 #endif
139
140
141 /* callbacks for console driver */
142 static int kbd_cc_open(struct cons_channel *);
143 static int kbd_cc_close(struct cons_channel *);
144
145 /* console input */
146 static void kbd_input_console(struct kbd_softc *, int);
147 static void kbd_repeat(void *);
148 static int kbd_input_keysym(struct kbd_softc *, int);
149 static void kbd_input_string(struct kbd_softc *, char *);
150 static void kbd_input_funckey(struct kbd_softc *, int);
151 static void kbd_update_leds(struct kbd_softc *);
152
153 #if NWSKBD > 0
154 static void kbd_input_wskbd(struct kbd_softc *, int);
155 #endif
156
157 /* firm events input */
158 static void kbd_input_event(struct kbd_softc *, int);
159
160
161
162 /****************************************************************
163 * Entry points for /dev/kbd
164 * (open,close,read,write,...)
165 ****************************************************************/
166
167 /*
168 * Open:
169 * Check exclusion, open actual device (_iopen),
170 * setup event channel, clear ASCII repeat stuff.
171 */
172 int
173 kbdopen(dev, flags, mode, l)
174 dev_t dev;
175 int flags, mode;
176 struct lwp *l;
177 {
178 struct kbd_softc *k;
179 int error, unit;
180
181 /* locate device */
182 unit = minor(dev);
183 if (unit >= kbd_cd.cd_ndevs)
184 return (ENXIO);
185 k = kbd_cd.cd_devs[unit];
186 if (k == NULL)
187 return (ENXIO);
188
189 /*
190 * NB: wscons support: while we can track if wskbd has called
191 * enable(), we can't tell if that's for console input or for
192 * events input, so we should probably just let the open to
193 * always succeed regardless (e.g. Xsun opening /dev/kbd).
194 */
195
196 /* exclusive open required for /dev/kbd */
197 if (k->k_events.ev_io)
198 return (EBUSY);
199 k->k_events.ev_io = l->l_proc;
200
201 /* stop pending autorepeat of console input */
202 if (k->k_repeating) {
203 k->k_repeating = 0;
204 callout_stop(&k->k_repeat_ch);
205 }
206
207 /* open actual underlying device */
208 if (k->k_ops != NULL && k->k_ops->open != NULL)
209 if ((error = (*k->k_ops->open)(k)) != 0) {
210 k->k_events.ev_io = NULL;
211 return (error);
212 }
213
214 ev_init(&k->k_events);
215 k->k_evmode = 0; /* XXX: OK? */
216
217 return (0);
218 }
219
220
221 /*
222 * Close:
223 * Turn off event mode, dump the queue, and close the keyboard
224 * unless it is supplying console input.
225 */
226 int
227 kbdclose(dev, flags, mode, l)
228 dev_t dev;
229 int flags, mode;
230 struct lwp *l;
231 {
232 struct kbd_softc *k;
233
234 k = kbd_cd.cd_devs[minor(dev)];
235 k->k_evmode = 0;
236 ev_fini(&k->k_events);
237 k->k_events.ev_io = NULL;
238
239 if (k->k_ops != NULL && k->k_ops->close != NULL) {
240 int error;
241 if ((error = (*k->k_ops->close)(k)) != 0)
242 return (error);
243 }
244 return (0);
245 }
246
247
248 int
249 kbdread(dev, uio, flags)
250 dev_t dev;
251 struct uio *uio;
252 int flags;
253 {
254 struct kbd_softc *k;
255
256 k = kbd_cd.cd_devs[minor(dev)];
257 return (ev_read(&k->k_events, uio, flags));
258 }
259
260
261 int
262 kbdpoll(dev, events, l)
263 dev_t dev;
264 int events;
265 struct lwp *l;
266 {
267 struct kbd_softc *k;
268
269 k = kbd_cd.cd_devs[minor(dev)];
270 return (ev_poll(&k->k_events, events, l));
271 }
272
273 int
274 kbdkqfilter(dev, kn)
275 dev_t dev;
276 struct knote *kn;
277 {
278 struct kbd_softc *k;
279
280 k = kbd_cd.cd_devs[minor(dev)];
281 return (ev_kqfilter(&k->k_events, kn));
282 }
283
284 int
285 kbdioctl(dev, cmd, data, flag, l)
286 dev_t dev;
287 u_long cmd;
288 caddr_t data;
289 int flag;
290 struct lwp *l;
291 {
292 struct kbd_softc *k;
293 struct kbd_state *ks;
294 int error = 0;
295
296 k = kbd_cd.cd_devs[minor(dev)];
297 ks = &k->k_state;
298
299 switch (cmd) {
300
301 case KIOCTRANS: /* Set translation mode */
302 /* We only support "raw" mode on /dev/kbd */
303 if (*(int *)data != TR_UNTRANS_EVENT)
304 error = EINVAL;
305 break;
306
307 case KIOCGTRANS: /* Get translation mode */
308 /* We only support "raw" mode on /dev/kbd */
309 *(int *)data = TR_UNTRANS_EVENT;
310 break;
311
312 #ifdef KIOCGETKEY
313 case KIOCGETKEY: /* Get keymap entry (old format) */
314 error = kbd_oldkeymap(ks, cmd, (struct okiockey *)data);
315 break;
316 #endif /* KIOCGETKEY */
317
318 case KIOCSKEY: /* Set keymap entry */
319 /* FALLTHROUGH */
320 case KIOCGKEY: /* Get keymap entry */
321 error = kbd_iockeymap(ks, cmd, (struct kiockeymap *)data);
322 break;
323
324 case KIOCCMD: /* Send a command to the keyboard */
325 /* pass it to the middle layer */
326 if (k->k_ops != NULL && k->k_ops->docmd != NULL)
327 error = (*k->k_ops->docmd)(k, *(int *)data, 1);
328 break;
329
330 case KIOCTYPE: /* Get keyboard type */
331 *(int *)data = ks->kbd_id;
332 break;
333
334 case KIOCSDIRECT: /* Where to send input */
335 k->k_evmode = *(int *)data;
336 break;
337
338 case KIOCLAYOUT: /* Get keyboard layout */
339 *(int *)data = ks->kbd_layout;
340 break;
341
342 case KIOCSLED: /* Set keyboard LEDs */
343 /* pass the request to the middle layer */
344 if (k->k_ops != NULL && k->k_ops->setleds != NULL)
345 error = (*k->k_ops->setleds)(k, *(char *)data, 1);
346 break;
347
348 case KIOCGLED: /* Get keyboard LEDs */
349 *(char *)data = ks->kbd_leds;
350 break;
351
352 case FIONBIO: /* we will remove this someday (soon???) */
353 break;
354
355 case FIOASYNC:
356 k->k_events.ev_async = (*(int *)data != 0);
357 break;
358
359 case TIOCSPGRP:
360 if (*(int *)data != k->k_events.ev_io->p_pgid)
361 error = EPERM;
362 break;
363
364 default:
365 error = ENOTTY;
366 break;
367 }
368
369 return (error);
370 }
371
372
373 /****************************************************************
374 * ioctl helpers
375 ****************************************************************/
376
377 /*
378 * Get/Set keymap entry
379 */
380 static int
381 kbd_iockeymap(ks, cmd, kio)
382 struct kbd_state *ks;
383 u_long cmd;
384 struct kiockeymap *kio;
385 {
386 u_short *km;
387 u_int station;
388
389 switch (kio->kio_tablemask) {
390 case KIOC_NOMASK:
391 km = ks->kbd_k.k_normal;
392 break;
393 case KIOC_SHIFTMASK:
394 km = ks->kbd_k.k_shifted;
395 break;
396 case KIOC_CTRLMASK:
397 km = ks->kbd_k.k_control;
398 break;
399 case KIOC_UPMASK:
400 km = ks->kbd_k.k_release;
401 break;
402 default:
403 /* Silently ignore unsupported masks */
404 return (0);
405 }
406
407 /* Range-check the table position. */
408 station = kio->kio_station;
409 if (station >= KEYMAP_SIZE)
410 return (EINVAL);
411
412 switch (cmd) {
413
414 case KIOCGKEY: /* Get keymap entry */
415 kio->kio_entry = km[station];
416 break;
417
418 case KIOCSKEY: /* Set keymap entry */
419 km[station] = kio->kio_entry;
420 break;
421
422 default:
423 return(ENOTTY);
424 }
425 return (0);
426 }
427
428
429 #ifdef KIOCGETKEY
430 /*
431 * Get/Set keymap entry,
432 * old format (compatibility)
433 */
434 int
435 kbd_oldkeymap(ks, cmd, kio)
436 struct kbd_state *ks;
437 u_long cmd;
438 struct okiockey *kio;
439 {
440 int error = 0;
441
442 switch (cmd) {
443
444 case KIOCGETKEY:
445 if (kio->kio_station == 118) {
446 /*
447 * This is X11 asking if a type 3 keyboard is
448 * really a type 3 keyboard. Say yes, it is,
449 * by reporting key station 118 as a "hole".
450 * Note old (SunOS 3.5) definition of HOLE!
451 */
452 kio->kio_entry = 0xA2;
453 break;
454 }
455 /* fall through */
456
457 default:
458 error = ENOTTY;
459 break;
460 }
461
462 return (error);
463 }
464 #endif /* KIOCGETKEY */
465
466
467
468 /****************************************************************
469 * Keyboard input - called by middle layer at spltty().
470 ****************************************************************/
471
472 void
473 kbd_input(k, code)
474 struct kbd_softc *k;
475 int code;
476 {
477 if (k->k_evmode) {
478
479 #ifdef KBD_IDLE_EVENTS
480 /*
481 * XXX: is this still true?
482 * IDLEs confuse the MIT X11R4 server badly, so we must drop them.
483 * This is bad as it means the server will not automatically resync
484 * on all-up IDLEs, but I did not drop them before, and the server
485 * goes crazy when it comes time to blank the screen....
486 */
487 if (code == KBD_IDLE)
488 return;
489 #endif
490
491 /*
492 * Keyboard is generating firm events. Turn this keystroke
493 * into an event and put it in the queue.
494 */
495 kbd_input_event(k, code);
496 return;
497 }
498
499 #if NWSKBD > 0
500 if (k->k_wskbd != NULL && k->k_wsenabled) {
501 /*
502 * We are using wskbd input mode, pass the event up.
503 */
504 kbd_input_wskbd(k, code);
505 return;
506 }
507 #endif
508
509 /*
510 * If /dev/kbd is not connected in event mode, or wskbd mode,
511 * translate and send upstream (to console).
512 */
513 kbd_input_console(k, code);
514 }
515
516
517
518 /****************************************************************
519 * Open/close routines called upon opening /dev/console
520 * if we serve console input.
521 ****************************************************************/
522
523 struct cons_channel *
524 kbd_cc_alloc(k)
525 struct kbd_softc *k;
526 {
527 struct cons_channel *cc;
528
529 if ((cc = malloc(sizeof *cc, M_DEVBUF, M_NOWAIT)) == NULL)
530 return (NULL);
531
532 /* our callbacks for the console driver */
533 cc->cc_dev = k;
534 cc->cc_iopen = kbd_cc_open;
535 cc->cc_iclose = kbd_cc_close;
536
537 /* will be provided by the console driver so that we can feed input */
538 cc->cc_upstream = NULL;
539
540 /*
541 * TODO: clean up cons_attach_input() vs kd_attach_input() in
542 * lower layers and move that code here.
543 */
544
545 k->k_cc = cc;
546 return (cc);
547 }
548
549
550 static int
551 kbd_cc_open(cc)
552 struct cons_channel *cc;
553 {
554 struct kbd_softc *k;
555 int ret;
556
557 if (cc == NULL)
558 return (0);
559
560 k = (struct kbd_softc *)cc->cc_dev;
561 if (k == NULL)
562 return (0);
563
564 if (k->k_ops != NULL && k->k_ops->open != NULL)
565 ret = (*k->k_ops->open)(k);
566 else
567 ret = 0;
568
569 /* XXX: verify that callout is not active? */
570 k->k_repeat_start = hz/2;
571 k->k_repeat_step = hz/20;
572 callout_init(&k->k_repeat_ch);
573
574 return (ret);
575 }
576
577
578 static int
579 kbd_cc_close(cc)
580 struct cons_channel *cc;
581 {
582 struct kbd_softc *k;
583 int ret;
584
585 if (cc == NULL)
586 return (0);
587
588 k = (struct kbd_softc *)cc->cc_dev;
589 if (k == NULL)
590 return (0);
591
592 if (k->k_ops != NULL && k->k_ops->close != NULL)
593 ret = (*k->k_ops->close)(k);
594 else
595 ret = 0;
596
597 /* stop any pending auto-repeat */
598 if (k->k_repeating) {
599 k->k_repeating = 0;
600 callout_stop(&k->k_repeat_ch);
601 }
602
603 return (ret);
604 }
605
606
607
608 /****************************************************************
609 * Console input - called by middle layer at spltty().
610 ****************************************************************/
611
612 static void
613 kbd_input_console(k, code)
614 struct kbd_softc *k;
615 int code;
616 {
617 struct kbd_state *ks= &k->k_state;
618 int keysym;
619
620 /* any input stops auto-repeat (i.e. key release) */
621 if (k->k_repeating) {
622 k->k_repeating = 0;
623 callout_stop(&k->k_repeat_ch);
624 }
625
626 keysym = kbd_code_to_keysym(ks, code);
627
628 /* pass to console */
629 if (kbd_input_keysym(k, keysym)) {
630 log(LOG_WARNING, "%s: code=0x%x with mod=0x%x"
631 " produced unexpected keysym 0x%x\n",
632 k->k_dev.dv_xname,
633 code, ks->kbd_modbits, keysym);
634 return; /* no point in auto-repeat here */
635 }
636
637 if (KEYSYM_NOREPEAT(keysym))
638 return;
639
640 /* setup for auto-repeat after initial delay */
641 k->k_repeating = 1;
642 k->k_repeatsym = keysym;
643 callout_reset(&k->k_repeat_ch, k->k_repeat_start,
644 kbd_repeat, k);
645 }
646
647
648 /*
649 * This is the autorepeat callout function scheduled by kbd_input() above.
650 * Called at splsoftclock().
651 */
652 static void
653 kbd_repeat(arg)
654 void *arg;
655 {
656 struct kbd_softc *k = (struct kbd_softc *)arg;
657 int s;
658
659 s = spltty();
660 if (k->k_repeating && k->k_repeatsym >= 0) {
661 /* feed typematic keysym to the console */
662 (void)kbd_input_keysym(k, k->k_repeatsym);
663
664 /* reschedule next repeat */
665 callout_reset(&k->k_repeat_ch, k->k_repeat_step,
666 kbd_repeat, k);
667 }
668 splx(s);
669 }
670
671
672
673 /*
674 * Supply keysym as console input. Convert keysym to character(s) and
675 * pass them up to cons_channel's upstream hook.
676 *
677 * Return zero on success, else the keysym that we could not handle
678 * (so that the caller may complain).
679 */
680 static int
681 kbd_input_keysym(k, keysym)
682 struct kbd_softc *k;
683 int keysym;
684 {
685 struct kbd_state *ks = &k->k_state;
686 int data;
687
688 /* Check if a recipient has been configured */
689 if (k->k_cc == NULL || k->k_cc->cc_upstream == NULL)
690 return (0);
691
692 switch (KEYSYM_CLASS(keysym)) {
693
694 case KEYSYM_ASCII:
695 data = KEYSYM_DATA(keysym);
696 if (ks->kbd_modbits & KBMOD_META_MASK)
697 data |= 0x80;
698 (*k->k_cc->cc_upstream)(data);
699 break;
700
701 case KEYSYM_STRING:
702 data = keysym & 0xF;
703 kbd_input_string(k, kbd_stringtab[data]);
704 break;
705
706 case KEYSYM_FUNC:
707 kbd_input_funckey(k, keysym);
708 break;
709
710 case KEYSYM_CLRMOD:
711 data = 1 << (keysym & 0x1F);
712 ks->kbd_modbits &= ~data;
713 break;
714
715 case KEYSYM_SETMOD:
716 data = 1 << (keysym & 0x1F);
717 ks->kbd_modbits |= data;
718 break;
719
720 case KEYSYM_INVMOD:
721 data = 1 << (keysym & 0x1F);
722 ks->kbd_modbits ^= data;
723 kbd_update_leds(k);
724 break;
725
726 case KEYSYM_ALL_UP:
727 ks->kbd_modbits &= ~0xFFFF;
728 break;
729
730 case KEYSYM_SPECIAL:
731 if (keysym == KEYSYM_NOP)
732 break;
733 /* FALLTHROUGH */
734 default:
735 /* We could not handle it. */
736 return (keysym);
737 }
738
739 return (0);
740 }
741
742
743 /*
744 * Send string upstream.
745 */
746 static void
747 kbd_input_string(k, str)
748 struct kbd_softc *k;
749 char *str;
750 {
751
752 while (*str) {
753 (*k->k_cc->cc_upstream)(*str);
754 ++str;
755 }
756 }
757
758
759 /*
760 * Format the F-key sequence and send as a string.
761 * XXX: Ugly compatibility mappings.
762 */
763 static void
764 kbd_input_funckey(k, keysym)
765 struct kbd_softc *k;
766 int keysym;
767 {
768 int n;
769 char str[12];
770
771 n = 0xC0 + (keysym & 0x3F);
772 sprintf(str, "\033[%dz", n);
773 kbd_input_string(k, str);
774 }
775
776
777 /*
778 * Update LEDs to reflect console input state.
779 */
780 static void
781 kbd_update_leds(k)
782 struct kbd_softc *k;
783 {
784 struct kbd_state *ks = &k->k_state;
785 char leds;
786
787 leds = ks->kbd_leds;
788 leds &= ~(LED_CAPS_LOCK|LED_NUM_LOCK);
789
790 if (ks->kbd_modbits & (1 << KBMOD_CAPSLOCK))
791 leds |= LED_CAPS_LOCK;
792 if (ks->kbd_modbits & (1 << KBMOD_NUMLOCK))
793 leds |= LED_NUM_LOCK;
794
795 if (k->k_ops != NULL && k->k_ops->setleds != NULL)
796 (void)(*k->k_ops->setleds)(k, leds, 0);
797 }
798
799
800
801 /****************************************************************
802 * Events input - called by middle layer at spltty().
803 ****************************************************************/
804
805 /*
806 * Supply raw keystrokes when keyboard is open in firm event mode.
807 *
808 * Turn the keystroke into an event and put it in the queue.
809 * If the queue is full, the keystroke is lost (sorry!).
810 */
811 static void
812 kbd_input_event(k, code)
813 struct kbd_softc *k;
814 int code;
815 {
816 struct firm_event *fe;
817 int put;
818
819 #ifdef DIAGNOSTIC
820 if (!k->k_evmode) {
821 printf("%s: kbd_input_event called when not in event mode\n",
822 k->k_dev.dv_xname);
823 return;
824 }
825 #endif
826 put = k->k_events.ev_put;
827 fe = &k->k_events.ev_q[put];
828 put = (put + 1) % EV_QSIZE;
829 if (put == k->k_events.ev_get) {
830 log(LOG_WARNING, "%s: event queue overflow\n",
831 k->k_dev.dv_xname);
832 return;
833 }
834
835 fe->id = KEY_CODE(code);
836 fe->value = KEY_UP(code) ? VKEY_UP : VKEY_DOWN;
837 fe->time = time;
838 k->k_events.ev_put = put;
839 EV_WAKEUP(&k->k_events);
840 }
841
842
843
844 /****************************************************************
845 * Translation stuff declared in kbd_xlate.h
846 ****************************************************************/
847
848 /*
849 * Initialization - called by either lower layer attach or by kdcninit.
850 */
851 void
852 kbd_xlate_init(ks)
853 struct kbd_state *ks;
854 {
855 struct keyboard *ktbls;
856 int id;
857
858 id = ks->kbd_id;
859 if (id < KBD_MIN_TYPE)
860 id = KBD_MIN_TYPE;
861 if (id > kbd_max_type)
862 id = kbd_max_type;
863 ktbls = keyboards[id];
864
865 ks->kbd_k = *ktbls; /* struct assignment */
866 ks->kbd_modbits = 0;
867 }
868
869 /*
870 * Turn keyboard up/down codes into a KEYSYM.
871 * Note that the "kd" driver (on sun3 and sparc64) uses this too!
872 */
873 int
874 kbd_code_to_keysym(ks, c)
875 struct kbd_state *ks;
876 int c;
877 {
878 u_short *km;
879 int keysym;
880
881 /*
882 * Get keymap pointer. One of these:
883 * release, control, shifted, normal, ...
884 */
885 if (KEY_UP(c))
886 km = ks->kbd_k.k_release;
887 else if (ks->kbd_modbits & KBMOD_CTRL_MASK)
888 km = ks->kbd_k.k_control;
889 else if (ks->kbd_modbits & KBMOD_SHIFT_MASK)
890 km = ks->kbd_k.k_shifted;
891 else
892 km = ks->kbd_k.k_normal;
893
894 if (km == NULL) {
895 /*
896 * Do not know how to translate yet.
897 * We will find out when a RESET comes along.
898 */
899 return (KEYSYM_NOP);
900 }
901 keysym = km[KEY_CODE(c)];
902
903 /*
904 * Post-processing for Caps-lock
905 */
906 if ((ks->kbd_modbits & (1 << KBMOD_CAPSLOCK)) &&
907 (KEYSYM_CLASS(keysym) == KEYSYM_ASCII) )
908 {
909 if (('a' <= keysym) && (keysym <= 'z'))
910 keysym -= ('a' - 'A');
911 }
912
913 /*
914 * Post-processing for Num-lock. All "function"
915 * keysyms get indirected through another table.
916 * (XXX: Only if numlock on. Want off also!)
917 */
918 if ((ks->kbd_modbits & (1 << KBMOD_NUMLOCK)) &&
919 (KEYSYM_CLASS(keysym) == KEYSYM_FUNC) )
920 {
921 keysym = kbd_numlock_map[keysym & 0x3F];
922 }
923
924 return (keysym);
925 }
926
927
928 /*
929 * Back door for rcons (fb.c)
930 */
931 void
932 kbd_bell(on)
933 int on;
934 {
935 struct kbd_softc *k = kbd_cd.cd_devs[0]; /* XXX: hardcoded minor */
936
937 if (k == NULL || k->k_ops == NULL || k->k_ops->docmd == NULL)
938 return;
939
940 (void)(*k->k_ops->docmd)(k, on ? KBD_CMD_BELL : KBD_CMD_NOBELL, 0);
941 }
942
943 #if NWSKBD > 0
944 static void
945 kbd_input_wskbd(struct kbd_softc *k, int code)
946 {
947 int type, key;
948
949 type = KEY_UP(code) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
950 key = KEY_CODE(code);
951 wskbd_input(k->k_wskbd, type, key);
952 }
953
954 int
955 wssunkbd_enable(v, on)
956 void *v;
957 int on;
958 {
959 struct kbd_softc *k = v;
960
961 k->k_wsenabled = on;
962 if (on) {
963 /* open actual underlying device */
964 if (k->k_ops != NULL && k->k_ops->open != NULL)
965 (*k->k_ops->open)(k);
966 ev_init(&k->k_events);
967 k->k_evmode = 0; /* XXX: OK? */
968 } else {
969 /* close underlying device */
970 if (k->k_ops != NULL && k->k_ops->close != NULL)
971 (*k->k_ops->close)(k);
972 }
973
974 return 0;
975 }
976
977 void
978 wssunkbd_set_leds(v, leds)
979 void *v;
980 int leds;
981 {
982 struct kbd_softc *k = v;
983 int l = 0;
984
985 if (leds & WSKBD_LED_CAPS)
986 l |= LED_CAPS_LOCK;
987 if (leds & WSKBD_LED_NUM)
988 l |= LED_NUM_LOCK;
989 if (leds & WSKBD_LED_SCROLL)
990 l |= LED_SCROLL_LOCK;
991 if (leds & WSKBD_LED_COMPOSE)
992 l |= LED_COMPOSE;
993 if (k->k_ops != NULL && k->k_ops->setleds != NULL)
994 (*k->k_ops->setleds)(k, l, 0);
995 }
996
997 int
998 wssunkbd_ioctl(v, cmd, data, flag, l)
999 void *v;
1000 u_long cmd;
1001 caddr_t data;
1002 int flag;
1003 struct lwp *l;
1004 {
1005 return EPASSTHROUGH;
1006 }
1007
1008 void
1009 sunkbd_wskbd_cngetc(v, type, data)
1010 void *v;
1011 u_int *type;
1012 int *data;
1013 {
1014 /* struct kbd_sun_softc *k = v; */
1015 }
1016
1017 void
1018 sunkbd_wskbd_cnpollc(v, on)
1019 void *v;
1020 int on;
1021 {
1022 }
1023
1024 static void
1025 sunkbd_bell_off(v)
1026 void *v;
1027 {
1028 struct kbd_softc *k = v;
1029 k->k_ops->docmd(k, KBD_CMD_NOBELL, 0);
1030 }
1031
1032 void
1033 sunkbd_wskbd_cnbell(v, pitch, period, volume)
1034 void *v;
1035 u_int pitch, period, volume;
1036 {
1037 struct kbd_softc *k = v;
1038
1039 callout_reset(&k->k_wsbell, period*1000/hz, sunkbd_bell_off, v);
1040 k->k_ops->docmd(k, KBD_CMD_BELL, 0);
1041 }
1042
1043 void
1044 kbd_wskbd_attach(k, isconsole)
1045 struct kbd_softc *k;
1046 int isconsole;
1047 {
1048 struct wskbddev_attach_args a;
1049
1050 a.console = isconsole;
1051
1052 if (a.console)
1053 wskbd_cnattach(&sunkbd_wskbd_consops, k, &sunkbd_wskbd_keymapdata);
1054
1055 a.keymap = &sunkbd_wskbd_keymapdata;
1056
1057 a.accessops = &sunkbd_wskbd_accessops;
1058 a.accesscookie = k;
1059
1060 /* Attach the wskbd */
1061 k->k_wskbd = config_found(&k->k_dev, &a, wskbddevprint);
1062 k->k_wsenabled = 0;
1063 callout_init(&k->k_wsbell);
1064 }
1065 #endif
1066