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