6 * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $
36 #include <sys/param.h>
39 #include <sys/consio.h>
40 #include <sys/fcntl.h>
42 #include <sys/kernel.h>
43 #include <sys/limits.h>
45 #include <sys/malloc.h>
46 #include <sys/module.h>
47 #include <sys/mutex.h>
50 #include <sys/queue.h>
51 #include <sys/selinfo.h>
52 #include <sys/systm.h>
53 #include <sys/taskqueue.h>
56 #include <dev/kbd/kbdreg.h>
57 #include <dev/kbd/kbdtables.h>
59 #define KEYBOARD_NAME "kbdmux"
61 MALLOC_DECLARE(M_KBDMUX);
62 MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
64 /*****************************************************************************
65 *****************************************************************************
67 *****************************************************************************
68 *****************************************************************************/
70 #define KBDMUX_Q_SIZE 512 /* input queue size */
74 * For now rely on Giant mutex to protect our data structures.
75 * Just like the rest of keyboard drivers and syscons(4) do.
76 * Note that callout is initialized as not MP-safe to make sure
81 #define KBDMUX_LOCK_DECL_GLOBAL \
83 #define KBDMUX_LOCK_INIT(s) \
84 mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE)
85 #define KBDMUX_LOCK_DESTROY(s) \
86 mtx_destroy(&(s)->ks_lock)
87 #define KBDMUX_LOCK(s) \
88 mtx_lock(&(s)->ks_lock)
89 #define KBDMUX_UNLOCK(s) \
90 mtx_unlock(&(s)->ks_lock)
91 #define KBDMUX_LOCK_ASSERT(s, w) \
92 mtx_assert(&(s)->ks_lock, (w))
93 #define KBDMUX_SLEEP(s, f, d, t) \
94 msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), (d), (t))
95 #define KBDMUX_CALLOUT_INIT(s) \
96 callout_init_mtx(&(s)->ks_timo, &(s)->ks_lock, 0)
97 #define KBDMUX_QUEUE_INTR(s) \
98 taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
100 #define KBDMUX_LOCK_DECL_GLOBAL
102 #define KBDMUX_LOCK_INIT(s)
104 #define KBDMUX_LOCK_DESTROY(s)
106 #define KBDMUX_LOCK(s)
108 #define KBDMUX_UNLOCK(s)
110 #define KBDMUX_LOCK_ASSERT(s, w)
112 #define KBDMUX_SLEEP(s, f, d, t) \
113 tsleep(&(s)->f, PCATCH | (PZERO + 1), (d), (t))
114 #define KBDMUX_CALLOUT_INIT(s) \
115 callout_init(&(s)->ks_timo, 0)
116 #define KBDMUX_QUEUE_INTR(s) \
117 taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
120 #define KBDMUX_INTR(kbd, arg) \
121 (*kbdsw[(kbd)->kb_index]->intr)((kbd), (arg))
123 #define KBDMUX_IOCTL(kbd, cmd, arg) \
124 (*kbdsw[(kbd)->kb_index]->ioctl)((kbd), (cmd), (caddr_t) (arg))
126 #define KBDMUX_CHECK_CHAR(kbd) \
127 (*kbdsw[(kbd)->kb_index]->check_char)((kbd))
129 #define KBDMUX_READ_CHAR(kbd, wait) \
130 (*kbdsw[(kbd)->kb_index]->read_char)((kbd), (wait))
132 #define KBDMUX_ENABLE(kbd) \
133 (*kbdsw[(kbd)->kb_index]->enable)((kbd))
135 #define KBDMUX_POLL(kbd, on) \
136 (*kbdsw[(kbd)->kb_index]->poll)((kbd), (on))
138 #define KBDMUX_CLEAR_STATE(kbd) \
139 (*kbdsw[(kbd)->kb_index]->clear_state)((kbd))
146 keyboard_t *kbd; /* keyboard */
147 SLIST_ENTRY(kbdmux_kbd) next; /* link to next */
150 typedef struct kbdmux_kbd kbdmux_kbd_t;
157 struct clist ks_inq; /* input chars queue */
158 struct task ks_task; /* interrupt task */
159 struct callout ks_timo; /* timeout handler */
160 #define TICKS (hz) /* rate */
162 int ks_flags; /* flags */
163 #define COMPOSE (1 << 0) /* compose char flag */
164 #define POLLING (1 << 1) /* polling */
165 #define TASK (1 << 2) /* interrupt task queued */
167 int ks_mode; /* K_XLATE, K_RAW, K_CODE */
168 int ks_state; /* state */
169 int ks_accents; /* accent key index (> 0) */
170 u_int ks_composed_char; /* composed char code */
171 u_char ks_prefix; /* AT scan code prefix */
173 SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */
175 KBDMUX_LOCK_DECL_GLOBAL;
178 typedef struct kbdmux_state kbdmux_state_t;
180 /*****************************************************************************
181 *****************************************************************************
183 *****************************************************************************
184 *****************************************************************************/
186 static task_fn_t kbdmux_kbd_intr;
187 static timeout_t kbdmux_kbd_intr_timo;
188 static kbd_callback_func_t kbdmux_kbd_event;
191 * Interrupt handler task
194 kbdmux_kbd_intr(void *xkbd, int pending)
196 keyboard_t *kbd = (keyboard_t *) xkbd;
197 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
199 KBDMUX_INTR(kbd, NULL);
203 state->ks_flags &= ~TASK;
204 wakeup(&state->ks_task);
206 KBDMUX_UNLOCK(state);
210 * Schedule interrupt handler on timeout. Called with locked state.
213 kbdmux_kbd_intr_timo(void *xstate)
215 kbdmux_state_t *state = (kbdmux_state_t *) xstate;
217 KBDMUX_LOCK_ASSERT(state, MA_OWNED);
219 if (callout_pending(&state->ks_timo))
220 return; /* callout was reset */
222 if (!callout_active(&state->ks_timo))
223 return; /* callout was stopped */
225 callout_deactivate(&state->ks_timo);
227 /* queue interrupt task if needed */
228 if (state->ks_inq.c_cc > 0 && !(state->ks_flags & TASK) &&
229 KBDMUX_QUEUE_INTR(state) == 0)
230 state->ks_flags |= TASK;
232 /* re-schedule timeout */
233 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
237 * Process event from one of our keyboards
240 kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
242 kbdmux_state_t *state = (kbdmux_state_t *) arg;
245 case KBDIO_KEYINPUT: {
251 * Read all chars from the keyboard
253 * Turns out that atkbd(4) check_char() method may return
254 * "true" while read_char() method returns NOKEY. If this
255 * happens we could stuck in the loop below. Avoid this
256 * by breaking out of the loop if read_char() method returns
260 while (KBDMUX_CHECK_CHAR(kbd)) {
261 c = KBDMUX_READ_CHAR(kbd, 0);
265 continue; /* XXX ring bell */
266 if (!KBD_IS_BUSY(kbd))
267 continue; /* not open - discard the input */
269 putc(c, &state->ks_inq);
272 /* queue interrupt task if needed */
273 if (state->ks_inq.c_cc > 0 && !(state->ks_flags & TASK) &&
274 KBDMUX_QUEUE_INTR(state) == 0)
275 state->ks_flags |= TASK;
277 KBDMUX_UNLOCK(state);
280 case KBDIO_UNLOADING: {
285 SLIST_FOREACH(k, &state->ks_kbds, next)
290 kbd_release(k->kbd, &k->kbd);
291 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
298 KBDMUX_UNLOCK(state);
309 /****************************************************************************
310 ****************************************************************************
312 ****************************************************************************
313 ****************************************************************************/
315 static int kbdmux_configure(int flags);
316 static kbd_probe_t kbdmux_probe;
317 static kbd_init_t kbdmux_init;
318 static kbd_term_t kbdmux_term;
319 static kbd_intr_t kbdmux_intr;
320 static kbd_test_if_t kbdmux_test_if;
321 static kbd_enable_t kbdmux_enable;
322 static kbd_disable_t kbdmux_disable;
323 static kbd_read_t kbdmux_read;
324 static kbd_check_t kbdmux_check;
325 static kbd_read_char_t kbdmux_read_char;
326 static kbd_check_char_t kbdmux_check_char;
327 static kbd_ioctl_t kbdmux_ioctl;
328 static kbd_lock_t kbdmux_lock;
329 static void kbdmux_clear_state_locked(kbdmux_state_t *state);
330 static kbd_clear_state_t kbdmux_clear_state;
331 static kbd_get_state_t kbdmux_get_state;
332 static kbd_set_state_t kbdmux_set_state;
333 static kbd_poll_mode_t kbdmux_poll;
335 static keyboard_switch_t kbdmuxsw = {
336 .probe = kbdmux_probe,
340 .test_if = kbdmux_test_if,
341 .enable = kbdmux_enable,
342 .disable = kbdmux_disable,
344 .check = kbdmux_check,
345 .read_char = kbdmux_read_char,
346 .check_char = kbdmux_check_char,
347 .ioctl = kbdmux_ioctl,
349 .clear_state = kbdmux_clear_state,
350 .get_state = kbdmux_get_state,
351 .set_state = kbdmux_set_state,
352 .get_fkeystr = genkbd_get_fkeystr,
358 * Return the number of found keyboards
361 kbdmux_configure(int flags)
370 kbdmux_probe(int unit, void *arg, int flags)
372 if (resource_disabled(KEYBOARD_NAME, unit))
379 * Reset and initialize the keyboard (stolen from atkbd.c)
382 kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
384 keyboard_t *kbd = NULL;
385 kbdmux_state_t *state = NULL;
386 keymap_t *keymap = NULL;
387 accentmap_t *accmap = NULL;
388 fkeytab_t *fkeymap = NULL;
389 int error, needfree, fkeymap_size, delay[2];
392 *kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
393 state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
394 keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
395 accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
396 fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
397 fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
400 if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
401 (accmap == NULL) || (fkeymap == NULL)) {
406 KBDMUX_LOCK_INIT(state);
407 clist_alloc_cblocks(&state->ks_inq,
408 KBDMUX_Q_SIZE, KBDMUX_Q_SIZE / 2);
409 TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
410 KBDMUX_CALLOUT_INIT(state);
411 SLIST_INIT(&state->ks_kbds);
412 } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
416 state = (kbdmux_state_t *) kbd->kb_data;
417 keymap = kbd->kb_keymap;
418 accmap = kbd->kb_accentmap;
419 fkeymap = kbd->kb_fkeytab;
420 fkeymap_size = kbd->kb_fkeytab_size;
424 if (!KBD_IS_PROBED(kbd)) {
425 /* XXX assume 101/102 keys keyboard */
426 kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0);
427 bcopy(&key_map, keymap, sizeof(key_map));
428 bcopy(&accent_map, accmap, sizeof(accent_map));
429 bcopy(fkey_tab, fkeymap,
430 imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
431 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
432 kbd->kb_data = (void *)state;
434 KBD_FOUND_DEVICE(kbd);
438 kbdmux_clear_state_locked(state);
439 state->ks_mode = K_XLATE;
440 KBDMUX_UNLOCK(state);
443 if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
444 kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
446 kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
448 delay[0] = kbd->kb_delay1;
449 delay[1] = kbd->kb_delay2;
450 kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
455 if (!KBD_IS_CONFIGURED(kbd)) {
456 if (kbd_register(kbd) < 0) {
461 KBD_CONFIG_DONE(kbd);
464 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
465 KBDMUX_UNLOCK(state);
472 clist_free_cblocks(&state->ks_inq);
473 free(state, M_KBDMUX);
476 free(keymap, M_KBDMUX);
478 free(accmap, M_KBDMUX);
480 free(fkeymap, M_KBDMUX);
483 *kbdp = NULL; /* insure ref doesn't leak to caller */
491 * Finish using this keyboard
494 kbdmux_term(keyboard_t *kbd)
496 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
502 callout_stop(&state->ks_timo);
504 /* wait for interrupt task */
505 while (state->ks_flags & TASK)
506 KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0);
508 /* release all keyboards from the mux */
509 while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
510 kbd_release(k->kbd, &k->kbd);
511 SLIST_REMOVE_HEAD(&state->ks_kbds, next);
518 /* flush input queue */
519 ndflush(&state->ks_inq, state->ks_inq.c_cc);
520 clist_free_cblocks(&state->ks_inq);
522 KBDMUX_UNLOCK(state);
526 KBDMUX_LOCK_DESTROY(state);
527 bzero(state, sizeof(*state));
528 free(state, M_KBDMUX);
530 free(kbd->kb_keymap, M_KBDMUX);
531 free(kbd->kb_accentmap, M_KBDMUX);
532 free(kbd->kb_fkeytab, M_KBDMUX);
539 * Keyboard interrupt routine
542 kbdmux_intr(keyboard_t *kbd, void *arg)
546 if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
547 /* let the callback function to process the input */
548 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
549 kbd->kb_callback.kc_arg);
551 /* read and discard the input; no one is waiting for input */
553 c = kbdmux_read_char(kbd, FALSE);
554 } while (c != NOKEY);
561 * Test the interface to the device
564 kbdmux_test_if(keyboard_t *kbd)
570 * Enable the access to the device; until this function is called,
571 * the client cannot read from the keyboard.
574 kbdmux_enable(keyboard_t *kbd)
581 * Disallow the access to the device
584 kbdmux_disable(keyboard_t *kbd)
591 * Read one byte from the keyboard if it's allowed
594 kbdmux_read(keyboard_t *kbd, int wait)
596 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
600 c = getc(&state->ks_inq);
601 KBDMUX_UNLOCK(state);
606 return (KBD_IS_ACTIVE(kbd)? c : -1);
610 * Check if data is waiting
613 kbdmux_check(keyboard_t *kbd)
615 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
618 if (!KBD_IS_ACTIVE(kbd))
622 ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE;
623 KBDMUX_UNLOCK(state);
629 * Read char from the keyboard (stolen from atkbd.c)
632 kbdmux_read_char(keyboard_t *kbd, int wait)
634 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
636 int scancode, keycode;
642 /* do we have a composed char to return? */
643 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
644 action = state->ks_composed_char;
645 state->ks_composed_char = 0;
646 if (action > UCHAR_MAX) {
647 KBDMUX_UNLOCK(state);
652 KBDMUX_UNLOCK(state);
657 /* see if there is something in the keyboard queue */
658 scancode = getc(&state->ks_inq);
659 if (scancode == -1) {
660 if (state->ks_flags & POLLING) {
663 SLIST_FOREACH(k, &state->ks_kbds, next) {
664 while (KBDMUX_CHECK_CHAR(k->kbd)) {
665 scancode = KBDMUX_READ_CHAR(k->kbd, 0);
666 if (scancode == NOKEY)
668 if (scancode == ERRKEY)
670 if (!KBD_IS_BUSY(k->kbd))
673 putc(scancode, &state->ks_inq);
677 if (state->ks_inq.c_cc > 0)
681 KBDMUX_UNLOCK(state);
684 /* XXX FIXME: check for -1 if wait == 1! */
688 /* return the byte as is for the K_RAW mode */
689 if (state->ks_mode == K_RAW) {
690 KBDMUX_UNLOCK(state);
694 /* translate the scan code into a keycode */
695 keycode = scancode & 0x7F;
696 switch (state->ks_prefix) {
697 case 0x00: /* normal scancode */
699 case 0xB8: /* left alt (compose key) released */
700 if (state->ks_flags & COMPOSE) {
701 state->ks_flags &= ~COMPOSE;
702 if (state->ks_composed_char > UCHAR_MAX)
703 state->ks_composed_char = 0;
706 case 0x38: /* left alt (compose key) pressed */
707 if (!(state->ks_flags & COMPOSE)) {
708 state->ks_flags |= COMPOSE;
709 state->ks_composed_char = 0;
714 state->ks_prefix = scancode;
718 case 0xE0: /* 0xE0 prefix */
719 state->ks_prefix = 0;
721 case 0x1C: /* right enter key */
724 case 0x1D: /* right ctrl key */
727 case 0x35: /* keypad divide key */
730 case 0x37: /* print scrn key */
733 case 0x38: /* right alt key (alt gr) */
736 case 0x46: /* ctrl-pause/break on AT 101 (see below) */
739 case 0x47: /* grey home key */
742 case 0x48: /* grey up arrow key */
745 case 0x49: /* grey page up key */
748 case 0x4B: /* grey left arrow key */
751 case 0x4D: /* grey right arrow key */
754 case 0x4F: /* grey end key */
757 case 0x50: /* grey down arrow key */
760 case 0x51: /* grey page down key */
763 case 0x52: /* grey insert key */
766 case 0x53: /* grey delete key */
769 /* the following 3 are only used on the MS "Natural" keyboard */
770 case 0x5b: /* left Window key */
773 case 0x5c: /* right Window key */
776 case 0x5d: /* menu key */
779 case 0x5e: /* power key */
782 case 0x5f: /* sleep key */
785 case 0x63: /* wake key */
788 case 0x64: /* [JP106USB] backslash, underscore */
791 default: /* ignore everything else */
795 case 0xE1: /* 0xE1 prefix */
797 * The pause/break key on the 101 keyboard produces:
799 * Ctrl-pause/break produces:
800 * E0-46 E0-C6 (See above.)
802 state->ks_prefix = 0;
804 state->ks_prefix = 0x1D;
807 case 0x1D: /* pause / break */
808 state->ks_prefix = 0;
815 /* XXX assume 101/102 keys AT keyboard */
817 case 0x5c: /* print screen */
818 if (state->ks_flags & ALTS)
819 keycode = 0x54; /* sysrq */
821 case 0x68: /* pause/break */
822 if (state->ks_flags & CTLS)
823 keycode = 0x6c; /* break */
827 /* return the key code in the K_CODE mode */
828 if (state->ks_mode == K_CODE) {
829 KBDMUX_UNLOCK(state);
830 return (keycode | (scancode & 0x80));
833 /* compose a character code */
834 if (state->ks_flags & COMPOSE) {
835 switch (keycode | (scancode & 0x80)) {
836 /* key pressed, process it */
837 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
838 state->ks_composed_char *= 10;
839 state->ks_composed_char += keycode - 0x40;
840 if (state->ks_composed_char > UCHAR_MAX) {
841 KBDMUX_UNLOCK(state);
845 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
846 state->ks_composed_char *= 10;
847 state->ks_composed_char += keycode - 0x47;
848 if (state->ks_composed_char > UCHAR_MAX) {
849 KBDMUX_UNLOCK(state);
853 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
854 state->ks_composed_char *= 10;
855 state->ks_composed_char += keycode - 0x4E;
856 if (state->ks_composed_char > UCHAR_MAX) {
857 KBDMUX_UNLOCK(state);
861 case 0x52: /* keypad 0 */
862 state->ks_composed_char *= 10;
863 if (state->ks_composed_char > UCHAR_MAX) {
864 KBDMUX_UNLOCK(state);
869 /* key released, no interest here */
870 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
871 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
872 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
873 case 0xD2: /* keypad 0 */
876 case 0x38: /* left alt key */
880 if (state->ks_composed_char > 0) {
881 state->ks_flags &= ~COMPOSE;
882 state->ks_composed_char = 0;
883 KBDMUX_UNLOCK(state);
890 /* keycode to key action */
891 action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
892 &state->ks_state, &state->ks_accents);
896 KBDMUX_UNLOCK(state);
902 * Check if char is waiting
905 kbdmux_check_char(keyboard_t *kbd)
907 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
910 if (!KBD_IS_ACTIVE(kbd))
915 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
918 ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE;
920 KBDMUX_UNLOCK(state);
929 kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
931 static int delays[] = {
935 static int rates[] = {
936 34, 38, 42, 46, 50, 55, 59, 63,
937 68, 76, 84, 92, 100, 110, 118, 126,
938 136, 152, 168, 184, 200, 220, 236, 252,
939 272, 304, 336, 368, 400, 440, 472, 504
942 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
952 case KBADDKBD: /* add keyboard to the mux */
953 ki = (keyboard_info_t *) arg;
955 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
956 strcmp(ki->kb_name, "*") == 0)
957 return (EINVAL); /* bad input */
961 SLIST_FOREACH(k, &state->ks_kbds, next)
962 if (k->kbd->kb_unit == ki->kb_unit &&
963 strcmp(k->kbd->kb_name, ki->kb_name) == 0)
967 KBDMUX_UNLOCK(state);
969 return (0); /* keyboard already in the mux */
972 k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
974 KBDMUX_UNLOCK(state);
976 return (ENOMEM); /* out of memory */
979 k->kbd = kbd_get_keyboard(
984 kbdmux_kbd_event, (void *) state));
985 if (k->kbd == NULL) {
986 KBDMUX_UNLOCK(state);
989 return (EINVAL); /* bad keyboard */
992 KBDMUX_ENABLE(k->kbd);
993 KBDMUX_CLEAR_STATE(k->kbd);
995 /* set K_RAW mode on slave keyboard */
997 error = KBDMUX_IOCTL(k->kbd, KDSKBMODE, &mode);
999 /* set lock keys state on slave keyboard */
1000 mode = state->ks_state & LOCK_MASK;
1001 error = KBDMUX_IOCTL(k->kbd, KDSKBSTATE, &mode);
1005 KBDMUX_UNLOCK(state);
1007 kbd_release(k->kbd, &k->kbd);
1012 return (error); /* could not set mode */
1015 SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
1017 KBDMUX_UNLOCK(state);
1020 case KBRELKBD: /* release keyboard from the mux */
1021 ki = (keyboard_info_t *) arg;
1023 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
1024 strcmp(ki->kb_name, "*") == 0)
1025 return (EINVAL); /* bad input */
1029 SLIST_FOREACH(k, &state->ks_kbds, next)
1030 if (k->kbd->kb_unit == ki->kb_unit &&
1031 strcmp(k->kbd->kb_name, ki->kb_name) == 0)
1035 error = kbd_release(k->kbd, &k->kbd);
1037 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
1044 error = ENXIO; /* keyboard is not in the mux */
1046 KBDMUX_UNLOCK(state);
1049 case KDGKBMODE: /* get kyboard mode */
1051 *(int *)arg = state->ks_mode;
1052 KBDMUX_UNLOCK(state);
1056 ival = IOCPARM_IVAL(arg);
1057 arg = (caddr_t)&ival;
1059 case KDSKBMODE: /* set keyboard mode */
1062 switch (*(int *)arg) {
1064 if (state->ks_mode != K_XLATE) {
1065 /* make lock key state and LED state match */
1066 state->ks_state &= ~LOCK_MASK;
1067 state->ks_state |= KBD_LED_VAL(kbd);
1073 if (state->ks_mode != *(int *)arg) {
1074 kbdmux_clear_state_locked(state);
1075 state->ks_mode = *(int *)arg;
1084 KBDMUX_UNLOCK(state);
1087 case KDGETLED: /* get keyboard LED */
1089 *(int *)arg = KBD_LED_VAL(kbd);
1090 KBDMUX_UNLOCK(state);
1094 ival = IOCPARM_IVAL(arg);
1095 arg = (caddr_t)&ival;
1097 case KDSETLED: /* set keyboard LED */
1100 /* NOTE: lock key state in ks_state won't be changed */
1101 if (*(int *)arg & ~LOCK_MASK) {
1102 KBDMUX_UNLOCK(state);
1107 KBD_LED_VAL(kbd) = *(int *)arg;
1109 /* KDSETLED on all slave keyboards */
1110 SLIST_FOREACH(k, &state->ks_kbds, next)
1111 KBDMUX_IOCTL(k->kbd, KDSETLED, arg);
1113 KBDMUX_UNLOCK(state);
1116 case KDGKBSTATE: /* get lock key state */
1118 *(int *)arg = state->ks_state & LOCK_MASK;
1119 KBDMUX_UNLOCK(state);
1123 ival = IOCPARM_IVAL(arg);
1124 arg = (caddr_t)&ival;
1126 case KDSKBSTATE: /* set lock key state */
1129 if (*(int *)arg & ~LOCK_MASK) {
1130 KBDMUX_UNLOCK(state);
1135 state->ks_state &= ~LOCK_MASK;
1136 state->ks_state |= *(int *)arg;
1138 /* KDSKBSTATE on all slave keyboards */
1139 SLIST_FOREACH(k, &state->ks_kbds, next)
1140 KBDMUX_IOCTL(k->kbd, KDSKBSTATE, arg);
1142 KBDMUX_UNLOCK(state);
1144 return (kbdmux_ioctl(kbd, KDSETLED, arg));
1149 ival = IOCPARM_IVAL(arg);
1150 arg = (caddr_t)&ival;
1152 case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1153 case KDSETRAD: /* set keyboard repeat rate (old interface) */
1156 if (cmd == KDSETREPEAT) {
1160 for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --)
1161 if (((int *)arg)[0] >= delays[i])
1166 for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --)
1167 if (((int *)arg)[1] >= rates[i])
1174 KBDMUX_UNLOCK(state);
1179 kbd->kb_delay1 = delays[(mode >> 5) & 3];
1180 kbd->kb_delay2 = rates[mode & 0x1f];
1182 /* perform command on all slave keyboards */
1183 SLIST_FOREACH(k, &state->ks_kbds, next)
1184 KBDMUX_IOCTL(k->kbd, cmd, arg);
1186 KBDMUX_UNLOCK(state);
1189 case PIO_KEYMAP: /* set keyboard translation table */
1190 case PIO_KEYMAPENT: /* set keyboard translation table entry */
1191 case PIO_DEADKEYMAP: /* set accent key translation table */
1193 state->ks_accents = 0;
1195 /* perform command on all slave keyboards */
1196 SLIST_FOREACH(k, &state->ks_kbds, next)
1197 KBDMUX_IOCTL(k->kbd, cmd, arg);
1199 KBDMUX_UNLOCK(state);
1203 error = genkbd_commonioctl(kbd, cmd, arg);
1211 * Lock the access to the keyboard
1214 kbdmux_lock(keyboard_t *kbd, int lock)
1216 return (1); /* XXX */
1220 * Clear the internal state of the keyboard
1223 kbdmux_clear_state_locked(kbdmux_state_t *state)
1225 KBDMUX_LOCK_ASSERT(state, MA_OWNED);
1227 state->ks_flags &= ~(COMPOSE|POLLING);
1228 state->ks_state &= LOCK_MASK; /* preserve locking key state */
1229 state->ks_accents = 0;
1230 state->ks_composed_char = 0;
1231 /* state->ks_prefix = 0; XXX */
1233 ndflush(&state->ks_inq, state->ks_inq.c_cc);
1237 kbdmux_clear_state(keyboard_t *kbd)
1239 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1242 kbdmux_clear_state_locked(state);
1243 KBDMUX_UNLOCK(state);
1247 * Save the internal state
1250 kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1253 return (sizeof(kbdmux_state_t));
1254 if (len < sizeof(kbdmux_state_t))
1257 bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1263 * Set the internal state
1266 kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1268 if (len < sizeof(kbdmux_state_t))
1271 bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1280 kbdmux_poll(keyboard_t *kbd, int on)
1282 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1288 state->ks_flags |= POLLING;
1290 state->ks_flags &= ~POLLING;
1292 /* set poll on slave keyboards */
1293 SLIST_FOREACH(k, &state->ks_kbds, next)
1294 KBDMUX_POLL(k->kbd, on);
1296 KBDMUX_UNLOCK(state);
1301 /*****************************************************************************
1302 *****************************************************************************
1304 *****************************************************************************
1305 *****************************************************************************/
1307 KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1310 kbdmux_modevent(module_t mod, int type, void *data)
1312 keyboard_switch_t *sw;
1318 if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1321 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1322 kbd_delete_driver(&kbdmux_kbd_driver);
1329 if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
1330 (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) {
1331 kbd_delete_driver(&kbdmux_kbd_driver);
1335 #ifdef KBD_INSTALL_CDEV
1336 if ((error = kbd_attach(kbd)) != 0) {
1338 kbd_delete_driver(&kbdmux_kbd_driver);
1343 if ((error = (*sw->enable)(kbd)) != 0) {
1344 (*sw->disable)(kbd);
1345 #ifdef KBD_INSTALL_CDEV
1349 kbd_delete_driver(&kbdmux_kbd_driver);
1355 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
1356 panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
1358 kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1360 panic("kbd_get_keyboard(kbd_find_keyboard(" KEYBOARD_NAME ", 0)) == NULL");
1362 (*sw->disable)(kbd);
1363 #ifdef KBD_INSTALL_CDEV
1367 kbd_delete_driver(&kbdmux_kbd_driver);
1379 DEV_MODULE(kbdmux, kbdmux_modevent, NULL);