Deleted Added
full compact
kbdmux.c (193752) kbdmux.c (213770)
1/*
2 * kbdmux.c
3 */
4
5/*-
6 * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
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.
17 *
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
28 * SUCH DAMAGE.
29 *
30 * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $
1/*
2 * kbdmux.c
3 */
4
5/*-
6 * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
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.
17 *
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
28 * SUCH DAMAGE.
29 *
30 * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $
31 * $FreeBSD: head/sys/dev/kbdmux/kbdmux.c 193752 2009-06-08 20:24:29Z ed $
31 * $FreeBSD: head/sys/dev/kbdmux/kbdmux.c 213770 2010-10-13 11:37:12Z rpaulo $
32 */
33
34#include "opt_compat.h"
35#include "opt_kbd.h"
36
37#include <sys/param.h>
38#include <sys/bus.h>
39#include <sys/conf.h>
40#include <sys/consio.h>
41#include <sys/fcntl.h>
42#include <sys/kbio.h>
43#include <sys/kernel.h>
44#include <sys/limits.h>
45#include <sys/lock.h>
46#include <sys/malloc.h>
47#include <sys/module.h>
48#include <sys/mutex.h>
49#include <sys/poll.h>
50#include <sys/proc.h>
51#include <sys/queue.h>
52#include <sys/selinfo.h>
53#include <sys/systm.h>
54#include <sys/taskqueue.h>
55#include <sys/uio.h>
56#include <dev/kbd/kbdreg.h>
57#include <dev/kbd/kbdtables.h>
58
59#define KEYBOARD_NAME "kbdmux"
60
61MALLOC_DECLARE(M_KBDMUX);
62MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
63
64/*****************************************************************************
65 *****************************************************************************
66 ** Keyboard state
67 *****************************************************************************
68 *****************************************************************************/
69
70#define KBDMUX_Q_SIZE 512 /* input queue size */
71
72/*
73 * XXX
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
77 * Giant is held.
78 */
79
80#if 0 /* not yet */
81#define KBDMUX_LOCK_DECL_GLOBAL \
82 struct mtx ks_lock
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)
99#else
100#define KBDMUX_LOCK_DECL_GLOBAL
101
102#define KBDMUX_LOCK_INIT(s)
103
104#define KBDMUX_LOCK_DESTROY(s)
105
106#define KBDMUX_LOCK(s)
107
108#define KBDMUX_UNLOCK(s)
109
110#define KBDMUX_LOCK_ASSERT(s, w)
111
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)
118#endif /* not yet */
119
120/*
121 * kbdmux keyboard
122 */
123struct kbdmux_kbd
124{
125 keyboard_t *kbd; /* keyboard */
126 SLIST_ENTRY(kbdmux_kbd) next; /* link to next */
127};
128
129typedef struct kbdmux_kbd kbdmux_kbd_t;
130
131/*
132 * kbdmux state
133 */
134struct kbdmux_state
135{
136 char ks_inq[KBDMUX_Q_SIZE]; /* input chars queue */
137 unsigned int ks_inq_start;
138 unsigned int ks_inq_length;
139 struct task ks_task; /* interrupt task */
140 struct callout ks_timo; /* timeout handler */
141#define TICKS (hz) /* rate */
142
143 int ks_flags; /* flags */
144#define COMPOSE (1 << 0) /* compose char flag */
145#define POLLING (1 << 1) /* polling */
146#define TASK (1 << 2) /* interrupt task queued */
147
148 int ks_mode; /* K_XLATE, K_RAW, K_CODE */
149 int ks_state; /* state */
150 int ks_accents; /* accent key index (> 0) */
151 u_int ks_composed_char; /* composed char code */
152 u_char ks_prefix; /* AT scan code prefix */
153
154 SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */
155
156 KBDMUX_LOCK_DECL_GLOBAL;
157};
158
159typedef struct kbdmux_state kbdmux_state_t;
160
161/*****************************************************************************
162 *****************************************************************************
163 ** Helper functions
164 *****************************************************************************
165 *****************************************************************************/
166
167static task_fn_t kbdmux_kbd_intr;
168static timeout_t kbdmux_kbd_intr_timo;
169static kbd_callback_func_t kbdmux_kbd_event;
170
171static void
172kbdmux_kbd_putc(kbdmux_state_t *state, char c)
173{
174 unsigned int p;
175
176 if (state->ks_inq_length == KBDMUX_Q_SIZE)
177 return;
178
179 p = (state->ks_inq_start + state->ks_inq_length) % KBDMUX_Q_SIZE;
180 state->ks_inq[p] = c;
181 state->ks_inq_length++;
182}
183
184static int
185kbdmux_kbd_getc(kbdmux_state_t *state)
186{
187 unsigned char c;
188
189 if (state->ks_inq_length == 0)
190 return (-1);
191
192 c = state->ks_inq[state->ks_inq_start];
193 state->ks_inq_start = (state->ks_inq_start + 1) % KBDMUX_Q_SIZE;
194 state->ks_inq_length--;
195
196 return (c);
197}
198
199/*
200 * Interrupt handler task
201 */
202void
203kbdmux_kbd_intr(void *xkbd, int pending)
204{
205 keyboard_t *kbd = (keyboard_t *) xkbd;
206 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
207
208 kbdd_intr(kbd, NULL);
209
210 KBDMUX_LOCK(state);
211
212 state->ks_flags &= ~TASK;
213 wakeup(&state->ks_task);
214
215 KBDMUX_UNLOCK(state);
216}
217
218/*
219 * Schedule interrupt handler on timeout. Called with locked state.
220 */
221void
222kbdmux_kbd_intr_timo(void *xstate)
223{
224 kbdmux_state_t *state = (kbdmux_state_t *) xstate;
225
226 KBDMUX_LOCK_ASSERT(state, MA_OWNED);
227
228 if (callout_pending(&state->ks_timo))
229 return; /* callout was reset */
230
231 if (!callout_active(&state->ks_timo))
232 return; /* callout was stopped */
233
234 callout_deactivate(&state->ks_timo);
235
236 /* queue interrupt task if needed */
237 if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) &&
238 KBDMUX_QUEUE_INTR(state) == 0)
239 state->ks_flags |= TASK;
240
241 /* re-schedule timeout */
242 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
243}
244
245/*
246 * Process event from one of our keyboards
247 */
248static int
249kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
250{
251 kbdmux_state_t *state = (kbdmux_state_t *) arg;
252
253 switch (event) {
254 case KBDIO_KEYINPUT: {
255 int c;
256
257 KBDMUX_LOCK(state);
258
259 /*
260 * Read all chars from the keyboard
261 *
262 * Turns out that atkbd(4) check_char() method may return
263 * "true" while read_char() method returns NOKEY. If this
264 * happens we could stuck in the loop below. Avoid this
265 * by breaking out of the loop if read_char() method returns
266 * NOKEY.
267 */
268
269 while (kbdd_check_char(kbd)) {
270 c = kbdd_read_char(kbd, 0);
271 if (c == NOKEY)
272 break;
273 if (c == ERRKEY)
274 continue; /* XXX ring bell */
275 if (!KBD_IS_BUSY(kbd))
276 continue; /* not open - discard the input */
277
278 kbdmux_kbd_putc(state, c);
279 }
280
281 /* queue interrupt task if needed */
282 if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) &&
283 KBDMUX_QUEUE_INTR(state) == 0)
284 state->ks_flags |= TASK;
285
286 KBDMUX_UNLOCK(state);
287 } break;
288
289 case KBDIO_UNLOADING: {
290 kbdmux_kbd_t *k;
291
292 KBDMUX_LOCK(state);
293
294 SLIST_FOREACH(k, &state->ks_kbds, next)
295 if (k->kbd == kbd)
296 break;
297
298 if (k != NULL) {
299 kbd_release(k->kbd, &k->kbd);
300 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
301
302 k->kbd = NULL;
303
304 free(k, M_KBDMUX);
305 }
306
307 KBDMUX_UNLOCK(state);
308 } break;
309
310 default:
311 return (EINVAL);
312 /* NOT REACHED */
313 }
314
315 return (0);
316}
317
318/****************************************************************************
319 ****************************************************************************
320 ** Keyboard driver
321 ****************************************************************************
322 ****************************************************************************/
323
324static int kbdmux_configure(int flags);
325static kbd_probe_t kbdmux_probe;
326static kbd_init_t kbdmux_init;
327static kbd_term_t kbdmux_term;
328static kbd_intr_t kbdmux_intr;
329static kbd_test_if_t kbdmux_test_if;
330static kbd_enable_t kbdmux_enable;
331static kbd_disable_t kbdmux_disable;
332static kbd_read_t kbdmux_read;
333static kbd_check_t kbdmux_check;
334static kbd_read_char_t kbdmux_read_char;
335static kbd_check_char_t kbdmux_check_char;
336static kbd_ioctl_t kbdmux_ioctl;
337static kbd_lock_t kbdmux_lock;
338static void kbdmux_clear_state_locked(kbdmux_state_t *state);
339static kbd_clear_state_t kbdmux_clear_state;
340static kbd_get_state_t kbdmux_get_state;
341static kbd_set_state_t kbdmux_set_state;
342static kbd_poll_mode_t kbdmux_poll;
343
344static keyboard_switch_t kbdmuxsw = {
345 .probe = kbdmux_probe,
346 .init = kbdmux_init,
347 .term = kbdmux_term,
348 .intr = kbdmux_intr,
349 .test_if = kbdmux_test_if,
350 .enable = kbdmux_enable,
351 .disable = kbdmux_disable,
352 .read = kbdmux_read,
353 .check = kbdmux_check,
354 .read_char = kbdmux_read_char,
355 .check_char = kbdmux_check_char,
356 .ioctl = kbdmux_ioctl,
357 .lock = kbdmux_lock,
358 .clear_state = kbdmux_clear_state,
359 .get_state = kbdmux_get_state,
360 .set_state = kbdmux_set_state,
361 .get_fkeystr = genkbd_get_fkeystr,
362 .poll = kbdmux_poll,
363 .diag = genkbd_diag,
364};
365
366/*
367 * Return the number of found keyboards
368 */
369static int
370kbdmux_configure(int flags)
371{
372 return (1);
373}
374
375/*
376 * Detect a keyboard
377 */
378static int
379kbdmux_probe(int unit, void *arg, int flags)
380{
381 if (resource_disabled(KEYBOARD_NAME, unit))
382 return (ENXIO);
383
384 return (0);
385}
386
387/*
388 * Reset and initialize the keyboard (stolen from atkbd.c)
389 */
390static int
391kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
392{
393 keyboard_t *kbd = NULL;
394 kbdmux_state_t *state = NULL;
395 keymap_t *keymap = NULL;
396 accentmap_t *accmap = NULL;
397 fkeytab_t *fkeymap = NULL;
398 int error, needfree, fkeymap_size, delay[2];
399
400 if (*kbdp == NULL) {
401 *kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
402 state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
403 keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
404 accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
405 fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
406 fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
407 needfree = 1;
408
409 if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
410 (accmap == NULL) || (fkeymap == NULL)) {
411 error = ENOMEM;
412 goto bad;
413 }
414
415 KBDMUX_LOCK_INIT(state);
416 TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
417 KBDMUX_CALLOUT_INIT(state);
418 SLIST_INIT(&state->ks_kbds);
419 } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
420 return (0);
421 } else {
422 kbd = *kbdp;
423 state = (kbdmux_state_t *) kbd->kb_data;
424 keymap = kbd->kb_keymap;
425 accmap = kbd->kb_accentmap;
426 fkeymap = kbd->kb_fkeytab;
427 fkeymap_size = kbd->kb_fkeytab_size;
428 needfree = 0;
429 }
430
431 if (!KBD_IS_PROBED(kbd)) {
432 /* XXX assume 101/102 keys keyboard */
433 kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0);
434 bcopy(&key_map, keymap, sizeof(key_map));
435 bcopy(&accent_map, accmap, sizeof(accent_map));
436 bcopy(fkey_tab, fkeymap,
437 imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
438 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
439 kbd->kb_data = (void *)state;
440
441 KBD_FOUND_DEVICE(kbd);
442 KBD_PROBE_DONE(kbd);
443
444 KBDMUX_LOCK(state);
445 kbdmux_clear_state_locked(state);
446 state->ks_mode = K_XLATE;
447 KBDMUX_UNLOCK(state);
448 }
449
450 if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
451 kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
452
453 kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
454
455 delay[0] = kbd->kb_delay1;
456 delay[1] = kbd->kb_delay2;
457 kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
458
459 KBD_INIT_DONE(kbd);
460 }
461
462 if (!KBD_IS_CONFIGURED(kbd)) {
463 if (kbd_register(kbd) < 0) {
464 error = ENXIO;
465 goto bad;
466 }
467
468 KBD_CONFIG_DONE(kbd);
469
470 KBDMUX_LOCK(state);
471 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
472 KBDMUX_UNLOCK(state);
473 }
474
475 return (0);
476bad:
477 if (needfree) {
478 if (state != NULL)
479 free(state, M_KBDMUX);
480 if (keymap != NULL)
481 free(keymap, M_KBDMUX);
482 if (accmap != NULL)
483 free(accmap, M_KBDMUX);
484 if (fkeymap != NULL)
485 free(fkeymap, M_KBDMUX);
486 if (kbd != NULL) {
487 free(kbd, M_KBDMUX);
488 *kbdp = NULL; /* insure ref doesn't leak to caller */
489 }
490 }
491
492 return (error);
493}
494
495/*
496 * Finish using this keyboard
497 */
498static int
499kbdmux_term(keyboard_t *kbd)
500{
501 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
502 kbdmux_kbd_t *k;
503
504 KBDMUX_LOCK(state);
505
506 /* kill callout */
507 callout_stop(&state->ks_timo);
508
509 /* wait for interrupt task */
510 while (state->ks_flags & TASK)
511 KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0);
512
513 /* release all keyboards from the mux */
514 while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
515 kbd_release(k->kbd, &k->kbd);
516 SLIST_REMOVE_HEAD(&state->ks_kbds, next);
517
518 k->kbd = NULL;
519
520 free(k, M_KBDMUX);
521 }
522
523 KBDMUX_UNLOCK(state);
524
525 kbd_unregister(kbd);
526
527 KBDMUX_LOCK_DESTROY(state);
528 bzero(state, sizeof(*state));
529 free(state, M_KBDMUX);
530
531 free(kbd->kb_keymap, M_KBDMUX);
532 free(kbd->kb_accentmap, M_KBDMUX);
533 free(kbd->kb_fkeytab, M_KBDMUX);
534 free(kbd, M_KBDMUX);
535
536 return (0);
537}
538
539/*
540 * Keyboard interrupt routine
541 */
542static int
543kbdmux_intr(keyboard_t *kbd, void *arg)
544{
545 int c;
546
547 if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
548 /* let the callback function to process the input */
549 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
550 kbd->kb_callback.kc_arg);
551 } else {
552 /* read and discard the input; no one is waiting for input */
553 do {
554 c = kbdmux_read_char(kbd, FALSE);
555 } while (c != NOKEY);
556 }
557
558 return (0);
559}
560
561/*
562 * Test the interface to the device
563 */
564static int
565kbdmux_test_if(keyboard_t *kbd)
566{
567 return (0);
568}
569
570/*
571 * Enable the access to the device; until this function is called,
572 * the client cannot read from the keyboard.
573 */
574static int
575kbdmux_enable(keyboard_t *kbd)
576{
577 KBD_ACTIVATE(kbd);
578 return (0);
579}
580
581/*
582 * Disallow the access to the device
583 */
584static int
585kbdmux_disable(keyboard_t *kbd)
586{
587 KBD_DEACTIVATE(kbd);
588 return (0);
589}
590
591/*
592 * Read one byte from the keyboard if it's allowed
593 */
594static int
595kbdmux_read(keyboard_t *kbd, int wait)
596{
597 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
598 int c;
599
600 KBDMUX_LOCK(state);
601 c = kbdmux_kbd_getc(state);
602 KBDMUX_UNLOCK(state);
603
604 if (c != -1)
605 kbd->kb_count ++;
606
607 return (KBD_IS_ACTIVE(kbd)? c : -1);
608}
609
610/*
611 * Check if data is waiting
612 */
613static int
614kbdmux_check(keyboard_t *kbd)
615{
616 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
617 int ready;
618
619 if (!KBD_IS_ACTIVE(kbd))
620 return (FALSE);
621
622 KBDMUX_LOCK(state);
623 ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
624 KBDMUX_UNLOCK(state);
625
626 return (ready);
627}
628
629/*
630 * Read char from the keyboard (stolen from atkbd.c)
631 */
632static u_int
633kbdmux_read_char(keyboard_t *kbd, int wait)
634{
635 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
636 u_int action;
637 int scancode, keycode;
638
639 KBDMUX_LOCK(state);
640
641next_code:
642
643 /* do we have a composed char to return? */
644 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
645 action = state->ks_composed_char;
646 state->ks_composed_char = 0;
647 if (action > UCHAR_MAX) {
648 KBDMUX_UNLOCK(state);
649
650 return (ERRKEY);
651 }
652
653 KBDMUX_UNLOCK(state);
654
655 return (action);
656 }
657
658 /* see if there is something in the keyboard queue */
659 scancode = kbdmux_kbd_getc(state);
660 if (scancode == -1) {
661 if (state->ks_flags & POLLING) {
662 kbdmux_kbd_t *k;
663
664 SLIST_FOREACH(k, &state->ks_kbds, next) {
665 while (kbdd_check_char(k->kbd)) {
666 scancode = kbdd_read_char(k->kbd, 0);
667 if (scancode == NOKEY)
668 break;
669 if (scancode == ERRKEY)
670 continue;
671 if (!KBD_IS_BUSY(k->kbd))
672 continue;
673
674 kbdmux_kbd_putc(state, scancode);
675 }
676 }
677
678 if (state->ks_inq_length > 0)
679 goto next_code;
680 }
681
682 KBDMUX_UNLOCK(state);
683 return (NOKEY);
684 }
685 /* XXX FIXME: check for -1 if wait == 1! */
686
687 kbd->kb_count ++;
688
689 /* return the byte as is for the K_RAW mode */
690 if (state->ks_mode == K_RAW) {
691 KBDMUX_UNLOCK(state);
692 return (scancode);
693 }
694
695 /* translate the scan code into a keycode */
696 keycode = scancode & 0x7F;
697 switch (state->ks_prefix) {
698 case 0x00: /* normal scancode */
699 switch(scancode) {
700 case 0xB8: /* left alt (compose key) released */
701 if (state->ks_flags & COMPOSE) {
702 state->ks_flags &= ~COMPOSE;
703 if (state->ks_composed_char > UCHAR_MAX)
704 state->ks_composed_char = 0;
705 }
706 break;
707 case 0x38: /* left alt (compose key) pressed */
708 if (!(state->ks_flags & COMPOSE)) {
709 state->ks_flags |= COMPOSE;
710 state->ks_composed_char = 0;
711 }
712 break;
713 case 0xE0:
714 case 0xE1:
715 state->ks_prefix = scancode;
716 goto next_code;
717 }
718 break;
719 case 0xE0: /* 0xE0 prefix */
720 state->ks_prefix = 0;
721 switch (keycode) {
722 case 0x1C: /* right enter key */
723 keycode = 0x59;
724 break;
725 case 0x1D: /* right ctrl key */
726 keycode = 0x5A;
727 break;
728 case 0x35: /* keypad divide key */
729 keycode = 0x5B;
730 break;
731 case 0x37: /* print scrn key */
732 keycode = 0x5C;
733 break;
734 case 0x38: /* right alt key (alt gr) */
735 keycode = 0x5D;
736 break;
737 case 0x46: /* ctrl-pause/break on AT 101 (see below) */
738 keycode = 0x68;
739 break;
740 case 0x47: /* grey home key */
741 keycode = 0x5E;
742 break;
743 case 0x48: /* grey up arrow key */
744 keycode = 0x5F;
745 break;
746 case 0x49: /* grey page up key */
747 keycode = 0x60;
748 break;
749 case 0x4B: /* grey left arrow key */
750 keycode = 0x61;
751 break;
752 case 0x4D: /* grey right arrow key */
753 keycode = 0x62;
754 break;
755 case 0x4F: /* grey end key */
756 keycode = 0x63;
757 break;
758 case 0x50: /* grey down arrow key */
759 keycode = 0x64;
760 break;
761 case 0x51: /* grey page down key */
762 keycode = 0x65;
763 break;
764 case 0x52: /* grey insert key */
765 keycode = 0x66;
766 break;
767 case 0x53: /* grey delete key */
768 keycode = 0x67;
769 break;
770 /* the following 3 are only used on the MS "Natural" keyboard */
771 case 0x5b: /* left Window key */
772 keycode = 0x69;
773 break;
774 case 0x5c: /* right Window key */
775 keycode = 0x6a;
776 break;
777 case 0x5d: /* menu key */
778 keycode = 0x6b;
779 break;
780 case 0x5e: /* power key */
781 keycode = 0x6d;
782 break;
783 case 0x5f: /* sleep key */
784 keycode = 0x6e;
785 break;
786 case 0x63: /* wake key */
787 keycode = 0x6f;
788 break;
789 case 0x64: /* [JP106USB] backslash, underscore */
790 keycode = 0x73;
791 break;
792 default: /* ignore everything else */
793 goto next_code;
794 }
795 break;
796 case 0xE1: /* 0xE1 prefix */
797 /*
798 * The pause/break key on the 101 keyboard produces:
799 * E1-1D-45 E1-9D-C5
800 * Ctrl-pause/break produces:
801 * E0-46 E0-C6 (See above.)
802 */
803 state->ks_prefix = 0;
804 if (keycode == 0x1D)
805 state->ks_prefix = 0x1D;
806 goto next_code;
807 /* NOT REACHED */
808 case 0x1D: /* pause / break */
809 state->ks_prefix = 0;
810 if (keycode != 0x45)
811 goto next_code;
812 keycode = 0x68;
813 break;
814 }
815
816 /* XXX assume 101/102 keys AT keyboard */
817 switch (keycode) {
818 case 0x5c: /* print screen */
819 if (state->ks_flags & ALTS)
820 keycode = 0x54; /* sysrq */
821 break;
822 case 0x68: /* pause/break */
823 if (state->ks_flags & CTLS)
824 keycode = 0x6c; /* break */
825 break;
826 }
827
828 /* return the key code in the K_CODE mode */
829 if (state->ks_mode == K_CODE) {
830 KBDMUX_UNLOCK(state);
831 return (keycode | (scancode & 0x80));
832 }
833
834 /* compose a character code */
835 if (state->ks_flags & COMPOSE) {
836 switch (keycode | (scancode & 0x80)) {
837 /* key pressed, process it */
838 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
839 state->ks_composed_char *= 10;
840 state->ks_composed_char += keycode - 0x40;
841 if (state->ks_composed_char > UCHAR_MAX) {
842 KBDMUX_UNLOCK(state);
843 return (ERRKEY);
844 }
845 goto next_code;
846 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
847 state->ks_composed_char *= 10;
848 state->ks_composed_char += keycode - 0x47;
849 if (state->ks_composed_char > UCHAR_MAX) {
850 KBDMUX_UNLOCK(state);
851 return (ERRKEY);
852 }
853 goto next_code;
854 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
855 state->ks_composed_char *= 10;
856 state->ks_composed_char += keycode - 0x4E;
857 if (state->ks_composed_char > UCHAR_MAX) {
858 KBDMUX_UNLOCK(state);
859 return (ERRKEY);
860 }
861 goto next_code;
862 case 0x52: /* keypad 0 */
863 state->ks_composed_char *= 10;
864 if (state->ks_composed_char > UCHAR_MAX) {
865 KBDMUX_UNLOCK(state);
866 return (ERRKEY);
867 }
868 goto next_code;
869
870 /* key released, no interest here */
871 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
872 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
873 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
874 case 0xD2: /* keypad 0 */
875 goto next_code;
876
877 case 0x38: /* left alt key */
878 break;
879
880 default:
881 if (state->ks_composed_char > 0) {
882 state->ks_flags &= ~COMPOSE;
883 state->ks_composed_char = 0;
884 KBDMUX_UNLOCK(state);
885 return (ERRKEY);
886 }
887 break;
888 }
889 }
890
891 /* keycode to key action */
892 action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
893 &state->ks_state, &state->ks_accents);
894 if (action == NOKEY)
895 goto next_code;
896
897 KBDMUX_UNLOCK(state);
898
899 return (action);
900}
901
902/*
903 * Check if char is waiting
904 */
905static int
906kbdmux_check_char(keyboard_t *kbd)
907{
908 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
909 int ready;
910
911 if (!KBD_IS_ACTIVE(kbd))
912 return (FALSE);
913
914 KBDMUX_LOCK(state);
915
916 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
917 ready = TRUE;
918 else
919 ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
920
921 KBDMUX_UNLOCK(state);
922
923 return (ready);
924}
925
926/*
927 * Keyboard ioctl's
928 */
929static int
930kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
931{
932 static int delays[] = {
933 250, 500, 750, 1000
934 };
935
936 static int rates[] = {
937 34, 38, 42, 46, 50, 55, 59, 63,
938 68, 76, 84, 92, 100, 110, 118, 126,
939 136, 152, 168, 184, 200, 220, 236, 252,
940 272, 304, 336, 368, 400, 440, 472, 504
941 };
942
943 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
944 kbdmux_kbd_t *k;
945 keyboard_info_t *ki;
946 int error = 0, mode;
947#ifdef COMPAT_FREEBSD6
948 int ival;
949#endif
950
951 if (state == NULL)
952 return (ENXIO);
953
954 switch (cmd) {
955 case KBADDKBD: /* add keyboard to the mux */
956 ki = (keyboard_info_t *) arg;
957
958 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
959 strcmp(ki->kb_name, "*") == 0)
960 return (EINVAL); /* bad input */
961
962 KBDMUX_LOCK(state);
963
964 SLIST_FOREACH(k, &state->ks_kbds, next)
965 if (k->kbd->kb_unit == ki->kb_unit &&
966 strcmp(k->kbd->kb_name, ki->kb_name) == 0)
967 break;
968
969 if (k != NULL) {
970 KBDMUX_UNLOCK(state);
971
972 return (0); /* keyboard already in the mux */
973 }
974
975 k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
976 if (k == NULL) {
977 KBDMUX_UNLOCK(state);
978
979 return (ENOMEM); /* out of memory */
980 }
981
982 k->kbd = kbd_get_keyboard(
983 kbd_allocate(
984 ki->kb_name,
985 ki->kb_unit,
986 (void *) &k->kbd,
987 kbdmux_kbd_event, (void *) state));
988 if (k->kbd == NULL) {
989 KBDMUX_UNLOCK(state);
990 free(k, M_KBDMUX);
991
992 return (EINVAL); /* bad keyboard */
993 }
994
995 kbdd_enable(k->kbd);
996 kbdd_clear_state(k->kbd);
997
998 /* set K_RAW mode on slave keyboard */
999 mode = K_RAW;
1000 error = kbdd_ioctl(k->kbd, KDSKBMODE, (caddr_t)&mode);
1001 if (error == 0) {
1002 /* set lock keys state on slave keyboard */
1003 mode = state->ks_state & LOCK_MASK;
1004 error = kbdd_ioctl(k->kbd, KDSKBSTATE, (caddr_t)&mode);
1005 }
1006
1007 if (error != 0) {
1008 KBDMUX_UNLOCK(state);
1009
1010 kbd_release(k->kbd, &k->kbd);
1011 k->kbd = NULL;
1012
1013 free(k, M_KBDMUX);
1014
1015 return (error); /* could not set mode */
1016 }
1017
1018 SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
1019
1020 KBDMUX_UNLOCK(state);
1021 break;
1022
1023 case KBRELKBD: /* release keyboard from the mux */
1024 ki = (keyboard_info_t *) arg;
1025
1026 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
1027 strcmp(ki->kb_name, "*") == 0)
1028 return (EINVAL); /* bad input */
1029
1030 KBDMUX_LOCK(state);
1031
1032 SLIST_FOREACH(k, &state->ks_kbds, next)
1033 if (k->kbd->kb_unit == ki->kb_unit &&
1034 strcmp(k->kbd->kb_name, ki->kb_name) == 0)
1035 break;
1036
1037 if (k != NULL) {
1038 error = kbd_release(k->kbd, &k->kbd);
1039 if (error == 0) {
1040 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
1041
1042 k->kbd = NULL;
1043
1044 free(k, M_KBDMUX);
1045 }
1046 } else
1047 error = ENXIO; /* keyboard is not in the mux */
1048
1049 KBDMUX_UNLOCK(state);
1050 break;
1051
1052 case KDGKBMODE: /* get kyboard mode */
1053 KBDMUX_LOCK(state);
1054 *(int *)arg = state->ks_mode;
1055 KBDMUX_UNLOCK(state);
1056 break;
1057
1058#ifdef COMPAT_FREEBSD6
1059 case _IO('K', 7):
1060 ival = IOCPARM_IVAL(arg);
1061 arg = (caddr_t)&ival;
1062 /* FALLTHROUGH */
1063#endif
1064 case KDSKBMODE: /* set keyboard mode */
1065 KBDMUX_LOCK(state);
1066
1067 switch (*(int *)arg) {
1068 case K_XLATE:
1069 if (state->ks_mode != K_XLATE) {
1070 /* make lock key state and LED state match */
1071 state->ks_state &= ~LOCK_MASK;
1072 state->ks_state |= KBD_LED_VAL(kbd);
1073 }
1074 /* FALLTHROUGH */
1075
1076 case K_RAW:
1077 case K_CODE:
1078 if (state->ks_mode != *(int *)arg) {
1079 kbdmux_clear_state_locked(state);
1080 state->ks_mode = *(int *)arg;
1081 }
1082 break;
1083
1084 default:
1085 error = EINVAL;
1086 break;
1087 }
1088
1089 KBDMUX_UNLOCK(state);
1090 break;
1091
1092 case KDGETLED: /* get keyboard LED */
1093 KBDMUX_LOCK(state);
1094 *(int *)arg = KBD_LED_VAL(kbd);
1095 KBDMUX_UNLOCK(state);
1096 break;
1097
1098#ifdef COMPAT_FREEBSD6
1099 case _IO('K', 66):
1100 ival = IOCPARM_IVAL(arg);
1101 arg = (caddr_t)&ival;
1102 /* FALLTHROUGH */
1103#endif
1104 case KDSETLED: /* set keyboard LED */
1105 KBDMUX_LOCK(state);
1106
1107 /* NOTE: lock key state in ks_state won't be changed */
1108 if (*(int *)arg & ~LOCK_MASK) {
1109 KBDMUX_UNLOCK(state);
1110
1111 return (EINVAL);
1112 }
1113
1114 KBD_LED_VAL(kbd) = *(int *)arg;
1115
1116 /* KDSETLED on all slave keyboards */
1117 SLIST_FOREACH(k, &state->ks_kbds, next)
32 */
33
34#include "opt_compat.h"
35#include "opt_kbd.h"
36
37#include <sys/param.h>
38#include <sys/bus.h>
39#include <sys/conf.h>
40#include <sys/consio.h>
41#include <sys/fcntl.h>
42#include <sys/kbio.h>
43#include <sys/kernel.h>
44#include <sys/limits.h>
45#include <sys/lock.h>
46#include <sys/malloc.h>
47#include <sys/module.h>
48#include <sys/mutex.h>
49#include <sys/poll.h>
50#include <sys/proc.h>
51#include <sys/queue.h>
52#include <sys/selinfo.h>
53#include <sys/systm.h>
54#include <sys/taskqueue.h>
55#include <sys/uio.h>
56#include <dev/kbd/kbdreg.h>
57#include <dev/kbd/kbdtables.h>
58
59#define KEYBOARD_NAME "kbdmux"
60
61MALLOC_DECLARE(M_KBDMUX);
62MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
63
64/*****************************************************************************
65 *****************************************************************************
66 ** Keyboard state
67 *****************************************************************************
68 *****************************************************************************/
69
70#define KBDMUX_Q_SIZE 512 /* input queue size */
71
72/*
73 * XXX
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
77 * Giant is held.
78 */
79
80#if 0 /* not yet */
81#define KBDMUX_LOCK_DECL_GLOBAL \
82 struct mtx ks_lock
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)
99#else
100#define KBDMUX_LOCK_DECL_GLOBAL
101
102#define KBDMUX_LOCK_INIT(s)
103
104#define KBDMUX_LOCK_DESTROY(s)
105
106#define KBDMUX_LOCK(s)
107
108#define KBDMUX_UNLOCK(s)
109
110#define KBDMUX_LOCK_ASSERT(s, w)
111
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)
118#endif /* not yet */
119
120/*
121 * kbdmux keyboard
122 */
123struct kbdmux_kbd
124{
125 keyboard_t *kbd; /* keyboard */
126 SLIST_ENTRY(kbdmux_kbd) next; /* link to next */
127};
128
129typedef struct kbdmux_kbd kbdmux_kbd_t;
130
131/*
132 * kbdmux state
133 */
134struct kbdmux_state
135{
136 char ks_inq[KBDMUX_Q_SIZE]; /* input chars queue */
137 unsigned int ks_inq_start;
138 unsigned int ks_inq_length;
139 struct task ks_task; /* interrupt task */
140 struct callout ks_timo; /* timeout handler */
141#define TICKS (hz) /* rate */
142
143 int ks_flags; /* flags */
144#define COMPOSE (1 << 0) /* compose char flag */
145#define POLLING (1 << 1) /* polling */
146#define TASK (1 << 2) /* interrupt task queued */
147
148 int ks_mode; /* K_XLATE, K_RAW, K_CODE */
149 int ks_state; /* state */
150 int ks_accents; /* accent key index (> 0) */
151 u_int ks_composed_char; /* composed char code */
152 u_char ks_prefix; /* AT scan code prefix */
153
154 SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */
155
156 KBDMUX_LOCK_DECL_GLOBAL;
157};
158
159typedef struct kbdmux_state kbdmux_state_t;
160
161/*****************************************************************************
162 *****************************************************************************
163 ** Helper functions
164 *****************************************************************************
165 *****************************************************************************/
166
167static task_fn_t kbdmux_kbd_intr;
168static timeout_t kbdmux_kbd_intr_timo;
169static kbd_callback_func_t kbdmux_kbd_event;
170
171static void
172kbdmux_kbd_putc(kbdmux_state_t *state, char c)
173{
174 unsigned int p;
175
176 if (state->ks_inq_length == KBDMUX_Q_SIZE)
177 return;
178
179 p = (state->ks_inq_start + state->ks_inq_length) % KBDMUX_Q_SIZE;
180 state->ks_inq[p] = c;
181 state->ks_inq_length++;
182}
183
184static int
185kbdmux_kbd_getc(kbdmux_state_t *state)
186{
187 unsigned char c;
188
189 if (state->ks_inq_length == 0)
190 return (-1);
191
192 c = state->ks_inq[state->ks_inq_start];
193 state->ks_inq_start = (state->ks_inq_start + 1) % KBDMUX_Q_SIZE;
194 state->ks_inq_length--;
195
196 return (c);
197}
198
199/*
200 * Interrupt handler task
201 */
202void
203kbdmux_kbd_intr(void *xkbd, int pending)
204{
205 keyboard_t *kbd = (keyboard_t *) xkbd;
206 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
207
208 kbdd_intr(kbd, NULL);
209
210 KBDMUX_LOCK(state);
211
212 state->ks_flags &= ~TASK;
213 wakeup(&state->ks_task);
214
215 KBDMUX_UNLOCK(state);
216}
217
218/*
219 * Schedule interrupt handler on timeout. Called with locked state.
220 */
221void
222kbdmux_kbd_intr_timo(void *xstate)
223{
224 kbdmux_state_t *state = (kbdmux_state_t *) xstate;
225
226 KBDMUX_LOCK_ASSERT(state, MA_OWNED);
227
228 if (callout_pending(&state->ks_timo))
229 return; /* callout was reset */
230
231 if (!callout_active(&state->ks_timo))
232 return; /* callout was stopped */
233
234 callout_deactivate(&state->ks_timo);
235
236 /* queue interrupt task if needed */
237 if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) &&
238 KBDMUX_QUEUE_INTR(state) == 0)
239 state->ks_flags |= TASK;
240
241 /* re-schedule timeout */
242 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
243}
244
245/*
246 * Process event from one of our keyboards
247 */
248static int
249kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
250{
251 kbdmux_state_t *state = (kbdmux_state_t *) arg;
252
253 switch (event) {
254 case KBDIO_KEYINPUT: {
255 int c;
256
257 KBDMUX_LOCK(state);
258
259 /*
260 * Read all chars from the keyboard
261 *
262 * Turns out that atkbd(4) check_char() method may return
263 * "true" while read_char() method returns NOKEY. If this
264 * happens we could stuck in the loop below. Avoid this
265 * by breaking out of the loop if read_char() method returns
266 * NOKEY.
267 */
268
269 while (kbdd_check_char(kbd)) {
270 c = kbdd_read_char(kbd, 0);
271 if (c == NOKEY)
272 break;
273 if (c == ERRKEY)
274 continue; /* XXX ring bell */
275 if (!KBD_IS_BUSY(kbd))
276 continue; /* not open - discard the input */
277
278 kbdmux_kbd_putc(state, c);
279 }
280
281 /* queue interrupt task if needed */
282 if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) &&
283 KBDMUX_QUEUE_INTR(state) == 0)
284 state->ks_flags |= TASK;
285
286 KBDMUX_UNLOCK(state);
287 } break;
288
289 case KBDIO_UNLOADING: {
290 kbdmux_kbd_t *k;
291
292 KBDMUX_LOCK(state);
293
294 SLIST_FOREACH(k, &state->ks_kbds, next)
295 if (k->kbd == kbd)
296 break;
297
298 if (k != NULL) {
299 kbd_release(k->kbd, &k->kbd);
300 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
301
302 k->kbd = NULL;
303
304 free(k, M_KBDMUX);
305 }
306
307 KBDMUX_UNLOCK(state);
308 } break;
309
310 default:
311 return (EINVAL);
312 /* NOT REACHED */
313 }
314
315 return (0);
316}
317
318/****************************************************************************
319 ****************************************************************************
320 ** Keyboard driver
321 ****************************************************************************
322 ****************************************************************************/
323
324static int kbdmux_configure(int flags);
325static kbd_probe_t kbdmux_probe;
326static kbd_init_t kbdmux_init;
327static kbd_term_t kbdmux_term;
328static kbd_intr_t kbdmux_intr;
329static kbd_test_if_t kbdmux_test_if;
330static kbd_enable_t kbdmux_enable;
331static kbd_disable_t kbdmux_disable;
332static kbd_read_t kbdmux_read;
333static kbd_check_t kbdmux_check;
334static kbd_read_char_t kbdmux_read_char;
335static kbd_check_char_t kbdmux_check_char;
336static kbd_ioctl_t kbdmux_ioctl;
337static kbd_lock_t kbdmux_lock;
338static void kbdmux_clear_state_locked(kbdmux_state_t *state);
339static kbd_clear_state_t kbdmux_clear_state;
340static kbd_get_state_t kbdmux_get_state;
341static kbd_set_state_t kbdmux_set_state;
342static kbd_poll_mode_t kbdmux_poll;
343
344static keyboard_switch_t kbdmuxsw = {
345 .probe = kbdmux_probe,
346 .init = kbdmux_init,
347 .term = kbdmux_term,
348 .intr = kbdmux_intr,
349 .test_if = kbdmux_test_if,
350 .enable = kbdmux_enable,
351 .disable = kbdmux_disable,
352 .read = kbdmux_read,
353 .check = kbdmux_check,
354 .read_char = kbdmux_read_char,
355 .check_char = kbdmux_check_char,
356 .ioctl = kbdmux_ioctl,
357 .lock = kbdmux_lock,
358 .clear_state = kbdmux_clear_state,
359 .get_state = kbdmux_get_state,
360 .set_state = kbdmux_set_state,
361 .get_fkeystr = genkbd_get_fkeystr,
362 .poll = kbdmux_poll,
363 .diag = genkbd_diag,
364};
365
366/*
367 * Return the number of found keyboards
368 */
369static int
370kbdmux_configure(int flags)
371{
372 return (1);
373}
374
375/*
376 * Detect a keyboard
377 */
378static int
379kbdmux_probe(int unit, void *arg, int flags)
380{
381 if (resource_disabled(KEYBOARD_NAME, unit))
382 return (ENXIO);
383
384 return (0);
385}
386
387/*
388 * Reset and initialize the keyboard (stolen from atkbd.c)
389 */
390static int
391kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
392{
393 keyboard_t *kbd = NULL;
394 kbdmux_state_t *state = NULL;
395 keymap_t *keymap = NULL;
396 accentmap_t *accmap = NULL;
397 fkeytab_t *fkeymap = NULL;
398 int error, needfree, fkeymap_size, delay[2];
399
400 if (*kbdp == NULL) {
401 *kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
402 state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
403 keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
404 accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
405 fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
406 fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
407 needfree = 1;
408
409 if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
410 (accmap == NULL) || (fkeymap == NULL)) {
411 error = ENOMEM;
412 goto bad;
413 }
414
415 KBDMUX_LOCK_INIT(state);
416 TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
417 KBDMUX_CALLOUT_INIT(state);
418 SLIST_INIT(&state->ks_kbds);
419 } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
420 return (0);
421 } else {
422 kbd = *kbdp;
423 state = (kbdmux_state_t *) kbd->kb_data;
424 keymap = kbd->kb_keymap;
425 accmap = kbd->kb_accentmap;
426 fkeymap = kbd->kb_fkeytab;
427 fkeymap_size = kbd->kb_fkeytab_size;
428 needfree = 0;
429 }
430
431 if (!KBD_IS_PROBED(kbd)) {
432 /* XXX assume 101/102 keys keyboard */
433 kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0);
434 bcopy(&key_map, keymap, sizeof(key_map));
435 bcopy(&accent_map, accmap, sizeof(accent_map));
436 bcopy(fkey_tab, fkeymap,
437 imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
438 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
439 kbd->kb_data = (void *)state;
440
441 KBD_FOUND_DEVICE(kbd);
442 KBD_PROBE_DONE(kbd);
443
444 KBDMUX_LOCK(state);
445 kbdmux_clear_state_locked(state);
446 state->ks_mode = K_XLATE;
447 KBDMUX_UNLOCK(state);
448 }
449
450 if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
451 kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
452
453 kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
454
455 delay[0] = kbd->kb_delay1;
456 delay[1] = kbd->kb_delay2;
457 kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
458
459 KBD_INIT_DONE(kbd);
460 }
461
462 if (!KBD_IS_CONFIGURED(kbd)) {
463 if (kbd_register(kbd) < 0) {
464 error = ENXIO;
465 goto bad;
466 }
467
468 KBD_CONFIG_DONE(kbd);
469
470 KBDMUX_LOCK(state);
471 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
472 KBDMUX_UNLOCK(state);
473 }
474
475 return (0);
476bad:
477 if (needfree) {
478 if (state != NULL)
479 free(state, M_KBDMUX);
480 if (keymap != NULL)
481 free(keymap, M_KBDMUX);
482 if (accmap != NULL)
483 free(accmap, M_KBDMUX);
484 if (fkeymap != NULL)
485 free(fkeymap, M_KBDMUX);
486 if (kbd != NULL) {
487 free(kbd, M_KBDMUX);
488 *kbdp = NULL; /* insure ref doesn't leak to caller */
489 }
490 }
491
492 return (error);
493}
494
495/*
496 * Finish using this keyboard
497 */
498static int
499kbdmux_term(keyboard_t *kbd)
500{
501 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
502 kbdmux_kbd_t *k;
503
504 KBDMUX_LOCK(state);
505
506 /* kill callout */
507 callout_stop(&state->ks_timo);
508
509 /* wait for interrupt task */
510 while (state->ks_flags & TASK)
511 KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0);
512
513 /* release all keyboards from the mux */
514 while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
515 kbd_release(k->kbd, &k->kbd);
516 SLIST_REMOVE_HEAD(&state->ks_kbds, next);
517
518 k->kbd = NULL;
519
520 free(k, M_KBDMUX);
521 }
522
523 KBDMUX_UNLOCK(state);
524
525 kbd_unregister(kbd);
526
527 KBDMUX_LOCK_DESTROY(state);
528 bzero(state, sizeof(*state));
529 free(state, M_KBDMUX);
530
531 free(kbd->kb_keymap, M_KBDMUX);
532 free(kbd->kb_accentmap, M_KBDMUX);
533 free(kbd->kb_fkeytab, M_KBDMUX);
534 free(kbd, M_KBDMUX);
535
536 return (0);
537}
538
539/*
540 * Keyboard interrupt routine
541 */
542static int
543kbdmux_intr(keyboard_t *kbd, void *arg)
544{
545 int c;
546
547 if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
548 /* let the callback function to process the input */
549 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
550 kbd->kb_callback.kc_arg);
551 } else {
552 /* read and discard the input; no one is waiting for input */
553 do {
554 c = kbdmux_read_char(kbd, FALSE);
555 } while (c != NOKEY);
556 }
557
558 return (0);
559}
560
561/*
562 * Test the interface to the device
563 */
564static int
565kbdmux_test_if(keyboard_t *kbd)
566{
567 return (0);
568}
569
570/*
571 * Enable the access to the device; until this function is called,
572 * the client cannot read from the keyboard.
573 */
574static int
575kbdmux_enable(keyboard_t *kbd)
576{
577 KBD_ACTIVATE(kbd);
578 return (0);
579}
580
581/*
582 * Disallow the access to the device
583 */
584static int
585kbdmux_disable(keyboard_t *kbd)
586{
587 KBD_DEACTIVATE(kbd);
588 return (0);
589}
590
591/*
592 * Read one byte from the keyboard if it's allowed
593 */
594static int
595kbdmux_read(keyboard_t *kbd, int wait)
596{
597 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
598 int c;
599
600 KBDMUX_LOCK(state);
601 c = kbdmux_kbd_getc(state);
602 KBDMUX_UNLOCK(state);
603
604 if (c != -1)
605 kbd->kb_count ++;
606
607 return (KBD_IS_ACTIVE(kbd)? c : -1);
608}
609
610/*
611 * Check if data is waiting
612 */
613static int
614kbdmux_check(keyboard_t *kbd)
615{
616 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
617 int ready;
618
619 if (!KBD_IS_ACTIVE(kbd))
620 return (FALSE);
621
622 KBDMUX_LOCK(state);
623 ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
624 KBDMUX_UNLOCK(state);
625
626 return (ready);
627}
628
629/*
630 * Read char from the keyboard (stolen from atkbd.c)
631 */
632static u_int
633kbdmux_read_char(keyboard_t *kbd, int wait)
634{
635 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
636 u_int action;
637 int scancode, keycode;
638
639 KBDMUX_LOCK(state);
640
641next_code:
642
643 /* do we have a composed char to return? */
644 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
645 action = state->ks_composed_char;
646 state->ks_composed_char = 0;
647 if (action > UCHAR_MAX) {
648 KBDMUX_UNLOCK(state);
649
650 return (ERRKEY);
651 }
652
653 KBDMUX_UNLOCK(state);
654
655 return (action);
656 }
657
658 /* see if there is something in the keyboard queue */
659 scancode = kbdmux_kbd_getc(state);
660 if (scancode == -1) {
661 if (state->ks_flags & POLLING) {
662 kbdmux_kbd_t *k;
663
664 SLIST_FOREACH(k, &state->ks_kbds, next) {
665 while (kbdd_check_char(k->kbd)) {
666 scancode = kbdd_read_char(k->kbd, 0);
667 if (scancode == NOKEY)
668 break;
669 if (scancode == ERRKEY)
670 continue;
671 if (!KBD_IS_BUSY(k->kbd))
672 continue;
673
674 kbdmux_kbd_putc(state, scancode);
675 }
676 }
677
678 if (state->ks_inq_length > 0)
679 goto next_code;
680 }
681
682 KBDMUX_UNLOCK(state);
683 return (NOKEY);
684 }
685 /* XXX FIXME: check for -1 if wait == 1! */
686
687 kbd->kb_count ++;
688
689 /* return the byte as is for the K_RAW mode */
690 if (state->ks_mode == K_RAW) {
691 KBDMUX_UNLOCK(state);
692 return (scancode);
693 }
694
695 /* translate the scan code into a keycode */
696 keycode = scancode & 0x7F;
697 switch (state->ks_prefix) {
698 case 0x00: /* normal scancode */
699 switch(scancode) {
700 case 0xB8: /* left alt (compose key) released */
701 if (state->ks_flags & COMPOSE) {
702 state->ks_flags &= ~COMPOSE;
703 if (state->ks_composed_char > UCHAR_MAX)
704 state->ks_composed_char = 0;
705 }
706 break;
707 case 0x38: /* left alt (compose key) pressed */
708 if (!(state->ks_flags & COMPOSE)) {
709 state->ks_flags |= COMPOSE;
710 state->ks_composed_char = 0;
711 }
712 break;
713 case 0xE0:
714 case 0xE1:
715 state->ks_prefix = scancode;
716 goto next_code;
717 }
718 break;
719 case 0xE0: /* 0xE0 prefix */
720 state->ks_prefix = 0;
721 switch (keycode) {
722 case 0x1C: /* right enter key */
723 keycode = 0x59;
724 break;
725 case 0x1D: /* right ctrl key */
726 keycode = 0x5A;
727 break;
728 case 0x35: /* keypad divide key */
729 keycode = 0x5B;
730 break;
731 case 0x37: /* print scrn key */
732 keycode = 0x5C;
733 break;
734 case 0x38: /* right alt key (alt gr) */
735 keycode = 0x5D;
736 break;
737 case 0x46: /* ctrl-pause/break on AT 101 (see below) */
738 keycode = 0x68;
739 break;
740 case 0x47: /* grey home key */
741 keycode = 0x5E;
742 break;
743 case 0x48: /* grey up arrow key */
744 keycode = 0x5F;
745 break;
746 case 0x49: /* grey page up key */
747 keycode = 0x60;
748 break;
749 case 0x4B: /* grey left arrow key */
750 keycode = 0x61;
751 break;
752 case 0x4D: /* grey right arrow key */
753 keycode = 0x62;
754 break;
755 case 0x4F: /* grey end key */
756 keycode = 0x63;
757 break;
758 case 0x50: /* grey down arrow key */
759 keycode = 0x64;
760 break;
761 case 0x51: /* grey page down key */
762 keycode = 0x65;
763 break;
764 case 0x52: /* grey insert key */
765 keycode = 0x66;
766 break;
767 case 0x53: /* grey delete key */
768 keycode = 0x67;
769 break;
770 /* the following 3 are only used on the MS "Natural" keyboard */
771 case 0x5b: /* left Window key */
772 keycode = 0x69;
773 break;
774 case 0x5c: /* right Window key */
775 keycode = 0x6a;
776 break;
777 case 0x5d: /* menu key */
778 keycode = 0x6b;
779 break;
780 case 0x5e: /* power key */
781 keycode = 0x6d;
782 break;
783 case 0x5f: /* sleep key */
784 keycode = 0x6e;
785 break;
786 case 0x63: /* wake key */
787 keycode = 0x6f;
788 break;
789 case 0x64: /* [JP106USB] backslash, underscore */
790 keycode = 0x73;
791 break;
792 default: /* ignore everything else */
793 goto next_code;
794 }
795 break;
796 case 0xE1: /* 0xE1 prefix */
797 /*
798 * The pause/break key on the 101 keyboard produces:
799 * E1-1D-45 E1-9D-C5
800 * Ctrl-pause/break produces:
801 * E0-46 E0-C6 (See above.)
802 */
803 state->ks_prefix = 0;
804 if (keycode == 0x1D)
805 state->ks_prefix = 0x1D;
806 goto next_code;
807 /* NOT REACHED */
808 case 0x1D: /* pause / break */
809 state->ks_prefix = 0;
810 if (keycode != 0x45)
811 goto next_code;
812 keycode = 0x68;
813 break;
814 }
815
816 /* XXX assume 101/102 keys AT keyboard */
817 switch (keycode) {
818 case 0x5c: /* print screen */
819 if (state->ks_flags & ALTS)
820 keycode = 0x54; /* sysrq */
821 break;
822 case 0x68: /* pause/break */
823 if (state->ks_flags & CTLS)
824 keycode = 0x6c; /* break */
825 break;
826 }
827
828 /* return the key code in the K_CODE mode */
829 if (state->ks_mode == K_CODE) {
830 KBDMUX_UNLOCK(state);
831 return (keycode | (scancode & 0x80));
832 }
833
834 /* compose a character code */
835 if (state->ks_flags & COMPOSE) {
836 switch (keycode | (scancode & 0x80)) {
837 /* key pressed, process it */
838 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
839 state->ks_composed_char *= 10;
840 state->ks_composed_char += keycode - 0x40;
841 if (state->ks_composed_char > UCHAR_MAX) {
842 KBDMUX_UNLOCK(state);
843 return (ERRKEY);
844 }
845 goto next_code;
846 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
847 state->ks_composed_char *= 10;
848 state->ks_composed_char += keycode - 0x47;
849 if (state->ks_composed_char > UCHAR_MAX) {
850 KBDMUX_UNLOCK(state);
851 return (ERRKEY);
852 }
853 goto next_code;
854 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
855 state->ks_composed_char *= 10;
856 state->ks_composed_char += keycode - 0x4E;
857 if (state->ks_composed_char > UCHAR_MAX) {
858 KBDMUX_UNLOCK(state);
859 return (ERRKEY);
860 }
861 goto next_code;
862 case 0x52: /* keypad 0 */
863 state->ks_composed_char *= 10;
864 if (state->ks_composed_char > UCHAR_MAX) {
865 KBDMUX_UNLOCK(state);
866 return (ERRKEY);
867 }
868 goto next_code;
869
870 /* key released, no interest here */
871 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
872 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
873 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
874 case 0xD2: /* keypad 0 */
875 goto next_code;
876
877 case 0x38: /* left alt key */
878 break;
879
880 default:
881 if (state->ks_composed_char > 0) {
882 state->ks_flags &= ~COMPOSE;
883 state->ks_composed_char = 0;
884 KBDMUX_UNLOCK(state);
885 return (ERRKEY);
886 }
887 break;
888 }
889 }
890
891 /* keycode to key action */
892 action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
893 &state->ks_state, &state->ks_accents);
894 if (action == NOKEY)
895 goto next_code;
896
897 KBDMUX_UNLOCK(state);
898
899 return (action);
900}
901
902/*
903 * Check if char is waiting
904 */
905static int
906kbdmux_check_char(keyboard_t *kbd)
907{
908 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
909 int ready;
910
911 if (!KBD_IS_ACTIVE(kbd))
912 return (FALSE);
913
914 KBDMUX_LOCK(state);
915
916 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
917 ready = TRUE;
918 else
919 ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
920
921 KBDMUX_UNLOCK(state);
922
923 return (ready);
924}
925
926/*
927 * Keyboard ioctl's
928 */
929static int
930kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
931{
932 static int delays[] = {
933 250, 500, 750, 1000
934 };
935
936 static int rates[] = {
937 34, 38, 42, 46, 50, 55, 59, 63,
938 68, 76, 84, 92, 100, 110, 118, 126,
939 136, 152, 168, 184, 200, 220, 236, 252,
940 272, 304, 336, 368, 400, 440, 472, 504
941 };
942
943 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
944 kbdmux_kbd_t *k;
945 keyboard_info_t *ki;
946 int error = 0, mode;
947#ifdef COMPAT_FREEBSD6
948 int ival;
949#endif
950
951 if (state == NULL)
952 return (ENXIO);
953
954 switch (cmd) {
955 case KBADDKBD: /* add keyboard to the mux */
956 ki = (keyboard_info_t *) arg;
957
958 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
959 strcmp(ki->kb_name, "*") == 0)
960 return (EINVAL); /* bad input */
961
962 KBDMUX_LOCK(state);
963
964 SLIST_FOREACH(k, &state->ks_kbds, next)
965 if (k->kbd->kb_unit == ki->kb_unit &&
966 strcmp(k->kbd->kb_name, ki->kb_name) == 0)
967 break;
968
969 if (k != NULL) {
970 KBDMUX_UNLOCK(state);
971
972 return (0); /* keyboard already in the mux */
973 }
974
975 k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
976 if (k == NULL) {
977 KBDMUX_UNLOCK(state);
978
979 return (ENOMEM); /* out of memory */
980 }
981
982 k->kbd = kbd_get_keyboard(
983 kbd_allocate(
984 ki->kb_name,
985 ki->kb_unit,
986 (void *) &k->kbd,
987 kbdmux_kbd_event, (void *) state));
988 if (k->kbd == NULL) {
989 KBDMUX_UNLOCK(state);
990 free(k, M_KBDMUX);
991
992 return (EINVAL); /* bad keyboard */
993 }
994
995 kbdd_enable(k->kbd);
996 kbdd_clear_state(k->kbd);
997
998 /* set K_RAW mode on slave keyboard */
999 mode = K_RAW;
1000 error = kbdd_ioctl(k->kbd, KDSKBMODE, (caddr_t)&mode);
1001 if (error == 0) {
1002 /* set lock keys state on slave keyboard */
1003 mode = state->ks_state & LOCK_MASK;
1004 error = kbdd_ioctl(k->kbd, KDSKBSTATE, (caddr_t)&mode);
1005 }
1006
1007 if (error != 0) {
1008 KBDMUX_UNLOCK(state);
1009
1010 kbd_release(k->kbd, &k->kbd);
1011 k->kbd = NULL;
1012
1013 free(k, M_KBDMUX);
1014
1015 return (error); /* could not set mode */
1016 }
1017
1018 SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
1019
1020 KBDMUX_UNLOCK(state);
1021 break;
1022
1023 case KBRELKBD: /* release keyboard from the mux */
1024 ki = (keyboard_info_t *) arg;
1025
1026 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
1027 strcmp(ki->kb_name, "*") == 0)
1028 return (EINVAL); /* bad input */
1029
1030 KBDMUX_LOCK(state);
1031
1032 SLIST_FOREACH(k, &state->ks_kbds, next)
1033 if (k->kbd->kb_unit == ki->kb_unit &&
1034 strcmp(k->kbd->kb_name, ki->kb_name) == 0)
1035 break;
1036
1037 if (k != NULL) {
1038 error = kbd_release(k->kbd, &k->kbd);
1039 if (error == 0) {
1040 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
1041
1042 k->kbd = NULL;
1043
1044 free(k, M_KBDMUX);
1045 }
1046 } else
1047 error = ENXIO; /* keyboard is not in the mux */
1048
1049 KBDMUX_UNLOCK(state);
1050 break;
1051
1052 case KDGKBMODE: /* get kyboard mode */
1053 KBDMUX_LOCK(state);
1054 *(int *)arg = state->ks_mode;
1055 KBDMUX_UNLOCK(state);
1056 break;
1057
1058#ifdef COMPAT_FREEBSD6
1059 case _IO('K', 7):
1060 ival = IOCPARM_IVAL(arg);
1061 arg = (caddr_t)&ival;
1062 /* FALLTHROUGH */
1063#endif
1064 case KDSKBMODE: /* set keyboard mode */
1065 KBDMUX_LOCK(state);
1066
1067 switch (*(int *)arg) {
1068 case K_XLATE:
1069 if (state->ks_mode != K_XLATE) {
1070 /* make lock key state and LED state match */
1071 state->ks_state &= ~LOCK_MASK;
1072 state->ks_state |= KBD_LED_VAL(kbd);
1073 }
1074 /* FALLTHROUGH */
1075
1076 case K_RAW:
1077 case K_CODE:
1078 if (state->ks_mode != *(int *)arg) {
1079 kbdmux_clear_state_locked(state);
1080 state->ks_mode = *(int *)arg;
1081 }
1082 break;
1083
1084 default:
1085 error = EINVAL;
1086 break;
1087 }
1088
1089 KBDMUX_UNLOCK(state);
1090 break;
1091
1092 case KDGETLED: /* get keyboard LED */
1093 KBDMUX_LOCK(state);
1094 *(int *)arg = KBD_LED_VAL(kbd);
1095 KBDMUX_UNLOCK(state);
1096 break;
1097
1098#ifdef COMPAT_FREEBSD6
1099 case _IO('K', 66):
1100 ival = IOCPARM_IVAL(arg);
1101 arg = (caddr_t)&ival;
1102 /* FALLTHROUGH */
1103#endif
1104 case KDSETLED: /* set keyboard LED */
1105 KBDMUX_LOCK(state);
1106
1107 /* NOTE: lock key state in ks_state won't be changed */
1108 if (*(int *)arg & ~LOCK_MASK) {
1109 KBDMUX_UNLOCK(state);
1110
1111 return (EINVAL);
1112 }
1113
1114 KBD_LED_VAL(kbd) = *(int *)arg;
1115
1116 /* KDSETLED on all slave keyboards */
1117 SLIST_FOREACH(k, &state->ks_kbds, next)
1118 kbdd_ioctl(k->kbd, KDSETLED, arg);
1118 (void)kbdd_ioctl(k->kbd, KDSETLED, arg);
1119
1120 KBDMUX_UNLOCK(state);
1121 break;
1122
1123 case KDGKBSTATE: /* get lock key state */
1124 KBDMUX_LOCK(state);
1125 *(int *)arg = state->ks_state & LOCK_MASK;
1126 KBDMUX_UNLOCK(state);
1127 break;
1128
1129#ifdef COMPAT_FREEBSD6
1130 case _IO('K', 20):
1131 ival = IOCPARM_IVAL(arg);
1132 arg = (caddr_t)&ival;
1133 /* FALLTHROUGH */
1134#endif
1135 case KDSKBSTATE: /* set lock key state */
1136 KBDMUX_LOCK(state);
1137
1138 if (*(int *)arg & ~LOCK_MASK) {
1139 KBDMUX_UNLOCK(state);
1140
1141 return (EINVAL);
1142 }
1143
1144 state->ks_state &= ~LOCK_MASK;
1145 state->ks_state |= *(int *)arg;
1146
1147 /* KDSKBSTATE on all slave keyboards */
1148 SLIST_FOREACH(k, &state->ks_kbds, next)
1119
1120 KBDMUX_UNLOCK(state);
1121 break;
1122
1123 case KDGKBSTATE: /* get lock key state */
1124 KBDMUX_LOCK(state);
1125 *(int *)arg = state->ks_state & LOCK_MASK;
1126 KBDMUX_UNLOCK(state);
1127 break;
1128
1129#ifdef COMPAT_FREEBSD6
1130 case _IO('K', 20):
1131 ival = IOCPARM_IVAL(arg);
1132 arg = (caddr_t)&ival;
1133 /* FALLTHROUGH */
1134#endif
1135 case KDSKBSTATE: /* set lock key state */
1136 KBDMUX_LOCK(state);
1137
1138 if (*(int *)arg & ~LOCK_MASK) {
1139 KBDMUX_UNLOCK(state);
1140
1141 return (EINVAL);
1142 }
1143
1144 state->ks_state &= ~LOCK_MASK;
1145 state->ks_state |= *(int *)arg;
1146
1147 /* KDSKBSTATE on all slave keyboards */
1148 SLIST_FOREACH(k, &state->ks_kbds, next)
1149 kbdd_ioctl(k->kbd, KDSKBSTATE, arg);
1149 (void)kbdd_ioctl(k->kbd, KDSKBSTATE, arg);
1150
1151 KBDMUX_UNLOCK(state);
1152
1153 return (kbdmux_ioctl(kbd, KDSETLED, arg));
1154 /* NOT REACHED */
1155
1156#ifdef COMPAT_FREEBSD6
1157 case _IO('K', 67):
1158 cmd = KDSETRAD;
1159 ival = IOCPARM_IVAL(arg);
1160 arg = (caddr_t)&ival;
1161 /* FALLTHROUGH */
1162#endif
1163 case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1164 case KDSETRAD: /* set keyboard repeat rate (old interface) */
1165 KBDMUX_LOCK(state);
1166
1167 if (cmd == KDSETREPEAT) {
1168 int i;
1169
1170 /* lookup delay */
1171 for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --)
1172 if (((int *)arg)[0] >= delays[i])
1173 break;
1174 mode = i << 5;
1175
1176 /* lookup rate */
1177 for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --)
1178 if (((int *)arg)[1] >= rates[i])
1179 break;
1180 mode |= i;
1181 } else
1182 mode = *(int *)arg;
1183
1184 if (mode & ~0x7f) {
1185 KBDMUX_UNLOCK(state);
1186
1187 return (EINVAL);
1188 }
1189
1190 kbd->kb_delay1 = delays[(mode >> 5) & 3];
1191 kbd->kb_delay2 = rates[mode & 0x1f];
1192
1193 /* perform command on all slave keyboards */
1194 SLIST_FOREACH(k, &state->ks_kbds, next)
1150
1151 KBDMUX_UNLOCK(state);
1152
1153 return (kbdmux_ioctl(kbd, KDSETLED, arg));
1154 /* NOT REACHED */
1155
1156#ifdef COMPAT_FREEBSD6
1157 case _IO('K', 67):
1158 cmd = KDSETRAD;
1159 ival = IOCPARM_IVAL(arg);
1160 arg = (caddr_t)&ival;
1161 /* FALLTHROUGH */
1162#endif
1163 case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1164 case KDSETRAD: /* set keyboard repeat rate (old interface) */
1165 KBDMUX_LOCK(state);
1166
1167 if (cmd == KDSETREPEAT) {
1168 int i;
1169
1170 /* lookup delay */
1171 for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --)
1172 if (((int *)arg)[0] >= delays[i])
1173 break;
1174 mode = i << 5;
1175
1176 /* lookup rate */
1177 for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --)
1178 if (((int *)arg)[1] >= rates[i])
1179 break;
1180 mode |= i;
1181 } else
1182 mode = *(int *)arg;
1183
1184 if (mode & ~0x7f) {
1185 KBDMUX_UNLOCK(state);
1186
1187 return (EINVAL);
1188 }
1189
1190 kbd->kb_delay1 = delays[(mode >> 5) & 3];
1191 kbd->kb_delay2 = rates[mode & 0x1f];
1192
1193 /* perform command on all slave keyboards */
1194 SLIST_FOREACH(k, &state->ks_kbds, next)
1195 kbdd_ioctl(k->kbd, cmd, arg);
1195 (void)kbdd_ioctl(k->kbd, cmd, arg);
1196
1197 KBDMUX_UNLOCK(state);
1198 break;
1199
1200 case PIO_KEYMAP: /* set keyboard translation table */
1201 case PIO_KEYMAPENT: /* set keyboard translation table entry */
1202 case PIO_DEADKEYMAP: /* set accent key translation table */
1203 KBDMUX_LOCK(state);
1204 state->ks_accents = 0;
1205
1206 /* perform command on all slave keyboards */
1207 SLIST_FOREACH(k, &state->ks_kbds, next)
1196
1197 KBDMUX_UNLOCK(state);
1198 break;
1199
1200 case PIO_KEYMAP: /* set keyboard translation table */
1201 case PIO_KEYMAPENT: /* set keyboard translation table entry */
1202 case PIO_DEADKEYMAP: /* set accent key translation table */
1203 KBDMUX_LOCK(state);
1204 state->ks_accents = 0;
1205
1206 /* perform command on all slave keyboards */
1207 SLIST_FOREACH(k, &state->ks_kbds, next)
1208 kbdd_ioctl(k->kbd, cmd, arg);
1208 (void)kbdd_ioctl(k->kbd, cmd, arg);
1209
1210 KBDMUX_UNLOCK(state);
1211 /* FALLTHROUGH */
1212
1213 default:
1214 error = genkbd_commonioctl(kbd, cmd, arg);
1215 break;
1216 }
1217
1218 return (error);
1219}
1220
1221/*
1222 * Lock the access to the keyboard
1223 */
1224static int
1225kbdmux_lock(keyboard_t *kbd, int lock)
1226{
1227 return (1); /* XXX */
1228}
1229
1230/*
1231 * Clear the internal state of the keyboard
1232 */
1233static void
1234kbdmux_clear_state_locked(kbdmux_state_t *state)
1235{
1236 KBDMUX_LOCK_ASSERT(state, MA_OWNED);
1237
1238 state->ks_flags &= ~(COMPOSE|POLLING);
1239 state->ks_state &= LOCK_MASK; /* preserve locking key state */
1240 state->ks_accents = 0;
1241 state->ks_composed_char = 0;
1242/* state->ks_prefix = 0; XXX */
1243 state->ks_inq_length = 0;
1244}
1245
1246static void
1247kbdmux_clear_state(keyboard_t *kbd)
1248{
1249 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1250
1251 KBDMUX_LOCK(state);
1252 kbdmux_clear_state_locked(state);
1253 KBDMUX_UNLOCK(state);
1254}
1255
1256/*
1257 * Save the internal state
1258 */
1259static int
1260kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1261{
1262 if (len == 0)
1263 return (sizeof(kbdmux_state_t));
1264 if (len < sizeof(kbdmux_state_t))
1265 return (-1);
1266
1267 bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1268
1269 return (0);
1270}
1271
1272/*
1273 * Set the internal state
1274 */
1275static int
1276kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1277{
1278 if (len < sizeof(kbdmux_state_t))
1279 return (ENOMEM);
1280
1281 bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1282
1283 return (0);
1284}
1285
1286/*
1287 * Set polling
1288 */
1289static int
1290kbdmux_poll(keyboard_t *kbd, int on)
1291{
1292 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1293 kbdmux_kbd_t *k;
1294
1295 KBDMUX_LOCK(state);
1296
1297 if (on)
1298 state->ks_flags |= POLLING;
1299 else
1300 state->ks_flags &= ~POLLING;
1301
1302 /* set poll on slave keyboards */
1303 SLIST_FOREACH(k, &state->ks_kbds, next)
1304 kbdd_poll(k->kbd, on);
1305
1306 KBDMUX_UNLOCK(state);
1307
1308 return (0);
1309}
1310
1311/*****************************************************************************
1312 *****************************************************************************
1313 ** Module
1314 *****************************************************************************
1315 *****************************************************************************/
1316
1317KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1318
1319static int
1320kbdmux_modevent(module_t mod, int type, void *data)
1321{
1322 keyboard_switch_t *sw;
1323 keyboard_t *kbd;
1324 int error;
1325
1326 switch (type) {
1327 case MOD_LOAD:
1328 if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1329 break;
1330
1331 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1332 kbd_delete_driver(&kbdmux_kbd_driver);
1333 error = ENXIO;
1334 break;
1335 }
1336
1337 kbd = NULL;
1338
1339 if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
1340 (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) {
1341 kbd_delete_driver(&kbdmux_kbd_driver);
1342 break;
1343 }
1344
1345#ifdef KBD_INSTALL_CDEV
1346 if ((error = kbd_attach(kbd)) != 0) {
1347 (*sw->term)(kbd);
1348 kbd_delete_driver(&kbdmux_kbd_driver);
1349 break;
1350 }
1351#endif
1352
1353 if ((error = (*sw->enable)(kbd)) != 0) {
1354 (*sw->disable)(kbd);
1355#ifdef KBD_INSTALL_CDEV
1356 kbd_detach(kbd);
1357#endif
1358 (*sw->term)(kbd);
1359 kbd_delete_driver(&kbdmux_kbd_driver);
1360 break;
1361 }
1362 break;
1363
1364 case MOD_UNLOAD:
1365 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
1366 panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
1367
1368 kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1369 if (kbd != NULL) {
1370 (*sw->disable)(kbd);
1371#ifdef KBD_INSTALL_CDEV
1372 kbd_detach(kbd);
1373#endif
1374 (*sw->term)(kbd);
1375 kbd_delete_driver(&kbdmux_kbd_driver);
1376 }
1377 error = 0;
1378 break;
1379
1380 default:
1381 error = EOPNOTSUPP;
1382 break;
1383 }
1384
1385 return (error);
1386}
1387
1388DEV_MODULE(kbdmux, kbdmux_modevent, NULL);
1389
1209
1210 KBDMUX_UNLOCK(state);
1211 /* FALLTHROUGH */
1212
1213 default:
1214 error = genkbd_commonioctl(kbd, cmd, arg);
1215 break;
1216 }
1217
1218 return (error);
1219}
1220
1221/*
1222 * Lock the access to the keyboard
1223 */
1224static int
1225kbdmux_lock(keyboard_t *kbd, int lock)
1226{
1227 return (1); /* XXX */
1228}
1229
1230/*
1231 * Clear the internal state of the keyboard
1232 */
1233static void
1234kbdmux_clear_state_locked(kbdmux_state_t *state)
1235{
1236 KBDMUX_LOCK_ASSERT(state, MA_OWNED);
1237
1238 state->ks_flags &= ~(COMPOSE|POLLING);
1239 state->ks_state &= LOCK_MASK; /* preserve locking key state */
1240 state->ks_accents = 0;
1241 state->ks_composed_char = 0;
1242/* state->ks_prefix = 0; XXX */
1243 state->ks_inq_length = 0;
1244}
1245
1246static void
1247kbdmux_clear_state(keyboard_t *kbd)
1248{
1249 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1250
1251 KBDMUX_LOCK(state);
1252 kbdmux_clear_state_locked(state);
1253 KBDMUX_UNLOCK(state);
1254}
1255
1256/*
1257 * Save the internal state
1258 */
1259static int
1260kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1261{
1262 if (len == 0)
1263 return (sizeof(kbdmux_state_t));
1264 if (len < sizeof(kbdmux_state_t))
1265 return (-1);
1266
1267 bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1268
1269 return (0);
1270}
1271
1272/*
1273 * Set the internal state
1274 */
1275static int
1276kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1277{
1278 if (len < sizeof(kbdmux_state_t))
1279 return (ENOMEM);
1280
1281 bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1282
1283 return (0);
1284}
1285
1286/*
1287 * Set polling
1288 */
1289static int
1290kbdmux_poll(keyboard_t *kbd, int on)
1291{
1292 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1293 kbdmux_kbd_t *k;
1294
1295 KBDMUX_LOCK(state);
1296
1297 if (on)
1298 state->ks_flags |= POLLING;
1299 else
1300 state->ks_flags &= ~POLLING;
1301
1302 /* set poll on slave keyboards */
1303 SLIST_FOREACH(k, &state->ks_kbds, next)
1304 kbdd_poll(k->kbd, on);
1305
1306 KBDMUX_UNLOCK(state);
1307
1308 return (0);
1309}
1310
1311/*****************************************************************************
1312 *****************************************************************************
1313 ** Module
1314 *****************************************************************************
1315 *****************************************************************************/
1316
1317KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1318
1319static int
1320kbdmux_modevent(module_t mod, int type, void *data)
1321{
1322 keyboard_switch_t *sw;
1323 keyboard_t *kbd;
1324 int error;
1325
1326 switch (type) {
1327 case MOD_LOAD:
1328 if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1329 break;
1330
1331 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1332 kbd_delete_driver(&kbdmux_kbd_driver);
1333 error = ENXIO;
1334 break;
1335 }
1336
1337 kbd = NULL;
1338
1339 if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
1340 (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) {
1341 kbd_delete_driver(&kbdmux_kbd_driver);
1342 break;
1343 }
1344
1345#ifdef KBD_INSTALL_CDEV
1346 if ((error = kbd_attach(kbd)) != 0) {
1347 (*sw->term)(kbd);
1348 kbd_delete_driver(&kbdmux_kbd_driver);
1349 break;
1350 }
1351#endif
1352
1353 if ((error = (*sw->enable)(kbd)) != 0) {
1354 (*sw->disable)(kbd);
1355#ifdef KBD_INSTALL_CDEV
1356 kbd_detach(kbd);
1357#endif
1358 (*sw->term)(kbd);
1359 kbd_delete_driver(&kbdmux_kbd_driver);
1360 break;
1361 }
1362 break;
1363
1364 case MOD_UNLOAD:
1365 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
1366 panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
1367
1368 kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1369 if (kbd != NULL) {
1370 (*sw->disable)(kbd);
1371#ifdef KBD_INSTALL_CDEV
1372 kbd_detach(kbd);
1373#endif
1374 (*sw->term)(kbd);
1375 kbd_delete_driver(&kbdmux_kbd_driver);
1376 }
1377 error = 0;
1378 break;
1379
1380 default:
1381 error = EOPNOTSUPP;
1382 break;
1383 }
1384
1385 return (error);
1386}
1387
1388DEV_MODULE(kbdmux, kbdmux_modevent, NULL);
1389