xref: /freebsd-src/sys/dev/kbdmux/kbdmux.c (revision 2ff63af9b88c7413b7d71715b5532625752a248e)
1dfa49439SMaksim Yevmenkin /*
2dfa49439SMaksim Yevmenkin  * kbdmux.c
3dfa49439SMaksim Yevmenkin  */
4dfa49439SMaksim Yevmenkin 
5dfa49439SMaksim Yevmenkin /*-
64d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
7718cf2ccSPedro F. Giffuni  *
8dfa49439SMaksim Yevmenkin  * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9dfa49439SMaksim Yevmenkin  * All rights reserved.
10dfa49439SMaksim Yevmenkin  *
11dfa49439SMaksim Yevmenkin  * Redistribution and use in source and binary forms, with or without
12dfa49439SMaksim Yevmenkin  * modification, are permitted provided that the following conditions
13dfa49439SMaksim Yevmenkin  * are met:
14dfa49439SMaksim Yevmenkin  * 1. Redistributions of source code must retain the above copyright
15dfa49439SMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer.
16dfa49439SMaksim Yevmenkin  * 2. Redistributions in binary form must reproduce the above copyright
17dfa49439SMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer in the
18dfa49439SMaksim Yevmenkin  *    documentation and/or other materials provided with the distribution.
19dfa49439SMaksim Yevmenkin  *
20dfa49439SMaksim Yevmenkin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21dfa49439SMaksim Yevmenkin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22dfa49439SMaksim Yevmenkin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23dfa49439SMaksim Yevmenkin  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24dfa49439SMaksim Yevmenkin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25dfa49439SMaksim Yevmenkin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26dfa49439SMaksim Yevmenkin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27dfa49439SMaksim Yevmenkin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28dfa49439SMaksim Yevmenkin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29dfa49439SMaksim Yevmenkin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30dfa49439SMaksim Yevmenkin  * SUCH DAMAGE.
31dfa49439SMaksim Yevmenkin  *
32dfa49439SMaksim Yevmenkin  * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $
33dfa49439SMaksim Yevmenkin  */
34dfa49439SMaksim Yevmenkin 
3597fc5dbeSOleksandr Tymoshenko #include "opt_evdev.h"
36dfa49439SMaksim Yevmenkin #include "opt_kbd.h"
3746360281SEd Maste #include "opt_kbdmux.h"
38dfa49439SMaksim Yevmenkin 
39dfa49439SMaksim Yevmenkin #include <sys/param.h>
40b569776dSMaksim Yevmenkin #include <sys/bus.h>
41dfa49439SMaksim Yevmenkin #include <sys/conf.h>
42dfa49439SMaksim Yevmenkin #include <sys/consio.h>
43dfa49439SMaksim Yevmenkin #include <sys/fcntl.h>
44dfa49439SMaksim Yevmenkin #include <sys/kbio.h>
45dfa49439SMaksim Yevmenkin #include <sys/kernel.h>
46dfa49439SMaksim Yevmenkin #include <sys/limits.h>
47dfa49439SMaksim Yevmenkin #include <sys/lock.h>
48dfa49439SMaksim Yevmenkin #include <sys/malloc.h>
49dfa49439SMaksim Yevmenkin #include <sys/module.h>
50dfa49439SMaksim Yevmenkin #include <sys/mutex.h>
51dfa49439SMaksim Yevmenkin #include <sys/poll.h>
52dfa49439SMaksim Yevmenkin #include <sys/proc.h>
53dfa49439SMaksim Yevmenkin #include <sys/queue.h>
54dfa49439SMaksim Yevmenkin #include <sys/selinfo.h>
55dfa49439SMaksim Yevmenkin #include <sys/systm.h>
56dfa49439SMaksim Yevmenkin #include <sys/taskqueue.h>
57dfa49439SMaksim Yevmenkin #include <sys/uio.h>
58dfa49439SMaksim Yevmenkin #include <dev/kbd/kbdreg.h>
5946360281SEd Maste 
6046360281SEd Maste /* the initial key map, accent map and fkey strings */
6146360281SEd Maste #ifdef KBDMUX_DFLT_KEYMAP
6246360281SEd Maste #define KBD_DFLT_KEYMAP
6346360281SEd Maste #include "kbdmuxmap.h"
6446360281SEd Maste #endif
6546360281SEd Maste 
66dfa49439SMaksim Yevmenkin #include <dev/kbd/kbdtables.h>
67dfa49439SMaksim Yevmenkin 
6897fc5dbeSOleksandr Tymoshenko #ifdef EVDEV_SUPPORT
6997fc5dbeSOleksandr Tymoshenko #include <dev/evdev/evdev.h>
7097fc5dbeSOleksandr Tymoshenko #include <dev/evdev/input.h>
7197fc5dbeSOleksandr Tymoshenko #endif
7297fc5dbeSOleksandr Tymoshenko 
73dfa49439SMaksim Yevmenkin #define KEYBOARD_NAME	"kbdmux"
74dfa49439SMaksim Yevmenkin 
75dfa49439SMaksim Yevmenkin MALLOC_DECLARE(M_KBDMUX);
76dfa49439SMaksim Yevmenkin MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
77dfa49439SMaksim Yevmenkin 
78dfa49439SMaksim Yevmenkin /*****************************************************************************
79dfa49439SMaksim Yevmenkin  *****************************************************************************
80dfa49439SMaksim Yevmenkin  **                             Keyboard state
81dfa49439SMaksim Yevmenkin  *****************************************************************************
82dfa49439SMaksim Yevmenkin  *****************************************************************************/
83dfa49439SMaksim Yevmenkin 
84dfa49439SMaksim Yevmenkin #define	KBDMUX_Q_SIZE	512	/* input queue size */
85dfa49439SMaksim Yevmenkin 
86dfa49439SMaksim Yevmenkin /*
87dfa49439SMaksim Yevmenkin  * XXX
88dfa49439SMaksim Yevmenkin  * For now rely on Giant mutex to protect our data structures.
89dfa49439SMaksim Yevmenkin  * Just like the rest of keyboard drivers and syscons(4) do.
90dfa49439SMaksim Yevmenkin  * Note that callout is initialized as not MP-safe to make sure
91dfa49439SMaksim Yevmenkin  * Giant is held.
92dfa49439SMaksim Yevmenkin  */
93dfa49439SMaksim Yevmenkin 
94dfa49439SMaksim Yevmenkin #if 0 /* not yet */
95dfa49439SMaksim Yevmenkin #define KBDMUX_LOCK_DECL_GLOBAL \
96dfa49439SMaksim Yevmenkin 	struct mtx ks_lock
97dfa49439SMaksim Yevmenkin #define KBDMUX_LOCK_INIT(s) \
98dfa49439SMaksim Yevmenkin 	mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE)
99dfa49439SMaksim Yevmenkin #define KBDMUX_LOCK_DESTROY(s) \
100dfa49439SMaksim Yevmenkin 	mtx_destroy(&(s)->ks_lock)
101dfa49439SMaksim Yevmenkin #define KBDMUX_LOCK(s) \
102dfa49439SMaksim Yevmenkin 	mtx_lock(&(s)->ks_lock)
103dfa49439SMaksim Yevmenkin #define KBDMUX_UNLOCK(s) \
104dfa49439SMaksim Yevmenkin 	mtx_unlock(&(s)->ks_lock)
105dfa49439SMaksim Yevmenkin #define KBDMUX_LOCK_ASSERT(s, w) \
106dfa49439SMaksim Yevmenkin 	mtx_assert(&(s)->ks_lock, (w))
107dfa49439SMaksim Yevmenkin #else
108dfa49439SMaksim Yevmenkin #define KBDMUX_LOCK_DECL_GLOBAL
109dfa49439SMaksim Yevmenkin 
110dfa49439SMaksim Yevmenkin #define KBDMUX_LOCK_INIT(s)
111dfa49439SMaksim Yevmenkin 
112dfa49439SMaksim Yevmenkin #define KBDMUX_LOCK_DESTROY(s)
113dfa49439SMaksim Yevmenkin 
114ed382753SMaksim Yevmenkin #define KBDMUX_LOCK(s)
115ed382753SMaksim Yevmenkin 
116ed382753SMaksim Yevmenkin #define KBDMUX_UNLOCK(s)
117ed382753SMaksim Yevmenkin 
118dfa49439SMaksim Yevmenkin #define KBDMUX_LOCK_ASSERT(s, w)
119dfa49439SMaksim Yevmenkin 
120dfa49439SMaksim Yevmenkin #endif /* not yet */
121dfa49439SMaksim Yevmenkin 
122dfa49439SMaksim Yevmenkin /*
123dfa49439SMaksim Yevmenkin  * kbdmux keyboard
124dfa49439SMaksim Yevmenkin  */
125dfa49439SMaksim Yevmenkin struct kbdmux_kbd
126dfa49439SMaksim Yevmenkin {
127dfa49439SMaksim Yevmenkin 	keyboard_t		*kbd;	/* keyboard */
128dfa49439SMaksim Yevmenkin 	SLIST_ENTRY(kbdmux_kbd)	 next;	/* link to next */
129dfa49439SMaksim Yevmenkin };
130dfa49439SMaksim Yevmenkin 
131dfa49439SMaksim Yevmenkin typedef struct kbdmux_kbd	kbdmux_kbd_t;
132dfa49439SMaksim Yevmenkin 
133dfa49439SMaksim Yevmenkin /*
134dfa49439SMaksim Yevmenkin  * kbdmux state
135dfa49439SMaksim Yevmenkin  */
136dfa49439SMaksim Yevmenkin struct kbdmux_state
137dfa49439SMaksim Yevmenkin {
1385f46eda1SEd Schouten 	char			 ks_inq[KBDMUX_Q_SIZE]; /* input chars queue */
1395f46eda1SEd Schouten 	unsigned int		 ks_inq_start;
1405f46eda1SEd Schouten 	unsigned int		 ks_inq_length;
141dfa49439SMaksim Yevmenkin 	struct task		 ks_task;	/* interrupt task */
142dfa49439SMaksim Yevmenkin 	struct callout		 ks_timo;	/* timeout handler */
143dfa49439SMaksim Yevmenkin #define TICKS			(hz)		/* rate */
144dfa49439SMaksim Yevmenkin 
145dfa49439SMaksim Yevmenkin 	int			 ks_flags;	/* flags */
146dfa49439SMaksim Yevmenkin #define COMPOSE			(1 << 0)	/* compose char flag */
147dfa49439SMaksim Yevmenkin 
148cc43fd1aSBruce Evans 	int			 ks_polling;	/* poll nesting count */
149dfa49439SMaksim Yevmenkin 	int			 ks_mode;	/* K_XLATE, K_RAW, K_CODE */
150dfa49439SMaksim Yevmenkin 	int			 ks_state;	/* state */
151dfa49439SMaksim Yevmenkin 	int			 ks_accents;	/* accent key index (> 0) */
152dfa49439SMaksim Yevmenkin 	u_int			 ks_composed_char; /* composed char code */
153dfa49439SMaksim Yevmenkin 	u_char			 ks_prefix;	/* AT scan code prefix */
154dfa49439SMaksim Yevmenkin 
15597fc5dbeSOleksandr Tymoshenko #ifdef EVDEV_SUPPORT
15697fc5dbeSOleksandr Tymoshenko 	struct evdev_dev *	 ks_evdev;
15797fc5dbeSOleksandr Tymoshenko 	int			 ks_evdev_state;
15897fc5dbeSOleksandr Tymoshenko #endif
15997fc5dbeSOleksandr Tymoshenko 
160dfa49439SMaksim Yevmenkin 	SLIST_HEAD(, kbdmux_kbd) ks_kbds;	/* keyboards */
161dfa49439SMaksim Yevmenkin 
162dfa49439SMaksim Yevmenkin 	KBDMUX_LOCK_DECL_GLOBAL;
163dfa49439SMaksim Yevmenkin };
164dfa49439SMaksim Yevmenkin 
165dfa49439SMaksim Yevmenkin typedef struct kbdmux_state	kbdmux_state_t;
166dfa49439SMaksim Yevmenkin 
167dfa49439SMaksim Yevmenkin /*****************************************************************************
168dfa49439SMaksim Yevmenkin  *****************************************************************************
169dfa49439SMaksim Yevmenkin  **                             Helper functions
170dfa49439SMaksim Yevmenkin  *****************************************************************************
171dfa49439SMaksim Yevmenkin  *****************************************************************************/
172dfa49439SMaksim Yevmenkin 
173dfa49439SMaksim Yevmenkin static task_fn_t		kbdmux_kbd_intr;
1745773ac11SJohn Baldwin static callout_func_t		kbdmux_kbd_intr_timo;
175dfa49439SMaksim Yevmenkin static kbd_callback_func_t	kbdmux_kbd_event;
176dfa49439SMaksim Yevmenkin 
1775f46eda1SEd Schouten static void
kbdmux_kbd_putc(kbdmux_state_t * state,char c)1785f46eda1SEd Schouten kbdmux_kbd_putc(kbdmux_state_t *state, char c)
1795f46eda1SEd Schouten {
1805f46eda1SEd Schouten 	unsigned int p;
1815f46eda1SEd Schouten 
1825f46eda1SEd Schouten 	if (state->ks_inq_length == KBDMUX_Q_SIZE)
1835f46eda1SEd Schouten 		return;
1845f46eda1SEd Schouten 
1855f46eda1SEd Schouten 	p = (state->ks_inq_start + state->ks_inq_length) % KBDMUX_Q_SIZE;
1865f46eda1SEd Schouten 	state->ks_inq[p] = c;
1875f46eda1SEd Schouten 	state->ks_inq_length++;
1885f46eda1SEd Schouten }
1895f46eda1SEd Schouten 
19041763573SEd Schouten static int
kbdmux_kbd_getc(kbdmux_state_t * state)1915f46eda1SEd Schouten kbdmux_kbd_getc(kbdmux_state_t *state)
1925f46eda1SEd Schouten {
19341763573SEd Schouten 	unsigned char c;
1945f46eda1SEd Schouten 
1955f46eda1SEd Schouten 	if (state->ks_inq_length == 0)
1965f46eda1SEd Schouten 		return (-1);
1975f46eda1SEd Schouten 
1985f46eda1SEd Schouten 	c = state->ks_inq[state->ks_inq_start];
1995f46eda1SEd Schouten 	state->ks_inq_start = (state->ks_inq_start + 1) % KBDMUX_Q_SIZE;
2005f46eda1SEd Schouten 	state->ks_inq_length--;
2015f46eda1SEd Schouten 
2025f46eda1SEd Schouten 	return (c);
2035f46eda1SEd Schouten }
2045f46eda1SEd Schouten 
205dfa49439SMaksim Yevmenkin /*
206dfa49439SMaksim Yevmenkin  * Interrupt handler task
207dfa49439SMaksim Yevmenkin  */
208dfa49439SMaksim Yevmenkin void
kbdmux_kbd_intr(void * xkbd,int pending)209dfa49439SMaksim Yevmenkin kbdmux_kbd_intr(void *xkbd, int pending)
210dfa49439SMaksim Yevmenkin {
211dfa49439SMaksim Yevmenkin 	keyboard_t	*kbd = (keyboard_t *) xkbd;
212dfa49439SMaksim Yevmenkin 
213259699b2SWojciech A. Koszek 	kbdd_intr(kbd, NULL);
214dfa49439SMaksim Yevmenkin }
215dfa49439SMaksim Yevmenkin 
216dfa49439SMaksim Yevmenkin /*
217dfa49439SMaksim Yevmenkin  * Schedule interrupt handler on timeout. Called with locked state.
218dfa49439SMaksim Yevmenkin  */
219dfa49439SMaksim Yevmenkin void
kbdmux_kbd_intr_timo(void * xstate)220dfa49439SMaksim Yevmenkin kbdmux_kbd_intr_timo(void *xstate)
221dfa49439SMaksim Yevmenkin {
222dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = (kbdmux_state_t *) xstate;
223dfa49439SMaksim Yevmenkin 
224dfa49439SMaksim Yevmenkin 	/* queue interrupt task if needed */
225e5018628SAlexander Motin 	if (state->ks_inq_length > 0)
226e5018628SAlexander Motin 		taskqueue_enqueue(taskqueue_swi_giant, &state->ks_task);
227dfa49439SMaksim Yevmenkin 
228dfa49439SMaksim Yevmenkin 	/* re-schedule timeout */
229e5018628SAlexander Motin 	callout_schedule(&state->ks_timo, TICKS);
230dfa49439SMaksim Yevmenkin }
231dfa49439SMaksim Yevmenkin 
232dfa49439SMaksim Yevmenkin /*
233dfa49439SMaksim Yevmenkin  * Process event from one of our keyboards
234dfa49439SMaksim Yevmenkin  */
235dfa49439SMaksim Yevmenkin static int
kbdmux_kbd_event(keyboard_t * kbd,int event,void * arg)236dfa49439SMaksim Yevmenkin kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
237dfa49439SMaksim Yevmenkin {
238dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = (kbdmux_state_t *) arg;
239dfa49439SMaksim Yevmenkin 
240dfa49439SMaksim Yevmenkin 	switch (event) {
241dfa49439SMaksim Yevmenkin 	case KBDIO_KEYINPUT: {
242dfa49439SMaksim Yevmenkin 		int	c;
243dfa49439SMaksim Yevmenkin 
244dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
245dfa49439SMaksim Yevmenkin 
24665b70c1dSMaksim Yevmenkin 		/*
24765b70c1dSMaksim Yevmenkin 		 * Read all chars from the keyboard
24865b70c1dSMaksim Yevmenkin 		 *
24965b70c1dSMaksim Yevmenkin 		 * Turns out that atkbd(4) check_char() method may return
25065b70c1dSMaksim Yevmenkin 		 * "true" while read_char() method returns NOKEY. If this
25165b70c1dSMaksim Yevmenkin 		 * happens we could stuck in the loop below. Avoid this
25265b70c1dSMaksim Yevmenkin 		 * by breaking out of the loop if read_char() method returns
25365b70c1dSMaksim Yevmenkin 		 * NOKEY.
25465b70c1dSMaksim Yevmenkin 		 */
25565b70c1dSMaksim Yevmenkin 
256259699b2SWojciech A. Koszek 		while (kbdd_check_char(kbd)) {
257259699b2SWojciech A. Koszek 			c = kbdd_read_char(kbd, 0);
258dfa49439SMaksim Yevmenkin 			if (c == NOKEY)
259fd4df699SMaksim Yevmenkin 				break;
260dfa49439SMaksim Yevmenkin 			if (c == ERRKEY)
261dfa49439SMaksim Yevmenkin 				continue; /* XXX ring bell */
262dfa49439SMaksim Yevmenkin 			if (!KBD_IS_BUSY(kbd))
263dfa49439SMaksim Yevmenkin 				continue; /* not open - discard the input */
264dfa49439SMaksim Yevmenkin 
2655f46eda1SEd Schouten 			kbdmux_kbd_putc(state, c);
266dfa49439SMaksim Yevmenkin 		}
267dfa49439SMaksim Yevmenkin 
268dfa49439SMaksim Yevmenkin 		/* queue interrupt task if needed */
269e5018628SAlexander Motin 		if (state->ks_inq_length > 0)
270e5018628SAlexander Motin 			taskqueue_enqueue(taskqueue_swi_giant, &state->ks_task);
271dfa49439SMaksim Yevmenkin 
272dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
273dfa49439SMaksim Yevmenkin 		} break;
274dfa49439SMaksim Yevmenkin 
275dfa49439SMaksim Yevmenkin 	case KBDIO_UNLOADING: {
276dfa49439SMaksim Yevmenkin 		kbdmux_kbd_t	*k;
277dfa49439SMaksim Yevmenkin 
278dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
279dfa49439SMaksim Yevmenkin 
280dfa49439SMaksim Yevmenkin 		SLIST_FOREACH(k, &state->ks_kbds, next)
281dfa49439SMaksim Yevmenkin 			if (k->kbd == kbd)
282dfa49439SMaksim Yevmenkin 				break;
283dfa49439SMaksim Yevmenkin 
284dfa49439SMaksim Yevmenkin 		if (k != NULL) {
285dfa49439SMaksim Yevmenkin 			kbd_release(k->kbd, &k->kbd);
286dfa49439SMaksim Yevmenkin 			SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
287dfa49439SMaksim Yevmenkin 
288dfa49439SMaksim Yevmenkin 			k->kbd = NULL;
289dfa49439SMaksim Yevmenkin 
290dfa49439SMaksim Yevmenkin 			free(k, M_KBDMUX);
291dfa49439SMaksim Yevmenkin 		}
292dfa49439SMaksim Yevmenkin 
293dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
294dfa49439SMaksim Yevmenkin 		} break;
295dfa49439SMaksim Yevmenkin 
296dfa49439SMaksim Yevmenkin 	default:
297dfa49439SMaksim Yevmenkin 		return (EINVAL);
298dfa49439SMaksim Yevmenkin 		/* NOT REACHED */
299dfa49439SMaksim Yevmenkin 	}
300dfa49439SMaksim Yevmenkin 
301dfa49439SMaksim Yevmenkin 	return (0);
302dfa49439SMaksim Yevmenkin }
303dfa49439SMaksim Yevmenkin 
304dfa49439SMaksim Yevmenkin /****************************************************************************
305dfa49439SMaksim Yevmenkin  ****************************************************************************
306dfa49439SMaksim Yevmenkin  **                              Keyboard driver
307dfa49439SMaksim Yevmenkin  ****************************************************************************
308dfa49439SMaksim Yevmenkin  ****************************************************************************/
309dfa49439SMaksim Yevmenkin 
310dfa49439SMaksim Yevmenkin static int		kbdmux_configure(int flags);
311dfa49439SMaksim Yevmenkin static kbd_probe_t	kbdmux_probe;
312dfa49439SMaksim Yevmenkin static kbd_init_t	kbdmux_init;
313dfa49439SMaksim Yevmenkin static kbd_term_t	kbdmux_term;
314dfa49439SMaksim Yevmenkin static kbd_intr_t	kbdmux_intr;
315dfa49439SMaksim Yevmenkin static kbd_test_if_t	kbdmux_test_if;
316dfa49439SMaksim Yevmenkin static kbd_enable_t	kbdmux_enable;
317dfa49439SMaksim Yevmenkin static kbd_disable_t	kbdmux_disable;
318dfa49439SMaksim Yevmenkin static kbd_read_t	kbdmux_read;
319dfa49439SMaksim Yevmenkin static kbd_check_t	kbdmux_check;
320dfa49439SMaksim Yevmenkin static kbd_read_char_t	kbdmux_read_char;
321dfa49439SMaksim Yevmenkin static kbd_check_char_t	kbdmux_check_char;
322dfa49439SMaksim Yevmenkin static kbd_ioctl_t	kbdmux_ioctl;
323dfa49439SMaksim Yevmenkin static kbd_lock_t	kbdmux_lock;
324dfa49439SMaksim Yevmenkin static void		kbdmux_clear_state_locked(kbdmux_state_t *state);
325dfa49439SMaksim Yevmenkin static kbd_clear_state_t kbdmux_clear_state;
326dfa49439SMaksim Yevmenkin static kbd_get_state_t	kbdmux_get_state;
327dfa49439SMaksim Yevmenkin static kbd_set_state_t	kbdmux_set_state;
328dfa49439SMaksim Yevmenkin static kbd_poll_mode_t	kbdmux_poll;
329dfa49439SMaksim Yevmenkin 
330dfa49439SMaksim Yevmenkin static keyboard_switch_t kbdmuxsw = {
331dfa49439SMaksim Yevmenkin 	.probe =	kbdmux_probe,
332dfa49439SMaksim Yevmenkin 	.init =		kbdmux_init,
333dfa49439SMaksim Yevmenkin 	.term =		kbdmux_term,
334dfa49439SMaksim Yevmenkin 	.intr =		kbdmux_intr,
335dfa49439SMaksim Yevmenkin 	.test_if =	kbdmux_test_if,
336dfa49439SMaksim Yevmenkin 	.enable =	kbdmux_enable,
337dfa49439SMaksim Yevmenkin 	.disable =	kbdmux_disable,
338dfa49439SMaksim Yevmenkin 	.read =		kbdmux_read,
339dfa49439SMaksim Yevmenkin 	.check =	kbdmux_check,
340dfa49439SMaksim Yevmenkin 	.read_char =	kbdmux_read_char,
341dfa49439SMaksim Yevmenkin 	.check_char =	kbdmux_check_char,
342dfa49439SMaksim Yevmenkin 	.ioctl =	kbdmux_ioctl,
343dfa49439SMaksim Yevmenkin 	.lock =		kbdmux_lock,
344dfa49439SMaksim Yevmenkin 	.clear_state =	kbdmux_clear_state,
345dfa49439SMaksim Yevmenkin 	.get_state =	kbdmux_get_state,
346dfa49439SMaksim Yevmenkin 	.set_state =	kbdmux_set_state,
347dfa49439SMaksim Yevmenkin 	.poll =		kbdmux_poll,
348dfa49439SMaksim Yevmenkin };
349dfa49439SMaksim Yevmenkin 
35097fc5dbeSOleksandr Tymoshenko #ifdef EVDEV_SUPPORT
35148f2b006SVladimir Kondratyev static evdev_event_t kbdmux_ev_event;
35248f2b006SVladimir Kondratyev 
35397fc5dbeSOleksandr Tymoshenko static const struct evdev_methods kbdmux_evdev_methods = {
35448f2b006SVladimir Kondratyev 	.ev_event = kbdmux_ev_event,
35597fc5dbeSOleksandr Tymoshenko };
35697fc5dbeSOleksandr Tymoshenko #endif
35797fc5dbeSOleksandr Tymoshenko 
358dfa49439SMaksim Yevmenkin /*
359dfa49439SMaksim Yevmenkin  * Return the number of found keyboards
360dfa49439SMaksim Yevmenkin  */
361dfa49439SMaksim Yevmenkin static int
kbdmux_configure(int flags)362dfa49439SMaksim Yevmenkin kbdmux_configure(int flags)
363dfa49439SMaksim Yevmenkin {
364dfa49439SMaksim Yevmenkin 	return (1);
365dfa49439SMaksim Yevmenkin }
366dfa49439SMaksim Yevmenkin 
367dfa49439SMaksim Yevmenkin /*
368dfa49439SMaksim Yevmenkin  * Detect a keyboard
369dfa49439SMaksim Yevmenkin  */
370dfa49439SMaksim Yevmenkin static int
kbdmux_probe(int unit,void * arg,int flags)371dfa49439SMaksim Yevmenkin kbdmux_probe(int unit, void *arg, int flags)
372dfa49439SMaksim Yevmenkin {
373a8de37b0SEitan Adler 	if (resource_disabled(KEYBOARD_NAME, unit))
374a8de37b0SEitan Adler 		return (ENXIO);
375b569776dSMaksim Yevmenkin 
376dfa49439SMaksim Yevmenkin 	return (0);
377dfa49439SMaksim Yevmenkin }
378dfa49439SMaksim Yevmenkin 
379dfa49439SMaksim Yevmenkin /*
380dfa49439SMaksim Yevmenkin  * Reset and initialize the keyboard (stolen from atkbd.c)
381dfa49439SMaksim Yevmenkin  */
382dfa49439SMaksim Yevmenkin static int
kbdmux_init(int unit,keyboard_t ** kbdp,void * arg,int flags)383dfa49439SMaksim Yevmenkin kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
384dfa49439SMaksim Yevmenkin {
385dfa49439SMaksim Yevmenkin 	keyboard_t	*kbd = NULL;
386dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = NULL;
387dfa49439SMaksim Yevmenkin 	keymap_t	*keymap = NULL;
388dfa49439SMaksim Yevmenkin         accentmap_t	*accmap = NULL;
389dfa49439SMaksim Yevmenkin         fkeytab_t	*fkeymap = NULL;
390dfa49439SMaksim Yevmenkin 	int		 error, needfree, fkeymap_size, delay[2];
39197fc5dbeSOleksandr Tymoshenko #ifdef EVDEV_SUPPORT
39297fc5dbeSOleksandr Tymoshenko 	struct evdev_dev *evdev;
39397fc5dbeSOleksandr Tymoshenko 	char		 phys_loc[NAMELEN];
39497fc5dbeSOleksandr Tymoshenko #endif
395dfa49439SMaksim Yevmenkin 
396dfa49439SMaksim Yevmenkin 	if (*kbdp == NULL) {
397dfa49439SMaksim Yevmenkin 		*kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
398dfa49439SMaksim Yevmenkin 		state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
399dfa49439SMaksim Yevmenkin 		keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
400dfa49439SMaksim Yevmenkin 		accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
401dfa49439SMaksim Yevmenkin 		fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
402dfa49439SMaksim Yevmenkin 		fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
403dfa49439SMaksim Yevmenkin 		needfree = 1;
404dfa49439SMaksim Yevmenkin 
405dfa49439SMaksim Yevmenkin 		if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
406dfa49439SMaksim Yevmenkin 		    (accmap == NULL) || (fkeymap == NULL)) {
407dfa49439SMaksim Yevmenkin 			error = ENOMEM;
408dfa49439SMaksim Yevmenkin 			goto bad;
409dfa49439SMaksim Yevmenkin 		}
410dfa49439SMaksim Yevmenkin 
411dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK_INIT(state);
412dfa49439SMaksim Yevmenkin 		TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
413e5018628SAlexander Motin 		callout_init(&state->ks_timo, 1);
414dfa49439SMaksim Yevmenkin 		SLIST_INIT(&state->ks_kbds);
415dfa49439SMaksim Yevmenkin 	} else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
416dfa49439SMaksim Yevmenkin 		return (0);
417dfa49439SMaksim Yevmenkin 	} else {
418dfa49439SMaksim Yevmenkin 		kbd = *kbdp;
419dfa49439SMaksim Yevmenkin 		state = (kbdmux_state_t *) kbd->kb_data;
420dfa49439SMaksim Yevmenkin 		keymap = kbd->kb_keymap;
421dfa49439SMaksim Yevmenkin 		accmap = kbd->kb_accentmap;
422dfa49439SMaksim Yevmenkin 		fkeymap = kbd->kb_fkeytab;
423dfa49439SMaksim Yevmenkin 		fkeymap_size = kbd->kb_fkeytab_size;
424dfa49439SMaksim Yevmenkin 		needfree = 0;
425dfa49439SMaksim Yevmenkin 	}
426dfa49439SMaksim Yevmenkin 
427dfa49439SMaksim Yevmenkin 	if (!KBD_IS_PROBED(kbd)) {
428dfa49439SMaksim Yevmenkin 		/* XXX assume 101/102 keys keyboard */
429dfa49439SMaksim Yevmenkin 		kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0);
430dfa49439SMaksim Yevmenkin 		bcopy(&key_map, keymap, sizeof(key_map));
431dfa49439SMaksim Yevmenkin 		bcopy(&accent_map, accmap, sizeof(accent_map));
432dfa49439SMaksim Yevmenkin 		bcopy(fkey_tab, fkeymap,
433dfa49439SMaksim Yevmenkin 			imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
434dfa49439SMaksim Yevmenkin 		kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
435dfa49439SMaksim Yevmenkin 		kbd->kb_data = (void *)state;
436dfa49439SMaksim Yevmenkin 
437dfa49439SMaksim Yevmenkin 		KBD_FOUND_DEVICE(kbd);
438dfa49439SMaksim Yevmenkin 		KBD_PROBE_DONE(kbd);
439dfa49439SMaksim Yevmenkin 
440dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
441dfa49439SMaksim Yevmenkin 		kbdmux_clear_state_locked(state);
442dfa49439SMaksim Yevmenkin 		state->ks_mode = K_XLATE;
443dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
444dfa49439SMaksim Yevmenkin 	}
445dfa49439SMaksim Yevmenkin 
446dfa49439SMaksim Yevmenkin 	if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
447dfa49439SMaksim Yevmenkin 		kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
448dfa49439SMaksim Yevmenkin 
449dfa49439SMaksim Yevmenkin 		kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
450dfa49439SMaksim Yevmenkin 
451dfa49439SMaksim Yevmenkin 		delay[0] = kbd->kb_delay1;
452dfa49439SMaksim Yevmenkin 		delay[1] = kbd->kb_delay2;
453dfa49439SMaksim Yevmenkin 		kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
454dfa49439SMaksim Yevmenkin 
45597fc5dbeSOleksandr Tymoshenko #ifdef EVDEV_SUPPORT
45697fc5dbeSOleksandr Tymoshenko 		/* register as evdev provider */
45797fc5dbeSOleksandr Tymoshenko 		evdev = evdev_alloc();
45897fc5dbeSOleksandr Tymoshenko 		evdev_set_name(evdev, "System keyboard multiplexer");
45997fc5dbeSOleksandr Tymoshenko 		snprintf(phys_loc, NAMELEN, KEYBOARD_NAME"%d", unit);
46097fc5dbeSOleksandr Tymoshenko 		evdev_set_phys(evdev, phys_loc);
46197fc5dbeSOleksandr Tymoshenko 		evdev_set_id(evdev, BUS_VIRTUAL, 0, 0, 0);
46297fc5dbeSOleksandr Tymoshenko 		evdev_set_methods(evdev, kbd, &kbdmux_evdev_methods);
46397fc5dbeSOleksandr Tymoshenko 		evdev_support_event(evdev, EV_SYN);
46497fc5dbeSOleksandr Tymoshenko 		evdev_support_event(evdev, EV_KEY);
46597fc5dbeSOleksandr Tymoshenko 		evdev_support_event(evdev, EV_LED);
46697fc5dbeSOleksandr Tymoshenko 		evdev_support_event(evdev, EV_REP);
46797fc5dbeSOleksandr Tymoshenko 		evdev_support_all_known_keys(evdev);
46897fc5dbeSOleksandr Tymoshenko 		evdev_support_led(evdev, LED_NUML);
46997fc5dbeSOleksandr Tymoshenko 		evdev_support_led(evdev, LED_CAPSL);
47097fc5dbeSOleksandr Tymoshenko 		evdev_support_led(evdev, LED_SCROLLL);
47197fc5dbeSOleksandr Tymoshenko 
472f86e7267SVladimir Kondratyev 		if (evdev_register_mtx(evdev, &Giant))
47397fc5dbeSOleksandr Tymoshenko 			evdev_free(evdev);
47497fc5dbeSOleksandr Tymoshenko 		else
47597fc5dbeSOleksandr Tymoshenko 			state->ks_evdev = evdev;
47697fc5dbeSOleksandr Tymoshenko 		state->ks_evdev_state = 0;
47797fc5dbeSOleksandr Tymoshenko #endif
47897fc5dbeSOleksandr Tymoshenko 
479dfa49439SMaksim Yevmenkin 		KBD_INIT_DONE(kbd);
480dfa49439SMaksim Yevmenkin 	}
481dfa49439SMaksim Yevmenkin 
482dfa49439SMaksim Yevmenkin 	if (!KBD_IS_CONFIGURED(kbd)) {
483dfa49439SMaksim Yevmenkin 		if (kbd_register(kbd) < 0) {
484dfa49439SMaksim Yevmenkin 			error = ENXIO;
485dfa49439SMaksim Yevmenkin 			goto bad;
486dfa49439SMaksim Yevmenkin 		}
487dfa49439SMaksim Yevmenkin 
488dfa49439SMaksim Yevmenkin 		KBD_CONFIG_DONE(kbd);
489dfa49439SMaksim Yevmenkin 
490dfa49439SMaksim Yevmenkin 		callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
491dfa49439SMaksim Yevmenkin 	}
492dfa49439SMaksim Yevmenkin 
493dfa49439SMaksim Yevmenkin 	return (0);
494dfa49439SMaksim Yevmenkin bad:
495dfa49439SMaksim Yevmenkin 	if (needfree) {
4965f46eda1SEd Schouten 		if (state != NULL)
497dfa49439SMaksim Yevmenkin 			free(state, M_KBDMUX);
498dfa49439SMaksim Yevmenkin 		if (keymap != NULL)
499dfa49439SMaksim Yevmenkin 			free(keymap, M_KBDMUX);
500dfa49439SMaksim Yevmenkin 		if (accmap != NULL)
501dfa49439SMaksim Yevmenkin 			free(accmap, M_KBDMUX);
502dfa49439SMaksim Yevmenkin 		if (fkeymap != NULL)
503dfa49439SMaksim Yevmenkin 			free(fkeymap, M_KBDMUX);
504dfa49439SMaksim Yevmenkin 		if (kbd != NULL) {
505dfa49439SMaksim Yevmenkin 			free(kbd, M_KBDMUX);
506dfa49439SMaksim Yevmenkin 			*kbdp = NULL;	/* insure ref doesn't leak to caller */
507dfa49439SMaksim Yevmenkin 		}
508dfa49439SMaksim Yevmenkin 	}
509dfa49439SMaksim Yevmenkin 
510dfa49439SMaksim Yevmenkin 	return (error);
511dfa49439SMaksim Yevmenkin }
512dfa49439SMaksim Yevmenkin 
513dfa49439SMaksim Yevmenkin /*
514dfa49439SMaksim Yevmenkin  * Finish using this keyboard
515dfa49439SMaksim Yevmenkin  */
516dfa49439SMaksim Yevmenkin static int
kbdmux_term(keyboard_t * kbd)517dfa49439SMaksim Yevmenkin kbdmux_term(keyboard_t *kbd)
518dfa49439SMaksim Yevmenkin {
519dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
520dfa49439SMaksim Yevmenkin 	kbdmux_kbd_t	*k;
521dfa49439SMaksim Yevmenkin 
522dfa49439SMaksim Yevmenkin 	/* release all keyboards from the mux */
523e5018628SAlexander Motin 	KBDMUX_LOCK(state);
524dfa49439SMaksim Yevmenkin 	while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
525dfa49439SMaksim Yevmenkin 		kbd_release(k->kbd, &k->kbd);
526dfa49439SMaksim Yevmenkin 		SLIST_REMOVE_HEAD(&state->ks_kbds, next);
527dfa49439SMaksim Yevmenkin 
528dfa49439SMaksim Yevmenkin 		k->kbd = NULL;
529dfa49439SMaksim Yevmenkin 
530dfa49439SMaksim Yevmenkin 		free(k, M_KBDMUX);
531dfa49439SMaksim Yevmenkin 	}
532dfa49439SMaksim Yevmenkin 	KBDMUX_UNLOCK(state);
533dfa49439SMaksim Yevmenkin 
534e5018628SAlexander Motin 	callout_drain(&state->ks_timo);
535e5018628SAlexander Motin 	taskqueue_drain(taskqueue_swi_giant, &state->ks_task);
536e5018628SAlexander Motin 
537dfa49439SMaksim Yevmenkin 	kbd_unregister(kbd);
538dfa49439SMaksim Yevmenkin 
53997fc5dbeSOleksandr Tymoshenko #ifdef EVDEV_SUPPORT
54097fc5dbeSOleksandr Tymoshenko 	evdev_free(state->ks_evdev);
54197fc5dbeSOleksandr Tymoshenko #endif
54297fc5dbeSOleksandr Tymoshenko 
543dfa49439SMaksim Yevmenkin 	KBDMUX_LOCK_DESTROY(state);
544dfa49439SMaksim Yevmenkin 	bzero(state, sizeof(*state));
545dfa49439SMaksim Yevmenkin 	free(state, M_KBDMUX);
54640a3c5eaSMaksim Yevmenkin 
54740a3c5eaSMaksim Yevmenkin 	free(kbd->kb_keymap, M_KBDMUX);
54840a3c5eaSMaksim Yevmenkin 	free(kbd->kb_accentmap, M_KBDMUX);
54940a3c5eaSMaksim Yevmenkin 	free(kbd->kb_fkeytab, M_KBDMUX);
550dfa49439SMaksim Yevmenkin 	free(kbd, M_KBDMUX);
551dfa49439SMaksim Yevmenkin 
552dfa49439SMaksim Yevmenkin 	return (0);
553dfa49439SMaksim Yevmenkin }
554dfa49439SMaksim Yevmenkin 
555dfa49439SMaksim Yevmenkin /*
556dfa49439SMaksim Yevmenkin  * Keyboard interrupt routine
557dfa49439SMaksim Yevmenkin  */
558dfa49439SMaksim Yevmenkin static int
kbdmux_intr(keyboard_t * kbd,void * arg)559dfa49439SMaksim Yevmenkin kbdmux_intr(keyboard_t *kbd, void *arg)
560dfa49439SMaksim Yevmenkin {
561dfa49439SMaksim Yevmenkin 	int	c;
562dfa49439SMaksim Yevmenkin 
563dfa49439SMaksim Yevmenkin 	if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
564dfa49439SMaksim Yevmenkin 		/* let the callback function to process the input */
565dfa49439SMaksim Yevmenkin 		(*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
566dfa49439SMaksim Yevmenkin 					    kbd->kb_callback.kc_arg);
567dfa49439SMaksim Yevmenkin 	} else {
568dfa49439SMaksim Yevmenkin 		/* read and discard the input; no one is waiting for input */
569dfa49439SMaksim Yevmenkin 		do {
570dfa49439SMaksim Yevmenkin 			c = kbdmux_read_char(kbd, FALSE);
571dfa49439SMaksim Yevmenkin 		} while (c != NOKEY);
572dfa49439SMaksim Yevmenkin 	}
573dfa49439SMaksim Yevmenkin 
574dfa49439SMaksim Yevmenkin 	return (0);
575dfa49439SMaksim Yevmenkin }
576dfa49439SMaksim Yevmenkin 
577dfa49439SMaksim Yevmenkin /*
578dfa49439SMaksim Yevmenkin  * Test the interface to the device
579dfa49439SMaksim Yevmenkin  */
580dfa49439SMaksim Yevmenkin static int
kbdmux_test_if(keyboard_t * kbd)581dfa49439SMaksim Yevmenkin kbdmux_test_if(keyboard_t *kbd)
582dfa49439SMaksim Yevmenkin {
583dfa49439SMaksim Yevmenkin 	return (0);
584dfa49439SMaksim Yevmenkin }
585dfa49439SMaksim Yevmenkin 
586dfa49439SMaksim Yevmenkin /*
587dfa49439SMaksim Yevmenkin  * Enable the access to the device; until this function is called,
588dfa49439SMaksim Yevmenkin  * the client cannot read from the keyboard.
589dfa49439SMaksim Yevmenkin  */
590dfa49439SMaksim Yevmenkin static int
kbdmux_enable(keyboard_t * kbd)591dfa49439SMaksim Yevmenkin kbdmux_enable(keyboard_t *kbd)
592dfa49439SMaksim Yevmenkin {
593dfa49439SMaksim Yevmenkin 	KBD_ACTIVATE(kbd);
594dfa49439SMaksim Yevmenkin 	return (0);
595dfa49439SMaksim Yevmenkin }
596dfa49439SMaksim Yevmenkin 
597dfa49439SMaksim Yevmenkin /*
598dfa49439SMaksim Yevmenkin  * Disallow the access to the device
599dfa49439SMaksim Yevmenkin  */
600dfa49439SMaksim Yevmenkin static int
kbdmux_disable(keyboard_t * kbd)601dfa49439SMaksim Yevmenkin kbdmux_disable(keyboard_t *kbd)
602dfa49439SMaksim Yevmenkin {
603dfa49439SMaksim Yevmenkin 	KBD_DEACTIVATE(kbd);
604dfa49439SMaksim Yevmenkin 	return (0);
605dfa49439SMaksim Yevmenkin }
606dfa49439SMaksim Yevmenkin 
607dfa49439SMaksim Yevmenkin /*
608dfa49439SMaksim Yevmenkin  * Read one byte from the keyboard if it's allowed
609dfa49439SMaksim Yevmenkin  */
610dfa49439SMaksim Yevmenkin static int
kbdmux_read(keyboard_t * kbd,int wait)611dfa49439SMaksim Yevmenkin kbdmux_read(keyboard_t *kbd, int wait)
612dfa49439SMaksim Yevmenkin {
613dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
614dfa49439SMaksim Yevmenkin 	int		 c;
615dfa49439SMaksim Yevmenkin 
616dfa49439SMaksim Yevmenkin 	KBDMUX_LOCK(state);
6175f46eda1SEd Schouten 	c = kbdmux_kbd_getc(state);
618dfa49439SMaksim Yevmenkin 	KBDMUX_UNLOCK(state);
619dfa49439SMaksim Yevmenkin 
620dfa49439SMaksim Yevmenkin 	if (c != -1)
621dfa49439SMaksim Yevmenkin 		kbd->kb_count ++;
622dfa49439SMaksim Yevmenkin 
623dfa49439SMaksim Yevmenkin 	return (KBD_IS_ACTIVE(kbd)? c : -1);
624dfa49439SMaksim Yevmenkin }
625dfa49439SMaksim Yevmenkin 
626dfa49439SMaksim Yevmenkin /*
627dfa49439SMaksim Yevmenkin  * Check if data is waiting
628dfa49439SMaksim Yevmenkin  */
629dfa49439SMaksim Yevmenkin static int
kbdmux_check(keyboard_t * kbd)630dfa49439SMaksim Yevmenkin kbdmux_check(keyboard_t *kbd)
631dfa49439SMaksim Yevmenkin {
632dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
633dfa49439SMaksim Yevmenkin 	int		 ready;
634dfa49439SMaksim Yevmenkin 
635dfa49439SMaksim Yevmenkin 	if (!KBD_IS_ACTIVE(kbd))
636dfa49439SMaksim Yevmenkin 		return (FALSE);
637dfa49439SMaksim Yevmenkin 
638dfa49439SMaksim Yevmenkin 	KBDMUX_LOCK(state);
6395f46eda1SEd Schouten 	ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
640dfa49439SMaksim Yevmenkin 	KBDMUX_UNLOCK(state);
641dfa49439SMaksim Yevmenkin 
642dfa49439SMaksim Yevmenkin 	return (ready);
643dfa49439SMaksim Yevmenkin }
644dfa49439SMaksim Yevmenkin 
645dfa49439SMaksim Yevmenkin /*
646dfa49439SMaksim Yevmenkin  * Read char from the keyboard (stolen from atkbd.c)
647dfa49439SMaksim Yevmenkin  */
648dfa49439SMaksim Yevmenkin static u_int
kbdmux_read_char(keyboard_t * kbd,int wait)649dfa49439SMaksim Yevmenkin kbdmux_read_char(keyboard_t *kbd, int wait)
650dfa49439SMaksim Yevmenkin {
651dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
652dfa49439SMaksim Yevmenkin 	u_int		 action;
653dfa49439SMaksim Yevmenkin 	int		 scancode, keycode;
654dfa49439SMaksim Yevmenkin 
655dfa49439SMaksim Yevmenkin 	KBDMUX_LOCK(state);
656dfa49439SMaksim Yevmenkin 
657dfa49439SMaksim Yevmenkin next_code:
658dfa49439SMaksim Yevmenkin 
659dfa49439SMaksim Yevmenkin 	/* do we have a composed char to return? */
660dfa49439SMaksim Yevmenkin 	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
661dfa49439SMaksim Yevmenkin 		action = state->ks_composed_char;
662dfa49439SMaksim Yevmenkin 		state->ks_composed_char = 0;
663dfa49439SMaksim Yevmenkin 		if (action > UCHAR_MAX) {
664dfa49439SMaksim Yevmenkin 			KBDMUX_UNLOCK(state);
665dfa49439SMaksim Yevmenkin 
666dfa49439SMaksim Yevmenkin 			return (ERRKEY);
667dfa49439SMaksim Yevmenkin 		}
668dfa49439SMaksim Yevmenkin 
669dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
670dfa49439SMaksim Yevmenkin 
671dfa49439SMaksim Yevmenkin 		return (action);
672dfa49439SMaksim Yevmenkin 	}
673dfa49439SMaksim Yevmenkin 
674dfa49439SMaksim Yevmenkin 	/* see if there is something in the keyboard queue */
6755f46eda1SEd Schouten 	scancode = kbdmux_kbd_getc(state);
676dfa49439SMaksim Yevmenkin 	if (scancode == -1) {
677cc43fd1aSBruce Evans 		if (state->ks_polling != 0) {
67804c1ba9bSMaksim Yevmenkin 			kbdmux_kbd_t	*k;
67904c1ba9bSMaksim Yevmenkin 
68004c1ba9bSMaksim Yevmenkin 			SLIST_FOREACH(k, &state->ks_kbds, next) {
681259699b2SWojciech A. Koszek 				while (kbdd_check_char(k->kbd)) {
682259699b2SWojciech A. Koszek 					scancode = kbdd_read_char(k->kbd, 0);
68304c1ba9bSMaksim Yevmenkin 					if (scancode == NOKEY)
68404c1ba9bSMaksim Yevmenkin 						break;
68504c1ba9bSMaksim Yevmenkin 					if (scancode == ERRKEY)
68604c1ba9bSMaksim Yevmenkin 						continue;
68704c1ba9bSMaksim Yevmenkin 					if (!KBD_IS_BUSY(k->kbd))
68804c1ba9bSMaksim Yevmenkin 						continue;
68904c1ba9bSMaksim Yevmenkin 
6905f46eda1SEd Schouten 					kbdmux_kbd_putc(state, scancode);
69104c1ba9bSMaksim Yevmenkin 				}
69204c1ba9bSMaksim Yevmenkin 			}
69304c1ba9bSMaksim Yevmenkin 
6945f46eda1SEd Schouten 			if (state->ks_inq_length > 0)
69504c1ba9bSMaksim Yevmenkin 				goto next_code;
69604c1ba9bSMaksim Yevmenkin 		}
69704c1ba9bSMaksim Yevmenkin 
698dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
699dfa49439SMaksim Yevmenkin 		return (NOKEY);
700dfa49439SMaksim Yevmenkin 	}
701dfa49439SMaksim Yevmenkin 	/* XXX FIXME: check for -1 if wait == 1! */
702dfa49439SMaksim Yevmenkin 
703dfa49439SMaksim Yevmenkin 	kbd->kb_count ++;
704dfa49439SMaksim Yevmenkin 
70597fc5dbeSOleksandr Tymoshenko #ifdef EVDEV_SUPPORT
70697fc5dbeSOleksandr Tymoshenko 	/* push evdev event */
70797fc5dbeSOleksandr Tymoshenko 	if (evdev_rcpt_mask & EVDEV_RCPT_KBDMUX && state->ks_evdev != NULL) {
70897fc5dbeSOleksandr Tymoshenko 		uint16_t key = evdev_scancode2key(&state->ks_evdev_state,
70997fc5dbeSOleksandr Tymoshenko 		    scancode);
71097fc5dbeSOleksandr Tymoshenko 
71197fc5dbeSOleksandr Tymoshenko 		if (key != KEY_RESERVED) {
71297fc5dbeSOleksandr Tymoshenko 			evdev_push_event(state->ks_evdev, EV_KEY,
71397fc5dbeSOleksandr Tymoshenko 			    key, scancode & 0x80 ? 0 : 1);
71497fc5dbeSOleksandr Tymoshenko 			evdev_sync(state->ks_evdev);
71597fc5dbeSOleksandr Tymoshenko 		}
71697fc5dbeSOleksandr Tymoshenko 	}
71718308893SVladimir Kondratyev 
71818308893SVladimir Kondratyev 	if (state->ks_evdev != NULL && evdev_is_grabbed(state->ks_evdev))
71918308893SVladimir Kondratyev 		return (NOKEY);
72097fc5dbeSOleksandr Tymoshenko #endif
72197fc5dbeSOleksandr Tymoshenko 
722dfa49439SMaksim Yevmenkin 	/* return the byte as is for the K_RAW mode */
723dfa49439SMaksim Yevmenkin 	if (state->ks_mode == K_RAW) {
724dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
725dfa49439SMaksim Yevmenkin 		return (scancode);
726dfa49439SMaksim Yevmenkin 	}
727dfa49439SMaksim Yevmenkin 
728dfa49439SMaksim Yevmenkin 	/* translate the scan code into a keycode */
729dfa49439SMaksim Yevmenkin 	keycode = scancode & 0x7F;
730dfa49439SMaksim Yevmenkin 	switch (state->ks_prefix) {
731dfa49439SMaksim Yevmenkin 	case 0x00:	/* normal scancode */
732dfa49439SMaksim Yevmenkin 		switch(scancode) {
733dfa49439SMaksim Yevmenkin 		case 0xB8:	/* left alt (compose key) released */
734dfa49439SMaksim Yevmenkin 			if (state->ks_flags & COMPOSE) {
735dfa49439SMaksim Yevmenkin 				state->ks_flags &= ~COMPOSE;
736dfa49439SMaksim Yevmenkin 				if (state->ks_composed_char > UCHAR_MAX)
737dfa49439SMaksim Yevmenkin 					state->ks_composed_char = 0;
738dfa49439SMaksim Yevmenkin 			}
739dfa49439SMaksim Yevmenkin 			break;
740dfa49439SMaksim Yevmenkin 		case 0x38:	/* left alt (compose key) pressed */
741dfa49439SMaksim Yevmenkin 			if (!(state->ks_flags & COMPOSE)) {
742dfa49439SMaksim Yevmenkin 				state->ks_flags |= COMPOSE;
743dfa49439SMaksim Yevmenkin 				state->ks_composed_char = 0;
744dfa49439SMaksim Yevmenkin 			}
745dfa49439SMaksim Yevmenkin 			break;
746dfa49439SMaksim Yevmenkin 		case 0xE0:
747dfa49439SMaksim Yevmenkin 		case 0xE1:
748dfa49439SMaksim Yevmenkin 			state->ks_prefix = scancode;
749dfa49439SMaksim Yevmenkin 			goto next_code;
750dfa49439SMaksim Yevmenkin 		}
751dfa49439SMaksim Yevmenkin 		break;
752dfa49439SMaksim Yevmenkin 	case 0xE0:      /* 0xE0 prefix */
753dfa49439SMaksim Yevmenkin 		state->ks_prefix = 0;
754dfa49439SMaksim Yevmenkin 		switch (keycode) {
755dfa49439SMaksim Yevmenkin 		case 0x1C:	/* right enter key */
756dfa49439SMaksim Yevmenkin 			keycode = 0x59;
757dfa49439SMaksim Yevmenkin 			break;
758dfa49439SMaksim Yevmenkin 		case 0x1D:	/* right ctrl key */
759dfa49439SMaksim Yevmenkin 			keycode = 0x5A;
760dfa49439SMaksim Yevmenkin 			break;
761dfa49439SMaksim Yevmenkin 		case 0x35:	/* keypad divide key */
762dfa49439SMaksim Yevmenkin 			keycode = 0x5B;
763dfa49439SMaksim Yevmenkin 			break;
764dfa49439SMaksim Yevmenkin 		case 0x37:	/* print scrn key */
765dfa49439SMaksim Yevmenkin 			keycode = 0x5C;
766dfa49439SMaksim Yevmenkin 			break;
767dfa49439SMaksim Yevmenkin 		case 0x38:	/* right alt key (alt gr) */
768dfa49439SMaksim Yevmenkin 			keycode = 0x5D;
769dfa49439SMaksim Yevmenkin 			break;
770dfa49439SMaksim Yevmenkin 		case 0x46:	/* ctrl-pause/break on AT 101 (see below) */
771dfa49439SMaksim Yevmenkin 			keycode = 0x68;
772dfa49439SMaksim Yevmenkin 			break;
773dfa49439SMaksim Yevmenkin 		case 0x47:	/* grey home key */
774dfa49439SMaksim Yevmenkin 			keycode = 0x5E;
775dfa49439SMaksim Yevmenkin 			break;
776dfa49439SMaksim Yevmenkin 		case 0x48:	/* grey up arrow key */
777dfa49439SMaksim Yevmenkin 			keycode = 0x5F;
778dfa49439SMaksim Yevmenkin 			break;
779dfa49439SMaksim Yevmenkin 		case 0x49:	/* grey page up key */
780dfa49439SMaksim Yevmenkin 			keycode = 0x60;
781dfa49439SMaksim Yevmenkin 			break;
782dfa49439SMaksim Yevmenkin 		case 0x4B:	/* grey left arrow key */
783dfa49439SMaksim Yevmenkin 			keycode = 0x61;
784dfa49439SMaksim Yevmenkin 			break;
785dfa49439SMaksim Yevmenkin 		case 0x4D:	/* grey right arrow key */
786dfa49439SMaksim Yevmenkin 			keycode = 0x62;
787dfa49439SMaksim Yevmenkin 			break;
788dfa49439SMaksim Yevmenkin 		case 0x4F:	/* grey end key */
789dfa49439SMaksim Yevmenkin 			keycode = 0x63;
790dfa49439SMaksim Yevmenkin 			break;
791dfa49439SMaksim Yevmenkin 		case 0x50:	/* grey down arrow key */
792dfa49439SMaksim Yevmenkin 			keycode = 0x64;
793dfa49439SMaksim Yevmenkin 			break;
794dfa49439SMaksim Yevmenkin 		case 0x51:	/* grey page down key */
795dfa49439SMaksim Yevmenkin 			keycode = 0x65;
796dfa49439SMaksim Yevmenkin 			break;
797dfa49439SMaksim Yevmenkin 		case 0x52:	/* grey insert key */
798dfa49439SMaksim Yevmenkin 			keycode = 0x66;
799dfa49439SMaksim Yevmenkin 			break;
800dfa49439SMaksim Yevmenkin 		case 0x53:	/* grey delete key */
801dfa49439SMaksim Yevmenkin 			keycode = 0x67;
802dfa49439SMaksim Yevmenkin 			break;
803dfa49439SMaksim Yevmenkin 		/* the following 3 are only used on the MS "Natural" keyboard */
804dfa49439SMaksim Yevmenkin 		case 0x5b:	/* left Window key */
805dfa49439SMaksim Yevmenkin 			keycode = 0x69;
806dfa49439SMaksim Yevmenkin 			break;
807dfa49439SMaksim Yevmenkin 		case 0x5c:	/* right Window key */
808dfa49439SMaksim Yevmenkin 			keycode = 0x6a;
809dfa49439SMaksim Yevmenkin 			break;
810dfa49439SMaksim Yevmenkin 		case 0x5d:	/* menu key */
811dfa49439SMaksim Yevmenkin 			keycode = 0x6b;
812dfa49439SMaksim Yevmenkin 			break;
813dfa49439SMaksim Yevmenkin 		case 0x5e:	/* power key */
814dfa49439SMaksim Yevmenkin 			keycode = 0x6d;
815dfa49439SMaksim Yevmenkin 			break;
816dfa49439SMaksim Yevmenkin 		case 0x5f:	/* sleep key */
817dfa49439SMaksim Yevmenkin 			keycode = 0x6e;
818dfa49439SMaksim Yevmenkin 			break;
819dfa49439SMaksim Yevmenkin 		case 0x63:	/* wake key */
820dfa49439SMaksim Yevmenkin 			keycode = 0x6f;
821dfa49439SMaksim Yevmenkin 			break;
822190fa66bSMaksim Yevmenkin 		case 0x64:	/* [JP106USB] backslash, underscore */
823190fa66bSMaksim Yevmenkin 			keycode = 0x73;
824190fa66bSMaksim Yevmenkin 			break;
825dfa49439SMaksim Yevmenkin 		default:	/* ignore everything else */
826dfa49439SMaksim Yevmenkin 			goto next_code;
827dfa49439SMaksim Yevmenkin 		}
828dfa49439SMaksim Yevmenkin 		break;
829dfa49439SMaksim Yevmenkin 	case 0xE1:	/* 0xE1 prefix */
830dfa49439SMaksim Yevmenkin 		/*
831dfa49439SMaksim Yevmenkin 		 * The pause/break key on the 101 keyboard produces:
832dfa49439SMaksim Yevmenkin 		 * E1-1D-45 E1-9D-C5
833dfa49439SMaksim Yevmenkin 		 * Ctrl-pause/break produces:
834dfa49439SMaksim Yevmenkin 		 * E0-46 E0-C6 (See above.)
835dfa49439SMaksim Yevmenkin 		 */
836dfa49439SMaksim Yevmenkin 		state->ks_prefix = 0;
837dfa49439SMaksim Yevmenkin 		if (keycode == 0x1D)
838dfa49439SMaksim Yevmenkin 			state->ks_prefix = 0x1D;
839dfa49439SMaksim Yevmenkin 		goto next_code;
840dfa49439SMaksim Yevmenkin 		/* NOT REACHED */
841dfa49439SMaksim Yevmenkin 	case 0x1D:	/* pause / break */
842dfa49439SMaksim Yevmenkin 		state->ks_prefix = 0;
843dfa49439SMaksim Yevmenkin 		if (keycode != 0x45)
844dfa49439SMaksim Yevmenkin 			goto next_code;
845dfa49439SMaksim Yevmenkin 		keycode = 0x68;
846dfa49439SMaksim Yevmenkin 		break;
847dfa49439SMaksim Yevmenkin 	}
848dfa49439SMaksim Yevmenkin 
849dfa49439SMaksim Yevmenkin 	/* XXX assume 101/102 keys AT keyboard */
850dfa49439SMaksim Yevmenkin 	switch (keycode) {
851dfa49439SMaksim Yevmenkin 	case 0x5c:	/* print screen */
852dfa49439SMaksim Yevmenkin 		if (state->ks_flags & ALTS)
853dfa49439SMaksim Yevmenkin 			keycode = 0x54;	/* sysrq */
854dfa49439SMaksim Yevmenkin 		break;
855dfa49439SMaksim Yevmenkin 	case 0x68:	/* pause/break */
856dfa49439SMaksim Yevmenkin 		if (state->ks_flags & CTLS)
857dfa49439SMaksim Yevmenkin 			keycode = 0x6c;	/* break */
858dfa49439SMaksim Yevmenkin 		break;
859dfa49439SMaksim Yevmenkin 	}
860dfa49439SMaksim Yevmenkin 
861dfa49439SMaksim Yevmenkin 	/* return the key code in the K_CODE mode */
862dfa49439SMaksim Yevmenkin 	if (state->ks_mode == K_CODE) {
863dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
864dfa49439SMaksim Yevmenkin 		return (keycode | (scancode & 0x80));
865dfa49439SMaksim Yevmenkin 	}
866dfa49439SMaksim Yevmenkin 
867dfa49439SMaksim Yevmenkin 	/* compose a character code */
868dfa49439SMaksim Yevmenkin 	if (state->ks_flags & COMPOSE) {
869dfa49439SMaksim Yevmenkin 		switch (keycode | (scancode & 0x80)) {
870dfa49439SMaksim Yevmenkin 		/* key pressed, process it */
871dfa49439SMaksim Yevmenkin 		case 0x47: case 0x48: case 0x49:	/* keypad 7,8,9 */
872dfa49439SMaksim Yevmenkin 			state->ks_composed_char *= 10;
873dfa49439SMaksim Yevmenkin 			state->ks_composed_char += keycode - 0x40;
874dfa49439SMaksim Yevmenkin 			if (state->ks_composed_char > UCHAR_MAX) {
875dfa49439SMaksim Yevmenkin 				KBDMUX_UNLOCK(state);
876dfa49439SMaksim Yevmenkin 				return (ERRKEY);
877dfa49439SMaksim Yevmenkin 			}
878dfa49439SMaksim Yevmenkin 			goto next_code;
879dfa49439SMaksim Yevmenkin 		case 0x4B: case 0x4C: case 0x4D:	/* keypad 4,5,6 */
880dfa49439SMaksim Yevmenkin 			state->ks_composed_char *= 10;
881dfa49439SMaksim Yevmenkin 			state->ks_composed_char += keycode - 0x47;
882dfa49439SMaksim Yevmenkin 			if (state->ks_composed_char > UCHAR_MAX) {
883dfa49439SMaksim Yevmenkin 				KBDMUX_UNLOCK(state);
884dfa49439SMaksim Yevmenkin 				return (ERRKEY);
885dfa49439SMaksim Yevmenkin 			}
886dfa49439SMaksim Yevmenkin 			goto next_code;
887dfa49439SMaksim Yevmenkin 		case 0x4F: case 0x50: case 0x51:	/* keypad 1,2,3 */
888dfa49439SMaksim Yevmenkin 			state->ks_composed_char *= 10;
889dfa49439SMaksim Yevmenkin 			state->ks_composed_char += keycode - 0x4E;
890dfa49439SMaksim Yevmenkin 			if (state->ks_composed_char > UCHAR_MAX) {
891dfa49439SMaksim Yevmenkin 				KBDMUX_UNLOCK(state);
892dfa49439SMaksim Yevmenkin 				return (ERRKEY);
893dfa49439SMaksim Yevmenkin 			}
894dfa49439SMaksim Yevmenkin 			goto next_code;
895dfa49439SMaksim Yevmenkin 		case 0x52:	/* keypad 0 */
896dfa49439SMaksim Yevmenkin 			state->ks_composed_char *= 10;
897dfa49439SMaksim Yevmenkin 			if (state->ks_composed_char > UCHAR_MAX) {
898dfa49439SMaksim Yevmenkin 				KBDMUX_UNLOCK(state);
899dfa49439SMaksim Yevmenkin 				return (ERRKEY);
900dfa49439SMaksim Yevmenkin 			}
901dfa49439SMaksim Yevmenkin 			goto next_code;
902dfa49439SMaksim Yevmenkin 
903dfa49439SMaksim Yevmenkin 		/* key released, no interest here */
904dfa49439SMaksim Yevmenkin 		case 0xC7: case 0xC8: case 0xC9:	/* keypad 7,8,9 */
905dfa49439SMaksim Yevmenkin 		case 0xCB: case 0xCC: case 0xCD:	/* keypad 4,5,6 */
906dfa49439SMaksim Yevmenkin 		case 0xCF: case 0xD0: case 0xD1:	/* keypad 1,2,3 */
907dfa49439SMaksim Yevmenkin 		case 0xD2:				/* keypad 0 */
908dfa49439SMaksim Yevmenkin 			goto next_code;
909dfa49439SMaksim Yevmenkin 
910dfa49439SMaksim Yevmenkin 		case 0x38:				/* left alt key */
911dfa49439SMaksim Yevmenkin 			break;
912dfa49439SMaksim Yevmenkin 
913dfa49439SMaksim Yevmenkin 		default:
914dfa49439SMaksim Yevmenkin 			if (state->ks_composed_char > 0) {
915dfa49439SMaksim Yevmenkin 				state->ks_flags &= ~COMPOSE;
916dfa49439SMaksim Yevmenkin 				state->ks_composed_char = 0;
917dfa49439SMaksim Yevmenkin 				KBDMUX_UNLOCK(state);
918dfa49439SMaksim Yevmenkin 				return (ERRKEY);
919dfa49439SMaksim Yevmenkin 			}
920dfa49439SMaksim Yevmenkin 			break;
921dfa49439SMaksim Yevmenkin 		}
922dfa49439SMaksim Yevmenkin 	}
923dfa49439SMaksim Yevmenkin 
924dfa49439SMaksim Yevmenkin 	/* keycode to key action */
925dfa49439SMaksim Yevmenkin 	action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
926dfa49439SMaksim Yevmenkin 			&state->ks_state, &state->ks_accents);
927dfa49439SMaksim Yevmenkin 	if (action == NOKEY)
928dfa49439SMaksim Yevmenkin 		goto next_code;
929dfa49439SMaksim Yevmenkin 
930dfa49439SMaksim Yevmenkin 	KBDMUX_UNLOCK(state);
931dfa49439SMaksim Yevmenkin 
932dfa49439SMaksim Yevmenkin 	return (action);
933dfa49439SMaksim Yevmenkin }
934dfa49439SMaksim Yevmenkin 
935dfa49439SMaksim Yevmenkin /*
936dfa49439SMaksim Yevmenkin  * Check if char is waiting
937dfa49439SMaksim Yevmenkin  */
938dfa49439SMaksim Yevmenkin static int
kbdmux_check_char(keyboard_t * kbd)939dfa49439SMaksim Yevmenkin kbdmux_check_char(keyboard_t *kbd)
940dfa49439SMaksim Yevmenkin {
941dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
942dfa49439SMaksim Yevmenkin 	int		 ready;
943dfa49439SMaksim Yevmenkin 
944dfa49439SMaksim Yevmenkin 	if (!KBD_IS_ACTIVE(kbd))
945dfa49439SMaksim Yevmenkin 		return (FALSE);
946dfa49439SMaksim Yevmenkin 
947dfa49439SMaksim Yevmenkin 	KBDMUX_LOCK(state);
948dfa49439SMaksim Yevmenkin 
949dfa49439SMaksim Yevmenkin 	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
950dfa49439SMaksim Yevmenkin 		ready = TRUE;
951dfa49439SMaksim Yevmenkin 	else
9525f46eda1SEd Schouten 		ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
953dfa49439SMaksim Yevmenkin 
954dfa49439SMaksim Yevmenkin 	KBDMUX_UNLOCK(state);
955dfa49439SMaksim Yevmenkin 
956dfa49439SMaksim Yevmenkin 	return (ready);
957dfa49439SMaksim Yevmenkin }
958dfa49439SMaksim Yevmenkin 
959dfa49439SMaksim Yevmenkin /*
960dfa49439SMaksim Yevmenkin  * Keyboard ioctl's
961dfa49439SMaksim Yevmenkin  */
962dfa49439SMaksim Yevmenkin static int
kbdmux_ioctl(keyboard_t * kbd,u_long cmd,caddr_t arg)963dfa49439SMaksim Yevmenkin kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
964dfa49439SMaksim Yevmenkin {
965dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
966dfa49439SMaksim Yevmenkin 	kbdmux_kbd_t	*k;
9674673ea01SMaksim Yevmenkin 	keyboard_info_t	*ki;
968dfa49439SMaksim Yevmenkin 	int		 error = 0, mode;
9699fddcc66SRuslan Ermilov #ifdef COMPAT_FREEBSD6
9709fddcc66SRuslan Ermilov 	int		 ival;
9719fddcc66SRuslan Ermilov #endif
972dfa49439SMaksim Yevmenkin 
973dfa49439SMaksim Yevmenkin 	if (state == NULL)
974dfa49439SMaksim Yevmenkin 		return (ENXIO);
975dfa49439SMaksim Yevmenkin 
976dfa49439SMaksim Yevmenkin 	switch (cmd) {
977dfa49439SMaksim Yevmenkin 	case KBADDKBD: /* add keyboard to the mux */
9784673ea01SMaksim Yevmenkin 		ki = (keyboard_info_t *) arg;
9794673ea01SMaksim Yevmenkin 
9804673ea01SMaksim Yevmenkin 		if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
9814673ea01SMaksim Yevmenkin 		    strcmp(ki->kb_name, "*") == 0)
9824673ea01SMaksim Yevmenkin 			return (EINVAL); /* bad input */
9834673ea01SMaksim Yevmenkin 
984dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
985dfa49439SMaksim Yevmenkin 
986dfa49439SMaksim Yevmenkin 		SLIST_FOREACH(k, &state->ks_kbds, next)
9874673ea01SMaksim Yevmenkin 			if (k->kbd->kb_unit == ki->kb_unit &&
9884673ea01SMaksim Yevmenkin 			    strcmp(k->kbd->kb_name, ki->kb_name) == 0)
989dfa49439SMaksim Yevmenkin 				break;
990dfa49439SMaksim Yevmenkin 
991dfa49439SMaksim Yevmenkin 		if (k != NULL) {
992dfa49439SMaksim Yevmenkin 			KBDMUX_UNLOCK(state);
993dfa49439SMaksim Yevmenkin 
994dfa49439SMaksim Yevmenkin 			return (0); /* keyboard already in the mux */
995dfa49439SMaksim Yevmenkin 		}
996dfa49439SMaksim Yevmenkin 
997dfa49439SMaksim Yevmenkin 		k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
998dfa49439SMaksim Yevmenkin 		if (k == NULL) {
999dfa49439SMaksim Yevmenkin 			KBDMUX_UNLOCK(state);
1000dfa49439SMaksim Yevmenkin 
1001dfa49439SMaksim Yevmenkin 			return (ENOMEM); /* out of memory */
1002dfa49439SMaksim Yevmenkin 		}
1003dfa49439SMaksim Yevmenkin 
10044673ea01SMaksim Yevmenkin 		k->kbd = kbd_get_keyboard(
10054673ea01SMaksim Yevmenkin 				kbd_allocate(
10064673ea01SMaksim Yevmenkin 					ki->kb_name,
10074673ea01SMaksim Yevmenkin 					ki->kb_unit,
10084673ea01SMaksim Yevmenkin 					(void *) &k->kbd,
10094673ea01SMaksim Yevmenkin 					kbdmux_kbd_event, (void *) state));
1010dfa49439SMaksim Yevmenkin 		if (k->kbd == NULL) {
1011dfa49439SMaksim Yevmenkin 			KBDMUX_UNLOCK(state);
1012dfa49439SMaksim Yevmenkin 			free(k, M_KBDMUX);
1013dfa49439SMaksim Yevmenkin 
10144673ea01SMaksim Yevmenkin 			return (EINVAL); /* bad keyboard */
1015dfa49439SMaksim Yevmenkin 		}
1016dfa49439SMaksim Yevmenkin 
1017259699b2SWojciech A. Koszek 		kbdd_enable(k->kbd);
1018259699b2SWojciech A. Koszek 		kbdd_clear_state(k->kbd);
1019dfa49439SMaksim Yevmenkin 
1020dfa49439SMaksim Yevmenkin 		/* set K_RAW mode on slave keyboard */
1021dfa49439SMaksim Yevmenkin 		mode = K_RAW;
1022259699b2SWojciech A. Koszek 		error = kbdd_ioctl(k->kbd, KDSKBMODE, (caddr_t)&mode);
1023dfa49439SMaksim Yevmenkin 		if (error == 0) {
1024dfa49439SMaksim Yevmenkin 			/* set lock keys state on slave keyboard */
1025dfa49439SMaksim Yevmenkin 			mode = state->ks_state & LOCK_MASK;
1026259699b2SWojciech A. Koszek 			error = kbdd_ioctl(k->kbd, KDSKBSTATE, (caddr_t)&mode);
1027dfa49439SMaksim Yevmenkin 		}
1028dfa49439SMaksim Yevmenkin 
1029dfa49439SMaksim Yevmenkin 		if (error != 0) {
1030dfa49439SMaksim Yevmenkin 			KBDMUX_UNLOCK(state);
1031dfa49439SMaksim Yevmenkin 
1032dfa49439SMaksim Yevmenkin 			kbd_release(k->kbd, &k->kbd);
1033dfa49439SMaksim Yevmenkin 			k->kbd = NULL;
1034dfa49439SMaksim Yevmenkin 
1035dfa49439SMaksim Yevmenkin 			free(k, M_KBDMUX);
1036dfa49439SMaksim Yevmenkin 
1037dfa49439SMaksim Yevmenkin 			return (error); /* could not set mode */
1038dfa49439SMaksim Yevmenkin 		}
1039dfa49439SMaksim Yevmenkin 
1040dfa49439SMaksim Yevmenkin 		SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
1041dfa49439SMaksim Yevmenkin 
1042dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
1043dfa49439SMaksim Yevmenkin 		break;
1044dfa49439SMaksim Yevmenkin 
1045dfa49439SMaksim Yevmenkin 	case KBRELKBD: /* release keyboard from the mux */
10464673ea01SMaksim Yevmenkin 		ki = (keyboard_info_t *) arg;
10474673ea01SMaksim Yevmenkin 
10484673ea01SMaksim Yevmenkin 		if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
10494673ea01SMaksim Yevmenkin 		    strcmp(ki->kb_name, "*") == 0)
10504673ea01SMaksim Yevmenkin 			return (EINVAL); /* bad input */
10514673ea01SMaksim Yevmenkin 
1052dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
1053dfa49439SMaksim Yevmenkin 
1054dfa49439SMaksim Yevmenkin 		SLIST_FOREACH(k, &state->ks_kbds, next)
10554673ea01SMaksim Yevmenkin 			if (k->kbd->kb_unit == ki->kb_unit &&
10564673ea01SMaksim Yevmenkin 			    strcmp(k->kbd->kb_name, ki->kb_name) == 0)
1057dfa49439SMaksim Yevmenkin 				break;
1058dfa49439SMaksim Yevmenkin 
1059dfa49439SMaksim Yevmenkin 		if (k != NULL) {
1060dfa49439SMaksim Yevmenkin 			error = kbd_release(k->kbd, &k->kbd);
1061dfa49439SMaksim Yevmenkin 			if (error == 0) {
1062dfa49439SMaksim Yevmenkin 				SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
1063dfa49439SMaksim Yevmenkin 
1064dfa49439SMaksim Yevmenkin 				k->kbd = NULL;
1065dfa49439SMaksim Yevmenkin 
1066dfa49439SMaksim Yevmenkin 				free(k, M_KBDMUX);
1067dfa49439SMaksim Yevmenkin 			}
1068dfa49439SMaksim Yevmenkin 		} else
1069dfa49439SMaksim Yevmenkin 			error = ENXIO; /* keyboard is not in the mux */
1070dfa49439SMaksim Yevmenkin 
1071dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
1072dfa49439SMaksim Yevmenkin 		break;
1073dfa49439SMaksim Yevmenkin 
1074dfa49439SMaksim Yevmenkin 	case KDGKBMODE: /* get kyboard mode */
1075dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
10769e24e7f6SRuslan Ermilov 		*(int *)arg = state->ks_mode;
1077dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
1078dfa49439SMaksim Yevmenkin 		break;
1079dfa49439SMaksim Yevmenkin 
10809fddcc66SRuslan Ermilov #ifdef COMPAT_FREEBSD6
10819fddcc66SRuslan Ermilov 	case _IO('K', 7):
10829fddcc66SRuslan Ermilov 		ival = IOCPARM_IVAL(arg);
10839fddcc66SRuslan Ermilov 		arg = (caddr_t)&ival;
10849fddcc66SRuslan Ermilov 		/* FALLTHROUGH */
10859fddcc66SRuslan Ermilov #endif
1086dfa49439SMaksim Yevmenkin 	case KDSKBMODE: /* set keyboard mode */
1087dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
1088dfa49439SMaksim Yevmenkin 
10898ad58ac6SRuslan Ermilov 		switch (*(int *)arg) {
1090dfa49439SMaksim Yevmenkin 		case K_XLATE:
1091dfa49439SMaksim Yevmenkin 			if (state->ks_mode != K_XLATE) {
1092dfa49439SMaksim Yevmenkin 				/* make lock key state and LED state match */
1093dfa49439SMaksim Yevmenkin 				state->ks_state &= ~LOCK_MASK;
1094dfa49439SMaksim Yevmenkin 				state->ks_state |= KBD_LED_VAL(kbd);
1095dfa49439SMaksim Yevmenkin                         }
1096dfa49439SMaksim Yevmenkin                         /* FALLTHROUGH */
1097dfa49439SMaksim Yevmenkin 
1098dfa49439SMaksim Yevmenkin 		case K_RAW:
1099dfa49439SMaksim Yevmenkin 		case K_CODE:
11008ad58ac6SRuslan Ermilov 			if (state->ks_mode != *(int *)arg) {
1101dfa49439SMaksim Yevmenkin 				kbdmux_clear_state_locked(state);
11028ad58ac6SRuslan Ermilov 				state->ks_mode = *(int *)arg;
1103dfa49439SMaksim Yevmenkin 			}
1104dfa49439SMaksim Yevmenkin 			break;
1105dfa49439SMaksim Yevmenkin 
1106dfa49439SMaksim Yevmenkin                 default:
1107dfa49439SMaksim Yevmenkin 			error = EINVAL;
1108dfa49439SMaksim Yevmenkin 			break;
1109dfa49439SMaksim Yevmenkin 		}
1110dfa49439SMaksim Yevmenkin 
1111dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
1112dfa49439SMaksim Yevmenkin 		break;
1113dfa49439SMaksim Yevmenkin 
1114dfa49439SMaksim Yevmenkin 	case KDGETLED: /* get keyboard LED */
1115dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
11169e24e7f6SRuslan Ermilov 		*(int *)arg = KBD_LED_VAL(kbd);
1117dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
1118dfa49439SMaksim Yevmenkin 		break;
1119dfa49439SMaksim Yevmenkin 
11209fddcc66SRuslan Ermilov #ifdef COMPAT_FREEBSD6
11219fddcc66SRuslan Ermilov 	case _IO('K', 66):
11229fddcc66SRuslan Ermilov 		ival = IOCPARM_IVAL(arg);
11239fddcc66SRuslan Ermilov 		arg = (caddr_t)&ival;
11249fddcc66SRuslan Ermilov 		/* FALLTHROUGH */
11259fddcc66SRuslan Ermilov #endif
1126dfa49439SMaksim Yevmenkin 	case KDSETLED: /* set keyboard LED */
1127dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
1128dfa49439SMaksim Yevmenkin 
1129dfa49439SMaksim Yevmenkin 		/* NOTE: lock key state in ks_state won't be changed */
11308ad58ac6SRuslan Ermilov 		if (*(int *)arg & ~LOCK_MASK) {
1131dfa49439SMaksim Yevmenkin 			KBDMUX_UNLOCK(state);
1132dfa49439SMaksim Yevmenkin 
1133dfa49439SMaksim Yevmenkin 			return (EINVAL);
1134dfa49439SMaksim Yevmenkin 		}
1135dfa49439SMaksim Yevmenkin 
11368ad58ac6SRuslan Ermilov 		KBD_LED_VAL(kbd) = *(int *)arg;
113797fc5dbeSOleksandr Tymoshenko #ifdef EVDEV_SUPPORT
113897fc5dbeSOleksandr Tymoshenko 		if (state->ks_evdev != NULL &&
113997fc5dbeSOleksandr Tymoshenko 		    evdev_rcpt_mask & EVDEV_RCPT_KBDMUX)
114097fc5dbeSOleksandr Tymoshenko 			evdev_push_leds(state->ks_evdev, *(int *)arg);
114197fc5dbeSOleksandr Tymoshenko #endif
1142dfa49439SMaksim Yevmenkin 		/* KDSETLED on all slave keyboards */
1143dfa49439SMaksim Yevmenkin 		SLIST_FOREACH(k, &state->ks_kbds, next)
1144cd1fa5bdSRui Paulo 			(void)kbdd_ioctl(k->kbd, KDSETLED, arg);
1145dfa49439SMaksim Yevmenkin 
1146dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
1147dfa49439SMaksim Yevmenkin 		break;
1148dfa49439SMaksim Yevmenkin 
1149dfa49439SMaksim Yevmenkin 	case KDGKBSTATE: /* get lock key state */
1150dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
11519e24e7f6SRuslan Ermilov 		*(int *)arg = state->ks_state & LOCK_MASK;
1152dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
1153dfa49439SMaksim Yevmenkin 		break;
1154dfa49439SMaksim Yevmenkin 
11559fddcc66SRuslan Ermilov #ifdef COMPAT_FREEBSD6
11569fddcc66SRuslan Ermilov 	case _IO('K', 20):
11579fddcc66SRuslan Ermilov 		ival = IOCPARM_IVAL(arg);
11589fddcc66SRuslan Ermilov 		arg = (caddr_t)&ival;
11599fddcc66SRuslan Ermilov 		/* FALLTHROUGH */
11609fddcc66SRuslan Ermilov #endif
1161dfa49439SMaksim Yevmenkin 	case KDSKBSTATE: /* set lock key state */
1162dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
1163dfa49439SMaksim Yevmenkin 
11648ad58ac6SRuslan Ermilov 		if (*(int *)arg & ~LOCK_MASK) {
1165dfa49439SMaksim Yevmenkin 			KBDMUX_UNLOCK(state);
1166dfa49439SMaksim Yevmenkin 
1167dfa49439SMaksim Yevmenkin 			return (EINVAL);
1168dfa49439SMaksim Yevmenkin 		}
1169dfa49439SMaksim Yevmenkin 
1170dfa49439SMaksim Yevmenkin 		state->ks_state &= ~LOCK_MASK;
11718ad58ac6SRuslan Ermilov 		state->ks_state |= *(int *)arg;
1172dfa49439SMaksim Yevmenkin 
1173dfa49439SMaksim Yevmenkin 		/* KDSKBSTATE on all slave keyboards */
1174dfa49439SMaksim Yevmenkin 		SLIST_FOREACH(k, &state->ks_kbds, next)
1175cd1fa5bdSRui Paulo 			(void)kbdd_ioctl(k->kbd, KDSKBSTATE, arg);
1176dfa49439SMaksim Yevmenkin 
1177dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
1178dfa49439SMaksim Yevmenkin 
1179dfa49439SMaksim Yevmenkin 		return (kbdmux_ioctl(kbd, KDSETLED, arg));
1180dfa49439SMaksim Yevmenkin 		/* NOT REACHED */
1181dfa49439SMaksim Yevmenkin 
11829fddcc66SRuslan Ermilov #ifdef COMPAT_FREEBSD6
11839fddcc66SRuslan Ermilov 	case _IO('K', 67):
11849fddcc66SRuslan Ermilov 		cmd = KDSETRAD;
11859fddcc66SRuslan Ermilov 		ival = IOCPARM_IVAL(arg);
11869fddcc66SRuslan Ermilov 		arg = (caddr_t)&ival;
11879fddcc66SRuslan Ermilov 		/* FALLTHROUGH */
11889fddcc66SRuslan Ermilov #endif
1189dfa49439SMaksim Yevmenkin 	case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1190dfa49439SMaksim Yevmenkin 	case KDSETRAD: /* set keyboard repeat rate (old interface) */
1191dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
1192dfa49439SMaksim Yevmenkin 
1193dfa49439SMaksim Yevmenkin 		if (cmd == KDSETREPEAT) {
1194dfa49439SMaksim Yevmenkin 			int	i;
1195dfa49439SMaksim Yevmenkin 
1196dfa49439SMaksim Yevmenkin 			/* lookup delay */
1197*971bac5aSMichael 			for (i = nitems(kbdelays) - 1; i > 0; i--)
1198*971bac5aSMichael 				if (((int *)arg)[0] >= kbdelays[i])
1199dfa49439SMaksim Yevmenkin 					break;
1200dfa49439SMaksim Yevmenkin 			mode = i << 5;
1201dfa49439SMaksim Yevmenkin 
1202dfa49439SMaksim Yevmenkin 			/* lookup rate */
1203*971bac5aSMichael 			for (i = nitems(kbrates) - 1; i > 0; i--)
1204*971bac5aSMichael 				if (((int *)arg)[1] >= kbrates[i])
1205dfa49439SMaksim Yevmenkin 					break;
1206dfa49439SMaksim Yevmenkin 			mode |= i;
1207dfa49439SMaksim Yevmenkin 		} else
12088ad58ac6SRuslan Ermilov 			mode = *(int *)arg;
1209dfa49439SMaksim Yevmenkin 
1210dfa49439SMaksim Yevmenkin 		if (mode & ~0x7f) {
1211dfa49439SMaksim Yevmenkin 			KBDMUX_UNLOCK(state);
1212dfa49439SMaksim Yevmenkin 
1213dfa49439SMaksim Yevmenkin 			return (EINVAL);
1214dfa49439SMaksim Yevmenkin 		}
1215dfa49439SMaksim Yevmenkin 
1216*971bac5aSMichael 		kbd->kb_delay1 = kbdelays[(mode >> 5) & 3];
1217*971bac5aSMichael 		kbd->kb_delay2 = kbrates[mode & 0x1f];
121897fc5dbeSOleksandr Tymoshenko #ifdef EVDEV_SUPPORT
121997fc5dbeSOleksandr Tymoshenko 		if (state->ks_evdev != NULL &&
122097fc5dbeSOleksandr Tymoshenko 		    evdev_rcpt_mask & EVDEV_RCPT_KBDMUX)
122197fc5dbeSOleksandr Tymoshenko 			evdev_push_repeats(state->ks_evdev, kbd);
122297fc5dbeSOleksandr Tymoshenko #endif
1223dfa49439SMaksim Yevmenkin 		/* perform command on all slave keyboards */
1224dfa49439SMaksim Yevmenkin 		SLIST_FOREACH(k, &state->ks_kbds, next)
1225cd1fa5bdSRui Paulo 			(void)kbdd_ioctl(k->kbd, cmd, arg);
1226dfa49439SMaksim Yevmenkin 
1227dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
1228dfa49439SMaksim Yevmenkin 		break;
1229dfa49439SMaksim Yevmenkin 
1230dfa49439SMaksim Yevmenkin 	case PIO_KEYMAP:	/* set keyboard translation table */
1231dfa49439SMaksim Yevmenkin 	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
1232dfa49439SMaksim Yevmenkin 	case PIO_DEADKEYMAP:	/* set accent key translation table */
1233f2005895SStefan Eßer #ifdef COMPAT_FREEBSD13
1234f2005895SStefan Eßer 	case OPIO_KEYMAP:	/* set keyboard translation table (compat) */
12354972fb92SStefan Eßer 	case OPIO_DEADKEYMAP:	/* set accent key translation table (compat) */
1236dfa49439SMaksim Yevmenkin 		KBDMUX_LOCK(state);
1237dfa49439SMaksim Yevmenkin 		state->ks_accents = 0;
1238f2005895SStefan Eßer #endif /* COMPAT_FREEBSD13 */
1239dfa49439SMaksim Yevmenkin 
1240dfa49439SMaksim Yevmenkin 		/* perform command on all slave keyboards */
1241dfa49439SMaksim Yevmenkin 		SLIST_FOREACH(k, &state->ks_kbds, next)
1242cd1fa5bdSRui Paulo 			(void)kbdd_ioctl(k->kbd, cmd, arg);
1243dfa49439SMaksim Yevmenkin 
1244dfa49439SMaksim Yevmenkin 		KBDMUX_UNLOCK(state);
1245dfa49439SMaksim Yevmenkin                 /* FALLTHROUGH */
1246dfa49439SMaksim Yevmenkin 
1247dfa49439SMaksim Yevmenkin 	default:
1248dfa49439SMaksim Yevmenkin 		error = genkbd_commonioctl(kbd, cmd, arg);
1249dfa49439SMaksim Yevmenkin 		break;
1250dfa49439SMaksim Yevmenkin 	}
1251dfa49439SMaksim Yevmenkin 
1252dfa49439SMaksim Yevmenkin 	return (error);
1253dfa49439SMaksim Yevmenkin }
1254dfa49439SMaksim Yevmenkin 
1255dfa49439SMaksim Yevmenkin /*
1256dfa49439SMaksim Yevmenkin  * Lock the access to the keyboard
1257dfa49439SMaksim Yevmenkin  */
1258dfa49439SMaksim Yevmenkin static int
kbdmux_lock(keyboard_t * kbd,int lock)1259dfa49439SMaksim Yevmenkin kbdmux_lock(keyboard_t *kbd, int lock)
1260dfa49439SMaksim Yevmenkin {
1261dfa49439SMaksim Yevmenkin 	return (1); /* XXX */
1262dfa49439SMaksim Yevmenkin }
1263dfa49439SMaksim Yevmenkin 
1264dfa49439SMaksim Yevmenkin /*
1265dfa49439SMaksim Yevmenkin  * Clear the internal state of the keyboard
1266dfa49439SMaksim Yevmenkin  */
1267dfa49439SMaksim Yevmenkin static void
kbdmux_clear_state_locked(kbdmux_state_t * state)1268dfa49439SMaksim Yevmenkin kbdmux_clear_state_locked(kbdmux_state_t *state)
1269dfa49439SMaksim Yevmenkin {
1270dfa49439SMaksim Yevmenkin 	KBDMUX_LOCK_ASSERT(state, MA_OWNED);
1271dfa49439SMaksim Yevmenkin 
1272cc43fd1aSBruce Evans 	state->ks_flags &= ~COMPOSE;
1273cc43fd1aSBruce Evans 	state->ks_polling = 0;
1274dfa49439SMaksim Yevmenkin 	state->ks_state &= LOCK_MASK;	/* preserve locking key state */
1275dfa49439SMaksim Yevmenkin 	state->ks_accents = 0;
1276dfa49439SMaksim Yevmenkin 	state->ks_composed_char = 0;
1277dfa49439SMaksim Yevmenkin /*	state->ks_prefix = 0;		XXX */
12785f46eda1SEd Schouten 	state->ks_inq_length = 0;
1279dfa49439SMaksim Yevmenkin }
1280dfa49439SMaksim Yevmenkin 
1281dfa49439SMaksim Yevmenkin static void
kbdmux_clear_state(keyboard_t * kbd)1282dfa49439SMaksim Yevmenkin kbdmux_clear_state(keyboard_t *kbd)
1283dfa49439SMaksim Yevmenkin {
1284dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
1285dfa49439SMaksim Yevmenkin 
1286dfa49439SMaksim Yevmenkin 	KBDMUX_LOCK(state);
1287dfa49439SMaksim Yevmenkin 	kbdmux_clear_state_locked(state);
1288dfa49439SMaksim Yevmenkin 	KBDMUX_UNLOCK(state);
1289dfa49439SMaksim Yevmenkin }
1290dfa49439SMaksim Yevmenkin 
1291dfa49439SMaksim Yevmenkin /*
1292dfa49439SMaksim Yevmenkin  * Save the internal state
1293dfa49439SMaksim Yevmenkin  */
1294dfa49439SMaksim Yevmenkin static int
kbdmux_get_state(keyboard_t * kbd,void * buf,size_t len)1295dfa49439SMaksim Yevmenkin kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1296dfa49439SMaksim Yevmenkin {
1297dfa49439SMaksim Yevmenkin 	if (len == 0)
1298dfa49439SMaksim Yevmenkin 		return (sizeof(kbdmux_state_t));
1299dfa49439SMaksim Yevmenkin 	if (len < sizeof(kbdmux_state_t))
1300dfa49439SMaksim Yevmenkin 		return (-1);
1301dfa49439SMaksim Yevmenkin 
1302dfa49439SMaksim Yevmenkin 	bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1303dfa49439SMaksim Yevmenkin 
1304dfa49439SMaksim Yevmenkin 	return (0);
1305dfa49439SMaksim Yevmenkin }
1306dfa49439SMaksim Yevmenkin 
1307dfa49439SMaksim Yevmenkin /*
1308dfa49439SMaksim Yevmenkin  * Set the internal state
1309dfa49439SMaksim Yevmenkin  */
1310dfa49439SMaksim Yevmenkin static int
kbdmux_set_state(keyboard_t * kbd,void * buf,size_t len)1311dfa49439SMaksim Yevmenkin kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1312dfa49439SMaksim Yevmenkin {
1313dfa49439SMaksim Yevmenkin 	if (len < sizeof(kbdmux_state_t))
1314dfa49439SMaksim Yevmenkin 		return (ENOMEM);
1315dfa49439SMaksim Yevmenkin 
1316dfa49439SMaksim Yevmenkin 	bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1317dfa49439SMaksim Yevmenkin 
1318dfa49439SMaksim Yevmenkin 	return (0);
1319dfa49439SMaksim Yevmenkin }
1320dfa49439SMaksim Yevmenkin 
1321dfa49439SMaksim Yevmenkin /*
1322dfa49439SMaksim Yevmenkin  * Set polling
1323dfa49439SMaksim Yevmenkin  */
1324dfa49439SMaksim Yevmenkin static int
kbdmux_poll(keyboard_t * kbd,int on)1325dfa49439SMaksim Yevmenkin kbdmux_poll(keyboard_t *kbd, int on)
1326dfa49439SMaksim Yevmenkin {
1327dfa49439SMaksim Yevmenkin 	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
1328dfa49439SMaksim Yevmenkin 	kbdmux_kbd_t	*k;
1329dfa49439SMaksim Yevmenkin 
1330dfa49439SMaksim Yevmenkin 	KBDMUX_LOCK(state);
1331dfa49439SMaksim Yevmenkin 
1332dfa49439SMaksim Yevmenkin 	if (on)
1333cc43fd1aSBruce Evans 		state->ks_polling++;
1334dfa49439SMaksim Yevmenkin 	else
1335cc43fd1aSBruce Evans 		state->ks_polling--;
1336dfa49439SMaksim Yevmenkin 
1337dfa49439SMaksim Yevmenkin 	/* set poll on slave keyboards */
1338dfa49439SMaksim Yevmenkin 	SLIST_FOREACH(k, &state->ks_kbds, next)
1339259699b2SWojciech A. Koszek 		kbdd_poll(k->kbd, on);
1340dfa49439SMaksim Yevmenkin 
1341dfa49439SMaksim Yevmenkin 	KBDMUX_UNLOCK(state);
1342dfa49439SMaksim Yevmenkin 
1343dfa49439SMaksim Yevmenkin 	return (0);
1344dfa49439SMaksim Yevmenkin }
1345dfa49439SMaksim Yevmenkin 
134648f2b006SVladimir Kondratyev #ifdef EVDEV_SUPPORT
134748f2b006SVladimir Kondratyev static void
kbdmux_ev_event(struct evdev_dev * evdev,uint16_t type,uint16_t code,int32_t value)134848f2b006SVladimir Kondratyev kbdmux_ev_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
134948f2b006SVladimir Kondratyev     int32_t value)
135048f2b006SVladimir Kondratyev {
135148f2b006SVladimir Kondratyev 	keyboard_t *kbd = evdev_get_softc(evdev);
135248f2b006SVladimir Kondratyev 
135348f2b006SVladimir Kondratyev 	if (evdev_rcpt_mask & EVDEV_RCPT_KBDMUX &&
135448f2b006SVladimir Kondratyev 	    (type == EV_LED || type == EV_REP)) {
135548f2b006SVladimir Kondratyev 		mtx_lock(&Giant);
135648f2b006SVladimir Kondratyev 		kbd_ev_event(kbd, type, code, value);
135748f2b006SVladimir Kondratyev 		mtx_unlock(&Giant);
135848f2b006SVladimir Kondratyev 	}
135948f2b006SVladimir Kondratyev }
136048f2b006SVladimir Kondratyev #endif
136148f2b006SVladimir Kondratyev 
1362dfa49439SMaksim Yevmenkin /*****************************************************************************
1363dfa49439SMaksim Yevmenkin  *****************************************************************************
1364dfa49439SMaksim Yevmenkin  **                                    Module
1365dfa49439SMaksim Yevmenkin  *****************************************************************************
1366dfa49439SMaksim Yevmenkin  *****************************************************************************/
1367dfa49439SMaksim Yevmenkin 
1368dfa49439SMaksim Yevmenkin KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1369dfa49439SMaksim Yevmenkin 
1370dfa49439SMaksim Yevmenkin static int
kbdmux_modevent(module_t mod,int type,void * data)1371dfa49439SMaksim Yevmenkin kbdmux_modevent(module_t mod, int type, void *data)
1372dfa49439SMaksim Yevmenkin {
1373dfa49439SMaksim Yevmenkin 	keyboard_switch_t	*sw;
1374dfa49439SMaksim Yevmenkin 	keyboard_t		*kbd;
1375dfa49439SMaksim Yevmenkin 	int			 error;
1376dfa49439SMaksim Yevmenkin 
1377dfa49439SMaksim Yevmenkin 	switch (type) {
1378dfa49439SMaksim Yevmenkin 	case MOD_LOAD:
1379dfa49439SMaksim Yevmenkin 		if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1380dfa49439SMaksim Yevmenkin 			break;
1381dfa49439SMaksim Yevmenkin 
1382dfa49439SMaksim Yevmenkin 		if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1383dfa49439SMaksim Yevmenkin 			error = ENXIO;
1384dfa49439SMaksim Yevmenkin 			break;
1385dfa49439SMaksim Yevmenkin 		}
1386dfa49439SMaksim Yevmenkin 
1387dfa49439SMaksim Yevmenkin 		kbd = NULL;
1388dfa49439SMaksim Yevmenkin 
1389dfa49439SMaksim Yevmenkin 		if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
139094551cebSKyle Evans 		    (error = (*sw->init)(0, &kbd, NULL, 0)) != 0)
1391dfa49439SMaksim Yevmenkin 			break;
1392dfa49439SMaksim Yevmenkin 
1393dfa49439SMaksim Yevmenkin #ifdef KBD_INSTALL_CDEV
1394dfa49439SMaksim Yevmenkin 		if ((error = kbd_attach(kbd)) != 0) {
1395dfa49439SMaksim Yevmenkin 			(*sw->term)(kbd);
1396dfa49439SMaksim Yevmenkin 			break;
1397dfa49439SMaksim Yevmenkin 		}
1398dfa49439SMaksim Yevmenkin #endif
1399dfa49439SMaksim Yevmenkin 
140094551cebSKyle Evans 		if ((error = (*sw->enable)(kbd)) != 0)
1401dfa49439SMaksim Yevmenkin 			break;
1402dfa49439SMaksim Yevmenkin 		break;
1403dfa49439SMaksim Yevmenkin 
1404dfa49439SMaksim Yevmenkin 	case MOD_UNLOAD:
140594551cebSKyle Evans 		if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
140694551cebSKyle Evans 			error = 0;
140794551cebSKyle Evans 			break;
140894551cebSKyle Evans 		}
1409dfa49439SMaksim Yevmenkin 
1410dfa49439SMaksim Yevmenkin 		kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1411fd66bfecSAndrew Thompson 		if (kbd != NULL) {
1412dfa49439SMaksim Yevmenkin 			(*sw->disable)(kbd);
1413dfa49439SMaksim Yevmenkin #ifdef KBD_INSTALL_CDEV
1414dfa49439SMaksim Yevmenkin 			kbd_detach(kbd);
1415dfa49439SMaksim Yevmenkin #endif
1416dfa49439SMaksim Yevmenkin 			(*sw->term)(kbd);
1417fd66bfecSAndrew Thompson 		}
141894551cebSKyle Evans 		kbd_delete_driver(&kbdmux_kbd_driver);
1419dfa49439SMaksim Yevmenkin 		error = 0;
1420dfa49439SMaksim Yevmenkin 		break;
1421dfa49439SMaksim Yevmenkin 
1422dfa49439SMaksim Yevmenkin 	default:
1423dfa49439SMaksim Yevmenkin 		error = EOPNOTSUPP;
1424dfa49439SMaksim Yevmenkin 		break;
1425dfa49439SMaksim Yevmenkin 	}
1426dfa49439SMaksim Yevmenkin 
14278de7d508SMaksim Yevmenkin 	return (error);
1428dfa49439SMaksim Yevmenkin }
1429dfa49439SMaksim Yevmenkin 
1430dfa49439SMaksim Yevmenkin DEV_MODULE(kbdmux, kbdmux_modevent, NULL);
143197fc5dbeSOleksandr Tymoshenko #ifdef EVDEV_SUPPORT
143297fc5dbeSOleksandr Tymoshenko MODULE_DEPEND(kbdmux, evdev, 1, 1, 1);
143397fc5dbeSOleksandr Tymoshenko #endif
1434