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