xref: /dragonfly/sys/dev/misc/kbd/kbd.c (revision a162a738eca94f99d45d88429e86cfd0fbfbe95d)
1 /*
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer as
10  *    the first lines of this file unmodified.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/dev/kbd/kbd.c,v 1.17.2.2 2001/07/30 16:46:43 yokota Exp $
27  */
28 /*
29  * Generic keyboard driver.
30  */
31 
32 #include "opt_kbd.h"
33 #include "opt_evdev.h"
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/caps.h>
40 #include <sys/conf.h>
41 #include <sys/proc.h>
42 #include <sys/tty.h>
43 #include <sys/event.h>
44 #include <sys/vnode.h>
45 #include <sys/uio.h>
46 #include <sys/thread.h>
47 
48 #include <machine/console.h>
49 
50 #include "kbdreg.h"
51 
52 #ifdef EVDEV_SUPPORT
53 #include <dev/misc/evdev/evdev.h>
54 #include <dev/misc/evdev/input.h>
55 #endif
56 
57 #if 0
58 #define lwkt_gettoken(x)
59 #define lwkt_reltoken(x)
60 #endif
61 
62 #define KBD_INDEX(dev)        minor(dev)
63 
64 #define KB_QSIZE    512
65 #define KB_BUFSIZE  64
66 
67 struct genkbd_softc {
68           int                 gkb_flags;          /* flag/status bits */
69 #define KB_ASLEEP   (1 << 0)
70           struct kqinfo       gkb_rkq;
71           char                gkb_q[KB_QSIZE];              /* input queue */
72           unsigned int        gkb_q_start;
73           unsigned int        gkb_q_length;
74 };
75 
76 typedef struct genkbd_softc *genkbd_softc_t;
77 
78 static    SLIST_HEAD(, keyboard_driver) keyboard_drivers =
79           SLIST_HEAD_INITIALIZER(keyboard_drivers);
80 
81 SET_DECLARE(kbddriver_set, const keyboard_driver_t);
82 
83 /* local arrays */
84 
85 /*
86  * We need at least one entry each in order to initialize a keyboard
87  * for the kernel console.  The arrays will be increased dynamically
88  * when necessary.
89  */
90 
91 static keyboard_t *keyboard[KBD_MAXKEYBOARDS];
92 
93 keyboard_switch_t *kbdsw[KBD_MAXKEYBOARDS];
94 
95 /*
96  * Low-level keyboard driver functions.
97  *
98  * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
99  * driver, call these functions to initialize the keyboard_t structure
100  * and register it to the virtual keyboard driver `kbd'.
101  *
102  * The reinit call is made when a driver has partially detached a keyboard
103  * but does not unregistered it, then wishes to reinitialize it later on.
104  * This is how the USB keyboard driver handles the 'default' keyboard,
105  * because unregistering the keyboard associated with the console will
106  * destroy its console association forever.
107  */
108 void
kbd_reinit_struct(keyboard_t * kbd,int config,int pref)109 kbd_reinit_struct(keyboard_t *kbd, int config, int pref)
110 {
111           lwkt_gettoken(&kbd_token);
112           kbd->kb_flags |= KB_NO_DEVICE;          /* device has not been found */
113           kbd->kb_config = config & ~KB_CONF_PROBE_ONLY;
114           kbd->kb_led = 0;              /* unknown */
115           kbd->kb_data = NULL;
116           kbd->kb_keymap = NULL;
117           kbd->kb_accentmap = NULL;
118           kbd->kb_fkeytab = NULL;
119           kbd->kb_fkeytab_size = 0;
120           kbd->kb_delay1 = KB_DELAY1;   /* these values are advisory only */
121           kbd->kb_delay2 = KB_DELAY2;
122           kbd->kb_count = 0;
123           kbd->kb_pref = pref;
124           bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact));
125           lwkt_reltoken(&kbd_token);
126 }
127 
128 /* initialize the keyboard_t structure */
129 void
kbd_init_struct(keyboard_t * kbd,char * name,int type,int unit,int config,int pref,int port,int port_size)130 kbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
131                     int pref, int port, int port_size)
132 {
133           lwkt_gettoken(&kbd_token);
134           kbd->kb_flags = 0;
135           kbd->kb_name = name;
136           kbd->kb_type = type;
137           kbd->kb_unit = unit;
138           kbd->kb_io_base = port;
139           kbd->kb_io_size = port_size;
140           kbd_reinit_struct(kbd, config, pref);
141           lockinit(&kbd->kb_lock, name, 0, LK_CANRECURSE);
142           lwkt_reltoken(&kbd_token);
143 }
144 
145 void
kbd_set_maps(keyboard_t * kbd,keymap_t * keymap,accentmap_t * accmap,fkeytab_t * fkeymap,int fkeymap_size)146 kbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
147                fkeytab_t *fkeymap, int fkeymap_size)
148 {
149           lwkt_gettoken(&kbd_token);
150           kbd->kb_keymap = keymap;
151           kbd->kb_accentmap = accmap;
152           kbd->kb_fkeytab = fkeymap;
153           kbd->kb_fkeytab_size = fkeymap_size;
154           lwkt_reltoken(&kbd_token);
155 }
156 
157 /* declare a new keyboard driver */
158 int
kbd_add_driver(keyboard_driver_t * driver)159 kbd_add_driver(keyboard_driver_t *driver)
160 {
161           lwkt_gettoken(&kbd_token);
162           if (SLIST_NEXT(driver, link)) {
163                     lwkt_reltoken(&kbd_token);
164                     return EINVAL;
165           }
166           SLIST_INSERT_HEAD(&keyboard_drivers, driver, link);
167           lwkt_reltoken(&kbd_token);
168           return 0;
169 }
170 
171 int
kbd_delete_driver(keyboard_driver_t * driver)172 kbd_delete_driver(keyboard_driver_t *driver)
173 {
174           lwkt_gettoken(&kbd_token);
175           SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link);
176           SLIST_NEXT(driver, link) = NULL;
177           lwkt_reltoken(&kbd_token);
178           return 0;
179 }
180 
181 /* register a keyboard and associate it with a function table */
182 int
kbd_register(keyboard_t * kbd)183 kbd_register(keyboard_t *kbd)
184 {
185           const keyboard_driver_t **list;
186           const keyboard_driver_t *p;
187           keyboard_t *mux;
188           keyboard_info_t ki;
189           int index;
190 
191           lwkt_gettoken(&kbd_token);
192           mux = kbd_get_keyboard(kbd_find_keyboard("kbdmux", -1));
193 
194           for (index = 0; index < KBD_MAXKEYBOARDS; ++index) {
195                     if (keyboard[index] == NULL)
196                               break;
197           }
198           if (index >= KBD_MAXKEYBOARDS) {
199                     lwkt_reltoken(&kbd_token);
200                     return -1;
201           }
202 
203           kbd->kb_index = index;
204           KBD_UNBUSY(kbd);
205           KBD_VALID(kbd);
206           kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */
207           kbd->kb_token = NULL;
208           kbd->kb_callback.kc_func = NULL;
209           kbd->kb_callback.kc_arg = NULL;
210           callout_init_mp(&kbd->kb_atkbd_timeout_ch);
211 
212           SLIST_FOREACH(p, &keyboard_drivers, link) {
213                     if (strcmp(p->name, kbd->kb_name) == 0) {
214                               keyboard[index] = kbd;
215                               kbdsw[index] = p->kbdsw;
216 
217                               if (mux != NULL) {
218                                         bzero(&ki, sizeof(ki));
219                                         strcpy(ki.kb_name, kbd->kb_name);
220                                         ki.kb_unit = kbd->kb_unit;
221                                         kbd_ioctl(mux, KBADDKBD, (caddr_t) &ki);
222                               }
223 
224                               lwkt_reltoken(&kbd_token);
225                               return index;
226                     }
227           }
228           SET_FOREACH(list, kbddriver_set) {
229                     p = *list;
230                     if (strcmp(p->name, kbd->kb_name) == 0) {
231                               keyboard[index] = kbd;
232                               kbdsw[index] = p->kbdsw;
233 
234                               if (mux != NULL) {
235                                         bzero(&ki, sizeof(ki));
236                                         strcpy(ki.kb_name, kbd->kb_name);
237                                         ki.kb_unit = kbd->kb_unit;
238                                         kbd_ioctl(mux, KBADDKBD, (caddr_t) &ki);
239                               }
240 
241                               lwkt_reltoken(&kbd_token);
242                               return index;
243                     }
244           }
245 
246           lwkt_reltoken(&kbd_token);
247           return -1;
248 }
249 
250 int
kbd_unregister(keyboard_t * kbd)251 kbd_unregister(keyboard_t *kbd)
252 {
253           int error;
254 
255           KBD_LOCK_ASSERT(kbd);
256           lwkt_gettoken(&kbd_token);
257           if ((kbd->kb_index < 0) || (kbd->kb_index >= KBD_MAXKEYBOARDS)) {
258                     lwkt_reltoken(&kbd_token);
259                     return ENOENT;
260           }
261           if (keyboard[kbd->kb_index] != kbd) {
262                     lwkt_reltoken(&kbd_token);
263                     return ENOENT;
264           }
265 
266           callout_stop(&kbd->kb_atkbd_timeout_ch);
267           if (KBD_IS_BUSY(kbd)) {
268                     error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
269                                                                 kbd->kb_callback.kc_arg);
270                     if (error) {
271                               lwkt_reltoken(&kbd_token);
272                               return error;
273                     }
274                     if (KBD_IS_BUSY(kbd)) {
275                               lwkt_reltoken(&kbd_token);
276                               return EBUSY;
277                     }
278           }
279           KBD_CONFIG_LOST(kbd);
280           KBD_INVALID(kbd);
281           keyboard[kbd->kb_index] = NULL;
282           kbdsw[kbd->kb_index] = NULL;
283 
284           KBD_ALWAYS_UNLOCK(kbd);
285           lockuninit(&kbd->kb_lock);
286 
287           lwkt_reltoken(&kbd_token);
288           return 0;
289 }
290 
291 /* find a funciton table by the driver name */
292 keyboard_switch_t *
kbd_get_switch(char * driver)293 kbd_get_switch(char *driver)
294 {
295           const keyboard_driver_t **list;
296           const keyboard_driver_t *p;
297 
298           lwkt_gettoken(&kbd_token);
299 
300           SLIST_FOREACH(p, &keyboard_drivers, link) {
301                     if (strcmp(p->name, driver) == 0) {
302                               lwkt_reltoken(&kbd_token);
303                               return p->kbdsw;
304                     }
305           }
306           SET_FOREACH(list, kbddriver_set) {
307                     p = *list;
308                     if (strcmp(p->name, driver) == 0) {
309                               lwkt_reltoken(&kbd_token);
310                               return p->kbdsw;
311                     }
312           }
313 
314           lwkt_reltoken(&kbd_token);
315           return NULL;
316 }
317 
318 /*
319  * Keyboard client functions
320  * Keyboard clients, such as the console driver `syscons' and the keyboard
321  * cdev driver, use these functions to claim and release a keyboard for
322  * exclusive use.
323  */
324 /*
325  * find the keyboard specified by a driver name and a unit number
326  * starting at given index
327  */
328 int
kbd_find_keyboard2(char * driver,int unit,int index,int legacy)329 kbd_find_keyboard2(char *driver, int unit, int index, int legacy)
330 {
331           int i;
332           int pref;
333           int pref_index;
334 
335           pref = 0;
336           pref_index = -1;
337 
338           lwkt_gettoken(&kbd_token);
339           if ((index < 0) || (index >= KBD_MAXKEYBOARDS)) {
340                     lwkt_reltoken(&kbd_token);
341                     return (-1);
342           }
343 
344           for (i = index; i < KBD_MAXKEYBOARDS; ++i) {
345                     if (keyboard[i] == NULL)
346                               continue;
347                     if (!KBD_IS_VALID(keyboard[i]))
348                               continue;
349                     if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
350                               continue;
351                     if ((unit != -1) && (keyboard[i]->kb_unit != unit))
352                               continue;
353                     /*
354                      * If we are in legacy mode, we do the old preference magic and
355                      * don't return on the first found unit.
356                      */
357                     if (legacy) {
358                               if (pref <= keyboard[i]->kb_pref) {
359                                         pref = keyboard[i]->kb_pref;
360                                         pref_index = i;
361                               }
362                     } else {
363                               lwkt_reltoken(&kbd_token);
364                               return i;
365                     }
366           }
367 
368           if (!legacy)
369                     KKASSERT(pref_index == -1);
370 
371           lwkt_reltoken(&kbd_token);
372           return (pref_index);
373 }
374 
375 /* find the keyboard specified by a driver name and a unit number */
376 int
kbd_find_keyboard(char * driver,int unit)377 kbd_find_keyboard(char *driver, int unit)
378 {
379           return (kbd_find_keyboard2(driver, unit, 0, 1));
380 }
381 
382 /* allocate a keyboard */
383 int
kbd_allocate(char * driver,int unit,void * id,kbd_callback_func_t * func,void * arg)384 kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
385                void *arg)
386 {
387           int index;
388 
389           if (func == NULL)
390                     return -1;
391 
392           lwkt_gettoken(&kbd_token);
393 
394           index = kbd_find_keyboard(driver, unit);
395           if (index >= 0) {
396                     if (KBD_IS_BUSY(keyboard[index])) {
397                               lwkt_reltoken(&kbd_token);
398                               return -1;
399                     }
400                     keyboard[index]->kb_token = id;
401                     KBD_BUSY(keyboard[index]);
402                     keyboard[index]->kb_callback.kc_func = func;
403                     keyboard[index]->kb_callback.kc_arg = arg;
404                     kbd_clear_state(keyboard[index]);
405           }
406 
407           lwkt_reltoken(&kbd_token);
408           return index;
409 }
410 
411 int
kbd_release(keyboard_t * kbd,void * id)412 kbd_release(keyboard_t *kbd, void *id)
413 {
414           int error;
415 
416           lwkt_gettoken(&kbd_token);
417 
418           if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
419                     error = EINVAL;
420           } else if (kbd->kb_token != id) {
421                     error = EPERM;
422           } else {
423                     kbd->kb_token = NULL;
424                     KBD_UNBUSY(kbd);
425                     kbd->kb_callback.kc_func = NULL;
426                     kbd->kb_callback.kc_arg = NULL;
427                     kbd_clear_state(kbd);
428                     error = 0;
429           }
430 
431           lwkt_reltoken(&kbd_token);
432           return error;
433 }
434 
435 int
kbd_change_callback(keyboard_t * kbd,void * id,kbd_callback_func_t * func,void * arg)436 kbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
437                         void *arg)
438 {
439           int error;
440 
441           lwkt_gettoken(&kbd_token);
442 
443           if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
444                     error = EINVAL;
445           } else if (kbd->kb_token != id) {
446                     error = EPERM;
447           } else if (func == NULL) {
448                     error = EINVAL;
449           } else {
450                     kbd->kb_callback.kc_func = func;
451                     kbd->kb_callback.kc_arg = arg;
452                     error = 0;
453           }
454 
455           lwkt_reltoken(&kbd_token);
456           return error;
457 }
458 
459 /* get a keyboard structure */
460 keyboard_t *
kbd_get_keyboard(int index)461 kbd_get_keyboard(int index)
462 {
463           keyboard_t *kbd;
464 
465           lwkt_gettoken(&kbd_token);
466           if ((index < 0) || (index >= KBD_MAXKEYBOARDS)) {
467                     lwkt_reltoken(&kbd_token);
468                     return NULL;
469           }
470           if (keyboard[index] == NULL) {
471                     lwkt_reltoken(&kbd_token);
472                     return NULL;
473           }
474           if (!KBD_IS_VALID(keyboard[index])) {
475                     lwkt_reltoken(&kbd_token);
476                     return NULL;
477           }
478           kbd = keyboard[index];
479           lwkt_reltoken(&kbd_token);
480 
481           return kbd;
482 }
483 
484 /*
485  * The back door for the console driver; configure keyboards
486  * This function is for the kernel console to initialize keyboards
487  * at very early stage.
488  */
489 
490 int
kbd_configure(int flags)491 kbd_configure(int flags)
492 {
493           const keyboard_driver_t **list;
494           const keyboard_driver_t *p;
495 
496           lwkt_gettoken(&kbd_token);
497 
498           SLIST_FOREACH(p, &keyboard_drivers, link) {
499                     if (p->configure != NULL)
500                               (*p->configure)(flags);
501           }
502           SET_FOREACH(list, kbddriver_set) {
503                     p = *list;
504                     if (p->configure != NULL)
505                               (*p->configure)(flags);
506           }
507 
508           lwkt_reltoken(&kbd_token);
509           return 0;
510 }
511 
512 #ifdef KBD_INSTALL_CDEV
513 
514 /*
515  * Virtual keyboard cdev driver functions
516  * The virtual keyboard driver dispatches driver functions to
517  * appropriate subdrivers.
518  */
519 
520 #define KBD_UNIT(dev)         minor(dev)
521 
522 static d_open_t               genkbdopen;
523 static d_close_t    genkbdclose;
524 static d_read_t               genkbdread;
525 static d_write_t    genkbdwrite;
526 static d_ioctl_t    genkbdioctl;
527 static d_kqfilter_t genkbdkqfilter;
528 
529 static void genkbdfiltdetach(struct knote *);
530 static int genkbdfilter(struct knote *, long);
531 
532 static struct dev_ops kbd_ops = {
533           { "kbd", 0, D_MPSAFE },
534           .d_open = genkbdopen,
535           .d_close =          genkbdclose,
536           .d_read = genkbdread,
537           .d_write =          genkbdwrite,
538           .d_ioctl =          genkbdioctl,
539           .d_kqfilter =       genkbdkqfilter
540 };
541 
542 /*
543  * Attach a keyboard.
544  *
545  * NOTE: The usb driver does not detach the default keyboard if it is
546  *         unplugged, but calls kbd_attach() when it is plugged back in.
547  */
548 int
kbd_attach(keyboard_t * kbd)549 kbd_attach(keyboard_t *kbd)
550 {
551           cdev_t dev;
552           char tbuf[MAKEDEV_MINNBUF];
553 
554           lwkt_gettoken(&kbd_token);
555           if (kbd->kb_index >= KBD_MAXKEYBOARDS) {
556                     lwkt_reltoken(&kbd_token);
557                     return EINVAL;
558           }
559           if (keyboard[kbd->kb_index] != kbd) {
560                     lwkt_reltoken(&kbd_token);
561                     return EINVAL;
562           }
563 
564           if (kbd->kb_dev == NULL) {
565                     kbd->kb_dev = make_dev(&kbd_ops, kbd->kb_index,
566                                                UID_ROOT, GID_WHEEL, 0600, "kbd%s",
567                                                makedev_unit_b32(tbuf, kbd->kb_index));
568           }
569           dev = kbd->kb_dev;
570           if (dev->si_drv1 == NULL) {
571                     dev->si_drv1 = kmalloc(sizeof(struct genkbd_softc), M_DEVBUF,
572                                                M_WAITOK);
573           }
574           bzero(dev->si_drv1, sizeof(struct genkbd_softc));
575 
576           kprintf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
577           lwkt_reltoken(&kbd_token);
578           return 0;
579 }
580 
581 int
kbd_detach(keyboard_t * kbd)582 kbd_detach(keyboard_t *kbd)
583 {
584           cdev_t dev;
585 
586           lwkt_gettoken(&kbd_token);
587 
588           if (kbd->kb_index >= KBD_MAXKEYBOARDS) {
589                     lwkt_reltoken(&kbd_token);
590                     return EINVAL;
591           }
592           if (keyboard[kbd->kb_index] != kbd) {
593                     lwkt_reltoken(&kbd_token);
594                     return EINVAL;
595           }
596 
597           if ((dev = kbd->kb_dev) != NULL) {
598                     if (dev->si_drv1) {
599                               kfree(dev->si_drv1, M_DEVBUF);
600                               dev->si_drv1 = NULL;
601                     }
602                     kbd->kb_dev = NULL;
603           }
604           dev_ops_remove_minor(&kbd_ops, kbd->kb_index);
605           lwkt_reltoken(&kbd_token);
606           return 0;
607 }
608 
609 /*
610  * Generic keyboard cdev driver functions
611  * Keyboard subdrivers may call these functions to implement common
612  * driver functions.
613  */
614 
615 static void
genkbd_putc(genkbd_softc_t sc,char c)616 genkbd_putc(genkbd_softc_t sc, char c)
617 {
618           unsigned int p;
619 
620           lwkt_gettoken(&kbd_token);
621 
622           if (sc->gkb_q_length == KB_QSIZE) {
623                     lwkt_reltoken(&kbd_token);
624                     return;
625           }
626 
627           p = (sc->gkb_q_start + sc->gkb_q_length) % KB_QSIZE;
628           sc->gkb_q[p] = c;
629           sc->gkb_q_length++;
630 
631           lwkt_reltoken(&kbd_token);
632 }
633 
634 static size_t
genkbd_getc(genkbd_softc_t sc,char * buf,size_t len)635 genkbd_getc(genkbd_softc_t sc, char *buf, size_t len)
636 {
637 
638           lwkt_gettoken(&kbd_token);
639 
640           /* Determine copy size. */
641           if (sc->gkb_q_length == 0) {
642                     lwkt_reltoken(&kbd_token);
643                     return (0);
644           }
645           if (len >= sc->gkb_q_length)
646                     len = sc->gkb_q_length;
647           if (len >= KB_QSIZE - sc->gkb_q_start)
648                     len = KB_QSIZE - sc->gkb_q_start;
649 
650           /* Copy out data and progress offset. */
651           memcpy(buf, sc->gkb_q + sc->gkb_q_start, len);
652           sc->gkb_q_start = (sc->gkb_q_start + len) % KB_QSIZE;
653           sc->gkb_q_length -= len;
654 
655           lwkt_reltoken(&kbd_token);
656           return (len);
657 }
658 
659 static kbd_callback_func_t genkbd_event;
660 
661 static int
genkbdopen(struct dev_open_args * ap)662 genkbdopen(struct dev_open_args *ap)
663 {
664           cdev_t dev = ap->a_head.a_dev;
665           keyboard_t *kbd;
666           genkbd_softc_t sc;
667           int i;
668 
669           /*
670            * Disallow access to disk volumes if RESTRICTEDROOT
671            */
672           if (caps_priv_check_self(SYSCAP_RESTRICTEDROOT))
673                     return (EPERM);
674 
675           lwkt_gettoken(&kbd_token);
676           sc = dev->si_drv1;
677           kbd = kbd_get_keyboard(KBD_INDEX(dev));
678           if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
679                     lwkt_reltoken(&kbd_token);
680                     return ENXIO;
681           }
682           i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
683                                genkbd_event, sc);
684           if (i < 0) {
685                     lwkt_reltoken(&kbd_token);
686                     return EBUSY;
687           }
688           /* assert(i == kbd->kb_index) */
689           /* assert(kbd == kbd_get_keyboard(i)) */
690 
691           /*
692            * NOTE: even when we have successfully claimed a keyboard,
693            * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
694            */
695 
696           sc->gkb_q_length = 0;
697           lwkt_reltoken(&kbd_token);
698 
699           return 0;
700 }
701 
702 static int
genkbdclose(struct dev_close_args * ap)703 genkbdclose(struct dev_close_args *ap)
704 {
705           cdev_t dev = ap->a_head.a_dev;
706           keyboard_t *kbd;
707           genkbd_softc_t sc;
708 
709           /*
710            * NOTE: the device may have already become invalid.
711            * kbd == NULL || !KBD_IS_VALID(kbd)
712            */
713           lwkt_gettoken(&kbd_token);
714           sc = dev->si_drv1;
715           kbd = kbd_get_keyboard(KBD_INDEX(dev));
716           if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
717                     /* XXX: we shall be forgiving and don't report error... */
718           } else {
719                     kbd_release(kbd, sc);
720           }
721           lwkt_reltoken(&kbd_token);
722           return 0;
723 }
724 
725 static int
genkbdread(struct dev_read_args * ap)726 genkbdread(struct dev_read_args *ap)
727 {
728           cdev_t dev = ap->a_head.a_dev;
729           struct uio *uio = ap->a_uio;
730           keyboard_t *kbd;
731           genkbd_softc_t sc;
732           u_char buffer[KB_BUFSIZE];
733           int len;
734           int error;
735 
736           /* wait for input */
737           lwkt_gettoken(&kbd_token);
738           sc = dev->si_drv1;
739           kbd = kbd_get_keyboard(KBD_INDEX(dev));
740           if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
741                     lwkt_reltoken(&kbd_token);
742                     return ENXIO;
743           }
744           while (sc->gkb_q_length == 0) {
745                     if (ap->a_ioflag & IO_NDELAY) { /* O_NONBLOCK? */
746                               lwkt_reltoken(&kbd_token);
747                               return EWOULDBLOCK;
748                     }
749                     sc->gkb_flags |= KB_ASLEEP;
750                     error = tsleep((caddr_t)sc, PCATCH, "kbdrea", 0);
751                     kbd = kbd_get_keyboard(KBD_INDEX(dev));
752                     if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
753                               lwkt_reltoken(&kbd_token);
754                               return ENXIO;       /* our keyboard has gone... */
755                     }
756                     if (error) {
757                               sc->gkb_flags &= ~KB_ASLEEP;
758                               lwkt_reltoken(&kbd_token);
759                               return error;
760                     }
761           }
762           lwkt_reltoken(&kbd_token);
763 
764           /* copy as much input as possible */
765           error = 0;
766           while (uio->uio_resid > 0) {
767                     len = (int)szmin(uio->uio_resid, sizeof(buffer));
768                     len = genkbd_getc(sc, buffer, len);
769                     if (len <= 0)
770                               break;
771                     error = uiomove(buffer, (size_t)len, uio);
772                     if (error)
773                               break;
774           }
775 
776           return error;
777 }
778 
779 static int
genkbdwrite(struct dev_write_args * ap)780 genkbdwrite(struct dev_write_args *ap)
781 {
782           cdev_t dev = ap->a_head.a_dev;
783           keyboard_t *kbd;
784 
785           lwkt_gettoken(&kbd_token);
786           kbd = kbd_get_keyboard(KBD_INDEX(dev));
787           if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
788                     lwkt_reltoken(&kbd_token);
789                     return ENXIO;
790           }
791           lwkt_reltoken(&kbd_token);
792           return ENODEV;
793 }
794 
795 static int
genkbdioctl(struct dev_ioctl_args * ap)796 genkbdioctl(struct dev_ioctl_args *ap)
797 {
798           cdev_t dev = ap->a_head.a_dev;
799           keyboard_t *kbd;
800           int error;
801 
802           lwkt_gettoken(&kbd_token);
803           kbd = kbd_get_keyboard(KBD_INDEX(dev));
804           if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
805                     lwkt_reltoken(&kbd_token);
806                     return ENXIO;
807           }
808           error = kbd_ioctl(kbd, ap->a_cmd, ap->a_data);
809           if (error == ENOIOCTL)
810                     error = ENODEV;
811 
812           lwkt_reltoken(&kbd_token);
813           return error;
814 }
815 
816 static struct filterops genkbdfiltops =
817           { FILTEROP_ISFD, NULL, genkbdfiltdetach, genkbdfilter };
818 
819 static int
genkbdkqfilter(struct dev_kqfilter_args * ap)820 genkbdkqfilter(struct dev_kqfilter_args *ap)
821 {
822           cdev_t dev = ap->a_head.a_dev;
823           struct knote *kn = ap->a_kn;
824           genkbd_softc_t sc;
825           struct klist *klist;
826 
827           ap->a_result = 0;
828 
829           switch (kn->kn_filter) {
830           case EVFILT_READ:
831                     kn->kn_fop = &genkbdfiltops;
832                     kn->kn_hook = (caddr_t)dev;
833                     break;
834           default:
835                     ap->a_result = EOPNOTSUPP;
836                     return (0);
837           }
838 
839           sc = dev->si_drv1;
840           klist = &sc->gkb_rkq.ki_note;
841           knote_insert(klist, kn);
842 
843           return (0);
844 }
845 
846 static void
genkbdfiltdetach(struct knote * kn)847 genkbdfiltdetach(struct knote *kn)
848 {
849           cdev_t dev = (cdev_t)kn->kn_hook;
850           genkbd_softc_t sc;
851           struct klist *klist;
852 
853           sc = dev->si_drv1;
854           klist = &sc->gkb_rkq.ki_note;
855           knote_remove(klist, kn);
856 }
857 
858 static int
genkbdfilter(struct knote * kn,long hint)859 genkbdfilter(struct knote *kn, long hint)
860 {
861           cdev_t dev = (cdev_t)kn->kn_hook;
862           keyboard_t *kbd;
863           genkbd_softc_t sc;
864           int ready = 0;
865 
866           lwkt_gettoken(&kbd_token);
867           sc = dev->si_drv1;
868         kbd = kbd_get_keyboard(KBD_INDEX(dev));
869           if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
870                     /* The keyboard has gone */
871                     kn->kn_flags |= (EV_EOF | EV_NODATA);
872                     ready = 1;
873           } else {
874                     if (sc->gkb_q_length > 0)
875                         ready = 1;
876         }
877           lwkt_reltoken(&kbd_token);
878 
879           return (ready);
880 }
881 
882 static int
genkbd_event(keyboard_t * kbd,int event,void * arg)883 genkbd_event(keyboard_t *kbd, int event, void *arg)
884 {
885           genkbd_softc_t sc;
886           size_t len;
887           u_char *cp;
888           int mode;
889           int c;
890 
891           lwkt_gettoken(&kbd_token);
892           /* assert(KBD_IS_VALID(kbd)) */
893           sc = (genkbd_softc_t)arg;
894 
895           switch (event) {
896           case KBDIO_KEYINPUT:
897                     break;
898           case KBDIO_UNLOADING:
899                     /* the keyboard is going... */
900                     kbd_release(kbd, sc);
901                     if (sc->gkb_flags & KB_ASLEEP) {
902                               sc->gkb_flags &= ~KB_ASLEEP;
903                               wakeup((caddr_t)sc);
904                     }
905                     KNOTE(&sc->gkb_rkq.ki_note, 0);
906                     lwkt_reltoken(&kbd_token);
907                     return 0;
908           default:
909                     lwkt_reltoken(&kbd_token);
910                     return EINVAL;
911           }
912 
913           /* obtain the current key input mode */
914           if (kbd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode))
915                     mode = K_XLATE;
916 
917           /* read all pending input */
918           while (kbd_check_char(kbd)) {
919                     c = kbd_read_char(kbd, FALSE);
920                     if (c == NOKEY)
921                               continue;
922                     if (c == ERRKEY)    /* XXX: ring bell? */
923                               continue;
924                     if (!KBD_IS_BUSY(kbd))
925                               /* the device is not open, discard the input */
926                               continue;
927 
928                     /* store the byte as is for K_RAW and K_CODE modes */
929                     if (mode != K_XLATE) {
930                               genkbd_putc(sc, KEYCHAR(c));
931                               continue;
932                     }
933 
934                     /* K_XLATE */
935                     if (c & RELKEY)     /* key release is ignored */
936                               continue;
937 
938                     /* process special keys; most of them are just ignored... */
939                     if (c & SPCLKEY) {
940                               switch (KEYCHAR(c)) {
941                               default:
942                                         /* ignore them... */
943                                         continue;
944                               case BTAB:          /* a backtab: ESC [ Z */
945                                         genkbd_putc(sc, 0x1b);
946                                         genkbd_putc(sc, '[');
947                                         genkbd_putc(sc, 'Z');
948                                         continue;
949                               }
950                     }
951 
952                     /* normal chars, normal chars with the META, function keys */
953                     switch (KEYFLAGS(c)) {
954                     case 0:                       /* a normal char */
955                               genkbd_putc(sc, KEYCHAR(c));
956                               break;
957                     case MKEY:                    /* the META flag: prepend ESC */
958                               genkbd_putc(sc, 0x1b);
959                               genkbd_putc(sc, KEYCHAR(c));
960                               break;
961                     case FKEY | SPCLKEY:          /* a function key, return string */
962                               cp = kbd_get_fkeystr(kbd, KEYCHAR(c), &len);
963                               if (cp != NULL) {
964                                         while (len-- >  0)
965                                                   genkbd_putc(sc, *cp++);
966                               }
967                               break;
968                     }
969           }
970 
971           /* wake up sleeping/polling processes */
972           if (sc->gkb_q_length > 0) {
973                     if (sc->gkb_flags & KB_ASLEEP) {
974                               sc->gkb_flags &= ~KB_ASLEEP;
975                               wakeup((caddr_t)sc);
976                     }
977                     KNOTE(&sc->gkb_rkq.ki_note, 0);
978           }
979 
980           lwkt_reltoken(&kbd_token);
981           return 0;
982 }
983 
984 #endif /* KBD_INSTALL_CDEV */
985 
986 /*
987  * Generic low-level keyboard functions
988  * The low-level functions in the keyboard subdriver may use these
989  * functions.
990  */
991 
992 int
genkbd_commonioctl(keyboard_t * kbd,u_long cmd,caddr_t arg)993 genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
994 {
995           keyarg_t *keyp;
996           fkeyarg_t *fkeyp;
997           int i;
998 
999           lwkt_gettoken(&kbd_token);
1000           switch (cmd) {
1001 
1002           case KDGKBINFO:               /* get keyboard information */
1003                     ((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
1004                     i = imin(strlen(kbd->kb_name) + 1,
1005                                sizeof(((keyboard_info_t *)arg)->kb_name));
1006                     bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
1007                     ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
1008                     ((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
1009                     ((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
1010                     ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
1011                     break;
1012 
1013           case KDGKBTYPE:               /* get keyboard type */
1014                     *(int *)arg = kbd->kb_type;
1015                     break;
1016 
1017           case KDGETREPEAT:   /* get keyboard repeat rate */
1018                     ((int *)arg)[0] = kbd->kb_delay1;
1019                     ((int *)arg)[1] = kbd->kb_delay2;
1020                     break;
1021 
1022           case GIO_KEYMAP:    /* get keyboard translation table */
1023                     bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
1024                     break;
1025           case PIO_KEYMAP:    /* set keyboard translation table */
1026 #ifndef KBD_DISABLE_KEYMAP_LOAD
1027                     bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
1028                     bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
1029                     break;
1030 #else
1031                     lwkt_reltoken(&kbd_token);
1032                     return ENODEV;
1033 #endif
1034 
1035           case GIO_KEYMAPENT: /* get keyboard translation table entry */
1036                     keyp = (keyarg_t *)arg;
1037                     if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
1038                                                   /sizeof(kbd->kb_keymap->key[0])) {
1039                               lwkt_reltoken(&kbd_token);
1040                               return EINVAL;
1041                     }
1042                     bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
1043                           sizeof(keyp->key));
1044                     break;
1045           case PIO_KEYMAPENT: /* set keyboard translation table entry */
1046 #ifndef KBD_DISABLE_KEYMAP_LOAD
1047                     keyp = (keyarg_t *)arg;
1048                     if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
1049                                                   /sizeof(kbd->kb_keymap->key[0])) {
1050                               lwkt_reltoken(&kbd_token);
1051                               return EINVAL;
1052                     }
1053                     bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
1054                           sizeof(keyp->key));
1055                     break;
1056 #else
1057                     lwkt_reltoken(&kbd_token);
1058                     return ENODEV;
1059 #endif
1060 
1061           case GIO_DEADKEYMAP:          /* get accent key translation table */
1062                     bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
1063                     break;
1064           case PIO_DEADKEYMAP:          /* set accent key translation table */
1065 #ifndef KBD_DISABLE_KEYMAP_LOAD
1066                     bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
1067                     break;
1068 #else
1069                     lwkt_reltoken(&kbd_token);
1070                     return ENODEV;
1071 #endif
1072 
1073           case GETFKEY:                 /* get functionkey string */
1074                     fkeyp = (fkeyarg_t *)arg;
1075                     if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
1076                               lwkt_reltoken(&kbd_token);
1077                               return EINVAL;
1078                     }
1079                     bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
1080                           kbd->kb_fkeytab[fkeyp->keynum].len);
1081                     fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
1082                     break;
1083           case SETFKEY:                 /* set functionkey string */
1084 #ifndef KBD_DISABLE_KEYMAP_LOAD
1085                     fkeyp = (fkeyarg_t *)arg;
1086                     if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
1087                               lwkt_reltoken(&kbd_token);
1088                               return EINVAL;
1089                     }
1090                     kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
1091                     bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
1092                           kbd->kb_fkeytab[fkeyp->keynum].len);
1093                     break;
1094 #else
1095                     lwkt_reltoken(&kbd_token);
1096                     return ENODEV;
1097 #endif
1098 
1099           default:
1100                     lwkt_reltoken(&kbd_token);
1101                     return ENOIOCTL;
1102           }
1103 
1104           lwkt_reltoken(&kbd_token);
1105           return 0;
1106 }
1107 
1108 /* get a pointer to the string associated with the given function key */
1109 u_char *
genkbd_get_fkeystr(keyboard_t * kbd,int fkey,size_t * len)1110 genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
1111 {
1112           u_char *ch;
1113 
1114           if (kbd == NULL)
1115                     return NULL;
1116 
1117           lwkt_gettoken(&kbd_token);
1118           fkey -= F_FN;
1119           if (fkey > kbd->kb_fkeytab_size) {
1120                     lwkt_reltoken(&kbd_token);
1121                     return NULL;
1122           }
1123           *len = kbd->kb_fkeytab[fkey].len;
1124           ch = kbd->kb_fkeytab[fkey].str;
1125 
1126           lwkt_reltoken(&kbd_token);
1127           return ch;
1128 }
1129 
1130 /* diagnostic dump */
1131 static char *
get_kbd_type_name(int type)1132 get_kbd_type_name(int type)
1133 {
1134           static struct {
1135                     int type;
1136                     char *name;
1137           } name_table[] = {
1138                     { KB_84,  "AT 84" },
1139                     { KB_101, "AT 101/102" },
1140                     { KB_OTHER,         "generic" },
1141           };
1142           int i;
1143 
1144           for (i = 0; i < NELEM(name_table); ++i) {
1145                     if (type == name_table[i].type)
1146                               return name_table[i].name;
1147           }
1148           return "unknown";
1149 }
1150 
1151 void
genkbd_diag(keyboard_t * kbd,int level)1152 genkbd_diag(keyboard_t *kbd, int level)
1153 {
1154           if (level > 0) {
1155                     kprintf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
1156                            kbd->kb_index, kbd->kb_name, kbd->kb_unit,
1157                            get_kbd_type_name(kbd->kb_type), kbd->kb_type,
1158                            kbd->kb_config, kbd->kb_flags);
1159                     if (kbd->kb_io_base > 0)
1160                               kprintf(", port:0x%x-0x%x", kbd->kb_io_base,
1161                                      kbd->kb_io_base + kbd->kb_io_size - 1);
1162                     kprintf("\n");
1163           }
1164 }
1165 
1166 #define set_lockkey_state(k, s, l)                                    \
1167           if (!((s) & l ## DOWN)) {                                   \
1168                     int i;                                                      \
1169                     (s) |= l ## DOWN;                                 \
1170                     (s) ^= l ## ED;                                             \
1171                     i = (s) & LOCK_MASK;                                        \
1172                     kbd_ioctl((k), KDSETLED, (caddr_t)&i); \
1173           }
1174 
1175 static u_int
save_accent_key(keyboard_t * kbd,u_int key,int * accents)1176 save_accent_key(keyboard_t *kbd, u_int key, int *accents)
1177 {
1178           int i;
1179 
1180           lwkt_gettoken(&kbd_token);
1181           /* make an index into the accent map */
1182           i = key - F_ACC + 1;
1183           if ((i > kbd->kb_accentmap->n_accs)
1184               || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
1185                     /* the index is out of range or pointing to an empty entry */
1186                     *accents = 0;
1187                     lwkt_reltoken(&kbd_token);
1188                     return ERRKEY;
1189           }
1190 
1191           /*
1192            * If the same accent key has been hit twice, produce the accent char
1193            * itself.
1194            */
1195           if (i == *accents) {
1196                     key = kbd->kb_accentmap->acc[i - 1].accchar;
1197                     *accents = 0;
1198                     lwkt_reltoken(&kbd_token);
1199                     return key;
1200           }
1201 
1202           /* remember the index and wait for the next key  */
1203           *accents = i;
1204           lwkt_reltoken(&kbd_token);
1205           return NOKEY;
1206 }
1207 
1208 static u_int
make_accent_char(keyboard_t * kbd,u_int ch,int * accents)1209 make_accent_char(keyboard_t *kbd, u_int ch, int *accents)
1210 {
1211           struct acc_t *acc;
1212           int i;
1213 
1214           lwkt_gettoken(&kbd_token);
1215           acc = &kbd->kb_accentmap->acc[*accents - 1];
1216           *accents = 0;
1217 
1218           /*
1219            * If the accent key is followed by the space key,
1220            * produce the accent char itself.
1221            */
1222           if (ch == ' ') {
1223                     lwkt_reltoken(&kbd_token);
1224                     return acc->accchar;
1225           }
1226 
1227           /* scan the accent map */
1228           for (i = 0; i < NUM_ACCENTCHARS; ++i) {
1229                     if (acc->map[i][0] == 0)      /* end of table */
1230                               break;
1231                     if (acc->map[i][0] == ch) {
1232                               lwkt_reltoken(&kbd_token);
1233                               return acc->map[i][1];
1234                     }
1235           }
1236           lwkt_reltoken(&kbd_token);
1237           /* this char cannot be accented... */
1238           return ERRKEY;
1239 }
1240 
1241 int
genkbd_keyaction(keyboard_t * kbd,int keycode,int up,int * shiftstate,int * accents)1242 genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
1243                      int *accents)
1244 {
1245           struct keyent_t *key;
1246           int state = *shiftstate;
1247           int action;
1248           int f;
1249           int i;
1250 
1251           lwkt_gettoken(&kbd_token);
1252           i = keycode;
1253           f = state & (AGRS | ALKED);
1254           if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
1255                     i += ALTGR_OFFSET;
1256           key = &kbd->kb_keymap->key[i];
1257           i = ((state & SHIFTS) ? 1 : 0)
1258               | ((state & CTLS) ? 2 : 0)
1259               | ((state & ALTS) ? 4 : 0);
1260           if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
1261                     || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
1262                     i ^= 1;
1263 
1264           if (up) { /* break: key released */
1265                     action = kbd->kb_lastact[keycode];
1266                     kbd->kb_lastact[keycode] = NOP;
1267                     switch (action) {
1268                     case LSHA:
1269                               if (state & SHIFTAON) {
1270                                         set_lockkey_state(kbd, state, ALK);
1271                                         state &= ~ALKDOWN;
1272                               }
1273                               action = LSH;
1274                               /* FALL THROUGH */
1275                     case LSH:
1276                               state &= ~SHIFTS1;
1277                               break;
1278                     case RSHA:
1279                               if (state & SHIFTAON) {
1280                                         set_lockkey_state(kbd, state, ALK);
1281                                         state &= ~ALKDOWN;
1282                               }
1283                               action = RSH;
1284                               /* FALL THROUGH */
1285                     case RSH:
1286                               state &= ~SHIFTS2;
1287                               break;
1288                     case LCTRA:
1289                               if (state & SHIFTAON) {
1290                                         set_lockkey_state(kbd, state, ALK);
1291                                         state &= ~ALKDOWN;
1292                               }
1293                               action = LCTR;
1294                               /* FALL THROUGH */
1295                     case LCTR:
1296                               state &= ~CTLS1;
1297                               break;
1298                     case RCTRA:
1299                               if (state & SHIFTAON) {
1300                                         set_lockkey_state(kbd, state, ALK);
1301                                         state &= ~ALKDOWN;
1302                               }
1303                               action = RCTR;
1304                               /* FALL THROUGH */
1305                     case RCTR:
1306                               state &= ~CTLS2;
1307                               break;
1308                     case LALTA:
1309                               if (state & SHIFTAON) {
1310                                         set_lockkey_state(kbd, state, ALK);
1311                                         state &= ~ALKDOWN;
1312                               }
1313                               action = LALT;
1314                               /* FALL THROUGH */
1315                     case LALT:
1316                               state &= ~ALTS1;
1317                               break;
1318                     case RALTA:
1319                               if (state & SHIFTAON) {
1320                                         set_lockkey_state(kbd, state, ALK);
1321                                         state &= ~ALKDOWN;
1322                               }
1323                               action = RALT;
1324                               /* FALL THROUGH */
1325                     case RALT:
1326                               state &= ~ALTS2;
1327                               break;
1328                     case ASH:
1329                               state &= ~AGRS1;
1330                               break;
1331                     case META:
1332                               state &= ~METAS1;
1333                               break;
1334                     case NLK:
1335                               state &= ~NLKDOWN;
1336                               break;
1337                     case CLK:
1338                               state &= ~CLKDOWN;
1339                               break;
1340                     case SLK:
1341                               state &= ~SLKDOWN;
1342                               break;
1343                     case ALK:
1344                               state &= ~ALKDOWN;
1345                               break;
1346                     case NOP:
1347                               /* release events of regular keys are not reported */
1348                               *shiftstate &= ~SHIFTAON;
1349                               lwkt_reltoken(&kbd_token);
1350                               return NOKEY;
1351                     }
1352                     *shiftstate = state & ~SHIFTAON;
1353                     lwkt_reltoken(&kbd_token);
1354                     return (SPCLKEY | RELKEY | action);
1355           } else {  /* make: key pressed */
1356                     action = key->map[i];
1357                     state &= ~SHIFTAON;
1358                     if (key->spcl & (0x80 >> i)) {
1359                               /* special keys */
1360                               if (kbd->kb_lastact[keycode] == NOP)
1361                                         kbd->kb_lastact[keycode] = action;
1362                               if (kbd->kb_lastact[keycode] != action)
1363                                         action = NOP;
1364                               switch (action) {
1365                               /* LOCKING KEYS */
1366                               case NLK:
1367                                         set_lockkey_state(kbd, state, NLK);
1368                                         break;
1369                               case CLK:
1370                                         set_lockkey_state(kbd, state, CLK);
1371                                         break;
1372                               case SLK:
1373                                         set_lockkey_state(kbd, state, SLK);
1374                                         break;
1375                               case ALK:
1376                                         set_lockkey_state(kbd, state, ALK);
1377                                         break;
1378                               /* NON-LOCKING KEYS */
1379                               case SPSC: case RBT:  case SUSP: case STBY:
1380                               case DBG:  case NEXT: case PREV: case PNC:
1381                               case HALT: case PDWN:
1382                                         *accents = 0;
1383                                         break;
1384                               case BTAB:
1385                                         *accents = 0;
1386                                         action |= BKEY;
1387                                         break;
1388                               case LSHA:
1389                                         state |= SHIFTAON;
1390                                         action = LSH;
1391                                         /* FALL THROUGH */
1392                               case LSH:
1393                                         state |= SHIFTS1;
1394                                         break;
1395                               case RSHA:
1396                                         state |= SHIFTAON;
1397                                         action = RSH;
1398                                         /* FALL THROUGH */
1399                               case RSH:
1400                                         state |= SHIFTS2;
1401                                         break;
1402                               case LCTRA:
1403                                         state |= SHIFTAON;
1404                                         action = LCTR;
1405                                         /* FALL THROUGH */
1406                               case LCTR:
1407                                         state |= CTLS1;
1408                                         break;
1409                               case RCTRA:
1410                                         state |= SHIFTAON;
1411                                         action = RCTR;
1412                                         /* FALL THROUGH */
1413                               case RCTR:
1414                                         state |= CTLS2;
1415                                         break;
1416                               case LALTA:
1417                                         state |= SHIFTAON;
1418                                         action = LALT;
1419                                         /* FALL THROUGH */
1420                               case LALT:
1421                                         state |= ALTS1;
1422                                         break;
1423                               case RALTA:
1424                                         state |= SHIFTAON;
1425                                         action = RALT;
1426                                         /* FALL THROUGH */
1427                               case RALT:
1428                                         state |= ALTS2;
1429                                         break;
1430                               case ASH:
1431                                         state |= AGRS1;
1432                                         break;
1433                               case META:
1434                                         state |= METAS1;
1435                                         break;
1436                               case NOP:
1437                                         *shiftstate = state;
1438                                         lwkt_reltoken(&kbd_token);
1439                                         return NOKEY;
1440                               default:
1441                                         /* is this an accent (dead) key? */
1442                                         *shiftstate = state;
1443                                         if (action >= F_ACC && action <= L_ACC) {
1444                                                   action = save_accent_key(kbd, action,
1445                                                                                  accents);
1446                                                   switch (action) {
1447                                                   case NOKEY:
1448                                                   case ERRKEY:
1449                                                             lwkt_reltoken(&kbd_token);
1450                                                             return action;
1451                                                   default:
1452                                                             if (state & METAS) {
1453                                                                       lwkt_reltoken(&kbd_token);
1454                                                                       return (action | MKEY);
1455                                                             } else {
1456                                                                       lwkt_reltoken(&kbd_token);
1457                                                                       return action;
1458                                                             }
1459                                                   }
1460                                                   /* NOT REACHED */
1461                                         }
1462                                         /* other special keys */
1463                                         if (*accents > 0) {
1464                                                   *accents = 0;
1465                                                   lwkt_reltoken(&kbd_token);
1466                                                   return ERRKEY;
1467                                         }
1468                                         if (action >= F_FN && action <= L_FN)
1469                                                   action |= FKEY;
1470                                         /* XXX: return fkey string for the FKEY? */
1471                                         lwkt_reltoken(&kbd_token);
1472                                         return (SPCLKEY | action);
1473                               }
1474                               *shiftstate = state;
1475                               lwkt_reltoken(&kbd_token);
1476                               return (SPCLKEY | action);
1477                     } else {
1478                               /* regular keys */
1479                               kbd->kb_lastact[keycode] = NOP;
1480                               *shiftstate = state;
1481                               if (*accents > 0) {
1482                                         /* make an accented char */
1483                                         action = make_accent_char(kbd, action, accents);
1484                                         if (action == ERRKEY) {
1485                                                   lwkt_reltoken(&kbd_token);
1486                                                   return action;
1487                                         }
1488                               }
1489                               if (state & METAS)
1490                                         action |= MKEY;
1491                               lwkt_reltoken(&kbd_token);
1492                               return action;
1493                     }
1494           }
1495           /* NOT REACHED */
1496           lwkt_reltoken(&kbd_token);
1497 }
1498 
1499 #ifdef EVDEV_SUPPORT
1500 void
kbd_ev_event(keyboard_t * kbd,uint16_t type,uint16_t code,int32_t value)1501 kbd_ev_event(keyboard_t *kbd, uint16_t type, uint16_t code, int32_t value)
1502 {
1503           int delay[2], led = 0, leds, oleds;
1504 
1505           if (type == EV_LED) {
1506                     leds = oleds = KBD_LED_VAL(kbd);
1507                     switch (code) {
1508                     case LED_CAPSL:
1509                               led = CLKED;
1510                               break;
1511                     case LED_NUML:
1512                               led = NLKED;
1513                               break;
1514                     case LED_SCROLLL:
1515                               led = SLKED;
1516                               break;
1517                     }
1518 
1519                     if (value)
1520                               leds |= led;
1521                     else
1522                               leds &= ~led;
1523 
1524                     if (leds != oleds)
1525                               kbd_ioctl(kbd, KDSETLED, (caddr_t)&leds);
1526 
1527           } else if (type == EV_REP && code == REP_DELAY) {
1528                     delay[0] = value;
1529                     delay[1] = kbd->kb_delay2;
1530                     kbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
1531           } else if (type == EV_REP && code == REP_PERIOD) {
1532                     delay[0] = kbd->kb_delay1;
1533                     delay[1] = value;
1534                     kbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
1535           }
1536 }
1537 #endif
1538