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