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$
32 */
33
34 #include "opt_kbd.h"
35
36 #include <sys/param.h>
37 #include <sys/bus.h>
38 #include <sys/conf.h>
39 #include <sys/consio.h>
40 #include <sys/fcntl.h>
41 #include <sys/kbio.h>
42 #include <sys/kernel.h>
43 #include <sys/limits.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/module.h>
47 #include <sys/mutex.h>
48 #include <sys/poll.h>
49 #include <sys/proc.h>
50 #include <sys/queue.h>
51 #include <sys/selinfo.h>
52 #include <sys/systm.h>
53 #include <sys/taskqueue.h>
54 #include <sys/tty.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
61 MALLOC_DECLARE(M_KBDMUX);
62 MALLOC_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 #define KBDMUX_INTR(kbd, arg) \
121 (*kbdsw[(kbd)->kb_index]->intr)((kbd), (arg))
122
123 #define KBDMUX_IOCTL(kbd, cmd, arg) \
124 (*kbdsw[(kbd)->kb_index]->ioctl)((kbd), (cmd), (caddr_t) (arg))
125
126 #define KBDMUX_CHECK_CHAR(kbd) \
127 (*kbdsw[(kbd)->kb_index]->check_char)((kbd))
128
129 #define KBDMUX_READ_CHAR(kbd, wait) \
130 (*kbdsw[(kbd)->kb_index]->read_char)((kbd), (wait))
131
132 #define KBDMUX_ENABLE(kbd) \
133 (*kbdsw[(kbd)->kb_index]->enable)((kbd))
134
135 #define KBDMUX_POLL(kbd, on) \
136 (*kbdsw[(kbd)->kb_index]->poll)((kbd), (on))
137
138 #define KBDMUX_CLEAR_STATE(kbd) \
139 (*kbdsw[(kbd)->kb_index]->clear_state)((kbd))
140
141 /*
142 * kbdmux keyboard
143 */
144 struct kbdmux_kbd
145 {
146 keyboard_t *kbd; /* keyboard */
147 SLIST_ENTRY(kbdmux_kbd) next; /* link to next */
148 };
149
150 typedef struct kbdmux_kbd kbdmux_kbd_t;
151
152 /*
153 * kbdmux state
154 */
155 struct kbdmux_state
156 {
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 */
161
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 */
166
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 */
172
173 SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */
174
175 KBDMUX_LOCK_DECL_GLOBAL;
176 };
177
178 typedef struct kbdmux_state kbdmux_state_t;
179
180 /*****************************************************************************
181 *****************************************************************************
182 ** Helper functions
183 *****************************************************************************
184 *****************************************************************************/
185
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;
189
190 /*
191 * Interrupt handler task
192 */
193 void
194 kbdmux_kbd_intr(void *xkbd, int pending)
195 {
196 keyboard_t *kbd = (keyboard_t *) xkbd;
197 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
198
199 KBDMUX_INTR(kbd, NULL);
200
201 KBDMUX_LOCK(state);
202
203 state->ks_flags &= ~TASK;
204 wakeup(&state->ks_task);
205
206 KBDMUX_UNLOCK(state);
207 }
208
209 /*
210 * Schedule interrupt handler on timeout. Called with locked state.
211 */
212 void
213 kbdmux_kbd_intr_timo(void *xstate)
214 {
215 kbdmux_state_t *state = (kbdmux_state_t *) xstate;
216
217 KBDMUX_LOCK_ASSERT(state, MA_OWNED);
218
219 if (callout_pending(&state->ks_timo))
220 return; /* callout was reset */
221
222 if (!callout_active(&state->ks_timo))
223 return; /* callout was stopped */
224
225 callout_deactivate(&state->ks_timo);
226
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;
231
232 /* re-schedule timeout */
233 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
234 }
235
236 /*
237 * Process event from one of our keyboards
238 */
239 static int
240 kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
241 {
242 kbdmux_state_t *state = (kbdmux_state_t *) arg;
243
244 switch (event) {
245 case KBDIO_KEYINPUT: {
246 int c;
247
248 KBDMUX_LOCK(state);
249
250 /*
251 * Read all chars from the keyboard
252 *
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
257 * NOKEY.
258 */
259
260 while (KBDMUX_CHECK_CHAR(kbd)) {
261 c = KBDMUX_READ_CHAR(kbd, 0);
262 if (c == NOKEY)
263 break;
264 if (c == ERRKEY)
265 continue; /* XXX ring bell */
266 if (!KBD_IS_BUSY(kbd))
267 continue; /* not open - discard the input */
268
269 putc(c, &state->ks_inq);
270 }
271
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;
276
277 KBDMUX_UNLOCK(state);
278 } break;
279
280 case KBDIO_UNLOADING: {
281 kbdmux_kbd_t *k;
282
283 KBDMUX_LOCK(state);
284
285 SLIST_FOREACH(k, &state->ks_kbds, next)
286 if (k->kbd == kbd)
287 break;
288
289 if (k != NULL) {
290 kbd_release(k->kbd, &k->kbd);
291 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
292
293 k->kbd = NULL;
294
295 free(k, M_KBDMUX);
296 }
297
298 KBDMUX_UNLOCK(state);
299 } break;
300
301 default:
302 return (EINVAL);
303 /* NOT REACHED */
304 }
305
306 return (0);
307 }
308
309 /****************************************************************************
310 ****************************************************************************
311 ** Keyboard driver
312 ****************************************************************************
313 ****************************************************************************/
314
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;
334
335 static keyboard_switch_t kbdmuxsw = {
336 .probe = kbdmux_probe,
337 .init = kbdmux_init,
338 .term = kbdmux_term,
339 .intr = kbdmux_intr,
340 .test_if = kbdmux_test_if,
341 .enable = kbdmux_enable,
342 .disable = kbdmux_disable,
343 .read = kbdmux_read,
344 .check = kbdmux_check,
345 .read_char = kbdmux_read_char,
346 .check_char = kbdmux_check_char,
347 .ioctl = kbdmux_ioctl,
348 .lock = kbdmux_lock,
349 .clear_state = kbdmux_clear_state,
350 .get_state = kbdmux_get_state,
351 .set_state = kbdmux_set_state,
352 .get_fkeystr = genkbd_get_fkeystr,
353 .poll = kbdmux_poll,
354 .diag = genkbd_diag,
355 };
356
357 /*
358 * Return the number of found keyboards
359 */
360 static int
361 kbdmux_configure(int flags)
362 {
363 return (1);
364 }
365
366 /*
367 * Detect a keyboard
368 */
369 static int
370 kbdmux_probe(int unit, void *arg, int flags)
371 {
372 if (resource_disabled(KEYBOARD_NAME, unit))
373 return (ENXIO);
374
375 return (0);
376 }
377
378 /*
379 * Reset and initialize the keyboard (stolen from atkbd.c)
380 */
381 static int
382 kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
383 {
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];
390
391 if (*kbdp == NULL) {
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]);
398 needfree = 1;
399
400 if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
401 (accmap == NULL) || (fkeymap == NULL)) {
402 error = ENOMEM;
403 goto bad;
404 }
405
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)) {
413 return (0);
414 } else {
415 kbd = *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;
421 needfree = 0;
422 }
423
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;
433
434 KBD_FOUND_DEVICE(kbd);
435 KBD_PROBE_DONE(kbd);
436
437 KBDMUX_LOCK(state);
438 kbdmux_clear_state_locked(state);
439 state->ks_mode = K_XLATE;
440 KBDMUX_UNLOCK(state);
441 }
442
443 if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
444 kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
445
446 kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
447
448 delay[0] = kbd->kb_delay1;
449 delay[1] = kbd->kb_delay2;
450 kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
451
452 KBD_INIT_DONE(kbd);
453 }
454
455 if (!KBD_IS_CONFIGURED(kbd)) {
456 if (kbd_register(kbd) < 0) {
457 error = ENXIO;
458 goto bad;
459 }
460
461 KBD_CONFIG_DONE(kbd);
462
463 KBDMUX_LOCK(state);
464 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
465 KBDMUX_UNLOCK(state);
466 }
467
468 return (0);
469 bad:
470 if (needfree) {
471 if (state != NULL) {
472 clist_free_cblocks(&state->ks_inq);
473 free(state, M_KBDMUX);
474 }
475 if (keymap != NULL)
476 free(keymap, M_KBDMUX);
477 if (accmap != NULL)
478 free(accmap, M_KBDMUX);
479 if (fkeymap != NULL)
480 free(fkeymap, M_KBDMUX);
481 if (kbd != NULL) {
482 free(kbd, M_KBDMUX);
483 *kbdp = NULL; /* insure ref doesn't leak to caller */
484 }
485 }
486
487 return (error);
488 }
489
490 /*
491 * Finish using this keyboard
492 */
493 static int
494 kbdmux_term(keyboard_t *kbd)
495 {
496 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
497 kbdmux_kbd_t *k;
498
499 KBDMUX_LOCK(state);
500
501 /* kill callout */
502 callout_stop(&state->ks_timo);
503
504 /* wait for interrupt task */
505 while (state->ks_flags & TASK)
506 KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0);
507
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);
512
513 k->kbd = NULL;
514
515 free(k, M_KBDMUX);
516 }
517
518 /* flush input queue */
519 ndflush(&state->ks_inq, state->ks_inq.c_cc);
520 clist_free_cblocks(&state->ks_inq);
521
522 KBDMUX_UNLOCK(state);
523
524 kbd_unregister(kbd);
525
526 KBDMUX_LOCK_DESTROY(state);
527 bzero(state, sizeof(*state));
528 free(state, M_KBDMUX);
529
530 free(kbd->kb_keymap, M_KBDMUX);
531 free(kbd->kb_accentmap, M_KBDMUX);
532 free(kbd->kb_fkeytab, M_KBDMUX);
533 free(kbd, M_KBDMUX);
534
535 return (0);
536 }
537
538 /*
539 * Keyboard interrupt routine
540 */
541 static int
542 kbdmux_intr(keyboard_t *kbd, void *arg)
543 {
544 int c;
545
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);
550 } else {
551 /* read and discard the input; no one is waiting for input */
552 do {
553 c = kbdmux_read_char(kbd, FALSE);
554 } while (c != NOKEY);
555 }
556
557 return (0);
558 }
559
560 /*
561 * Test the interface to the device
562 */
563 static int
564 kbdmux_test_if(keyboard_t *kbd)
565 {
566 return (0);
567 }
568
569 /*
570 * Enable the access to the device; until this function is called,
571 * the client cannot read from the keyboard.
572 */
573 static int
574 kbdmux_enable(keyboard_t *kbd)
575 {
576 KBD_ACTIVATE(kbd);
577 return (0);
578 }
579
580 /*
581 * Disallow the access to the device
582 */
583 static int
584 kbdmux_disable(keyboard_t *kbd)
585 {
586 KBD_DEACTIVATE(kbd);
587 return (0);
588 }
589
590 /*
591 * Read one byte from the keyboard if it's allowed
592 */
593 static int
594 kbdmux_read(keyboard_t *kbd, int wait)
595 {
596 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
597 int c;
598
599 KBDMUX_LOCK(state);
600 c = getc(&state->ks_inq);
601 KBDMUX_UNLOCK(state);
602
603 if (c != -1)
604 kbd->kb_count ++;
605
606 return (KBD_IS_ACTIVE(kbd)? c : -1);
607 }
608
609 /*
610 * Check if data is waiting
611 */
612 static int
613 kbdmux_check(keyboard_t *kbd)
614 {
615 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
616 int ready;
617
618 if (!KBD_IS_ACTIVE(kbd))
619 return (FALSE);
620
621 KBDMUX_LOCK(state);
622 ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE;
623 KBDMUX_UNLOCK(state);
624
625 return (ready);
626 }
627
628 /*
629 * Read char from the keyboard (stolen from atkbd.c)
630 */
631 static u_int
632 kbdmux_read_char(keyboard_t *kbd, int wait)
633 {
634 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
635 u_int action;
636 int scancode, keycode;
637
638 KBDMUX_LOCK(state);
639
640 next_code:
641
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);
648
649 return (ERRKEY);
650 }
651
652 KBDMUX_UNLOCK(state);
653
654 return (action);
655 }
656
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) {
661 kbdmux_kbd_t *k;
662
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)
667 break;
668 if (scancode == ERRKEY)
669 continue;
670 if (!KBD_IS_BUSY(k->kbd))
671 continue;
672
673 putc(scancode, &state->ks_inq);
674 }
675 }
676
677 if (state->ks_inq.c_cc > 0)
678 goto next_code;
679 }
680
681 KBDMUX_UNLOCK(state);
682 return (NOKEY);
683 }
684 /* XXX FIXME: check for -1 if wait == 1! */
685
686 kbd->kb_count ++;
687
688 /* return the byte as is for the K_RAW mode */
689 if (state->ks_mode == K_RAW) {
690 KBDMUX_UNLOCK(state);
691 return (scancode);
692 }
693
694 /* translate the scan code into a keycode */
695 keycode = scancode & 0x7F;
696 switch (state->ks_prefix) {
697 case 0x00: /* normal scancode */
698 switch(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;
704 }
705 break;
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;
710 }
711 break;
712 case 0xE0:
713 case 0xE1:
714 state->ks_prefix = scancode;
715 goto next_code;
716 }
717 break;
718 case 0xE0: /* 0xE0 prefix */
719 state->ks_prefix = 0;
720 switch (keycode) {
721 case 0x1C: /* right enter key */
722 keycode = 0x59;
723 break;
724 case 0x1D: /* right ctrl key */
725 keycode = 0x5A;
726 break;
727 case 0x35: /* keypad divide key */
728 keycode = 0x5B;
729 break;
730 case 0x37: /* print scrn key */
731 keycode = 0x5C;
732 break;
733 case 0x38: /* right alt key (alt gr) */
734 keycode = 0x5D;
735 break;
736 case 0x46: /* ctrl-pause/break on AT 101 (see below) */
737 keycode = 0x68;
738 break;
739 case 0x47: /* grey home key */
740 keycode = 0x5E;
741 break;
742 case 0x48: /* grey up arrow key */
743 keycode = 0x5F;
744 break;
745 case 0x49: /* grey page up key */
746 keycode = 0x60;
747 break;
748 case 0x4B: /* grey left arrow key */
749 keycode = 0x61;
750 break;
751 case 0x4D: /* grey right arrow key */
752 keycode = 0x62;
753 break;
754 case 0x4F: /* grey end key */
755 keycode = 0x63;
756 break;
757 case 0x50: /* grey down arrow key */
758 keycode = 0x64;
759 break;
760 case 0x51: /* grey page down key */
761 keycode = 0x65;
762 break;
763 case 0x52: /* grey insert key */
764 keycode = 0x66;
765 break;
766 case 0x53: /* grey delete key */
767 keycode = 0x67;
768 break;
769 /* the following 3 are only used on the MS "Natural" keyboard */
770 case 0x5b: /* left Window key */
771 keycode = 0x69;
772 break;
773 case 0x5c: /* right Window key */
774 keycode = 0x6a;
775 break;
776 case 0x5d: /* menu key */
777 keycode = 0x6b;
778 break;
779 case 0x5e: /* power key */
780 keycode = 0x6d;
781 break;
782 case 0x5f: /* sleep key */
783 keycode = 0x6e;
784 break;
785 case 0x63: /* wake key */
786 keycode = 0x6f;
787 break;
788 case 0x64: /* [JP106USB] backslash, underscore */
789 keycode = 0x73;
790 break;
791 default: /* ignore everything else */
792 goto next_code;
793 }
794 break;
795 case 0xE1: /* 0xE1 prefix */
796 /*
797 * The pause/break key on the 101 keyboard produces:
798 * E1-1D-45 E1-9D-C5
799 * Ctrl-pause/break produces:
800 * E0-46 E0-C6 (See above.)
801 */
802 state->ks_prefix = 0;
803 if (keycode == 0x1D)
804 state->ks_prefix = 0x1D;
805 goto next_code;
806 /* NOT REACHED */
807 case 0x1D: /* pause / break */
808 state->ks_prefix = 0;
809 if (keycode != 0x45)
810 goto next_code;
811 keycode = 0x68;
812 break;
813 }
814
815 /* XXX assume 101/102 keys AT keyboard */
816 switch (keycode) {
817 case 0x5c: /* print screen */
818 if (state->ks_flags & ALTS)
819 keycode = 0x54; /* sysrq */
820 break;
821 case 0x68: /* pause/break */
822 if (state->ks_flags & CTLS)
823 keycode = 0x6c; /* break */
824 break;
825 }
826
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));
831 }
832
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);
842 return (ERRKEY);
843 }
844 goto next_code;
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);
850 return (ERRKEY);
851 }
852 goto next_code;
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);
858 return (ERRKEY);
859 }
860 goto next_code;
861 case 0x52: /* keypad 0 */
862 state->ks_composed_char *= 10;
863 if (state->ks_composed_char > UCHAR_MAX) {
864 KBDMUX_UNLOCK(state);
865 return (ERRKEY);
866 }
867 goto next_code;
868
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 */
874 goto next_code;
875
876 case 0x38: /* left alt key */
877 break;
878
879 default:
880 if (state->ks_composed_char > 0) {
881 state->ks_flags &= ~COMPOSE;
882 state->ks_composed_char = 0;
883 KBDMUX_UNLOCK(state);
884 return (ERRKEY);
885 }
886 break;
887 }
888 }
889
890 /* keycode to key action */
891 action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
892 &state->ks_state, &state->ks_accents);
893 if (action == NOKEY)
894 goto next_code;
895
896 KBDMUX_UNLOCK(state);
897
898 return (action);
899 }
900
901 /*
902 * Check if char is waiting
903 */
904 static int
905 kbdmux_check_char(keyboard_t *kbd)
906 {
907 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
908 int ready;
909
910 if (!KBD_IS_ACTIVE(kbd))
911 return (FALSE);
912
913 KBDMUX_LOCK(state);
914
915 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
916 ready = TRUE;
917 else
918 ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE;
919
920 KBDMUX_UNLOCK(state);
921
922 return (ready);
923 }
924
925 /*
926 * Keyboard ioctl's
927 */
928 static int
929 kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
930 {
931 static int delays[] = {
932 250, 500, 750, 1000
933 };
934
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
940 };
941
942 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
943 kbdmux_kbd_t *k;
944 keyboard_info_t *ki;
945 int error = 0, mode;
946 int ival;
947
948 if (state == NULL)
949 return (ENXIO);
950
951 switch (cmd) {
952 case KBADDKBD: /* add keyboard to the mux */
953 ki = (keyboard_info_t *) arg;
954
955 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
956 strcmp(ki->kb_name, "*") == 0)
957 return (EINVAL); /* bad input */
958
959 KBDMUX_LOCK(state);
960
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)
964 break;
965
966 if (k != NULL) {
967 KBDMUX_UNLOCK(state);
968
969 return (0); /* keyboard already in the mux */
970 }
971
972 k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
973 if (k == NULL) {
974 KBDMUX_UNLOCK(state);
975
976 return (ENOMEM); /* out of memory */
977 }
978
979 k->kbd = kbd_get_keyboard(
980 kbd_allocate(
981 ki->kb_name,
982 ki->kb_unit,
983 (void *) &k->kbd,
984 kbdmux_kbd_event, (void *) state));
985 if (k->kbd == NULL) {
986 KBDMUX_UNLOCK(state);
987 free(k, M_KBDMUX);
988
989 return (EINVAL); /* bad keyboard */
990 }
991
992 KBDMUX_ENABLE(k->kbd);
993 KBDMUX_CLEAR_STATE(k->kbd);
994
995 /* set K_RAW mode on slave keyboard */
996 mode = K_RAW;
997 error = KBDMUX_IOCTL(k->kbd, KDSKBMODE, &mode);
998 if (error == 0) {
999 /* set lock keys state on slave keyboard */
1000 mode = state->ks_state & LOCK_MASK;
1001 error = KBDMUX_IOCTL(k->kbd, KDSKBSTATE, &mode);
1002 }
1003
1004 if (error != 0) {
1005 KBDMUX_UNLOCK(state);
1006
1007 kbd_release(k->kbd, &k->kbd);
1008 k->kbd = NULL;
1009
1010 free(k, M_KBDMUX);
1011
1012 return (error); /* could not set mode */
1013 }
1014
1015 SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
1016
1017 KBDMUX_UNLOCK(state);
1018 break;
1019
1020 case KBRELKBD: /* release keyboard from the mux */
1021 ki = (keyboard_info_t *) arg;
1022
1023 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
1024 strcmp(ki->kb_name, "*") == 0)
1025 return (EINVAL); /* bad input */
1026
1027 KBDMUX_LOCK(state);
1028
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)
1032 break;
1033
1034 if (k != NULL) {
1035 error = kbd_release(k->kbd, &k->kbd);
1036 if (error == 0) {
1037 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
1038
1039 k->kbd = NULL;
1040
1041 free(k, M_KBDMUX);
1042 }
1043 } else
1044 error = ENXIO; /* keyboard is not in the mux */
1045
1046 KBDMUX_UNLOCK(state);
1047 break;
1048
1049 case KDGKBMODE: /* get kyboard mode */
1050 KBDMUX_LOCK(state);
1051 *(int *)arg = state->ks_mode;
1052 KBDMUX_UNLOCK(state);
1053 break;
1054
1055 case _IO('K', 7):
1056 ival = IOCPARM_IVAL(arg);
1057 arg = (caddr_t)&ival;
1058 /* FALLTHROUGH */
1059 case KDSKBMODE: /* set keyboard mode */
1060 KBDMUX_LOCK(state);
1061
1062 switch (*(int *)arg) {
1063 case K_XLATE:
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);
1068 }
1069 /* FALLTHROUGH */
1070
1071 case K_RAW:
1072 case K_CODE:
1073 if (state->ks_mode != *(int *)arg) {
1074 kbdmux_clear_state_locked(state);
1075 state->ks_mode = *(int *)arg;
1076 }
1077 break;
1078
1079 default:
1080 error = EINVAL;
1081 break;
1082 }
1083
1084 KBDMUX_UNLOCK(state);
1085 break;
1086
1087 case KDGETLED: /* get keyboard LED */
1088 KBDMUX_LOCK(state);
1089 *(int *)arg = KBD_LED_VAL(kbd);
1090 KBDMUX_UNLOCK(state);
1091 break;
1092
1093 case _IO('K', 66):
1094 ival = IOCPARM_IVAL(arg);
1095 arg = (caddr_t)&ival;
1096 /* FALLTHROUGH */
1097 case KDSETLED: /* set keyboard LED */
1098 KBDMUX_LOCK(state);
1099
1100 /* NOTE: lock key state in ks_state won't be changed */
1101 if (*(int *)arg & ~LOCK_MASK) {
1102 KBDMUX_UNLOCK(state);
1103
1104 return (EINVAL);
1105 }
1106
1107 KBD_LED_VAL(kbd) = *(int *)arg;
1108
1109 /* KDSETLED on all slave keyboards */
1110 SLIST_FOREACH(k, &state->ks_kbds, next)
1111 KBDMUX_IOCTL(k->kbd, KDSETLED, arg);
1112
1113 KBDMUX_UNLOCK(state);
1114 break;
1115
1116 case KDGKBSTATE: /* get lock key state */
1117 KBDMUX_LOCK(state);
1118 *(int *)arg = state->ks_state & LOCK_MASK;
1119 KBDMUX_UNLOCK(state);
1120 break;
1121
1122 case _IO('K', 20):
1123 ival = IOCPARM_IVAL(arg);
1124 arg = (caddr_t)&ival;
1125 /* FALLTHROUGH */
1126 case KDSKBSTATE: /* set lock key state */
1127 KBDMUX_LOCK(state);
1128
1129 if (*(int *)arg & ~LOCK_MASK) {
1130 KBDMUX_UNLOCK(state);
1131
1132 return (EINVAL);
1133 }
1134
1135 state->ks_state &= ~LOCK_MASK;
1136 state->ks_state |= *(int *)arg;
1137
1138 /* KDSKBSTATE on all slave keyboards */
1139 SLIST_FOREACH(k, &state->ks_kbds, next)
1140 KBDMUX_IOCTL(k->kbd, KDSKBSTATE, arg);
1141
1142 KBDMUX_UNLOCK(state);
1143
1144 return (kbdmux_ioctl(kbd, KDSETLED, arg));
1145 /* NOT REACHED */
1146
1147 case _IO('K', 67):
1148 cmd = KDSETRAD;
1149 ival = IOCPARM_IVAL(arg);
1150 arg = (caddr_t)&ival;
1151 /* FALLTHROUGH */
1152 case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1153 case KDSETRAD: /* set keyboard repeat rate (old interface) */
1154 KBDMUX_LOCK(state);
1155
1156 if (cmd == KDSETREPEAT) {
1157 int i;
1158
1159 /* lookup delay */
1160 for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --)
1161 if (((int *)arg)[0] >= delays[i])
1162 break;
1163 mode = i << 5;
1164
1165 /* lookup rate */
1166 for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --)
1167 if (((int *)arg)[1] >= rates[i])
1168 break;
1169 mode |= i;
1170 } else
1171 mode = *(int *)arg;
1172
1173 if (mode & ~0x7f) {
1174 KBDMUX_UNLOCK(state);
1175
1176 return (EINVAL);
1177 }
1178
1179 kbd->kb_delay1 = delays[(mode >> 5) & 3];
1180 kbd->kb_delay2 = rates[mode & 0x1f];
1181
1182 /* perform command on all slave keyboards */
1183 SLIST_FOREACH(k, &state->ks_kbds, next)
1184 KBDMUX_IOCTL(k->kbd, cmd, arg);
1185
1186 KBDMUX_UNLOCK(state);
1187 break;
1188
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 */
1192 KBDMUX_LOCK(state);
1193 state->ks_accents = 0;
1194
1195 /* perform command on all slave keyboards */
1196 SLIST_FOREACH(k, &state->ks_kbds, next)
1197 KBDMUX_IOCTL(k->kbd, cmd, arg);
1198
1199 KBDMUX_UNLOCK(state);
1200 /* FALLTHROUGH */
1201
1202 default:
1203 error = genkbd_commonioctl(kbd, cmd, arg);
1204 break;
1205 }
1206
1207 return (error);
1208 }
1209
1210 /*
1211 * Lock the access to the keyboard
1212 */
1213 static int
1214 kbdmux_lock(keyboard_t *kbd, int lock)
1215 {
1216 return (1); /* XXX */
1217 }
1218
1219 /*
1220 * Clear the internal state of the keyboard
1221 */
1222 static void
1223 kbdmux_clear_state_locked(kbdmux_state_t *state)
1224 {
1225 KBDMUX_LOCK_ASSERT(state, MA_OWNED);
1226
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 */
1232
1233 ndflush(&state->ks_inq, state->ks_inq.c_cc);
1234 }
1235
1236 static void
1237 kbdmux_clear_state(keyboard_t *kbd)
1238 {
1239 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1240
1241 KBDMUX_LOCK(state);
1242 kbdmux_clear_state_locked(state);
1243 KBDMUX_UNLOCK(state);
1244 }
1245
1246 /*
1247 * Save the internal state
1248 */
1249 static int
1250 kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1251 {
1252 if (len == 0)
1253 return (sizeof(kbdmux_state_t));
1254 if (len < sizeof(kbdmux_state_t))
1255 return (-1);
1256
1257 bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1258
1259 return (0);
1260 }
1261
1262 /*
1263 * Set the internal state
1264 */
1265 static int
1266 kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1267 {
1268 if (len < sizeof(kbdmux_state_t))
1269 return (ENOMEM);
1270
1271 bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1272
1273 return (0);
1274 }
1275
1276 /*
1277 * Set polling
1278 */
1279 static int
1280 kbdmux_poll(keyboard_t *kbd, int on)
1281 {
1282 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1283 kbdmux_kbd_t *k;
1284
1285 KBDMUX_LOCK(state);
1286
1287 if (on)
1288 state->ks_flags |= POLLING;
1289 else
1290 state->ks_flags &= ~POLLING;
1291
1292 /* set poll on slave keyboards */
1293 SLIST_FOREACH(k, &state->ks_kbds, next)
1294 KBDMUX_POLL(k->kbd, on);
1295
1296 KBDMUX_UNLOCK(state);
1297
1298 return (0);
1299 }
1300
1301 /*****************************************************************************
1302 *****************************************************************************
1303 ** Module
1304 *****************************************************************************
1305 *****************************************************************************/
1306
1307 KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1308
1309 static int
1310 kbdmux_modevent(module_t mod, int type, void *data)
1311 {
1312 keyboard_switch_t *sw;
1313 keyboard_t *kbd;
1314 int error;
1315
1316 switch (type) {
1317 case MOD_LOAD:
1318 if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1319 break;
1320
1321 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1322 kbd_delete_driver(&kbdmux_kbd_driver);
1323 error = ENXIO;
1324 break;
1325 }
1326
1327 kbd = NULL;
1328
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);
1332 break;
1333 }
1334
1335 #ifdef KBD_INSTALL_CDEV
1336 if ((error = kbd_attach(kbd)) != 0) {
1337 (*sw->term)(kbd);
1338 kbd_delete_driver(&kbdmux_kbd_driver);
1339 break;
1340 }
1341 #endif
1342
1343 if ((error = (*sw->enable)(kbd)) != 0) {
1344 (*sw->disable)(kbd);
1345 #ifdef KBD_INSTALL_CDEV
1346 kbd_detach(kbd);
1347 #endif
1348 (*sw->term)(kbd);
1349 kbd_delete_driver(&kbdmux_kbd_driver);
1350 break;
1351 }
1352 break;
1353
1354 case MOD_UNLOAD:
1355 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
1356 panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
1357
1358 kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1359 if (kbd == NULL)
1360 panic("kbd_get_keyboard(kbd_find_keyboard(" KEYBOARD_NAME ", 0)) == NULL");
1361
1362 (*sw->disable)(kbd);
1363 #ifdef KBD_INSTALL_CDEV
1364 kbd_detach(kbd);
1365 #endif
1366 (*sw->term)(kbd);
1367 kbd_delete_driver(&kbdmux_kbd_driver);
1368 error = 0;
1369 break;
1370
1371 default:
1372 error = EOPNOTSUPP;
1373 break;
1374 }
1375
1376 return (0);
1377 }
1378
1379 DEV_MODULE(kbdmux, kbdmux_modevent, NULL);
1380
Cache object: e38ca162f612d5b301455d3e353eb52a
|