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_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			(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)
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)
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 OPIO_KEYMAP:	/* set keyboard translation table (compat) */
1202	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
1203	case PIO_DEADKEYMAP:	/* set accent key translation table */
1204		KBDMUX_LOCK(state);
1205                state->ks_accents = 0;
1206
1207		/* perform command on all slave keyboards */
1208		SLIST_FOREACH(k, &state->ks_kbds, next)
1209			(void)kbdd_ioctl(k->kbd, cmd, arg);
1210
1211		KBDMUX_UNLOCK(state);
1212                /* FALLTHROUGH */
1213
1214	default:
1215		error = genkbd_commonioctl(kbd, cmd, arg);
1216		break;
1217	}
1218
1219	return (error);
1220}
1221
1222/*
1223 * Lock the access to the keyboard
1224 */
1225static int
1226kbdmux_lock(keyboard_t *kbd, int lock)
1227{
1228	return (1); /* XXX */
1229}
1230
1231/*
1232 * Clear the internal state of the keyboard
1233 */
1234static void
1235kbdmux_clear_state_locked(kbdmux_state_t *state)
1236{
1237	KBDMUX_LOCK_ASSERT(state, MA_OWNED);
1238
1239	state->ks_flags &= ~(COMPOSE|POLLING);
1240	state->ks_state &= LOCK_MASK;	/* preserve locking key state */
1241	state->ks_accents = 0;
1242	state->ks_composed_char = 0;
1243/*	state->ks_prefix = 0;		XXX */
1244	state->ks_inq_length = 0;
1245}
1246
1247static void
1248kbdmux_clear_state(keyboard_t *kbd)
1249{
1250	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
1251
1252	KBDMUX_LOCK(state);
1253	kbdmux_clear_state_locked(state);
1254	KBDMUX_UNLOCK(state);
1255}
1256
1257/*
1258 * Save the internal state
1259 */
1260static int
1261kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1262{
1263	if (len == 0)
1264		return (sizeof(kbdmux_state_t));
1265	if (len < sizeof(kbdmux_state_t))
1266		return (-1);
1267
1268	bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1269
1270	return (0);
1271}
1272
1273/*
1274 * Set the internal state
1275 */
1276static int
1277kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1278{
1279	if (len < sizeof(kbdmux_state_t))
1280		return (ENOMEM);
1281
1282	bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1283
1284	return (0);
1285}
1286
1287/*
1288 * Set polling
1289 */
1290static int
1291kbdmux_poll(keyboard_t *kbd, int on)
1292{
1293	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
1294	kbdmux_kbd_t	*k;
1295
1296	KBDMUX_LOCK(state);
1297
1298	if (on)
1299		state->ks_flags |= POLLING;
1300	else
1301		state->ks_flags &= ~POLLING;
1302
1303	/* set poll on slave keyboards */
1304	SLIST_FOREACH(k, &state->ks_kbds, next)
1305		kbdd_poll(k->kbd, on);
1306
1307	KBDMUX_UNLOCK(state);
1308
1309	return (0);
1310}
1311
1312/*****************************************************************************
1313 *****************************************************************************
1314 **                                    Module
1315 *****************************************************************************
1316 *****************************************************************************/
1317
1318KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1319
1320static int
1321kbdmux_modevent(module_t mod, int type, void *data)
1322{
1323	keyboard_switch_t	*sw;
1324	keyboard_t		*kbd;
1325	int			 error;
1326
1327	switch (type) {
1328	case MOD_LOAD:
1329		if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1330			break;
1331
1332		if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1333			kbd_delete_driver(&kbdmux_kbd_driver);
1334			error = ENXIO;
1335			break;
1336		}
1337
1338		kbd = NULL;
1339
1340		if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
1341		    (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) {
1342			kbd_delete_driver(&kbdmux_kbd_driver);
1343			break;
1344		}
1345
1346#ifdef KBD_INSTALL_CDEV
1347		if ((error = kbd_attach(kbd)) != 0) {
1348			(*sw->term)(kbd);
1349			kbd_delete_driver(&kbdmux_kbd_driver);
1350			break;
1351		}
1352#endif
1353
1354		if ((error = (*sw->enable)(kbd)) != 0) {
1355			(*sw->disable)(kbd);
1356#ifdef KBD_INSTALL_CDEV
1357			kbd_detach(kbd);
1358#endif
1359			(*sw->term)(kbd);
1360			kbd_delete_driver(&kbdmux_kbd_driver);
1361			break;
1362		}
1363		break;
1364
1365	case MOD_UNLOAD:
1366		if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
1367			panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
1368
1369		kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1370		if (kbd != NULL) {
1371			(*sw->disable)(kbd);
1372#ifdef KBD_INSTALL_CDEV
1373			kbd_detach(kbd);
1374#endif
1375			(*sw->term)(kbd);
1376			kbd_delete_driver(&kbdmux_kbd_driver);
1377		}
1378		error = 0;
1379		break;
1380
1381	default:
1382		error = EOPNOTSUPP;
1383		break;
1384	}
1385
1386	return (error);
1387}
1388
1389DEV_MODULE(kbdmux, kbdmux_modevent, NULL);
1390
1391