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