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