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$
32147999Semax */
33147999Semax
34162711Sru#include "opt_compat.h"
35147999Semax#include "opt_kbd.h"
36298430Semaste#include "opt_kbdmux.h"
37147999Semax
38147999Semax#include <sys/param.h>
39156167Semax#include <sys/bus.h>
40147999Semax#include <sys/conf.h>
41147999Semax#include <sys/consio.h>
42147999Semax#include <sys/fcntl.h>
43147999Semax#include <sys/kbio.h>
44147999Semax#include <sys/kernel.h>
45147999Semax#include <sys/limits.h>
46147999Semax#include <sys/lock.h>
47147999Semax#include <sys/malloc.h>
48147999Semax#include <sys/module.h>
49147999Semax#include <sys/mutex.h>
50147999Semax#include <sys/poll.h>
51147999Semax#include <sys/proc.h>
52147999Semax#include <sys/queue.h>
53147999Semax#include <sys/selinfo.h>
54147999Semax#include <sys/systm.h>
55147999Semax#include <sys/taskqueue.h>
56147999Semax#include <sys/uio.h>
57147999Semax#include <dev/kbd/kbdreg.h>
58298430Semaste
59298430Semaste/* the initial key map, accent map and fkey strings */
60298430Semaste#ifdef KBDMUX_DFLT_KEYMAP
61298430Semaste#define KBD_DFLT_KEYMAP
62298430Semaste#include "kbdmuxmap.h"
63298430Semaste#endif
64298430Semaste
65147999Semax#include <dev/kbd/kbdtables.h>
66147999Semax
67147999Semax#define KEYBOARD_NAME	"kbdmux"
68147999Semax
69147999SemaxMALLOC_DECLARE(M_KBDMUX);
70147999SemaxMALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
71147999Semax
72147999Semax/*****************************************************************************
73147999Semax *****************************************************************************
74147999Semax **                             Keyboard state
75147999Semax *****************************************************************************
76147999Semax *****************************************************************************/
77147999Semax
78147999Semax#define	KBDMUX_Q_SIZE	512	/* input queue size */
79147999Semax
80147999Semax/*
81147999Semax * XXX
82147999Semax * For now rely on Giant mutex to protect our data structures.
83147999Semax * Just like the rest of keyboard drivers and syscons(4) do.
84147999Semax * Note that callout is initialized as not MP-safe to make sure
85147999Semax * Giant is held.
86147999Semax */
87147999Semax
88147999Semax#if 0 /* not yet */
89147999Semax#define KBDMUX_LOCK_DECL_GLOBAL \
90147999Semax	struct mtx ks_lock
91147999Semax#define KBDMUX_LOCK_INIT(s) \
92147999Semax	mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE)
93147999Semax#define KBDMUX_LOCK_DESTROY(s) \
94147999Semax	mtx_destroy(&(s)->ks_lock)
95147999Semax#define KBDMUX_LOCK(s) \
96147999Semax	mtx_lock(&(s)->ks_lock)
97147999Semax#define KBDMUX_UNLOCK(s) \
98147999Semax	mtx_unlock(&(s)->ks_lock)
99147999Semax#define KBDMUX_LOCK_ASSERT(s, w) \
100147999Semax	mtx_assert(&(s)->ks_lock, (w))
101147999Semax#define KBDMUX_SLEEP(s, f, d, t) \
102147999Semax	msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), (d), (t))
103147999Semax#define KBDMUX_CALLOUT_INIT(s) \
104147999Semax	callout_init_mtx(&(s)->ks_timo, &(s)->ks_lock, 0)
105147999Semax#define KBDMUX_QUEUE_INTR(s) \
106147999Semax	taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
107147999Semax#else
108147999Semax#define KBDMUX_LOCK_DECL_GLOBAL
109147999Semax
110147999Semax#define KBDMUX_LOCK_INIT(s)
111147999Semax
112147999Semax#define KBDMUX_LOCK_DESTROY(s)
113147999Semax
114190857Semax#define KBDMUX_LOCK(s)
115190857Semax
116190857Semax#define KBDMUX_UNLOCK(s)
117190857Semax
118147999Semax#define KBDMUX_LOCK_ASSERT(s, w)
119147999Semax
120147999Semax#define KBDMUX_SLEEP(s, f, d, t) \
121147999Semax	tsleep(&(s)->f, PCATCH | (PZERO + 1), (d), (t))
122147999Semax#define KBDMUX_CALLOUT_INIT(s) \
123147999Semax	callout_init(&(s)->ks_timo, 0)
124147999Semax#define KBDMUX_QUEUE_INTR(s) \
125147999Semax	taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
126147999Semax#endif /* not yet */
127147999Semax
128147999Semax/*
129147999Semax * kbdmux keyboard
130147999Semax */
131147999Semaxstruct kbdmux_kbd
132147999Semax{
133147999Semax	keyboard_t		*kbd;	/* keyboard */
134147999Semax	SLIST_ENTRY(kbdmux_kbd)	 next;	/* link to next */
135147999Semax};
136147999Semax
137147999Semaxtypedef struct kbdmux_kbd	kbdmux_kbd_t;
138147999Semax
139147999Semax/*
140147999Semax * kbdmux state
141147999Semax */
142147999Semaxstruct kbdmux_state
143147999Semax{
144193512Sed	char			 ks_inq[KBDMUX_Q_SIZE]; /* input chars queue */
145193512Sed	unsigned int		 ks_inq_start;
146193512Sed	unsigned int		 ks_inq_length;
147147999Semax	struct task		 ks_task;	/* interrupt task */
148147999Semax	struct callout		 ks_timo;	/* timeout handler */
149147999Semax#define TICKS			(hz)		/* rate */
150147999Semax
151147999Semax	int			 ks_flags;	/* flags */
152147999Semax#define COMPOSE			(1 << 0)	/* compose char flag */
153147999Semax#define POLLING			(1 << 1)	/* polling */
154147999Semax#define TASK			(1 << 2)	/* interrupt task queued */
155147999Semax
156147999Semax	int			 ks_mode;	/* K_XLATE, K_RAW, K_CODE */
157147999Semax	int			 ks_state;	/* state */
158147999Semax	int			 ks_accents;	/* accent key index (> 0) */
159147999Semax	u_int			 ks_composed_char; /* composed char code */
160147999Semax	u_char			 ks_prefix;	/* AT scan code prefix */
161147999Semax
162147999Semax	SLIST_HEAD(, kbdmux_kbd) ks_kbds;	/* keyboards */
163147999Semax
164147999Semax	KBDMUX_LOCK_DECL_GLOBAL;
165147999Semax};
166147999Semax
167147999Semaxtypedef struct kbdmux_state	kbdmux_state_t;
168147999Semax
169147999Semax/*****************************************************************************
170147999Semax *****************************************************************************
171147999Semax **                             Helper functions
172147999Semax *****************************************************************************
173147999Semax *****************************************************************************/
174147999Semax
175147999Semaxstatic task_fn_t		kbdmux_kbd_intr;
176147999Semaxstatic timeout_t		kbdmux_kbd_intr_timo;
177147999Semaxstatic kbd_callback_func_t	kbdmux_kbd_event;
178147999Semax
179193512Sedstatic void
180193512Sedkbdmux_kbd_putc(kbdmux_state_t *state, char c)
181193512Sed{
182193512Sed	unsigned int p;
183193512Sed
184193512Sed	if (state->ks_inq_length == KBDMUX_Q_SIZE)
185193512Sed		return;
186193512Sed
187193512Sed	p = (state->ks_inq_start + state->ks_inq_length) % KBDMUX_Q_SIZE;
188193512Sed	state->ks_inq[p] = c;
189193512Sed	state->ks_inq_length++;
190193512Sed}
191193512Sed
192193752Sedstatic int
193193512Sedkbdmux_kbd_getc(kbdmux_state_t *state)
194193512Sed{
195193752Sed	unsigned char c;
196193512Sed
197193512Sed	if (state->ks_inq_length == 0)
198193512Sed		return (-1);
199193512Sed
200193512Sed	c = state->ks_inq[state->ks_inq_start];
201193512Sed	state->ks_inq_start = (state->ks_inq_start + 1) % KBDMUX_Q_SIZE;
202193512Sed	state->ks_inq_length--;
203193512Sed
204193512Sed	return (c);
205193512Sed}
206193512Sed
207147999Semax/*
208147999Semax * Interrupt handler task
209147999Semax */
210147999Semaxvoid
211147999Semaxkbdmux_kbd_intr(void *xkbd, int pending)
212147999Semax{
213147999Semax	keyboard_t	*kbd = (keyboard_t *) xkbd;
214147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
215147999Semax
216174984Swkoszek	kbdd_intr(kbd, NULL);
217147999Semax
218147999Semax	KBDMUX_LOCK(state);
219147999Semax
220147999Semax	state->ks_flags &= ~TASK;
221147999Semax	wakeup(&state->ks_task);
222147999Semax
223147999Semax	KBDMUX_UNLOCK(state);
224147999Semax}
225147999Semax
226147999Semax/*
227147999Semax * Schedule interrupt handler on timeout. Called with locked state.
228147999Semax */
229147999Semaxvoid
230147999Semaxkbdmux_kbd_intr_timo(void *xstate)
231147999Semax{
232147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) xstate;
233147999Semax
234147999Semax	KBDMUX_LOCK_ASSERT(state, MA_OWNED);
235147999Semax
236147999Semax	if (callout_pending(&state->ks_timo))
237147999Semax		return; /* callout was reset */
238147999Semax
239147999Semax	if (!callout_active(&state->ks_timo))
240147999Semax		return; /* callout was stopped */
241147999Semax
242147999Semax	callout_deactivate(&state->ks_timo);
243147999Semax
244147999Semax	/* queue interrupt task if needed */
245193512Sed	if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) &&
246147999Semax	    KBDMUX_QUEUE_INTR(state) == 0)
247147999Semax		state->ks_flags |= TASK;
248147999Semax
249147999Semax	/* re-schedule timeout */
250147999Semax	callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
251147999Semax}
252147999Semax
253147999Semax/*
254147999Semax * Process event from one of our keyboards
255147999Semax */
256147999Semaxstatic int
257147999Semaxkbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
258147999Semax{
259147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) arg;
260147999Semax
261147999Semax	switch (event) {
262147999Semax	case KBDIO_KEYINPUT: {
263147999Semax		int	c;
264147999Semax
265147999Semax		KBDMUX_LOCK(state);
266147999Semax
267156013Semax		/*
268156013Semax		 * Read all chars from the keyboard
269156013Semax		 *
270156013Semax		 * Turns out that atkbd(4) check_char() method may return
271156013Semax		 * "true" while read_char() method returns NOKEY. If this
272156013Semax		 * happens we could stuck in the loop below. Avoid this
273156013Semax		 * by breaking out of the loop if read_char() method returns
274156013Semax		 * NOKEY.
275156013Semax		 */
276156013Semax
277174984Swkoszek		while (kbdd_check_char(kbd)) {
278174984Swkoszek			c = kbdd_read_char(kbd, 0);
279147999Semax			if (c == NOKEY)
280156010Semax				break;
281147999Semax			if (c == ERRKEY)
282147999Semax				continue; /* XXX ring bell */
283147999Semax			if (!KBD_IS_BUSY(kbd))
284147999Semax				continue; /* not open - discard the input */
285147999Semax
286193512Sed			kbdmux_kbd_putc(state, c);
287147999Semax		}
288147999Semax
289147999Semax		/* queue interrupt task if needed */
290193512Sed		if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) &&
291147999Semax		    KBDMUX_QUEUE_INTR(state) == 0)
292147999Semax			state->ks_flags |= TASK;
293147999Semax
294147999Semax		KBDMUX_UNLOCK(state);
295147999Semax		} break;
296147999Semax
297147999Semax	case KBDIO_UNLOADING: {
298147999Semax		kbdmux_kbd_t	*k;
299147999Semax
300147999Semax		KBDMUX_LOCK(state);
301147999Semax
302147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
303147999Semax			if (k->kbd == kbd)
304147999Semax				break;
305147999Semax
306147999Semax		if (k != NULL) {
307147999Semax			kbd_release(k->kbd, &k->kbd);
308147999Semax			SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
309147999Semax
310147999Semax			k->kbd = NULL;
311147999Semax
312147999Semax			free(k, M_KBDMUX);
313147999Semax		}
314147999Semax
315147999Semax		KBDMUX_UNLOCK(state);
316147999Semax		} break;
317147999Semax
318147999Semax	default:
319147999Semax		return (EINVAL);
320147999Semax		/* NOT REACHED */
321147999Semax	}
322147999Semax
323147999Semax	return (0);
324147999Semax}
325147999Semax
326147999Semax/****************************************************************************
327147999Semax ****************************************************************************
328147999Semax **                              Keyboard driver
329147999Semax ****************************************************************************
330147999Semax ****************************************************************************/
331147999Semax
332147999Semaxstatic int		kbdmux_configure(int flags);
333147999Semaxstatic kbd_probe_t	kbdmux_probe;
334147999Semaxstatic kbd_init_t	kbdmux_init;
335147999Semaxstatic kbd_term_t	kbdmux_term;
336147999Semaxstatic kbd_intr_t	kbdmux_intr;
337147999Semaxstatic kbd_test_if_t	kbdmux_test_if;
338147999Semaxstatic kbd_enable_t	kbdmux_enable;
339147999Semaxstatic kbd_disable_t	kbdmux_disable;
340147999Semaxstatic kbd_read_t	kbdmux_read;
341147999Semaxstatic kbd_check_t	kbdmux_check;
342147999Semaxstatic kbd_read_char_t	kbdmux_read_char;
343147999Semaxstatic kbd_check_char_t	kbdmux_check_char;
344147999Semaxstatic kbd_ioctl_t	kbdmux_ioctl;
345147999Semaxstatic kbd_lock_t	kbdmux_lock;
346147999Semaxstatic void		kbdmux_clear_state_locked(kbdmux_state_t *state);
347147999Semaxstatic kbd_clear_state_t kbdmux_clear_state;
348147999Semaxstatic kbd_get_state_t	kbdmux_get_state;
349147999Semaxstatic kbd_set_state_t	kbdmux_set_state;
350147999Semaxstatic kbd_poll_mode_t	kbdmux_poll;
351147999Semax
352147999Semaxstatic keyboard_switch_t kbdmuxsw = {
353147999Semax	.probe =	kbdmux_probe,
354147999Semax	.init =		kbdmux_init,
355147999Semax	.term =		kbdmux_term,
356147999Semax	.intr =		kbdmux_intr,
357147999Semax	.test_if =	kbdmux_test_if,
358147999Semax	.enable =	kbdmux_enable,
359147999Semax	.disable =	kbdmux_disable,
360147999Semax	.read =		kbdmux_read,
361147999Semax	.check =	kbdmux_check,
362147999Semax	.read_char =	kbdmux_read_char,
363147999Semax	.check_char =	kbdmux_check_char,
364147999Semax	.ioctl =	kbdmux_ioctl,
365147999Semax	.lock =		kbdmux_lock,
366147999Semax	.clear_state =	kbdmux_clear_state,
367147999Semax	.get_state =	kbdmux_get_state,
368147999Semax	.set_state =	kbdmux_set_state,
369147999Semax	.get_fkeystr =	genkbd_get_fkeystr,
370147999Semax	.poll =		kbdmux_poll,
371147999Semax	.diag =		genkbd_diag,
372147999Semax};
373147999Semax
374147999Semax/*
375147999Semax * Return the number of found keyboards
376147999Semax */
377147999Semaxstatic int
378147999Semaxkbdmux_configure(int flags)
379147999Semax{
380147999Semax	return (1);
381147999Semax}
382147999Semax
383147999Semax/*
384147999Semax * Detect a keyboard
385147999Semax */
386147999Semaxstatic int
387147999Semaxkbdmux_probe(int unit, void *arg, int flags)
388147999Semax{
389241885Seadler	if (resource_disabled(KEYBOARD_NAME, unit))
390241885Seadler		return (ENXIO);
391156167Semax
392147999Semax	return (0);
393147999Semax}
394147999Semax
395147999Semax/*
396147999Semax * Reset and initialize the keyboard (stolen from atkbd.c)
397147999Semax */
398147999Semaxstatic int
399147999Semaxkbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
400147999Semax{
401147999Semax	keyboard_t	*kbd = NULL;
402147999Semax	kbdmux_state_t	*state = NULL;
403147999Semax	keymap_t	*keymap = NULL;
404147999Semax        accentmap_t	*accmap = NULL;
405147999Semax        fkeytab_t	*fkeymap = NULL;
406147999Semax	int		 error, needfree, fkeymap_size, delay[2];
407147999Semax
408147999Semax	if (*kbdp == NULL) {
409147999Semax		*kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
410147999Semax		state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
411147999Semax		keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
412147999Semax		accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
413147999Semax		fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
414147999Semax		fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
415147999Semax		needfree = 1;
416147999Semax
417147999Semax		if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
418147999Semax		    (accmap == NULL) || (fkeymap == NULL)) {
419147999Semax			error = ENOMEM;
420147999Semax			goto bad;
421147999Semax		}
422147999Semax
423147999Semax		KBDMUX_LOCK_INIT(state);
424147999Semax		TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
425147999Semax		KBDMUX_CALLOUT_INIT(state);
426147999Semax		SLIST_INIT(&state->ks_kbds);
427147999Semax	} else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
428147999Semax		return (0);
429147999Semax	} else {
430147999Semax		kbd = *kbdp;
431147999Semax		state = (kbdmux_state_t *) kbd->kb_data;
432147999Semax		keymap = kbd->kb_keymap;
433147999Semax		accmap = kbd->kb_accentmap;
434147999Semax		fkeymap = kbd->kb_fkeytab;
435147999Semax		fkeymap_size = kbd->kb_fkeytab_size;
436147999Semax		needfree = 0;
437147999Semax	}
438147999Semax
439147999Semax	if (!KBD_IS_PROBED(kbd)) {
440147999Semax		/* XXX assume 101/102 keys keyboard */
441147999Semax		kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0);
442147999Semax		bcopy(&key_map, keymap, sizeof(key_map));
443147999Semax		bcopy(&accent_map, accmap, sizeof(accent_map));
444147999Semax		bcopy(fkey_tab, fkeymap,
445147999Semax			imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
446147999Semax		kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
447147999Semax		kbd->kb_data = (void *)state;
448147999Semax
449147999Semax		KBD_FOUND_DEVICE(kbd);
450147999Semax		KBD_PROBE_DONE(kbd);
451147999Semax
452147999Semax		KBDMUX_LOCK(state);
453147999Semax		kbdmux_clear_state_locked(state);
454147999Semax		state->ks_mode = K_XLATE;
455147999Semax		KBDMUX_UNLOCK(state);
456147999Semax	}
457147999Semax
458147999Semax	if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
459147999Semax		kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
460147999Semax
461147999Semax		kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
462147999Semax
463147999Semax		delay[0] = kbd->kb_delay1;
464147999Semax		delay[1] = kbd->kb_delay2;
465147999Semax		kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
466147999Semax
467147999Semax		KBD_INIT_DONE(kbd);
468147999Semax	}
469147999Semax
470147999Semax	if (!KBD_IS_CONFIGURED(kbd)) {
471147999Semax		if (kbd_register(kbd) < 0) {
472147999Semax			error = ENXIO;
473147999Semax			goto bad;
474147999Semax		}
475147999Semax
476147999Semax		KBD_CONFIG_DONE(kbd);
477147999Semax
478147999Semax		KBDMUX_LOCK(state);
479147999Semax		callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
480147999Semax		KBDMUX_UNLOCK(state);
481147999Semax	}
482147999Semax
483147999Semax	return (0);
484147999Semaxbad:
485147999Semax	if (needfree) {
486193512Sed		if (state != NULL)
487147999Semax			free(state, M_KBDMUX);
488147999Semax		if (keymap != NULL)
489147999Semax			free(keymap, M_KBDMUX);
490147999Semax		if (accmap != NULL)
491147999Semax			free(accmap, M_KBDMUX);
492147999Semax		if (fkeymap != NULL)
493147999Semax			free(fkeymap, M_KBDMUX);
494147999Semax		if (kbd != NULL) {
495147999Semax			free(kbd, M_KBDMUX);
496147999Semax			*kbdp = NULL;	/* insure ref doesn't leak to caller */
497147999Semax		}
498147999Semax	}
499147999Semax
500147999Semax	return (error);
501147999Semax}
502147999Semax
503147999Semax/*
504147999Semax * Finish using this keyboard
505147999Semax */
506147999Semaxstatic int
507147999Semaxkbdmux_term(keyboard_t *kbd)
508147999Semax{
509147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
510147999Semax	kbdmux_kbd_t	*k;
511147999Semax
512147999Semax	KBDMUX_LOCK(state);
513147999Semax
514147999Semax	/* kill callout */
515147999Semax	callout_stop(&state->ks_timo);
516147999Semax
517147999Semax	/* wait for interrupt task */
518147999Semax	while (state->ks_flags & TASK)
519147999Semax		KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0);
520147999Semax
521147999Semax	/* release all keyboards from the mux */
522147999Semax	while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
523147999Semax		kbd_release(k->kbd, &k->kbd);
524147999Semax		SLIST_REMOVE_HEAD(&state->ks_kbds, next);
525147999Semax
526147999Semax		k->kbd = NULL;
527147999Semax
528147999Semax		free(k, M_KBDMUX);
529147999Semax	}
530147999Semax
531147999Semax	KBDMUX_UNLOCK(state);
532147999Semax
533147999Semax	kbd_unregister(kbd);
534147999Semax
535147999Semax	KBDMUX_LOCK_DESTROY(state);
536147999Semax	bzero(state, sizeof(*state));
537147999Semax	free(state, M_KBDMUX);
538156086Semax
539156086Semax	free(kbd->kb_keymap, M_KBDMUX);
540156086Semax	free(kbd->kb_accentmap, M_KBDMUX);
541156086Semax	free(kbd->kb_fkeytab, M_KBDMUX);
542147999Semax	free(kbd, M_KBDMUX);
543147999Semax
544147999Semax	return (0);
545147999Semax}
546147999Semax
547147999Semax/*
548147999Semax * Keyboard interrupt routine
549147999Semax */
550147999Semaxstatic int
551147999Semaxkbdmux_intr(keyboard_t *kbd, void *arg)
552147999Semax{
553147999Semax	int	c;
554147999Semax
555147999Semax	if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
556147999Semax		/* let the callback function to process the input */
557147999Semax		(*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
558147999Semax					    kbd->kb_callback.kc_arg);
559147999Semax	} else {
560147999Semax		/* read and discard the input; no one is waiting for input */
561147999Semax		do {
562147999Semax			c = kbdmux_read_char(kbd, FALSE);
563147999Semax		} while (c != NOKEY);
564147999Semax	}
565147999Semax
566147999Semax	return (0);
567147999Semax}
568147999Semax
569147999Semax/*
570147999Semax * Test the interface to the device
571147999Semax */
572147999Semaxstatic int
573147999Semaxkbdmux_test_if(keyboard_t *kbd)
574147999Semax{
575147999Semax	return (0);
576147999Semax}
577147999Semax
578147999Semax/*
579147999Semax * Enable the access to the device; until this function is called,
580147999Semax * the client cannot read from the keyboard.
581147999Semax */
582147999Semaxstatic int
583147999Semaxkbdmux_enable(keyboard_t *kbd)
584147999Semax{
585147999Semax	KBD_ACTIVATE(kbd);
586147999Semax	return (0);
587147999Semax}
588147999Semax
589147999Semax/*
590147999Semax * Disallow the access to the device
591147999Semax */
592147999Semaxstatic int
593147999Semaxkbdmux_disable(keyboard_t *kbd)
594147999Semax{
595147999Semax	KBD_DEACTIVATE(kbd);
596147999Semax	return (0);
597147999Semax}
598147999Semax
599147999Semax/*
600147999Semax * Read one byte from the keyboard if it's allowed
601147999Semax */
602147999Semaxstatic int
603147999Semaxkbdmux_read(keyboard_t *kbd, int wait)
604147999Semax{
605147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
606147999Semax	int		 c;
607147999Semax
608147999Semax	KBDMUX_LOCK(state);
609193512Sed	c = kbdmux_kbd_getc(state);
610147999Semax	KBDMUX_UNLOCK(state);
611147999Semax
612147999Semax	if (c != -1)
613147999Semax		kbd->kb_count ++;
614147999Semax
615147999Semax	return (KBD_IS_ACTIVE(kbd)? c : -1);
616147999Semax}
617147999Semax
618147999Semax/*
619147999Semax * Check if data is waiting
620147999Semax */
621147999Semaxstatic int
622147999Semaxkbdmux_check(keyboard_t *kbd)
623147999Semax{
624147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
625147999Semax	int		 ready;
626147999Semax
627147999Semax	if (!KBD_IS_ACTIVE(kbd))
628147999Semax		return (FALSE);
629147999Semax
630147999Semax	KBDMUX_LOCK(state);
631193512Sed	ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
632147999Semax	KBDMUX_UNLOCK(state);
633147999Semax
634147999Semax	return (ready);
635147999Semax}
636147999Semax
637147999Semax/*
638147999Semax * Read char from the keyboard (stolen from atkbd.c)
639147999Semax */
640147999Semaxstatic u_int
641147999Semaxkbdmux_read_char(keyboard_t *kbd, int wait)
642147999Semax{
643147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
644147999Semax	u_int		 action;
645147999Semax	int		 scancode, keycode;
646147999Semax
647147999Semax	KBDMUX_LOCK(state);
648147999Semax
649147999Semaxnext_code:
650147999Semax
651147999Semax	/* do we have a composed char to return? */
652147999Semax	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
653147999Semax		action = state->ks_composed_char;
654147999Semax		state->ks_composed_char = 0;
655147999Semax		if (action > UCHAR_MAX) {
656147999Semax			KBDMUX_UNLOCK(state);
657147999Semax
658147999Semax			return (ERRKEY);
659147999Semax		}
660147999Semax
661147999Semax		KBDMUX_UNLOCK(state);
662147999Semax
663147999Semax		return (action);
664147999Semax	}
665147999Semax
666147999Semax	/* see if there is something in the keyboard queue */
667193512Sed	scancode = kbdmux_kbd_getc(state);
668147999Semax	if (scancode == -1) {
669160768Semax		if (state->ks_flags & POLLING) {
670160768Semax			kbdmux_kbd_t	*k;
671160768Semax
672160768Semax			SLIST_FOREACH(k, &state->ks_kbds, next) {
673174984Swkoszek				while (kbdd_check_char(k->kbd)) {
674174984Swkoszek					scancode = kbdd_read_char(k->kbd, 0);
675160768Semax					if (scancode == NOKEY)
676160768Semax						break;
677160768Semax					if (scancode == ERRKEY)
678160768Semax						continue;
679160768Semax					if (!KBD_IS_BUSY(k->kbd))
680160768Semax						continue;
681160768Semax
682193512Sed					kbdmux_kbd_putc(state, scancode);
683160768Semax				}
684160768Semax			}
685160768Semax
686193512Sed			if (state->ks_inq_length > 0)
687160768Semax				goto next_code;
688160768Semax		}
689160768Semax
690147999Semax		KBDMUX_UNLOCK(state);
691147999Semax		return (NOKEY);
692147999Semax	}
693147999Semax	/* XXX FIXME: check for -1 if wait == 1! */
694147999Semax
695147999Semax	kbd->kb_count ++;
696147999Semax
697147999Semax	/* return the byte as is for the K_RAW mode */
698147999Semax	if (state->ks_mode == K_RAW) {
699147999Semax		KBDMUX_UNLOCK(state);
700147999Semax		return (scancode);
701147999Semax	}
702147999Semax
703147999Semax	/* translate the scan code into a keycode */
704147999Semax	keycode = scancode & 0x7F;
705147999Semax	switch (state->ks_prefix) {
706147999Semax	case 0x00:	/* normal scancode */
707147999Semax		switch(scancode) {
708147999Semax		case 0xB8:	/* left alt (compose key) released */
709147999Semax			if (state->ks_flags & COMPOSE) {
710147999Semax				state->ks_flags &= ~COMPOSE;
711147999Semax				if (state->ks_composed_char > UCHAR_MAX)
712147999Semax					state->ks_composed_char = 0;
713147999Semax			}
714147999Semax			break;
715147999Semax		case 0x38:	/* left alt (compose key) pressed */
716147999Semax			if (!(state->ks_flags & COMPOSE)) {
717147999Semax				state->ks_flags |= COMPOSE;
718147999Semax				state->ks_composed_char = 0;
719147999Semax			}
720147999Semax			break;
721147999Semax		case 0xE0:
722147999Semax		case 0xE1:
723147999Semax			state->ks_prefix = scancode;
724147999Semax			goto next_code;
725147999Semax		}
726147999Semax		break;
727147999Semax	case 0xE0:      /* 0xE0 prefix */
728147999Semax		state->ks_prefix = 0;
729147999Semax		switch (keycode) {
730147999Semax		case 0x1C:	/* right enter key */
731147999Semax			keycode = 0x59;
732147999Semax			break;
733147999Semax		case 0x1D:	/* right ctrl key */
734147999Semax			keycode = 0x5A;
735147999Semax			break;
736147999Semax		case 0x35:	/* keypad divide key */
737147999Semax			keycode = 0x5B;
738147999Semax			break;
739147999Semax		case 0x37:	/* print scrn key */
740147999Semax			keycode = 0x5C;
741147999Semax			break;
742147999Semax		case 0x38:	/* right alt key (alt gr) */
743147999Semax			keycode = 0x5D;
744147999Semax			break;
745147999Semax		case 0x46:	/* ctrl-pause/break on AT 101 (see below) */
746147999Semax			keycode = 0x68;
747147999Semax			break;
748147999Semax		case 0x47:	/* grey home key */
749147999Semax			keycode = 0x5E;
750147999Semax			break;
751147999Semax		case 0x48:	/* grey up arrow key */
752147999Semax			keycode = 0x5F;
753147999Semax			break;
754147999Semax		case 0x49:	/* grey page up key */
755147999Semax			keycode = 0x60;
756147999Semax			break;
757147999Semax		case 0x4B:	/* grey left arrow key */
758147999Semax			keycode = 0x61;
759147999Semax			break;
760147999Semax		case 0x4D:	/* grey right arrow key */
761147999Semax			keycode = 0x62;
762147999Semax			break;
763147999Semax		case 0x4F:	/* grey end key */
764147999Semax			keycode = 0x63;
765147999Semax			break;
766147999Semax		case 0x50:	/* grey down arrow key */
767147999Semax			keycode = 0x64;
768147999Semax			break;
769147999Semax		case 0x51:	/* grey page down key */
770147999Semax			keycode = 0x65;
771147999Semax			break;
772147999Semax		case 0x52:	/* grey insert key */
773147999Semax			keycode = 0x66;
774147999Semax			break;
775147999Semax		case 0x53:	/* grey delete key */
776147999Semax			keycode = 0x67;
777147999Semax			break;
778147999Semax		/* the following 3 are only used on the MS "Natural" keyboard */
779147999Semax		case 0x5b:	/* left Window key */
780147999Semax			keycode = 0x69;
781147999Semax			break;
782147999Semax		case 0x5c:	/* right Window key */
783147999Semax			keycode = 0x6a;
784147999Semax			break;
785147999Semax		case 0x5d:	/* menu key */
786147999Semax			keycode = 0x6b;
787147999Semax			break;
788147999Semax		case 0x5e:	/* power key */
789147999Semax			keycode = 0x6d;
790147999Semax			break;
791147999Semax		case 0x5f:	/* sleep key */
792147999Semax			keycode = 0x6e;
793147999Semax			break;
794147999Semax		case 0x63:	/* wake key */
795147999Semax			keycode = 0x6f;
796147999Semax			break;
797171373Semax		case 0x64:	/* [JP106USB] backslash, underscore */
798171373Semax			keycode = 0x73;
799171373Semax			break;
800147999Semax		default:	/* ignore everything else */
801147999Semax			goto next_code;
802147999Semax		}
803147999Semax		break;
804147999Semax	case 0xE1:	/* 0xE1 prefix */
805147999Semax		/*
806147999Semax		 * The pause/break key on the 101 keyboard produces:
807147999Semax		 * E1-1D-45 E1-9D-C5
808147999Semax		 * Ctrl-pause/break produces:
809147999Semax		 * E0-46 E0-C6 (See above.)
810147999Semax		 */
811147999Semax		state->ks_prefix = 0;
812147999Semax		if (keycode == 0x1D)
813147999Semax			state->ks_prefix = 0x1D;
814147999Semax		goto next_code;
815147999Semax		/* NOT REACHED */
816147999Semax	case 0x1D:	/* pause / break */
817147999Semax		state->ks_prefix = 0;
818147999Semax		if (keycode != 0x45)
819147999Semax			goto next_code;
820147999Semax		keycode = 0x68;
821147999Semax		break;
822147999Semax	}
823147999Semax
824147999Semax	/* XXX assume 101/102 keys AT keyboard */
825147999Semax	switch (keycode) {
826147999Semax	case 0x5c:	/* print screen */
827147999Semax		if (state->ks_flags & ALTS)
828147999Semax			keycode = 0x54;	/* sysrq */
829147999Semax		break;
830147999Semax	case 0x68:	/* pause/break */
831147999Semax		if (state->ks_flags & CTLS)
832147999Semax			keycode = 0x6c;	/* break */
833147999Semax		break;
834147999Semax	}
835147999Semax
836147999Semax	/* return the key code in the K_CODE mode */
837147999Semax	if (state->ks_mode == K_CODE) {
838147999Semax		KBDMUX_UNLOCK(state);
839147999Semax		return (keycode | (scancode & 0x80));
840147999Semax	}
841147999Semax
842147999Semax	/* compose a character code */
843147999Semax	if (state->ks_flags & COMPOSE) {
844147999Semax		switch (keycode | (scancode & 0x80)) {
845147999Semax		/* key pressed, process it */
846147999Semax		case 0x47: case 0x48: case 0x49:	/* keypad 7,8,9 */
847147999Semax			state->ks_composed_char *= 10;
848147999Semax			state->ks_composed_char += keycode - 0x40;
849147999Semax			if (state->ks_composed_char > UCHAR_MAX) {
850147999Semax				KBDMUX_UNLOCK(state);
851147999Semax				return (ERRKEY);
852147999Semax			}
853147999Semax			goto next_code;
854147999Semax		case 0x4B: case 0x4C: case 0x4D:	/* keypad 4,5,6 */
855147999Semax			state->ks_composed_char *= 10;
856147999Semax			state->ks_composed_char += keycode - 0x47;
857147999Semax			if (state->ks_composed_char > UCHAR_MAX) {
858147999Semax				KBDMUX_UNLOCK(state);
859147999Semax				return (ERRKEY);
860147999Semax			}
861147999Semax			goto next_code;
862147999Semax		case 0x4F: case 0x50: case 0x51:	/* keypad 1,2,3 */
863147999Semax			state->ks_composed_char *= 10;
864147999Semax			state->ks_composed_char += keycode - 0x4E;
865147999Semax			if (state->ks_composed_char > UCHAR_MAX) {
866147999Semax				KBDMUX_UNLOCK(state);
867147999Semax				return (ERRKEY);
868147999Semax			}
869147999Semax			goto next_code;
870147999Semax		case 0x52:	/* keypad 0 */
871147999Semax			state->ks_composed_char *= 10;
872147999Semax			if (state->ks_composed_char > UCHAR_MAX) {
873147999Semax				KBDMUX_UNLOCK(state);
874147999Semax				return (ERRKEY);
875147999Semax			}
876147999Semax			goto next_code;
877147999Semax
878147999Semax		/* key released, no interest here */
879147999Semax		case 0xC7: case 0xC8: case 0xC9:	/* keypad 7,8,9 */
880147999Semax		case 0xCB: case 0xCC: case 0xCD:	/* keypad 4,5,6 */
881147999Semax		case 0xCF: case 0xD0: case 0xD1:	/* keypad 1,2,3 */
882147999Semax		case 0xD2:				/* keypad 0 */
883147999Semax			goto next_code;
884147999Semax
885147999Semax		case 0x38:				/* left alt key */
886147999Semax			break;
887147999Semax
888147999Semax		default:
889147999Semax			if (state->ks_composed_char > 0) {
890147999Semax				state->ks_flags &= ~COMPOSE;
891147999Semax				state->ks_composed_char = 0;
892147999Semax				KBDMUX_UNLOCK(state);
893147999Semax				return (ERRKEY);
894147999Semax			}
895147999Semax			break;
896147999Semax		}
897147999Semax	}
898147999Semax
899147999Semax	/* keycode to key action */
900147999Semax	action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
901147999Semax			&state->ks_state, &state->ks_accents);
902147999Semax	if (action == NOKEY)
903147999Semax		goto next_code;
904147999Semax
905147999Semax	KBDMUX_UNLOCK(state);
906147999Semax
907147999Semax	return (action);
908147999Semax}
909147999Semax
910147999Semax/*
911147999Semax * Check if char is waiting
912147999Semax */
913147999Semaxstatic int
914147999Semaxkbdmux_check_char(keyboard_t *kbd)
915147999Semax{
916147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
917147999Semax	int		 ready;
918147999Semax
919147999Semax	if (!KBD_IS_ACTIVE(kbd))
920147999Semax		return (FALSE);
921147999Semax
922147999Semax	KBDMUX_LOCK(state);
923147999Semax
924147999Semax	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
925147999Semax		ready = TRUE;
926147999Semax	else
927193512Sed		ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
928147999Semax
929147999Semax	KBDMUX_UNLOCK(state);
930147999Semax
931147999Semax	return (ready);
932147999Semax}
933147999Semax
934147999Semax/*
935147999Semax * Keyboard ioctl's
936147999Semax */
937147999Semaxstatic int
938147999Semaxkbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
939147999Semax{
940147999Semax	static int	 delays[] = {
941147999Semax		250, 500, 750, 1000
942147999Semax	};
943147999Semax
944147999Semax	static int	 rates[]  =  {
945147999Semax		34,  38,  42,  46,  50,   55,  59,  63,
946147999Semax		68,  76,  84,  92,  100, 110, 118, 126,
947147999Semax		136, 152, 168, 184, 200, 220, 236, 252,
948147999Semax		272, 304, 336, 368, 400, 440, 472, 504
949147999Semax	};
950147999Semax
951147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
952147999Semax	kbdmux_kbd_t	*k;
953148017Semax	keyboard_info_t	*ki;
954147999Semax	int		 error = 0, mode;
955162711Sru#ifdef COMPAT_FREEBSD6
956162711Sru	int		 ival;
957162711Sru#endif
958147999Semax
959147999Semax	if (state == NULL)
960147999Semax		return (ENXIO);
961147999Semax
962147999Semax	switch (cmd) {
963147999Semax	case KBADDKBD: /* add keyboard to the mux */
964148017Semax		ki = (keyboard_info_t *) arg;
965148017Semax
966148017Semax		if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
967148017Semax		    strcmp(ki->kb_name, "*") == 0)
968148017Semax			return (EINVAL); /* bad input */
969148017Semax
970147999Semax		KBDMUX_LOCK(state);
971147999Semax
972147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
973148017Semax			if (k->kbd->kb_unit == ki->kb_unit &&
974148017Semax			    strcmp(k->kbd->kb_name, ki->kb_name) == 0)
975147999Semax				break;
976147999Semax
977147999Semax		if (k != NULL) {
978147999Semax			KBDMUX_UNLOCK(state);
979147999Semax
980147999Semax			return (0); /* keyboard already in the mux */
981147999Semax		}
982147999Semax
983147999Semax		k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
984147999Semax		if (k == NULL) {
985147999Semax			KBDMUX_UNLOCK(state);
986147999Semax
987147999Semax			return (ENOMEM); /* out of memory */
988147999Semax		}
989147999Semax
990148017Semax		k->kbd = kbd_get_keyboard(
991148017Semax				kbd_allocate(
992148017Semax					ki->kb_name,
993148017Semax					ki->kb_unit,
994148017Semax					(void *) &k->kbd,
995148017Semax					kbdmux_kbd_event, (void *) state));
996147999Semax		if (k->kbd == NULL) {
997147999Semax			KBDMUX_UNLOCK(state);
998147999Semax			free(k, M_KBDMUX);
999147999Semax
1000148017Semax			return (EINVAL); /* bad keyboard */
1001147999Semax		}
1002147999Semax
1003174984Swkoszek		kbdd_enable(k->kbd);
1004174984Swkoszek		kbdd_clear_state(k->kbd);
1005147999Semax
1006147999Semax		/* set K_RAW mode on slave keyboard */
1007147999Semax		mode = K_RAW;
1008174984Swkoszek		error = kbdd_ioctl(k->kbd, KDSKBMODE, (caddr_t)&mode);
1009147999Semax		if (error == 0) {
1010147999Semax			/* set lock keys state on slave keyboard */
1011147999Semax			mode = state->ks_state & LOCK_MASK;
1012174984Swkoszek			error = kbdd_ioctl(k->kbd, KDSKBSTATE, (caddr_t)&mode);
1013147999Semax		}
1014147999Semax
1015147999Semax		if (error != 0) {
1016147999Semax			KBDMUX_UNLOCK(state);
1017147999Semax
1018147999Semax			kbd_release(k->kbd, &k->kbd);
1019147999Semax			k->kbd = NULL;
1020147999Semax
1021147999Semax			free(k, M_KBDMUX);
1022147999Semax
1023147999Semax			return (error); /* could not set mode */
1024147999Semax		}
1025147999Semax
1026147999Semax		SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
1027147999Semax
1028147999Semax		KBDMUX_UNLOCK(state);
1029147999Semax		break;
1030147999Semax
1031147999Semax	case KBRELKBD: /* release keyboard from the mux */
1032148017Semax		ki = (keyboard_info_t *) arg;
1033148017Semax
1034148017Semax		if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
1035148017Semax		    strcmp(ki->kb_name, "*") == 0)
1036148017Semax			return (EINVAL); /* bad input */
1037148017Semax
1038147999Semax		KBDMUX_LOCK(state);
1039147999Semax
1040147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
1041148017Semax			if (k->kbd->kb_unit == ki->kb_unit &&
1042148017Semax			    strcmp(k->kbd->kb_name, ki->kb_name) == 0)
1043147999Semax				break;
1044147999Semax
1045147999Semax		if (k != NULL) {
1046147999Semax			error = kbd_release(k->kbd, &k->kbd);
1047147999Semax			if (error == 0) {
1048147999Semax				SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
1049147999Semax
1050147999Semax				k->kbd = NULL;
1051147999Semax
1052147999Semax				free(k, M_KBDMUX);
1053147999Semax			}
1054147999Semax		} else
1055147999Semax			error = ENXIO; /* keyboard is not in the mux */
1056147999Semax
1057147999Semax		KBDMUX_UNLOCK(state);
1058147999Semax		break;
1059147999Semax
1060147999Semax	case KDGKBMODE: /* get kyboard mode */
1061147999Semax		KBDMUX_LOCK(state);
1062162441Sru		*(int *)arg = state->ks_mode;
1063147999Semax		KBDMUX_UNLOCK(state);
1064147999Semax		break;
1065147999Semax
1066162711Sru#ifdef COMPAT_FREEBSD6
1067162711Sru	case _IO('K', 7):
1068162711Sru		ival = IOCPARM_IVAL(arg);
1069162711Sru		arg = (caddr_t)&ival;
1070162711Sru		/* FALLTHROUGH */
1071162711Sru#endif
1072147999Semax	case KDSKBMODE: /* set keyboard mode */
1073147999Semax		KBDMUX_LOCK(state);
1074147999Semax
1075162461Sru		switch (*(int *)arg) {
1076147999Semax		case K_XLATE:
1077147999Semax			if (state->ks_mode != K_XLATE) {
1078147999Semax				/* make lock key state and LED state match */
1079147999Semax				state->ks_state &= ~LOCK_MASK;
1080147999Semax				state->ks_state |= KBD_LED_VAL(kbd);
1081147999Semax                        }
1082147999Semax                        /* FALLTHROUGH */
1083147999Semax
1084147999Semax		case K_RAW:
1085147999Semax		case K_CODE:
1086162461Sru			if (state->ks_mode != *(int *)arg) {
1087147999Semax				kbdmux_clear_state_locked(state);
1088162461Sru				state->ks_mode = *(int *)arg;
1089147999Semax			}
1090147999Semax			break;
1091147999Semax
1092147999Semax                default:
1093147999Semax			error = EINVAL;
1094147999Semax			break;
1095147999Semax		}
1096147999Semax
1097147999Semax		KBDMUX_UNLOCK(state);
1098147999Semax		break;
1099147999Semax
1100147999Semax	case KDGETLED: /* get keyboard LED */
1101147999Semax		KBDMUX_LOCK(state);
1102162441Sru		*(int *)arg = KBD_LED_VAL(kbd);
1103147999Semax		KBDMUX_UNLOCK(state);
1104147999Semax		break;
1105147999Semax
1106162711Sru#ifdef COMPAT_FREEBSD6
1107162711Sru	case _IO('K', 66):
1108162711Sru		ival = IOCPARM_IVAL(arg);
1109162711Sru		arg = (caddr_t)&ival;
1110162711Sru		/* FALLTHROUGH */
1111162711Sru#endif
1112147999Semax	case KDSETLED: /* set keyboard LED */
1113147999Semax		KBDMUX_LOCK(state);
1114147999Semax
1115147999Semax		/* NOTE: lock key state in ks_state won't be changed */
1116162461Sru		if (*(int *)arg & ~LOCK_MASK) {
1117147999Semax			KBDMUX_UNLOCK(state);
1118147999Semax
1119147999Semax			return (EINVAL);
1120147999Semax		}
1121147999Semax
1122162461Sru		KBD_LED_VAL(kbd) = *(int *)arg;
1123147999Semax
1124147999Semax		/* KDSETLED on all slave keyboards */
1125147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
1126213770Srpaulo			(void)kbdd_ioctl(k->kbd, KDSETLED, arg);
1127147999Semax
1128147999Semax		KBDMUX_UNLOCK(state);
1129147999Semax		break;
1130147999Semax
1131147999Semax	case KDGKBSTATE: /* get lock key state */
1132147999Semax		KBDMUX_LOCK(state);
1133162441Sru		*(int *)arg = state->ks_state & LOCK_MASK;
1134147999Semax		KBDMUX_UNLOCK(state);
1135147999Semax		break;
1136147999Semax
1137162711Sru#ifdef COMPAT_FREEBSD6
1138162711Sru	case _IO('K', 20):
1139162711Sru		ival = IOCPARM_IVAL(arg);
1140162711Sru		arg = (caddr_t)&ival;
1141162711Sru		/* FALLTHROUGH */
1142162711Sru#endif
1143147999Semax	case KDSKBSTATE: /* set lock key state */
1144147999Semax		KBDMUX_LOCK(state);
1145147999Semax
1146162461Sru		if (*(int *)arg & ~LOCK_MASK) {
1147147999Semax			KBDMUX_UNLOCK(state);
1148147999Semax
1149147999Semax			return (EINVAL);
1150147999Semax		}
1151147999Semax
1152147999Semax		state->ks_state &= ~LOCK_MASK;
1153162461Sru		state->ks_state |= *(int *)arg;
1154147999Semax
1155147999Semax		/* KDSKBSTATE on all slave keyboards */
1156147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
1157213770Srpaulo			(void)kbdd_ioctl(k->kbd, KDSKBSTATE, arg);
1158147999Semax
1159147999Semax		KBDMUX_UNLOCK(state);
1160147999Semax
1161147999Semax		return (kbdmux_ioctl(kbd, KDSETLED, arg));
1162147999Semax		/* NOT REACHED */
1163147999Semax
1164162711Sru#ifdef COMPAT_FREEBSD6
1165162711Sru	case _IO('K', 67):
1166162711Sru		cmd = KDSETRAD;
1167162711Sru		ival = IOCPARM_IVAL(arg);
1168162711Sru		arg = (caddr_t)&ival;
1169162711Sru		/* FALLTHROUGH */
1170162711Sru#endif
1171147999Semax	case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1172147999Semax	case KDSETRAD: /* set keyboard repeat rate (old interface) */
1173147999Semax		KBDMUX_LOCK(state);
1174147999Semax
1175147999Semax		if (cmd == KDSETREPEAT) {
1176147999Semax			int	i;
1177147999Semax
1178147999Semax			/* lookup delay */
1179147999Semax			for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --)
1180162441Sru				if (((int *)arg)[0] >= delays[i])
1181147999Semax					break;
1182147999Semax			mode = i << 5;
1183147999Semax
1184147999Semax			/* lookup rate */
1185147999Semax			for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --)
1186162441Sru				if (((int *)arg)[1] >= rates[i])
1187147999Semax					break;
1188147999Semax			mode |= i;
1189147999Semax		} else
1190162461Sru			mode = *(int *)arg;
1191147999Semax
1192147999Semax		if (mode & ~0x7f) {
1193147999Semax			KBDMUX_UNLOCK(state);
1194147999Semax
1195147999Semax			return (EINVAL);
1196147999Semax		}
1197147999Semax
1198147999Semax		kbd->kb_delay1 = delays[(mode >> 5) & 3];
1199147999Semax		kbd->kb_delay2 = rates[mode & 0x1f];
1200147999Semax
1201147999Semax		/* perform command on all slave keyboards */
1202147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
1203213770Srpaulo			(void)kbdd_ioctl(k->kbd, cmd, arg);
1204147999Semax
1205147999Semax		KBDMUX_UNLOCK(state);
1206147999Semax		break;
1207147999Semax
1208147999Semax	case PIO_KEYMAP:	/* set keyboard translation table */
1209224126Sed	case OPIO_KEYMAP:	/* set keyboard translation table (compat) */
1210156013Semax	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
1211156013Semax	case PIO_DEADKEYMAP:	/* set accent key translation table */
1212147999Semax		KBDMUX_LOCK(state);
1213147999Semax                state->ks_accents = 0;
1214147999Semax
1215147999Semax		/* perform command on all slave keyboards */
1216147999Semax		SLIST_FOREACH(k, &state->ks_kbds, next)
1217213770Srpaulo			(void)kbdd_ioctl(k->kbd, cmd, arg);
1218147999Semax
1219147999Semax		KBDMUX_UNLOCK(state);
1220147999Semax                /* FALLTHROUGH */
1221147999Semax
1222147999Semax	default:
1223147999Semax		error = genkbd_commonioctl(kbd, cmd, arg);
1224147999Semax		break;
1225147999Semax	}
1226147999Semax
1227147999Semax	return (error);
1228147999Semax}
1229147999Semax
1230147999Semax/*
1231147999Semax * Lock the access to the keyboard
1232147999Semax */
1233147999Semaxstatic int
1234147999Semaxkbdmux_lock(keyboard_t *kbd, int lock)
1235147999Semax{
1236147999Semax	return (1); /* XXX */
1237147999Semax}
1238147999Semax
1239147999Semax/*
1240147999Semax * Clear the internal state of the keyboard
1241147999Semax */
1242147999Semaxstatic void
1243147999Semaxkbdmux_clear_state_locked(kbdmux_state_t *state)
1244147999Semax{
1245147999Semax	KBDMUX_LOCK_ASSERT(state, MA_OWNED);
1246147999Semax
1247147999Semax	state->ks_flags &= ~(COMPOSE|POLLING);
1248147999Semax	state->ks_state &= LOCK_MASK;	/* preserve locking key state */
1249147999Semax	state->ks_accents = 0;
1250147999Semax	state->ks_composed_char = 0;
1251147999Semax/*	state->ks_prefix = 0;		XXX */
1252193512Sed	state->ks_inq_length = 0;
1253147999Semax}
1254147999Semax
1255147999Semaxstatic void
1256147999Semaxkbdmux_clear_state(keyboard_t *kbd)
1257147999Semax{
1258147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
1259147999Semax
1260147999Semax	KBDMUX_LOCK(state);
1261147999Semax	kbdmux_clear_state_locked(state);
1262147999Semax	KBDMUX_UNLOCK(state);
1263147999Semax}
1264147999Semax
1265147999Semax/*
1266147999Semax * Save the internal state
1267147999Semax */
1268147999Semaxstatic int
1269147999Semaxkbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1270147999Semax{
1271147999Semax	if (len == 0)
1272147999Semax		return (sizeof(kbdmux_state_t));
1273147999Semax	if (len < sizeof(kbdmux_state_t))
1274147999Semax		return (-1);
1275147999Semax
1276147999Semax	bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1277147999Semax
1278147999Semax	return (0);
1279147999Semax}
1280147999Semax
1281147999Semax/*
1282147999Semax * Set the internal state
1283147999Semax */
1284147999Semaxstatic int
1285147999Semaxkbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1286147999Semax{
1287147999Semax	if (len < sizeof(kbdmux_state_t))
1288147999Semax		return (ENOMEM);
1289147999Semax
1290147999Semax	bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1291147999Semax
1292147999Semax	return (0);
1293147999Semax}
1294147999Semax
1295147999Semax/*
1296147999Semax * Set polling
1297147999Semax */
1298147999Semaxstatic int
1299147999Semaxkbdmux_poll(keyboard_t *kbd, int on)
1300147999Semax{
1301147999Semax	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
1302147999Semax	kbdmux_kbd_t	*k;
1303147999Semax
1304147999Semax	KBDMUX_LOCK(state);
1305147999Semax
1306147999Semax	if (on)
1307147999Semax		state->ks_flags |= POLLING;
1308147999Semax	else
1309147999Semax		state->ks_flags &= ~POLLING;
1310147999Semax
1311147999Semax	/* set poll on slave keyboards */
1312147999Semax	SLIST_FOREACH(k, &state->ks_kbds, next)
1313174984Swkoszek		kbdd_poll(k->kbd, on);
1314147999Semax
1315147999Semax	KBDMUX_UNLOCK(state);
1316147999Semax
1317147999Semax	return (0);
1318147999Semax}
1319147999Semax
1320147999Semax/*****************************************************************************
1321147999Semax *****************************************************************************
1322147999Semax **                                    Module
1323147999Semax *****************************************************************************
1324147999Semax *****************************************************************************/
1325147999Semax
1326147999SemaxKEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1327147999Semax
1328147999Semaxstatic int
1329147999Semaxkbdmux_modevent(module_t mod, int type, void *data)
1330147999Semax{
1331147999Semax	keyboard_switch_t	*sw;
1332147999Semax	keyboard_t		*kbd;
1333147999Semax	int			 error;
1334147999Semax
1335147999Semax	switch (type) {
1336147999Semax	case MOD_LOAD:
1337147999Semax		if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1338147999Semax			break;
1339147999Semax
1340147999Semax		if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1341147999Semax			kbd_delete_driver(&kbdmux_kbd_driver);
1342147999Semax			error = ENXIO;
1343147999Semax			break;
1344147999Semax		}
1345147999Semax
1346147999Semax		kbd = NULL;
1347147999Semax
1348147999Semax		if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
1349147999Semax		    (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) {
1350147999Semax			kbd_delete_driver(&kbdmux_kbd_driver);
1351147999Semax			break;
1352147999Semax		}
1353147999Semax
1354147999Semax#ifdef KBD_INSTALL_CDEV
1355147999Semax		if ((error = kbd_attach(kbd)) != 0) {
1356147999Semax			(*sw->term)(kbd);
1357147999Semax			kbd_delete_driver(&kbdmux_kbd_driver);
1358147999Semax			break;
1359147999Semax		}
1360147999Semax#endif
1361147999Semax
1362147999Semax		if ((error = (*sw->enable)(kbd)) != 0) {
1363147999Semax			(*sw->disable)(kbd);
1364151440Syar#ifdef KBD_INSTALL_CDEV
1365147999Semax			kbd_detach(kbd);
1366151440Syar#endif
1367147999Semax			(*sw->term)(kbd);
1368147999Semax			kbd_delete_driver(&kbdmux_kbd_driver);
1369147999Semax			break;
1370147999Semax		}
1371147999Semax		break;
1372147999Semax
1373147999Semax	case MOD_UNLOAD:
1374147999Semax		if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
1375147999Semax			panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
1376147999Semax
1377147999Semax		kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1378188603Sthompsa		if (kbd != NULL) {
1379188603Sthompsa			(*sw->disable)(kbd);
1380147999Semax#ifdef KBD_INSTALL_CDEV
1381188603Sthompsa			kbd_detach(kbd);
1382147999Semax#endif
1383188603Sthompsa			(*sw->term)(kbd);
1384188603Sthompsa			kbd_delete_driver(&kbdmux_kbd_driver);
1385188603Sthompsa		}
1386147999Semax		error = 0;
1387147999Semax		break;
1388147999Semax
1389147999Semax	default:
1390147999Semax		error = EOPNOTSUPP;
1391147999Semax		break;
1392147999Semax	}
1393147999Semax
1394188030Semax	return (error);
1395147999Semax}
1396147999Semax
1397147999SemaxDEV_MODULE(kbdmux, kbdmux_modevent, NULL);
1398147999Semax
1399