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