1147999Semax/*
2147999Semax * kbdmux.c
3147999Semax */
4147999Semax
5147999Semax/*-
6147999Semax * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7147999Semax * All rights reserved.
8147999Semax *
9147999Semax * Redistribution and use in source and binary forms, with or without
10147999Semax * modification, are permitted provided that the following conditions
11147999Semax * are met:
12147999Semax * 1. Redistributions of source code must retain the above copyright
13147999Semax *    notice, this list of conditions and the following disclaimer.
14147999Semax * 2. Redistributions in binary form must reproduce the above copyright
15147999Semax *    notice, this list of conditions and the following disclaimer in the
16147999Semax *    documentation and/or other materials provided with the distribution.
17147999Semax *
18147999Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19147999Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20147999Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21147999Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22147999Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23147999Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24147999Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25147999Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26147999Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27147999Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28147999Semax * SUCH DAMAGE.
29147999Semax *
30147999Semax * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $
31147999Semax * $FreeBSD: releng/10.3/sys/dev/kbdmux/kbdmux.c 241885 2012-10-22 13:06:09Z eadler $
32147999Semax */
33147999Semax
34162711Sru#include "opt_compat.h"
35147999Semax#include "opt_kbd.h"
36147999Semax
37147999Semax#include <sys/param.h>
38156167Semax#include <sys/bus.h>
39147999Semax#include <sys/conf.h>
40147999Semax#include <sys/consio.h>
41147999Semax#include <sys/fcntl.h>
42147999Semax#include <sys/kbio.h>
43147999Semax#include <sys/kernel.h>
44147999Semax#include <sys/limits.h>
45147999Semax#include <sys/lock.h>
46147999Semax#include <sys/malloc.h>
47147999Semax#include <sys/module.h>
48147999Semax#include <sys/mutex.h>
49147999Semax#include <sys/poll.h>
50147999Semax#include <sys/proc.h>
51147999Semax#include <sys/queue.h>
52147999Semax#include <sys/selinfo.h>
53147999Semax#include <sys/systm.h>
54147999Semax#include <sys/taskqueue.h>
55147999Semax#include <sys/uio.h>
56147999Semax#include <dev/kbd/kbdreg.h>
57147999Semax#include <dev/kbd/kbdtables.h>
58147999Semax
59147999Semax#define KEYBOARD_NAME	"kbdmux"
60147999Semax
61147999SemaxMALLOC_DECLARE(M_KBDMUX);
62147999SemaxMALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
63147999Semax
64147999Semax/*****************************************************************************
65147999Semax *****************************************************************************
66147999Semax **                             Keyboard state
67147999Semax *****************************************************************************
68147999Semax *****************************************************************************/
69147999Semax
70147999Semax#define	KBDMUX_Q_SIZE	512	/* input queue size */
71147999Semax
72147999Semax/*
73147999Semax * XXX
74147999Semax * For now rely on Giant mutex to protect our data structures.
75147999Semax * Just like the rest of keyboard drivers and syscons(4) do.
76147999Semax * Note that callout is initialized as not MP-safe to make sure
77147999Semax * Giant is held.
78147999Semax */
79147999Semax
80147999Semax#if 0 /* not yet */
81147999Semax#define KBDMUX_LOCK_DECL_GLOBAL \
82147999Semax	struct mtx ks_lock
83147999Semax#define KBDMUX_LOCK_INIT(s) \
84147999Semax	mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE)
85147999Semax#define KBDMUX_LOCK_DESTROY(s) \
86147999Semax	mtx_destroy(&(s)->ks_lock)
87147999Semax#define KBDMUX_LOCK(s) \
88147999Semax	mtx_lock(&(s)->ks_lock)
89147999Semax#define KBDMUX_UNLOCK(s) \
90147999Semax	mtx_unlock(&(s)->ks_lock)
91147999Semax#define KBDMUX_LOCK_ASSERT(s, w) \
92147999Semax	mtx_assert(&(s)->ks_lock, (w))
93147999Semax#define KBDMUX_SLEEP(s, f, d, t) \
94147999Semax	msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), (d), (t))
95147999Semax#define KBDMUX_CALLOUT_INIT(s) \
96147999Semax	callout_init_mtx(&(s)->ks_timo, &(s)->ks_lock, 0)
97147999Semax#define KBDMUX_QUEUE_INTR(s) \
98147999Semax	taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
99147999Semax#else
100147999Semax#define KBDMUX_LOCK_DECL_GLOBAL
101147999Semax
102147999Semax#define KBDMUX_LOCK_INIT(s)
103147999Semax
104147999Semax#define KBDMUX_LOCK_DESTROY(s)
105147999Semax
106190857Semax#define KBDMUX_LOCK(s)
107190857Semax
108190857Semax#define KBDMUX_UNLOCK(s)
109190857Semax
110147999Semax#define KBDMUX_LOCK_ASSERT(s, w)
111147999Semax
112147999Semax#define KBDMUX_SLEEP(s, f, d, t) \
113147999Semax	tsleep(&(s)->f, PCATCH | (PZERO + 1), (d), (t))
114147999Semax#define KBDMUX_CALLOUT_INIT(s) \
115147999Semax	callout_init(&(s)->ks_timo, 0)
116147999Semax#define KBDMUX_QUEUE_INTR(s) \
117147999Semax	taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
118147999Semax#endif /* not yet */
119147999Semax
120147999Semax/*
121147999Semax * kbdmux keyboard
122147999Semax */
123147999Semaxstruct kbdmux_kbd
124147999Semax{
125147999Semax	keyboard_t		*kbd;	/* keyboard */
126147999Semax	SLIST_ENTRY(kbdmux_kbd)	 next;	/* link to next */
127147999Semax};
128147999Semax
129147999Semaxtypedef struct kbdmux_kbd	kbdmux_kbd_t;
130147999Semax
131147999Semax/*
132147999Semax * kbdmux state
133147999Semax */
134147999Semaxstruct kbdmux_state
135147999Semax{
136193512Sed	char			 ks_inq[KBDMUX_Q_SIZE]; /* input chars queue */
137193512Sed	unsigned int		 ks_inq_start;
138193512Sed	unsigned int		 ks_inq_length;
139147999Semax	struct task		 ks_task;	/* interrupt task */
140147999Semax	struct callout		 ks_timo;	/* timeout handler */
141147999Semax#define TICKS			(hz)		/* rate */
142147999Semax
143147999Semax	int			 ks_flags;	/* flags */
144147999Semax#define COMPOSE			(1 << 0)	/* compose char flag */
145147999Semax#define POLLING			(1 << 1)	/* polling */
146147999Semax#define TASK			(1 << 2)	/* interrupt task queued */
147147999Semax
148147999Semax	int			 ks_mode;	/* K_XLATE, K_RAW, K_CODE */
149147999Semax	int			 ks_state;	/* state */
150147999Semax	int			 ks_accents;	/* accent key index (> 0) */
151147999Semax	u_int			 ks_composed_char; /* composed char code */
152147999Semax	u_char			 ks_prefix;	/* AT scan code prefix */
153147999Semax
154147999Semax	SLIST_HEAD(, kbdmux_kbd) ks_kbds;	/* keyboards */
155147999Semax
156147999Semax	KBDMUX_LOCK_DECL_GLOBAL;
157147999Semax};
158147999Semax
159147999Semaxtypedef struct kbdmux_state	kbdmux_state_t;
160147999Semax
161147999Semax/*****************************************************************************
162147999Semax *****************************************************************************
163147999Semax **                             Helper functions
164147999Semax *****************************************************************************
165147999Semax *****************************************************************************/
166147999Semax
167147999Semaxstatic task_fn_t		kbdmux_kbd_intr;
168147999Semaxstatic timeout_t		kbdmux_kbd_intr_timo;
169147999Semaxstatic kbd_callback_func_t	kbdmux_kbd_event;
170147999Semax
171193512Sedstatic void
172193512Sedkbdmux_kbd_putc(kbdmux_state_t *state, char c)
173193512Sed{
174193512Sed	unsigned int p;
175193512Sed
176193512Sed	if (state->ks_inq_length == KBDMUX_Q_SIZE)
177193512Sed		return;
178193512Sed
179193512Sed	p = (state->ks_inq_start + state->ks_inq_length) % KBDMUX_Q_SIZE;
180193512Sed	state->ks_inq[p] = c;
181193512Sed	state->ks_inq_length++;
182193512Sed}
183193512Sed
184193752Sedstatic int
185193512Sedkbdmux_kbd_getc(kbdmux_state_t *state)
186193512Sed{
187193752Sed	unsigned char c;
188193512Sed
189193512Sed	if (state->ks_inq_length == 0)
190193512Sed		return (-1);
191193512Sed
192193512Sed	c = state->ks_inq[state->ks_inq_start];
193193512Sed	state->ks_inq_start = (state->ks_inq_start + 1) % KBDMUX_Q_SIZE;
194193512Sed	state->ks_inq_length--;
195193512Sed
196193512Sed	return (c);
197193512Sed}
198193512Sed
199147999Semax/*
200147999Semax * Interrupt handler task
201147999Semax */
202147999Semaxvoid
203147999Semaxkbdmux_kbd_intr(void *xkbd, int pending)
204147999Semax{
205147999Semax	keyboard_t	*kbd = (keyboard_t *) xkbd;
206147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
207147999Semax
208174984Swkoszek	kbdd_intr(kbd, NULL);
209147999Semax
210147999Semax	KBDMUX_LOCK(state);
211147999Semax
212147999Semax	state->ks_flags &= ~TASK;
213147999Semax	wakeup(&state->ks_task);
214147999Semax
215147999Semax	KBDMUX_UNLOCK(state);
216147999Semax}
217147999Semax
218147999Semax/*
219147999Semax * Schedule interrupt handler on timeout. Called with locked state.
220147999Semax */
221147999Semaxvoid
222147999Semaxkbdmux_kbd_intr_timo(void *xstate)
223147999Semax{
224147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) xstate;
225147999Semax
226147999Semax	KBDMUX_LOCK_ASSERT(state, MA_OWNED);
227147999Semax
228147999Semax	if (callout_pending(&state->ks_timo))
229147999Semax		return; /* callout was reset */
230147999Semax
231147999Semax	if (!callout_active(&state->ks_timo))
232147999Semax		return; /* callout was stopped */
233147999Semax
234147999Semax	callout_deactivate(&state->ks_timo);
235147999Semax
236147999Semax	/* queue interrupt task if needed */
237193512Sed	if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) &&
238147999Semax	    KBDMUX_QUEUE_INTR(state) == 0)
239147999Semax		state->ks_flags |= TASK;
240147999Semax
241147999Semax	/* re-schedule timeout */
242147999Semax	callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
243147999Semax}
244147999Semax
245147999Semax/*
246147999Semax * Process event from one of our keyboards
247147999Semax */
248147999Semaxstatic int
249147999Semaxkbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
250147999Semax{
251147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) arg;
252147999Semax
253147999Semax	switch (event) {
254147999Semax	case KBDIO_KEYINPUT: {
255147999Semax		int	c;
256147999Semax
257147999Semax		KBDMUX_LOCK(state);
258147999Semax
259156013Semax		/*
260156013Semax		 * Read all chars from the keyboard
261156013Semax		 *
262156013Semax		 * Turns out that atkbd(4) check_char() method may return
263156013Semax		 * "true" while read_char() method returns NOKEY. If this
264156013Semax		 * happens we could stuck in the loop below. Avoid this
265156013Semax		 * by breaking out of the loop if read_char() method returns
266156013Semax		 * NOKEY.
267156013Semax		 */
268156013Semax
269174984Swkoszek		while (kbdd_check_char(kbd)) {
270174984Swkoszek			c = kbdd_read_char(kbd, 0);
271147999Semax			if (c == NOKEY)
272156010Semax				break;
273147999Semax			if (c == ERRKEY)
274147999Semax				continue; /* XXX ring bell */
275147999Semax			if (!KBD_IS_BUSY(kbd))
276147999Semax				continue; /* not open - discard the input */
277147999Semax
278193512Sed			kbdmux_kbd_putc(state, c);
279147999Semax		}
280147999Semax
281147999Semax		/* queue interrupt task if needed */
282193512Sed		if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) &&
283147999Semax		    KBDMUX_QUEUE_INTR(state) == 0)
284147999Semax			state->ks_flags |= TASK;
285147999Semax
286147999Semax		KBDMUX_UNLOCK(state);
287147999Semax		} break;
288147999Semax
289147999Semax	case KBDIO_UNLOADING: {
290147999Semax		kbdmux_kbd_t	*k;
291147999Semax
292147999Semax		KBDMUX_LOCK(state);
293147999Semax
294147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
295147999Semax			if (k->kbd == kbd)
296147999Semax				break;
297147999Semax
298147999Semax		if (k != NULL) {
299147999Semax			kbd_release(k->kbd, &k->kbd);
300147999Semax			SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
301147999Semax
302147999Semax			k->kbd = NULL;
303147999Semax
304147999Semax			free(k, M_KBDMUX);
305147999Semax		}
306147999Semax
307147999Semax		KBDMUX_UNLOCK(state);
308147999Semax		} break;
309147999Semax
310147999Semax	default:
311147999Semax		return (EINVAL);
312147999Semax		/* NOT REACHED */
313147999Semax	}
314147999Semax
315147999Semax	return (0);
316147999Semax}
317147999Semax
318147999Semax/****************************************************************************
319147999Semax ****************************************************************************
320147999Semax **                              Keyboard driver
321147999Semax ****************************************************************************
322147999Semax ****************************************************************************/
323147999Semax
324147999Semaxstatic int		kbdmux_configure(int flags);
325147999Semaxstatic kbd_probe_t	kbdmux_probe;
326147999Semaxstatic kbd_init_t	kbdmux_init;
327147999Semaxstatic kbd_term_t	kbdmux_term;
328147999Semaxstatic kbd_intr_t	kbdmux_intr;
329147999Semaxstatic kbd_test_if_t	kbdmux_test_if;
330147999Semaxstatic kbd_enable_t	kbdmux_enable;
331147999Semaxstatic kbd_disable_t	kbdmux_disable;
332147999Semaxstatic kbd_read_t	kbdmux_read;
333147999Semaxstatic kbd_check_t	kbdmux_check;
334147999Semaxstatic kbd_read_char_t	kbdmux_read_char;
335147999Semaxstatic kbd_check_char_t	kbdmux_check_char;
336147999Semaxstatic kbd_ioctl_t	kbdmux_ioctl;
337147999Semaxstatic kbd_lock_t	kbdmux_lock;
338147999Semaxstatic void		kbdmux_clear_state_locked(kbdmux_state_t *state);
339147999Semaxstatic kbd_clear_state_t kbdmux_clear_state;
340147999Semaxstatic kbd_get_state_t	kbdmux_get_state;
341147999Semaxstatic kbd_set_state_t	kbdmux_set_state;
342147999Semaxstatic kbd_poll_mode_t	kbdmux_poll;
343147999Semax
344147999Semaxstatic keyboard_switch_t kbdmuxsw = {
345147999Semax	.probe =	kbdmux_probe,
346147999Semax	.init =		kbdmux_init,
347147999Semax	.term =		kbdmux_term,
348147999Semax	.intr =		kbdmux_intr,
349147999Semax	.test_if =	kbdmux_test_if,
350147999Semax	.enable =	kbdmux_enable,
351147999Semax	.disable =	kbdmux_disable,
352147999Semax	.read =		kbdmux_read,
353147999Semax	.check =	kbdmux_check,
354147999Semax	.read_char =	kbdmux_read_char,
355147999Semax	.check_char =	kbdmux_check_char,
356147999Semax	.ioctl =	kbdmux_ioctl,
357147999Semax	.lock =		kbdmux_lock,
358147999Semax	.clear_state =	kbdmux_clear_state,
359147999Semax	.get_state =	kbdmux_get_state,
360147999Semax	.set_state =	kbdmux_set_state,
361147999Semax	.get_fkeystr =	genkbd_get_fkeystr,
362147999Semax	.poll =		kbdmux_poll,
363147999Semax	.diag =		genkbd_diag,
364147999Semax};
365147999Semax
366147999Semax/*
367147999Semax * Return the number of found keyboards
368147999Semax */
369147999Semaxstatic int
370147999Semaxkbdmux_configure(int flags)
371147999Semax{
372147999Semax	return (1);
373147999Semax}
374147999Semax
375147999Semax/*
376147999Semax * Detect a keyboard
377147999Semax */
378147999Semaxstatic int
379147999Semaxkbdmux_probe(int unit, void *arg, int flags)
380147999Semax{
381241885Seadler	if (resource_disabled(KEYBOARD_NAME, unit))
382241885Seadler		return (ENXIO);
383156167Semax
384147999Semax	return (0);
385147999Semax}
386147999Semax
387147999Semax/*
388147999Semax * Reset and initialize the keyboard (stolen from atkbd.c)
389147999Semax */
390147999Semaxstatic int
391147999Semaxkbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
392147999Semax{
393147999Semax	keyboard_t	*kbd = NULL;
394147999Semax	kbdmux_state_t	*state = NULL;
395147999Semax	keymap_t	*keymap = NULL;
396147999Semax        accentmap_t	*accmap = NULL;
397147999Semax        fkeytab_t	*fkeymap = NULL;
398147999Semax	int		 error, needfree, fkeymap_size, delay[2];
399147999Semax
400147999Semax	if (*kbdp == NULL) {
401147999Semax		*kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
402147999Semax		state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
403147999Semax		keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
404147999Semax		accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
405147999Semax		fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
406147999Semax		fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
407147999Semax		needfree = 1;
408147999Semax
409147999Semax		if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
410147999Semax		    (accmap == NULL) || (fkeymap == NULL)) {
411147999Semax			error = ENOMEM;
412147999Semax			goto bad;
413147999Semax		}
414147999Semax
415147999Semax		KBDMUX_LOCK_INIT(state);
416147999Semax		TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
417147999Semax		KBDMUX_CALLOUT_INIT(state);
418147999Semax		SLIST_INIT(&state->ks_kbds);
419147999Semax	} else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
420147999Semax		return (0);
421147999Semax	} else {
422147999Semax		kbd = *kbdp;
423147999Semax		state = (kbdmux_state_t *) kbd->kb_data;
424147999Semax		keymap = kbd->kb_keymap;
425147999Semax		accmap = kbd->kb_accentmap;
426147999Semax		fkeymap = kbd->kb_fkeytab;
427147999Semax		fkeymap_size = kbd->kb_fkeytab_size;
428147999Semax		needfree = 0;
429147999Semax	}
430147999Semax
431147999Semax	if (!KBD_IS_PROBED(kbd)) {
432147999Semax		/* XXX assume 101/102 keys keyboard */
433147999Semax		kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0);
434147999Semax		bcopy(&key_map, keymap, sizeof(key_map));
435147999Semax		bcopy(&accent_map, accmap, sizeof(accent_map));
436147999Semax		bcopy(fkey_tab, fkeymap,
437147999Semax			imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
438147999Semax		kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
439147999Semax		kbd->kb_data = (void *)state;
440147999Semax
441147999Semax		KBD_FOUND_DEVICE(kbd);
442147999Semax		KBD_PROBE_DONE(kbd);
443147999Semax
444147999Semax		KBDMUX_LOCK(state);
445147999Semax		kbdmux_clear_state_locked(state);
446147999Semax		state->ks_mode = K_XLATE;
447147999Semax		KBDMUX_UNLOCK(state);
448147999Semax	}
449147999Semax
450147999Semax	if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
451147999Semax		kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
452147999Semax
453147999Semax		kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
454147999Semax
455147999Semax		delay[0] = kbd->kb_delay1;
456147999Semax		delay[1] = kbd->kb_delay2;
457147999Semax		kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
458147999Semax
459147999Semax		KBD_INIT_DONE(kbd);
460147999Semax	}
461147999Semax
462147999Semax	if (!KBD_IS_CONFIGURED(kbd)) {
463147999Semax		if (kbd_register(kbd) < 0) {
464147999Semax			error = ENXIO;
465147999Semax			goto bad;
466147999Semax		}
467147999Semax
468147999Semax		KBD_CONFIG_DONE(kbd);
469147999Semax
470147999Semax		KBDMUX_LOCK(state);
471147999Semax		callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
472147999Semax		KBDMUX_UNLOCK(state);
473147999Semax	}
474147999Semax
475147999Semax	return (0);
476147999Semaxbad:
477147999Semax	if (needfree) {
478193512Sed		if (state != NULL)
479147999Semax			free(state, M_KBDMUX);
480147999Semax		if (keymap != NULL)
481147999Semax			free(keymap, M_KBDMUX);
482147999Semax		if (accmap != NULL)
483147999Semax			free(accmap, M_KBDMUX);
484147999Semax		if (fkeymap != NULL)
485147999Semax			free(fkeymap, M_KBDMUX);
486147999Semax		if (kbd != NULL) {
487147999Semax			free(kbd, M_KBDMUX);
488147999Semax			*kbdp = NULL;	/* insure ref doesn't leak to caller */
489147999Semax		}
490147999Semax	}
491147999Semax
492147999Semax	return (error);
493147999Semax}
494147999Semax
495147999Semax/*
496147999Semax * Finish using this keyboard
497147999Semax */
498147999Semaxstatic int
499147999Semaxkbdmux_term(keyboard_t *kbd)
500147999Semax{
501147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
502147999Semax	kbdmux_kbd_t	*k;
503147999Semax
504147999Semax	KBDMUX_LOCK(state);
505147999Semax
506147999Semax	/* kill callout */
507147999Semax	callout_stop(&state->ks_timo);
508147999Semax
509147999Semax	/* wait for interrupt task */
510147999Semax	while (state->ks_flags & TASK)
511147999Semax		KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0);
512147999Semax
513147999Semax	/* release all keyboards from the mux */
514147999Semax	while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
515147999Semax		kbd_release(k->kbd, &k->kbd);
516147999Semax		SLIST_REMOVE_HEAD(&state->ks_kbds, next);
517147999Semax
518147999Semax		k->kbd = NULL;
519147999Semax
520147999Semax		free(k, M_KBDMUX);
521147999Semax	}
522147999Semax
523147999Semax	KBDMUX_UNLOCK(state);
524147999Semax
525147999Semax	kbd_unregister(kbd);
526147999Semax
527147999Semax	KBDMUX_LOCK_DESTROY(state);
528147999Semax	bzero(state, sizeof(*state));
529147999Semax	free(state, M_KBDMUX);
530156086Semax
531156086Semax	free(kbd->kb_keymap, M_KBDMUX);
532156086Semax	free(kbd->kb_accentmap, M_KBDMUX);
533156086Semax	free(kbd->kb_fkeytab, M_KBDMUX);
534147999Semax	free(kbd, M_KBDMUX);
535147999Semax
536147999Semax	return (0);
537147999Semax}
538147999Semax
539147999Semax/*
540147999Semax * Keyboard interrupt routine
541147999Semax */
542147999Semaxstatic int
543147999Semaxkbdmux_intr(keyboard_t *kbd, void *arg)
544147999Semax{
545147999Semax	int	c;
546147999Semax
547147999Semax	if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
548147999Semax		/* let the callback function to process the input */
549147999Semax		(*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
550147999Semax					    kbd->kb_callback.kc_arg);
551147999Semax	} else {
552147999Semax		/* read and discard the input; no one is waiting for input */
553147999Semax		do {
554147999Semax			c = kbdmux_read_char(kbd, FALSE);
555147999Semax		} while (c != NOKEY);
556147999Semax	}
557147999Semax
558147999Semax	return (0);
559147999Semax}
560147999Semax
561147999Semax/*
562147999Semax * Test the interface to the device
563147999Semax */
564147999Semaxstatic int
565147999Semaxkbdmux_test_if(keyboard_t *kbd)
566147999Semax{
567147999Semax	return (0);
568147999Semax}
569147999Semax
570147999Semax/*
571147999Semax * Enable the access to the device; until this function is called,
572147999Semax * the client cannot read from the keyboard.
573147999Semax */
574147999Semaxstatic int
575147999Semaxkbdmux_enable(keyboard_t *kbd)
576147999Semax{
577147999Semax	KBD_ACTIVATE(kbd);
578147999Semax	return (0);
579147999Semax}
580147999Semax
581147999Semax/*
582147999Semax * Disallow the access to the device
583147999Semax */
584147999Semaxstatic int
585147999Semaxkbdmux_disable(keyboard_t *kbd)
586147999Semax{
587147999Semax	KBD_DEACTIVATE(kbd);
588147999Semax	return (0);
589147999Semax}
590147999Semax
591147999Semax/*
592147999Semax * Read one byte from the keyboard if it's allowed
593147999Semax */
594147999Semaxstatic int
595147999Semaxkbdmux_read(keyboard_t *kbd, int wait)
596147999Semax{
597147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
598147999Semax	int		 c;
599147999Semax
600147999Semax	KBDMUX_LOCK(state);
601193512Sed	c = kbdmux_kbd_getc(state);
602147999Semax	KBDMUX_UNLOCK(state);
603147999Semax
604147999Semax	if (c != -1)
605147999Semax		kbd->kb_count ++;
606147999Semax
607147999Semax	return (KBD_IS_ACTIVE(kbd)? c : -1);
608147999Semax}
609147999Semax
610147999Semax/*
611147999Semax * Check if data is waiting
612147999Semax */
613147999Semaxstatic int
614147999Semaxkbdmux_check(keyboard_t *kbd)
615147999Semax{
616147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
617147999Semax	int		 ready;
618147999Semax
619147999Semax	if (!KBD_IS_ACTIVE(kbd))
620147999Semax		return (FALSE);
621147999Semax
622147999Semax	KBDMUX_LOCK(state);
623193512Sed	ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
624147999Semax	KBDMUX_UNLOCK(state);
625147999Semax
626147999Semax	return (ready);
627147999Semax}
628147999Semax
629147999Semax/*
630147999Semax * Read char from the keyboard (stolen from atkbd.c)
631147999Semax */
632147999Semaxstatic u_int
633147999Semaxkbdmux_read_char(keyboard_t *kbd, int wait)
634147999Semax{
635147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
636147999Semax	u_int		 action;
637147999Semax	int		 scancode, keycode;
638147999Semax
639147999Semax	KBDMUX_LOCK(state);
640147999Semax
641147999Semaxnext_code:
642147999Semax
643147999Semax	/* do we have a composed char to return? */
644147999Semax	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
645147999Semax		action = state->ks_composed_char;
646147999Semax		state->ks_composed_char = 0;
647147999Semax		if (action > UCHAR_MAX) {
648147999Semax			KBDMUX_UNLOCK(state);
649147999Semax
650147999Semax			return (ERRKEY);
651147999Semax		}
652147999Semax
653147999Semax		KBDMUX_UNLOCK(state);
654147999Semax
655147999Semax		return (action);
656147999Semax	}
657147999Semax
658147999Semax	/* see if there is something in the keyboard queue */
659193512Sed	scancode = kbdmux_kbd_getc(state);
660147999Semax	if (scancode == -1) {
661160768Semax		if (state->ks_flags & POLLING) {
662160768Semax			kbdmux_kbd_t	*k;
663160768Semax
664160768Semax			SLIST_FOREACH(k, &state->ks_kbds, next) {
665174984Swkoszek				while (kbdd_check_char(k->kbd)) {
666174984Swkoszek					scancode = kbdd_read_char(k->kbd, 0);
667160768Semax					if (scancode == NOKEY)
668160768Semax						break;
669160768Semax					if (scancode == ERRKEY)
670160768Semax						continue;
671160768Semax					if (!KBD_IS_BUSY(k->kbd))
672160768Semax						continue;
673160768Semax
674193512Sed					kbdmux_kbd_putc(state, scancode);
675160768Semax				}
676160768Semax			}
677160768Semax
678193512Sed			if (state->ks_inq_length > 0)
679160768Semax				goto next_code;
680160768Semax		}
681160768Semax
682147999Semax		KBDMUX_UNLOCK(state);
683147999Semax		return (NOKEY);
684147999Semax	}
685147999Semax	/* XXX FIXME: check for -1 if wait == 1! */
686147999Semax
687147999Semax	kbd->kb_count ++;
688147999Semax
689147999Semax	/* return the byte as is for the K_RAW mode */
690147999Semax	if (state->ks_mode == K_RAW) {
691147999Semax		KBDMUX_UNLOCK(state);
692147999Semax		return (scancode);
693147999Semax	}
694147999Semax
695147999Semax	/* translate the scan code into a keycode */
696147999Semax	keycode = scancode & 0x7F;
697147999Semax	switch (state->ks_prefix) {
698147999Semax	case 0x00:	/* normal scancode */
699147999Semax		switch(scancode) {
700147999Semax		case 0xB8:	/* left alt (compose key) released */
701147999Semax			if (state->ks_flags & COMPOSE) {
702147999Semax				state->ks_flags &= ~COMPOSE;
703147999Semax				if (state->ks_composed_char > UCHAR_MAX)
704147999Semax					state->ks_composed_char = 0;
705147999Semax			}
706147999Semax			break;
707147999Semax		case 0x38:	/* left alt (compose key) pressed */
708147999Semax			if (!(state->ks_flags & COMPOSE)) {
709147999Semax				state->ks_flags |= COMPOSE;
710147999Semax				state->ks_composed_char = 0;
711147999Semax			}
712147999Semax			break;
713147999Semax		case 0xE0:
714147999Semax		case 0xE1:
715147999Semax			state->ks_prefix = scancode;
716147999Semax			goto next_code;
717147999Semax		}
718147999Semax		break;
719147999Semax	case 0xE0:      /* 0xE0 prefix */
720147999Semax		state->ks_prefix = 0;
721147999Semax		switch (keycode) {
722147999Semax		case 0x1C:	/* right enter key */
723147999Semax			keycode = 0x59;
724147999Semax			break;
725147999Semax		case 0x1D:	/* right ctrl key */
726147999Semax			keycode = 0x5A;
727147999Semax			break;
728147999Semax		case 0x35:	/* keypad divide key */
729147999Semax			keycode = 0x5B;
730147999Semax			break;
731147999Semax		case 0x37:	/* print scrn key */
732147999Semax			keycode = 0x5C;
733147999Semax			break;
734147999Semax		case 0x38:	/* right alt key (alt gr) */
735147999Semax			keycode = 0x5D;
736147999Semax			break;
737147999Semax		case 0x46:	/* ctrl-pause/break on AT 101 (see below) */
738147999Semax			keycode = 0x68;
739147999Semax			break;
740147999Semax		case 0x47:	/* grey home key */
741147999Semax			keycode = 0x5E;
742147999Semax			break;
743147999Semax		case 0x48:	/* grey up arrow key */
744147999Semax			keycode = 0x5F;
745147999Semax			break;
746147999Semax		case 0x49:	/* grey page up key */
747147999Semax			keycode = 0x60;
748147999Semax			break;
749147999Semax		case 0x4B:	/* grey left arrow key */
750147999Semax			keycode = 0x61;
751147999Semax			break;
752147999Semax		case 0x4D:	/* grey right arrow key */
753147999Semax			keycode = 0x62;
754147999Semax			break;
755147999Semax		case 0x4F:	/* grey end key */
756147999Semax			keycode = 0x63;
757147999Semax			break;
758147999Semax		case 0x50:	/* grey down arrow key */
759147999Semax			keycode = 0x64;
760147999Semax			break;
761147999Semax		case 0x51:	/* grey page down key */
762147999Semax			keycode = 0x65;
763147999Semax			break;
764147999Semax		case 0x52:	/* grey insert key */
765147999Semax			keycode = 0x66;
766147999Semax			break;
767147999Semax		case 0x53:	/* grey delete key */
768147999Semax			keycode = 0x67;
769147999Semax			break;
770147999Semax		/* the following 3 are only used on the MS "Natural" keyboard */
771147999Semax		case 0x5b:	/* left Window key */
772147999Semax			keycode = 0x69;
773147999Semax			break;
774147999Semax		case 0x5c:	/* right Window key */
775147999Semax			keycode = 0x6a;
776147999Semax			break;
777147999Semax		case 0x5d:	/* menu key */
778147999Semax			keycode = 0x6b;
779147999Semax			break;
780147999Semax		case 0x5e:	/* power key */
781147999Semax			keycode = 0x6d;
782147999Semax			break;
783147999Semax		case 0x5f:	/* sleep key */
784147999Semax			keycode = 0x6e;
785147999Semax			break;
786147999Semax		case 0x63:	/* wake key */
787147999Semax			keycode = 0x6f;
788147999Semax			break;
789171373Semax		case 0x64:	/* [JP106USB] backslash, underscore */
790171373Semax			keycode = 0x73;
791171373Semax			break;
792147999Semax		default:	/* ignore everything else */
793147999Semax			goto next_code;
794147999Semax		}
795147999Semax		break;
796147999Semax	case 0xE1:	/* 0xE1 prefix */
797147999Semax		/*
798147999Semax		 * The pause/break key on the 101 keyboard produces:
799147999Semax		 * E1-1D-45 E1-9D-C5
800147999Semax		 * Ctrl-pause/break produces:
801147999Semax		 * E0-46 E0-C6 (See above.)
802147999Semax		 */
803147999Semax		state->ks_prefix = 0;
804147999Semax		if (keycode == 0x1D)
805147999Semax			state->ks_prefix = 0x1D;
806147999Semax		goto next_code;
807147999Semax		/* NOT REACHED */
808147999Semax	case 0x1D:	/* pause / break */
809147999Semax		state->ks_prefix = 0;
810147999Semax		if (keycode != 0x45)
811147999Semax			goto next_code;
812147999Semax		keycode = 0x68;
813147999Semax		break;
814147999Semax	}
815147999Semax
816147999Semax	/* XXX assume 101/102 keys AT keyboard */
817147999Semax	switch (keycode) {
818147999Semax	case 0x5c:	/* print screen */
819147999Semax		if (state->ks_flags & ALTS)
820147999Semax			keycode = 0x54;	/* sysrq */
821147999Semax		break;
822147999Semax	case 0x68:	/* pause/break */
823147999Semax		if (state->ks_flags & CTLS)
824147999Semax			keycode = 0x6c;	/* break */
825147999Semax		break;
826147999Semax	}
827147999Semax
828147999Semax	/* return the key code in the K_CODE mode */
829147999Semax	if (state->ks_mode == K_CODE) {
830147999Semax		KBDMUX_UNLOCK(state);
831147999Semax		return (keycode | (scancode & 0x80));
832147999Semax	}
833147999Semax
834147999Semax	/* compose a character code */
835147999Semax	if (state->ks_flags & COMPOSE) {
836147999Semax		switch (keycode | (scancode & 0x80)) {
837147999Semax		/* key pressed, process it */
838147999Semax		case 0x47: case 0x48: case 0x49:	/* keypad 7,8,9 */
839147999Semax			state->ks_composed_char *= 10;
840147999Semax			state->ks_composed_char += keycode - 0x40;
841147999Semax			if (state->ks_composed_char > UCHAR_MAX) {
842147999Semax				KBDMUX_UNLOCK(state);
843147999Semax				return (ERRKEY);
844147999Semax			}
845147999Semax			goto next_code;
846147999Semax		case 0x4B: case 0x4C: case 0x4D:	/* keypad 4,5,6 */
847147999Semax			state->ks_composed_char *= 10;
848147999Semax			state->ks_composed_char += keycode - 0x47;
849147999Semax			if (state->ks_composed_char > UCHAR_MAX) {
850147999Semax				KBDMUX_UNLOCK(state);
851147999Semax				return (ERRKEY);
852147999Semax			}
853147999Semax			goto next_code;
854147999Semax		case 0x4F: case 0x50: case 0x51:	/* keypad 1,2,3 */
855147999Semax			state->ks_composed_char *= 10;
856147999Semax			state->ks_composed_char += keycode - 0x4E;
857147999Semax			if (state->ks_composed_char > UCHAR_MAX) {
858147999Semax				KBDMUX_UNLOCK(state);
859147999Semax				return (ERRKEY);
860147999Semax			}
861147999Semax			goto next_code;
862147999Semax		case 0x52:	/* keypad 0 */
863147999Semax			state->ks_composed_char *= 10;
864147999Semax			if (state->ks_composed_char > UCHAR_MAX) {
865147999Semax				KBDMUX_UNLOCK(state);
866147999Semax				return (ERRKEY);
867147999Semax			}
868147999Semax			goto next_code;
869147999Semax
870147999Semax		/* key released, no interest here */
871147999Semax		case 0xC7: case 0xC8: case 0xC9:	/* keypad 7,8,9 */
872147999Semax		case 0xCB: case 0xCC: case 0xCD:	/* keypad 4,5,6 */
873147999Semax		case 0xCF: case 0xD0: case 0xD1:	/* keypad 1,2,3 */
874147999Semax		case 0xD2:				/* keypad 0 */
875147999Semax			goto next_code;
876147999Semax
877147999Semax		case 0x38:				/* left alt key */
878147999Semax			break;
879147999Semax
880147999Semax		default:
881147999Semax			if (state->ks_composed_char > 0) {
882147999Semax				state->ks_flags &= ~COMPOSE;
883147999Semax				state->ks_composed_char = 0;
884147999Semax				KBDMUX_UNLOCK(state);
885147999Semax				return (ERRKEY);
886147999Semax			}
887147999Semax			break;
888147999Semax		}
889147999Semax	}
890147999Semax
891147999Semax	/* keycode to key action */
892147999Semax	action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
893147999Semax			&state->ks_state, &state->ks_accents);
894147999Semax	if (action == NOKEY)
895147999Semax		goto next_code;
896147999Semax
897147999Semax	KBDMUX_UNLOCK(state);
898147999Semax
899147999Semax	return (action);
900147999Semax}
901147999Semax
902147999Semax/*
903147999Semax * Check if char is waiting
904147999Semax */
905147999Semaxstatic int
906147999Semaxkbdmux_check_char(keyboard_t *kbd)
907147999Semax{
908147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
909147999Semax	int		 ready;
910147999Semax
911147999Semax	if (!KBD_IS_ACTIVE(kbd))
912147999Semax		return (FALSE);
913147999Semax
914147999Semax	KBDMUX_LOCK(state);
915147999Semax
916147999Semax	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
917147999Semax		ready = TRUE;
918147999Semax	else
919193512Sed		ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
920147999Semax
921147999Semax	KBDMUX_UNLOCK(state);
922147999Semax
923147999Semax	return (ready);
924147999Semax}
925147999Semax
926147999Semax/*
927147999Semax * Keyboard ioctl's
928147999Semax */
929147999Semaxstatic int
930147999Semaxkbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
931147999Semax{
932147999Semax	static int	 delays[] = {
933147999Semax		250, 500, 750, 1000
934147999Semax	};
935147999Semax
936147999Semax	static int	 rates[]  =  {
937147999Semax		34,  38,  42,  46,  50,   55,  59,  63,
938147999Semax		68,  76,  84,  92,  100, 110, 118, 126,
939147999Semax		136, 152, 168, 184, 200, 220, 236, 252,
940147999Semax		272, 304, 336, 368, 400, 440, 472, 504
941147999Semax	};
942147999Semax
943147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
944147999Semax	kbdmux_kbd_t	*k;
945148017Semax	keyboard_info_t	*ki;
946147999Semax	int		 error = 0, mode;
947162711Sru#ifdef COMPAT_FREEBSD6
948162711Sru	int		 ival;
949162711Sru#endif
950147999Semax
951147999Semax	if (state == NULL)
952147999Semax		return (ENXIO);
953147999Semax
954147999Semax	switch (cmd) {
955147999Semax	case KBADDKBD: /* add keyboard to the mux */
956148017Semax		ki = (keyboard_info_t *) arg;
957148017Semax
958148017Semax		if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
959148017Semax		    strcmp(ki->kb_name, "*") == 0)
960148017Semax			return (EINVAL); /* bad input */
961148017Semax
962147999Semax		KBDMUX_LOCK(state);
963147999Semax
964147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
965148017Semax			if (k->kbd->kb_unit == ki->kb_unit &&
966148017Semax			    strcmp(k->kbd->kb_name, ki->kb_name) == 0)
967147999Semax				break;
968147999Semax
969147999Semax		if (k != NULL) {
970147999Semax			KBDMUX_UNLOCK(state);
971147999Semax
972147999Semax			return (0); /* keyboard already in the mux */
973147999Semax		}
974147999Semax
975147999Semax		k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
976147999Semax		if (k == NULL) {
977147999Semax			KBDMUX_UNLOCK(state);
978147999Semax
979147999Semax			return (ENOMEM); /* out of memory */
980147999Semax		}
981147999Semax
982148017Semax		k->kbd = kbd_get_keyboard(
983148017Semax				kbd_allocate(
984148017Semax					ki->kb_name,
985148017Semax					ki->kb_unit,
986148017Semax					(void *) &k->kbd,
987148017Semax					kbdmux_kbd_event, (void *) state));
988147999Semax		if (k->kbd == NULL) {
989147999Semax			KBDMUX_UNLOCK(state);
990147999Semax			free(k, M_KBDMUX);
991147999Semax
992148017Semax			return (EINVAL); /* bad keyboard */
993147999Semax		}
994147999Semax
995174984Swkoszek		kbdd_enable(k->kbd);
996174984Swkoszek		kbdd_clear_state(k->kbd);
997147999Semax
998147999Semax		/* set K_RAW mode on slave keyboard */
999147999Semax		mode = K_RAW;
1000174984Swkoszek		error = kbdd_ioctl(k->kbd, KDSKBMODE, (caddr_t)&mode);
1001147999Semax		if (error == 0) {
1002147999Semax			/* set lock keys state on slave keyboard */
1003147999Semax			mode = state->ks_state & LOCK_MASK;
1004174984Swkoszek			error = kbdd_ioctl(k->kbd, KDSKBSTATE, (caddr_t)&mode);
1005147999Semax		}
1006147999Semax
1007147999Semax		if (error != 0) {
1008147999Semax			KBDMUX_UNLOCK(state);
1009147999Semax
1010147999Semax			kbd_release(k->kbd, &k->kbd);
1011147999Semax			k->kbd = NULL;
1012147999Semax
1013147999Semax			free(k, M_KBDMUX);
1014147999Semax
1015147999Semax			return (error); /* could not set mode */
1016147999Semax		}
1017147999Semax
1018147999Semax		SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
1019147999Semax
1020147999Semax		KBDMUX_UNLOCK(state);
1021147999Semax		break;
1022147999Semax
1023147999Semax	case KBRELKBD: /* release keyboard from the mux */
1024148017Semax		ki = (keyboard_info_t *) arg;
1025148017Semax
1026148017Semax		if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
1027148017Semax		    strcmp(ki->kb_name, "*") == 0)
1028148017Semax			return (EINVAL); /* bad input */
1029148017Semax
1030147999Semax		KBDMUX_LOCK(state);
1031147999Semax
1032147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
1033148017Semax			if (k->kbd->kb_unit == ki->kb_unit &&
1034148017Semax			    strcmp(k->kbd->kb_name, ki->kb_name) == 0)
1035147999Semax				break;
1036147999Semax
1037147999Semax		if (k != NULL) {
1038147999Semax			error = kbd_release(k->kbd, &k->kbd);
1039147999Semax			if (error == 0) {
1040147999Semax				SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
1041147999Semax
1042147999Semax				k->kbd = NULL;
1043147999Semax
1044147999Semax				free(k, M_KBDMUX);
1045147999Semax			}
1046147999Semax		} else
1047147999Semax			error = ENXIO; /* keyboard is not in the mux */
1048147999Semax
1049147999Semax		KBDMUX_UNLOCK(state);
1050147999Semax		break;
1051147999Semax
1052147999Semax	case KDGKBMODE: /* get kyboard mode */
1053147999Semax		KBDMUX_LOCK(state);
1054162441Sru		*(int *)arg = state->ks_mode;
1055147999Semax		KBDMUX_UNLOCK(state);
1056147999Semax		break;
1057147999Semax
1058162711Sru#ifdef COMPAT_FREEBSD6
1059162711Sru	case _IO('K', 7):
1060162711Sru		ival = IOCPARM_IVAL(arg);
1061162711Sru		arg = (caddr_t)&ival;
1062162711Sru		/* FALLTHROUGH */
1063162711Sru#endif
1064147999Semax	case KDSKBMODE: /* set keyboard mode */
1065147999Semax		KBDMUX_LOCK(state);
1066147999Semax
1067162461Sru		switch (*(int *)arg) {
1068147999Semax		case K_XLATE:
1069147999Semax			if (state->ks_mode != K_XLATE) {
1070147999Semax				/* make lock key state and LED state match */
1071147999Semax				state->ks_state &= ~LOCK_MASK;
1072147999Semax				state->ks_state |= KBD_LED_VAL(kbd);
1073147999Semax                        }
1074147999Semax                        /* FALLTHROUGH */
1075147999Semax
1076147999Semax		case K_RAW:
1077147999Semax		case K_CODE:
1078162461Sru			if (state->ks_mode != *(int *)arg) {
1079147999Semax				kbdmux_clear_state_locked(state);
1080162461Sru				state->ks_mode = *(int *)arg;
1081147999Semax			}
1082147999Semax			break;
1083147999Semax
1084147999Semax                default:
1085147999Semax			error = EINVAL;
1086147999Semax			break;
1087147999Semax		}
1088147999Semax
1089147999Semax		KBDMUX_UNLOCK(state);
1090147999Semax		break;
1091147999Semax
1092147999Semax	case KDGETLED: /* get keyboard LED */
1093147999Semax		KBDMUX_LOCK(state);
1094162441Sru		*(int *)arg = KBD_LED_VAL(kbd);
1095147999Semax		KBDMUX_UNLOCK(state);
1096147999Semax		break;
1097147999Semax
1098162711Sru#ifdef COMPAT_FREEBSD6
1099162711Sru	case _IO('K', 66):
1100162711Sru		ival = IOCPARM_IVAL(arg);
1101162711Sru		arg = (caddr_t)&ival;
1102162711Sru		/* FALLTHROUGH */
1103162711Sru#endif
1104147999Semax	case KDSETLED: /* set keyboard LED */
1105147999Semax		KBDMUX_LOCK(state);
1106147999Semax
1107147999Semax		/* NOTE: lock key state in ks_state won't be changed */
1108162461Sru		if (*(int *)arg & ~LOCK_MASK) {
1109147999Semax			KBDMUX_UNLOCK(state);
1110147999Semax
1111147999Semax			return (EINVAL);
1112147999Semax		}
1113147999Semax
1114162461Sru		KBD_LED_VAL(kbd) = *(int *)arg;
1115147999Semax
1116147999Semax		/* KDSETLED on all slave keyboards */
1117147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
1118213770Srpaulo			(void)kbdd_ioctl(k->kbd, KDSETLED, arg);
1119147999Semax
1120147999Semax		KBDMUX_UNLOCK(state);
1121147999Semax		break;
1122147999Semax
1123147999Semax	case KDGKBSTATE: /* get lock key state */
1124147999Semax		KBDMUX_LOCK(state);
1125162441Sru		*(int *)arg = state->ks_state & LOCK_MASK;
1126147999Semax		KBDMUX_UNLOCK(state);
1127147999Semax		break;
1128147999Semax
1129162711Sru#ifdef COMPAT_FREEBSD6
1130162711Sru	case _IO('K', 20):
1131162711Sru		ival = IOCPARM_IVAL(arg);
1132162711Sru		arg = (caddr_t)&ival;
1133162711Sru		/* FALLTHROUGH */
1134162711Sru#endif
1135147999Semax	case KDSKBSTATE: /* set lock key state */
1136147999Semax		KBDMUX_LOCK(state);
1137147999Semax
1138162461Sru		if (*(int *)arg & ~LOCK_MASK) {
1139147999Semax			KBDMUX_UNLOCK(state);
1140147999Semax
1141147999Semax			return (EINVAL);
1142147999Semax		}
1143147999Semax
1144147999Semax		state->ks_state &= ~LOCK_MASK;
1145162461Sru		state->ks_state |= *(int *)arg;
1146147999Semax
1147147999Semax		/* KDSKBSTATE on all slave keyboards */
1148147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
1149213770Srpaulo			(void)kbdd_ioctl(k->kbd, KDSKBSTATE, arg);
1150147999Semax
1151147999Semax		KBDMUX_UNLOCK(state);
1152147999Semax
1153147999Semax		return (kbdmux_ioctl(kbd, KDSETLED, arg));
1154147999Semax		/* NOT REACHED */
1155147999Semax
1156162711Sru#ifdef COMPAT_FREEBSD6
1157162711Sru	case _IO('K', 67):
1158162711Sru		cmd = KDSETRAD;
1159162711Sru		ival = IOCPARM_IVAL(arg);
1160162711Sru		arg = (caddr_t)&ival;
1161162711Sru		/* FALLTHROUGH */
1162162711Sru#endif
1163147999Semax	case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1164147999Semax	case KDSETRAD: /* set keyboard repeat rate (old interface) */
1165147999Semax		KBDMUX_LOCK(state);
1166147999Semax
1167147999Semax		if (cmd == KDSETREPEAT) {
1168147999Semax			int	i;
1169147999Semax
1170147999Semax			/* lookup delay */
1171147999Semax			for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --)
1172162441Sru				if (((int *)arg)[0] >= delays[i])
1173147999Semax					break;
1174147999Semax			mode = i << 5;
1175147999Semax
1176147999Semax			/* lookup rate */
1177147999Semax			for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --)
1178162441Sru				if (((int *)arg)[1] >= rates[i])
1179147999Semax					break;
1180147999Semax			mode |= i;
1181147999Semax		} else
1182162461Sru			mode = *(int *)arg;
1183147999Semax
1184147999Semax		if (mode & ~0x7f) {
1185147999Semax			KBDMUX_UNLOCK(state);
1186147999Semax
1187147999Semax			return (EINVAL);
1188147999Semax		}
1189147999Semax
1190147999Semax		kbd->kb_delay1 = delays[(mode >> 5) & 3];
1191147999Semax		kbd->kb_delay2 = rates[mode & 0x1f];
1192147999Semax
1193147999Semax		/* perform command on all slave keyboards */
1194147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
1195213770Srpaulo			(void)kbdd_ioctl(k->kbd, cmd, arg);
1196147999Semax
1197147999Semax		KBDMUX_UNLOCK(state);
1198147999Semax		break;
1199147999Semax
1200147999Semax	case PIO_KEYMAP:	/* set keyboard translation table */
1201224126Sed	case OPIO_KEYMAP:	/* set keyboard translation table (compat) */
1202156013Semax	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
1203156013Semax	case PIO_DEADKEYMAP:	/* set accent key translation table */
1204147999Semax		KBDMUX_LOCK(state);
1205147999Semax                state->ks_accents = 0;
1206147999Semax
1207147999Semax		/* perform command on all slave keyboards */
1208147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
1209213770Srpaulo			(void)kbdd_ioctl(k->kbd, cmd, arg);
1210147999Semax
1211147999Semax		KBDMUX_UNLOCK(state);
1212147999Semax                /* FALLTHROUGH */
1213147999Semax
1214147999Semax	default:
1215147999Semax		error = genkbd_commonioctl(kbd, cmd, arg);
1216147999Semax		break;
1217147999Semax	}
1218147999Semax
1219147999Semax	return (error);
1220147999Semax}
1221147999Semax
1222147999Semax/*
1223147999Semax * Lock the access to the keyboard
1224147999Semax */
1225147999Semaxstatic int
1226147999Semaxkbdmux_lock(keyboard_t *kbd, int lock)
1227147999Semax{
1228147999Semax	return (1); /* XXX */
1229147999Semax}
1230147999Semax
1231147999Semax/*
1232147999Semax * Clear the internal state of the keyboard
1233147999Semax */
1234147999Semaxstatic void
1235147999Semaxkbdmux_clear_state_locked(kbdmux_state_t *state)
1236147999Semax{
1237147999Semax	KBDMUX_LOCK_ASSERT(state, MA_OWNED);
1238147999Semax
1239147999Semax	state->ks_flags &= ~(COMPOSE|POLLING);
1240147999Semax	state->ks_state &= LOCK_MASK;	/* preserve locking key state */
1241147999Semax	state->ks_accents = 0;
1242147999Semax	state->ks_composed_char = 0;
1243147999Semax/*	state->ks_prefix = 0;		XXX */
1244193512Sed	state->ks_inq_length = 0;
1245147999Semax}
1246147999Semax
1247147999Semaxstatic void
1248147999Semaxkbdmux_clear_state(keyboard_t *kbd)
1249147999Semax{
1250147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
1251147999Semax
1252147999Semax	KBDMUX_LOCK(state);
1253147999Semax	kbdmux_clear_state_locked(state);
1254147999Semax	KBDMUX_UNLOCK(state);
1255147999Semax}
1256147999Semax
1257147999Semax/*
1258147999Semax * Save the internal state
1259147999Semax */
1260147999Semaxstatic int
1261147999Semaxkbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1262147999Semax{
1263147999Semax	if (len == 0)
1264147999Semax		return (sizeof(kbdmux_state_t));
1265147999Semax	if (len < sizeof(kbdmux_state_t))
1266147999Semax		return (-1);
1267147999Semax
1268147999Semax	bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1269147999Semax
1270147999Semax	return (0);
1271147999Semax}
1272147999Semax
1273147999Semax/*
1274147999Semax * Set the internal state
1275147999Semax */
1276147999Semaxstatic int
1277147999Semaxkbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1278147999Semax{
1279147999Semax	if (len < sizeof(kbdmux_state_t))
1280147999Semax		return (ENOMEM);
1281147999Semax
1282147999Semax	bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1283147999Semax
1284147999Semax	return (0);
1285147999Semax}
1286147999Semax
1287147999Semax/*
1288147999Semax * Set polling
1289147999Semax */
1290147999Semaxstatic int
1291147999Semaxkbdmux_poll(keyboard_t *kbd, int on)
1292147999Semax{
1293147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
1294147999Semax	kbdmux_kbd_t	*k;
1295147999Semax
1296147999Semax	KBDMUX_LOCK(state);
1297147999Semax
1298147999Semax	if (on)
1299147999Semax		state->ks_flags |= POLLING;
1300147999Semax	else
1301147999Semax		state->ks_flags &= ~POLLING;
1302147999Semax
1303147999Semax	/* set poll on slave keyboards */
1304147999Semax	SLIST_FOREACH(k, &state->ks_kbds, next)
1305174984Swkoszek		kbdd_poll(k->kbd, on);
1306147999Semax
1307147999Semax	KBDMUX_UNLOCK(state);
1308147999Semax
1309147999Semax	return (0);
1310147999Semax}
1311147999Semax
1312147999Semax/*****************************************************************************
1313147999Semax *****************************************************************************
1314147999Semax **                                    Module
1315147999Semax *****************************************************************************
1316147999Semax *****************************************************************************/
1317147999Semax
1318147999SemaxKEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1319147999Semax
1320147999Semaxstatic int
1321147999Semaxkbdmux_modevent(module_t mod, int type, void *data)
1322147999Semax{
1323147999Semax	keyboard_switch_t	*sw;
1324147999Semax	keyboard_t		*kbd;
1325147999Semax	int			 error;
1326147999Semax
1327147999Semax	switch (type) {
1328147999Semax	case MOD_LOAD:
1329147999Semax		if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1330147999Semax			break;
1331147999Semax
1332147999Semax		if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1333147999Semax			kbd_delete_driver(&kbdmux_kbd_driver);
1334147999Semax			error = ENXIO;
1335147999Semax			break;
1336147999Semax		}
1337147999Semax
1338147999Semax		kbd = NULL;
1339147999Semax
1340147999Semax		if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
1341147999Semax		    (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) {
1342147999Semax			kbd_delete_driver(&kbdmux_kbd_driver);
1343147999Semax			break;
1344147999Semax		}
1345147999Semax
1346147999Semax#ifdef KBD_INSTALL_CDEV
1347147999Semax		if ((error = kbd_attach(kbd)) != 0) {
1348147999Semax			(*sw->term)(kbd);
1349147999Semax			kbd_delete_driver(&kbdmux_kbd_driver);
1350147999Semax			break;
1351147999Semax		}
1352147999Semax#endif
1353147999Semax
1354147999Semax		if ((error = (*sw->enable)(kbd)) != 0) {
1355147999Semax			(*sw->disable)(kbd);
1356151440Syar#ifdef KBD_INSTALL_CDEV
1357147999Semax			kbd_detach(kbd);
1358151440Syar#endif
1359147999Semax			(*sw->term)(kbd);
1360147999Semax			kbd_delete_driver(&kbdmux_kbd_driver);
1361147999Semax			break;
1362147999Semax		}
1363147999Semax		break;
1364147999Semax
1365147999Semax	case MOD_UNLOAD:
1366147999Semax		if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
1367147999Semax			panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
1368147999Semax
1369147999Semax		kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1370188603Sthompsa		if (kbd != NULL) {
1371188603Sthompsa			(*sw->disable)(kbd);
1372147999Semax#ifdef KBD_INSTALL_CDEV
1373188603Sthompsa			kbd_detach(kbd);
1374147999Semax#endif
1375188603Sthompsa			(*sw->term)(kbd);
1376188603Sthompsa			kbd_delete_driver(&kbdmux_kbd_driver);
1377188603Sthompsa		}
1378147999Semax		error = 0;
1379147999Semax		break;
1380147999Semax
1381147999Semax	default:
1382147999Semax		error = EOPNOTSUPP;
1383147999Semax		break;
1384147999Semax	}
1385147999Semax
1386188030Semax	return (error);
1387147999Semax}
1388147999Semax
1389147999SemaxDEV_MODULE(kbdmux, kbdmux_modevent, NULL);
1390147999Semax
1391