1fc16838fSAlex Hornung /*-
222ff886eSAlex Hornung * (MPSAFE)
322ff886eSAlex Hornung *
4fc16838fSAlex Hornung * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5fc16838fSAlex Hornung * All rights reserved.
6fc16838fSAlex Hornung *
7fc16838fSAlex Hornung * Redistribution and use in source and binary forms, with or without
8fc16838fSAlex Hornung * modification, are permitted provided that the following conditions
9fc16838fSAlex Hornung * are met:
10fc16838fSAlex Hornung * 1. Redistributions of source code must retain the above copyright
11fc16838fSAlex Hornung * notice, this list of conditions and the following disclaimer.
12fc16838fSAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright
13fc16838fSAlex Hornung * notice, this list of conditions and the following disclaimer in the
14fc16838fSAlex Hornung * documentation and/or other materials provided with the distribution.
15fc16838fSAlex Hornung *
16fc16838fSAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17fc16838fSAlex Hornung * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18fc16838fSAlex Hornung * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19fc16838fSAlex Hornung * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20fc16838fSAlex Hornung * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21fc16838fSAlex Hornung * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22fc16838fSAlex Hornung * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23fc16838fSAlex Hornung * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24fc16838fSAlex Hornung * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25fc16838fSAlex Hornung * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26fc16838fSAlex Hornung * SUCH DAMAGE.
27fc16838fSAlex Hornung *
28fc16838fSAlex Hornung * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $
29fc16838fSAlex Hornung * $FreeBSD$
30fc16838fSAlex Hornung */
31fc16838fSAlex Hornung
323d1294c7SPeeter Must #include "opt_evdev.h"
33b272d910SAlex Hornung #include "opt_kbd.h"
34b272d910SAlex Hornung
35fc16838fSAlex Hornung #include <sys/param.h>
36fc16838fSAlex Hornung #include <sys/bus.h>
37fc16838fSAlex Hornung #include <sys/conf.h>
38fc16838fSAlex Hornung #include <sys/consio.h>
39fc16838fSAlex Hornung #include <sys/fcntl.h>
40fc16838fSAlex Hornung #include <sys/kbio.h>
41fc16838fSAlex Hornung #include <sys/kernel.h>
42fc16838fSAlex Hornung #include <sys/limits.h>
43fc16838fSAlex Hornung #include <sys/lock.h>
44fc16838fSAlex Hornung #include <sys/malloc.h>
45fc16838fSAlex Hornung #include <sys/module.h>
46fc16838fSAlex Hornung #include <sys/poll.h>
47fc16838fSAlex Hornung #include <sys/proc.h>
48fc16838fSAlex Hornung #include <sys/queue.h>
495b22f1a7SSamuel J. Greear #include <sys/event.h>
50fc16838fSAlex Hornung #include <sys/systm.h>
51fc16838fSAlex Hornung #include <sys/taskqueue.h>
52fc16838fSAlex Hornung #include <sys/uio.h>
53bcc53404SAlex Hornung #include <dev/misc/kbd/kbdreg.h>
54bcc53404SAlex Hornung #include <dev/misc/kbd/kbdtables.h>
55fc16838fSAlex Hornung
563d1294c7SPeeter Must #ifdef EVDEV_SUPPORT
573d1294c7SPeeter Must #include <dev/misc/evdev/evdev.h>
583d1294c7SPeeter Must #include <dev/misc/evdev/input.h>
593d1294c7SPeeter Must #endif
603d1294c7SPeeter Must
61fc16838fSAlex Hornung #define KEYBOARD_NAME "kbdmux"
62fc16838fSAlex Hornung
63fc16838fSAlex Hornung MALLOC_DECLARE(M_KBDMUX);
64fc16838fSAlex Hornung MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
65fc16838fSAlex Hornung
66fc16838fSAlex Hornung /*****************************************************************************
67fc16838fSAlex Hornung *****************************************************************************
68fc16838fSAlex Hornung ** Keyboard state
69fc16838fSAlex Hornung *****************************************************************************
70fc16838fSAlex Hornung *****************************************************************************/
71fc16838fSAlex Hornung
72fc16838fSAlex Hornung #define KBDMUX_Q_SIZE 512 /* input queue size */
73fc16838fSAlex Hornung
74fc16838fSAlex Hornung /*
75fc16838fSAlex Hornung * kbdmux keyboard
76fc16838fSAlex Hornung */
77fc16838fSAlex Hornung struct kbdmux_kbd
78fc16838fSAlex Hornung {
79fc16838fSAlex Hornung keyboard_t *kbd; /* keyboard */
80fc16838fSAlex Hornung SLIST_ENTRY(kbdmux_kbd) next; /* link to next */
81fc16838fSAlex Hornung };
82fc16838fSAlex Hornung
83fc16838fSAlex Hornung typedef struct kbdmux_kbd kbdmux_kbd_t;
84fc16838fSAlex Hornung
85fc16838fSAlex Hornung /*
86fc16838fSAlex Hornung * kbdmux state
87fc16838fSAlex Hornung */
88fc16838fSAlex Hornung struct kbdmux_state
89fc16838fSAlex Hornung {
90fc16838fSAlex Hornung char ks_inq[KBDMUX_Q_SIZE]; /* input chars queue */
91fc16838fSAlex Hornung unsigned int ks_inq_start;
92fc16838fSAlex Hornung unsigned int ks_inq_length;
93fc16838fSAlex Hornung struct task ks_task; /* interrupt task */
94fc16838fSAlex Hornung
95fc16838fSAlex Hornung int ks_flags; /* flags */
96fc16838fSAlex Hornung #define COMPOSE (1 << 0) /* compose char flag */
97fc16838fSAlex Hornung #define POLLING (1 << 1) /* polling */
98fc16838fSAlex Hornung
99fc16838fSAlex Hornung int ks_mode; /* K_XLATE, K_RAW, K_CODE */
100fc16838fSAlex Hornung int ks_state; /* state */
101fc16838fSAlex Hornung int ks_accents; /* accent key index (> 0) */
102fc16838fSAlex Hornung u_int ks_composed_char; /* composed char code */
103fc16838fSAlex Hornung u_char ks_prefix; /* AT scan code prefix */
104fc16838fSAlex Hornung
1053d1294c7SPeeter Must #ifdef EVDEV_SUPPORT
1063d1294c7SPeeter Must struct evdev_dev * ks_evdev;
1073d1294c7SPeeter Must int ks_evdev_state;
1083d1294c7SPeeter Must #endif
1093d1294c7SPeeter Must
110fc16838fSAlex Hornung SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */
111fc16838fSAlex Hornung };
112fc16838fSAlex Hornung
113fc16838fSAlex Hornung typedef struct kbdmux_state kbdmux_state_t;
114fc16838fSAlex Hornung
115fc16838fSAlex Hornung /*****************************************************************************
116fc16838fSAlex Hornung *****************************************************************************
117fc16838fSAlex Hornung ** Helper functions
118fc16838fSAlex Hornung *****************************************************************************
119fc16838fSAlex Hornung *****************************************************************************/
120fc16838fSAlex Hornung
121fc16838fSAlex Hornung static task_fn_t kbdmux_kbd_intr;
122fc16838fSAlex Hornung static kbd_callback_func_t kbdmux_kbd_event;
123fc16838fSAlex Hornung
124fc16838fSAlex Hornung static void
kbdmux_kbd_putc(kbdmux_state_t * state,char c)125fc16838fSAlex Hornung kbdmux_kbd_putc(kbdmux_state_t *state, char c)
126fc16838fSAlex Hornung {
127fc16838fSAlex Hornung unsigned int p;
128fc16838fSAlex Hornung
129fc16838fSAlex Hornung if (state->ks_inq_length == KBDMUX_Q_SIZE)
130fc16838fSAlex Hornung return;
131fc16838fSAlex Hornung
132fc16838fSAlex Hornung p = (state->ks_inq_start + state->ks_inq_length) % KBDMUX_Q_SIZE;
133fc16838fSAlex Hornung state->ks_inq[p] = c;
134fc16838fSAlex Hornung state->ks_inq_length++;
135fc16838fSAlex Hornung }
136fc16838fSAlex Hornung
137fc16838fSAlex Hornung static int
kbdmux_kbd_getc(kbdmux_state_t * state)138fc16838fSAlex Hornung kbdmux_kbd_getc(kbdmux_state_t *state)
139fc16838fSAlex Hornung {
140fc16838fSAlex Hornung unsigned char c;
141fc16838fSAlex Hornung
142fc16838fSAlex Hornung if (state->ks_inq_length == 0)
143fc16838fSAlex Hornung return (-1);
144fc16838fSAlex Hornung
145fc16838fSAlex Hornung c = state->ks_inq[state->ks_inq_start];
146fc16838fSAlex Hornung state->ks_inq_start = (state->ks_inq_start + 1) % KBDMUX_Q_SIZE;
147fc16838fSAlex Hornung state->ks_inq_length--;
148fc16838fSAlex Hornung
149fc16838fSAlex Hornung return (c);
150fc16838fSAlex Hornung }
151fc16838fSAlex Hornung
152fc16838fSAlex Hornung /*
153fc16838fSAlex Hornung * Interrupt handler task
154fc16838fSAlex Hornung */
1558406cf70SSascha Wildner static void
kbdmux_kbd_intr(void * xkbd,int pending)156fc16838fSAlex Hornung kbdmux_kbd_intr(void *xkbd, int pending)
157fc16838fSAlex Hornung {
158fc16838fSAlex Hornung keyboard_t *kbd = (keyboard_t *) xkbd;
159fc9700a1SMatthew Dillon KBD_LOCK_DECLARE;
160fc16838fSAlex Hornung
161fc9700a1SMatthew Dillon KBD_LOCK(kbd); /* recursive so ok */
162bcc53404SAlex Hornung kbd_intr(kbd, NULL);
163fc9700a1SMatthew Dillon KBD_UNLOCK(kbd);
164fc16838fSAlex Hornung }
165fc16838fSAlex Hornung
166fc16838fSAlex Hornung /*
167fc16838fSAlex Hornung * Process event from one of our keyboards
168fc16838fSAlex Hornung */
169fc16838fSAlex Hornung static int
kbdmux_kbd_event(keyboard_t * kbd,int event,void * arg)170fc16838fSAlex Hornung kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
171fc16838fSAlex Hornung {
172fc16838fSAlex Hornung kbdmux_state_t *state = (kbdmux_state_t *) arg;
173fc16838fSAlex Hornung
174fc16838fSAlex Hornung switch (event) {
175fc16838fSAlex Hornung case KBDIO_KEYINPUT: {
176fc16838fSAlex Hornung int c;
177fc16838fSAlex Hornung
178fc16838fSAlex Hornung /*
179fc16838fSAlex Hornung * Read all chars from the keyboard
180fc16838fSAlex Hornung *
181fc16838fSAlex Hornung * Turns out that atkbd(4) check_char() method may return
182fc16838fSAlex Hornung * "true" while read_char() method returns NOKEY. If this
183fc16838fSAlex Hornung * happens we could stuck in the loop below. Avoid this
184fc16838fSAlex Hornung * by breaking out of the loop if read_char() method returns
185fc16838fSAlex Hornung * NOKEY.
186fc16838fSAlex Hornung */
187fc16838fSAlex Hornung
188bcc53404SAlex Hornung while (kbd_check_char(kbd)) {
189bcc53404SAlex Hornung c = kbd_read_char(kbd, 0);
190fc16838fSAlex Hornung if (c == NOKEY)
191fc16838fSAlex Hornung break;
192fc16838fSAlex Hornung if (c == ERRKEY)
193fc16838fSAlex Hornung continue; /* XXX ring bell */
194fc16838fSAlex Hornung if (!KBD_IS_BUSY(kbd))
195fc16838fSAlex Hornung continue; /* not open - discard the input */
196fc16838fSAlex Hornung
197fc16838fSAlex Hornung kbdmux_kbd_putc(state, c);
198fc16838fSAlex Hornung }
199fc16838fSAlex Hornung
200fc16838fSAlex Hornung /* queue interrupt task if needed */
20151b03d73SImre Vadász if (state->ks_inq_length > 0)
20251b03d73SImre Vadász taskqueue_enqueue(taskqueue_swi, &state->ks_task);
203fc16838fSAlex Hornung
204fc16838fSAlex Hornung } break;
205fc16838fSAlex Hornung
206fc16838fSAlex Hornung case KBDIO_UNLOADING: {
207fc16838fSAlex Hornung kbdmux_kbd_t *k;
208fc16838fSAlex Hornung
209fc16838fSAlex Hornung SLIST_FOREACH(k, &state->ks_kbds, next)
210fc16838fSAlex Hornung if (k->kbd == kbd)
211fc16838fSAlex Hornung break;
212fc16838fSAlex Hornung
213fc16838fSAlex Hornung if (k != NULL) {
214fc16838fSAlex Hornung kbd_release(k->kbd, &k->kbd);
215fc16838fSAlex Hornung SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
216fc16838fSAlex Hornung
217fc16838fSAlex Hornung k->kbd = NULL;
218fc16838fSAlex Hornung
219bcc53404SAlex Hornung kfree(k, M_KBDMUX);
220fc16838fSAlex Hornung }
221fc16838fSAlex Hornung
222fc16838fSAlex Hornung } break;
223fc16838fSAlex Hornung
224fc16838fSAlex Hornung default:
225fc16838fSAlex Hornung return (EINVAL);
226fc16838fSAlex Hornung /* NOT REACHED */
227fc16838fSAlex Hornung }
228fc16838fSAlex Hornung return (0);
229fc16838fSAlex Hornung }
230fc16838fSAlex Hornung
231fc16838fSAlex Hornung /****************************************************************************
232fc16838fSAlex Hornung ****************************************************************************
233fc16838fSAlex Hornung ** Keyboard driver
234fc16838fSAlex Hornung ****************************************************************************
235fc16838fSAlex Hornung ****************************************************************************/
236fc16838fSAlex Hornung
237fc16838fSAlex Hornung static int kbdmux_configure(int flags);
238fc16838fSAlex Hornung static kbd_probe_t kbdmux_probe;
239fc16838fSAlex Hornung static kbd_init_t kbdmux_init;
240fc16838fSAlex Hornung static kbd_term_t kbdmux_term;
241fc16838fSAlex Hornung static kbd_intr_t kbdmux_intr;
242fc16838fSAlex Hornung static kbd_test_if_t kbdmux_test_if;
243fc16838fSAlex Hornung static kbd_enable_t kbdmux_enable;
244fc16838fSAlex Hornung static kbd_disable_t kbdmux_disable;
245fc16838fSAlex Hornung static kbd_read_t kbdmux_read;
246fc16838fSAlex Hornung static kbd_check_t kbdmux_check;
247fc16838fSAlex Hornung static kbd_read_char_t kbdmux_read_char;
248fc16838fSAlex Hornung static kbd_check_char_t kbdmux_check_char;
249fc16838fSAlex Hornung static kbd_ioctl_t kbdmux_ioctl;
250fc16838fSAlex Hornung static kbd_lock_t kbdmux_lock;
251fc16838fSAlex Hornung static kbd_clear_state_t kbdmux_clear_state;
252fc16838fSAlex Hornung static kbd_get_state_t kbdmux_get_state;
253fc16838fSAlex Hornung static kbd_set_state_t kbdmux_set_state;
254fc16838fSAlex Hornung static kbd_poll_mode_t kbdmux_poll;
255fc16838fSAlex Hornung
256fc16838fSAlex Hornung static keyboard_switch_t kbdmuxsw = {
257fc16838fSAlex Hornung .probe = kbdmux_probe,
258fc16838fSAlex Hornung .init = kbdmux_init,
259fc16838fSAlex Hornung .term = kbdmux_term,
260fc16838fSAlex Hornung .intr = kbdmux_intr,
261fc16838fSAlex Hornung .test_if = kbdmux_test_if,
262fc16838fSAlex Hornung .enable = kbdmux_enable,
263fc16838fSAlex Hornung .disable = kbdmux_disable,
264fc16838fSAlex Hornung .read = kbdmux_read,
265fc16838fSAlex Hornung .check = kbdmux_check,
266fc16838fSAlex Hornung .read_char = kbdmux_read_char,
267fc16838fSAlex Hornung .check_char = kbdmux_check_char,
268fc16838fSAlex Hornung .ioctl = kbdmux_ioctl,
269fc16838fSAlex Hornung .lock = kbdmux_lock,
270fc16838fSAlex Hornung .clear_state = kbdmux_clear_state,
271fc16838fSAlex Hornung .get_state = kbdmux_get_state,
272fc16838fSAlex Hornung .set_state = kbdmux_set_state,
273fc16838fSAlex Hornung .get_fkeystr = genkbd_get_fkeystr,
274fc16838fSAlex Hornung .poll = kbdmux_poll,
275fc16838fSAlex Hornung .diag = genkbd_diag,
276fc16838fSAlex Hornung };
277fc16838fSAlex Hornung
2783d1294c7SPeeter Must #ifdef EVDEV_SUPPORT
2793d1294c7SPeeter Must static const struct evdev_methods kbdmux_evdev_methods = {
2803d1294c7SPeeter Must .ev_event = evdev_ev_kbd_event,
2813d1294c7SPeeter Must };
2823d1294c7SPeeter Must #endif
2833d1294c7SPeeter Must
284fc16838fSAlex Hornung /*
285fc16838fSAlex Hornung * Return the number of found keyboards
286fc16838fSAlex Hornung */
287fc16838fSAlex Hornung static int
kbdmux_configure(int flags)288fc16838fSAlex Hornung kbdmux_configure(int flags)
289fc16838fSAlex Hornung {
290fc16838fSAlex Hornung return (1);
291fc16838fSAlex Hornung }
292fc16838fSAlex Hornung
293fc16838fSAlex Hornung /*
294fc16838fSAlex Hornung * Detect a keyboard
295fc16838fSAlex Hornung */
296fc16838fSAlex Hornung static int
kbdmux_probe(int unit,void * arg,int flags)297fc16838fSAlex Hornung kbdmux_probe(int unit, void *arg, int flags)
298fc16838fSAlex Hornung {
299fc16838fSAlex Hornung if (resource_disabled(KEYBOARD_NAME, unit))
300fc16838fSAlex Hornung return (ENXIO);
301fc16838fSAlex Hornung
302fc16838fSAlex Hornung return (0);
303fc16838fSAlex Hornung }
304fc16838fSAlex Hornung
305fc16838fSAlex Hornung /*
306fc16838fSAlex Hornung * Reset and initialize the keyboard (stolen from atkbd.c)
307fc9700a1SMatthew Dillon *
308fc9700a1SMatthew Dillon * Called without kbd lock held.
309fc16838fSAlex Hornung */
310fc16838fSAlex Hornung static int
kbdmux_init(int unit,keyboard_t ** kbdp,void * arg,int flags)311fc16838fSAlex Hornung kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
312fc16838fSAlex Hornung {
313fc16838fSAlex Hornung kbdmux_state_t *state = NULL;
314fc16838fSAlex Hornung keymap_t *keymap = NULL;
315fc16838fSAlex Hornung accentmap_t *accmap = NULL;
316fc16838fSAlex Hornung fkeytab_t *fkeymap = NULL;
317fc9700a1SMatthew Dillon keyboard_t *kbd = NULL;
318fc16838fSAlex Hornung int error, needfree, fkeymap_size, delay[2];
3193d1294c7SPeeter Must #ifdef EVDEV_SUPPORT
3203d1294c7SPeeter Must struct evdev_dev *evdev;
3213d1294c7SPeeter Must char phys_loc[NAMELEN];
3223d1294c7SPeeter Must #endif
323fc16838fSAlex Hornung
324fc16838fSAlex Hornung if (*kbdp == NULL) {
325bcc53404SAlex Hornung *kbdp = kbd = kmalloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
326bcc53404SAlex Hornung state = kmalloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
327bcc53404SAlex Hornung keymap = kmalloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
328bcc53404SAlex Hornung accmap = kmalloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
329bcc53404SAlex Hornung fkeymap = kmalloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
330c157ff7aSSascha Wildner fkeymap_size = NELEM(fkey_tab);
331fc16838fSAlex Hornung needfree = 1;
332fc16838fSAlex Hornung
333fc16838fSAlex Hornung if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
334fc16838fSAlex Hornung (accmap == NULL) || (fkeymap == NULL)) {
335fc16838fSAlex Hornung error = ENOMEM;
336fc16838fSAlex Hornung goto bad;
337fc16838fSAlex Hornung }
338fc16838fSAlex Hornung
339fc16838fSAlex Hornung TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
340fc16838fSAlex Hornung SLIST_INIT(&state->ks_kbds);
341fc16838fSAlex Hornung } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
342fc16838fSAlex Hornung return (0);
343fc16838fSAlex Hornung } else {
344fc16838fSAlex Hornung kbd = *kbdp;
345fc16838fSAlex Hornung state = (kbdmux_state_t *) kbd->kb_data;
346fc16838fSAlex Hornung keymap = kbd->kb_keymap;
347fc16838fSAlex Hornung accmap = kbd->kb_accentmap;
348fc16838fSAlex Hornung fkeymap = kbd->kb_fkeytab;
349fc16838fSAlex Hornung fkeymap_size = kbd->kb_fkeytab_size;
350fc16838fSAlex Hornung needfree = 0;
351fc16838fSAlex Hornung }
352fc16838fSAlex Hornung
353fc16838fSAlex Hornung if (!KBD_IS_PROBED(kbd)) {
354fc16838fSAlex Hornung /* XXX assume 101/102 keys keyboard */
355bcc53404SAlex Hornung kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags,
356bcc53404SAlex Hornung KB_PRI_MUX, 0, 0);
357fc16838fSAlex Hornung bcopy(&key_map, keymap, sizeof(key_map));
358fc16838fSAlex Hornung bcopy(&accent_map, accmap, sizeof(accent_map));
359fc16838fSAlex Hornung bcopy(fkey_tab, fkeymap,
360fc16838fSAlex Hornung imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
361fc16838fSAlex Hornung kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
362fc16838fSAlex Hornung kbd->kb_data = (void *)state;
363fc16838fSAlex Hornung
364fc16838fSAlex Hornung KBD_FOUND_DEVICE(kbd);
365fc16838fSAlex Hornung KBD_PROBE_DONE(kbd);
366fc16838fSAlex Hornung
367fc9700a1SMatthew Dillon kbdmux_clear_state(kbd);
368fc16838fSAlex Hornung state->ks_mode = K_XLATE;
369fc16838fSAlex Hornung }
370fc16838fSAlex Hornung
371fc16838fSAlex Hornung if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
372fc16838fSAlex Hornung kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
373fc16838fSAlex Hornung
374fc16838fSAlex Hornung kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
375fc16838fSAlex Hornung
376fc16838fSAlex Hornung delay[0] = kbd->kb_delay1;
377fc16838fSAlex Hornung delay[1] = kbd->kb_delay2;
378fc16838fSAlex Hornung kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
379fc16838fSAlex Hornung
3803d1294c7SPeeter Must #ifdef EVDEV_SUPPORT
3813d1294c7SPeeter Must /* register as evdev provider */
3823d1294c7SPeeter Must evdev = evdev_alloc();
3833d1294c7SPeeter Must evdev_set_name(evdev, "System keyboard multiplexer");
3843d1294c7SPeeter Must ksnprintf(phys_loc, NAMELEN, KEYBOARD_NAME"%d", unit);
3853d1294c7SPeeter Must evdev_set_phys(evdev, phys_loc);
3863d1294c7SPeeter Must evdev_set_id(evdev, BUS_VIRTUAL, 0, 0, 0);
3873d1294c7SPeeter Must evdev_set_methods(evdev, kbd, &kbdmux_evdev_methods);
3883d1294c7SPeeter Must evdev_support_event(evdev, EV_SYN);
3893d1294c7SPeeter Must evdev_support_event(evdev, EV_KEY);
3903d1294c7SPeeter Must evdev_support_event(evdev, EV_LED);
3913d1294c7SPeeter Must evdev_support_event(evdev, EV_REP);
3923d1294c7SPeeter Must evdev_support_all_known_keys(evdev);
3933d1294c7SPeeter Must evdev_support_led(evdev, LED_NUML);
3943d1294c7SPeeter Must evdev_support_led(evdev, LED_CAPSL);
3953d1294c7SPeeter Must evdev_support_led(evdev, LED_SCROLLL);
3963d1294c7SPeeter Must
3973d1294c7SPeeter Must if (evdev_register(evdev))
3983d1294c7SPeeter Must evdev_free(evdev);
3993d1294c7SPeeter Must else
4003d1294c7SPeeter Must state->ks_evdev = evdev;
4013d1294c7SPeeter Must state->ks_evdev_state = 0;
4023d1294c7SPeeter Must #endif
4033d1294c7SPeeter Must
404fc16838fSAlex Hornung KBD_INIT_DONE(kbd);
405fc16838fSAlex Hornung }
406fc16838fSAlex Hornung
407fc16838fSAlex Hornung if (!KBD_IS_CONFIGURED(kbd)) {
408fc16838fSAlex Hornung if (kbd_register(kbd) < 0) {
409fc16838fSAlex Hornung error = ENXIO;
410fc16838fSAlex Hornung goto bad;
411fc16838fSAlex Hornung }
412fc16838fSAlex Hornung
413fc16838fSAlex Hornung KBD_CONFIG_DONE(kbd);
414fc16838fSAlex Hornung }
415fc16838fSAlex Hornung
416fc16838fSAlex Hornung return (0);
417fc16838fSAlex Hornung bad:
418fc16838fSAlex Hornung if (needfree) {
419fc16838fSAlex Hornung if (state != NULL)
420bcc53404SAlex Hornung kfree(state, M_KBDMUX);
421fc16838fSAlex Hornung if (keymap != NULL)
422bcc53404SAlex Hornung kfree(keymap, M_KBDMUX);
423fc16838fSAlex Hornung if (accmap != NULL)
424bcc53404SAlex Hornung kfree(accmap, M_KBDMUX);
425fc16838fSAlex Hornung if (fkeymap != NULL)
426bcc53404SAlex Hornung kfree(fkeymap, M_KBDMUX);
427fc16838fSAlex Hornung if (kbd != NULL) {
428bcc53404SAlex Hornung kfree(kbd, M_KBDMUX);
429fc16838fSAlex Hornung *kbdp = NULL; /* insure ref doesn't leak to caller */
430fc16838fSAlex Hornung }
431fc16838fSAlex Hornung }
432fc16838fSAlex Hornung
433fc16838fSAlex Hornung return (error);
434fc16838fSAlex Hornung }
435fc16838fSAlex Hornung
436fc16838fSAlex Hornung /*
437fc16838fSAlex Hornung * Finish using this keyboard
438fc9700a1SMatthew Dillon *
439fc9700a1SMatthew Dillon * NOTE: deregistration automatically unlocks lock.
440fc16838fSAlex Hornung */
441fc16838fSAlex Hornung static int
kbdmux_term(keyboard_t * kbd)442fc16838fSAlex Hornung kbdmux_term(keyboard_t *kbd)
443fc16838fSAlex Hornung {
444fc16838fSAlex Hornung kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
445fc16838fSAlex Hornung kbdmux_kbd_t *k;
446fc16838fSAlex Hornung
447fc16838fSAlex Hornung /* wait for interrupt task */
44851b03d73SImre Vadász while (taskqueue_cancel(taskqueue_swi, &state->ks_task, NULL) != 0)
44951b03d73SImre Vadász taskqueue_drain(taskqueue_swi, &state->ks_task);
450fc16838fSAlex Hornung
451fc16838fSAlex Hornung /* release all keyboards from the mux */
452fc16838fSAlex Hornung while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
453fc16838fSAlex Hornung kbd_release(k->kbd, &k->kbd);
454fc16838fSAlex Hornung SLIST_REMOVE_HEAD(&state->ks_kbds, next);
455fc16838fSAlex Hornung
456fc16838fSAlex Hornung k->kbd = NULL;
457fc16838fSAlex Hornung
458bcc53404SAlex Hornung kfree(k, M_KBDMUX);
459fc16838fSAlex Hornung }
460fc16838fSAlex Hornung
461fc16838fSAlex Hornung kbd_unregister(kbd);
462fc16838fSAlex Hornung
4633d1294c7SPeeter Must #ifdef EVDEV_SUPPORT
4643d1294c7SPeeter Must evdev_free(state->ks_evdev);
4653d1294c7SPeeter Must #endif
4663d1294c7SPeeter Must
467fc16838fSAlex Hornung bzero(state, sizeof(*state));
468bcc53404SAlex Hornung kfree(state, M_KBDMUX);
469fc16838fSAlex Hornung
470bcc53404SAlex Hornung kfree(kbd->kb_keymap, M_KBDMUX);
471bcc53404SAlex Hornung kfree(kbd->kb_accentmap, M_KBDMUX);
472bcc53404SAlex Hornung kfree(kbd->kb_fkeytab, M_KBDMUX);
473bcc53404SAlex Hornung kfree(kbd, M_KBDMUX);
474fc16838fSAlex Hornung
475fc16838fSAlex Hornung return (0);
476fc16838fSAlex Hornung }
477fc16838fSAlex Hornung
478fc16838fSAlex Hornung /*
479fc16838fSAlex Hornung * Keyboard interrupt routine
480fc16838fSAlex Hornung */
481fc16838fSAlex Hornung static int
kbdmux_intr(keyboard_t * kbd,void * arg)482fc16838fSAlex Hornung kbdmux_intr(keyboard_t *kbd, void *arg)
483fc16838fSAlex Hornung {
484fc16838fSAlex Hornung int c;
485fc16838fSAlex Hornung
486fc16838fSAlex Hornung if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
487fc16838fSAlex Hornung /* let the callback function to process the input */
488fc16838fSAlex Hornung (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
489fc16838fSAlex Hornung kbd->kb_callback.kc_arg);
490fc16838fSAlex Hornung } else {
491fc16838fSAlex Hornung /* read and discard the input; no one is waiting for input */
492fc16838fSAlex Hornung do {
493fc16838fSAlex Hornung c = kbdmux_read_char(kbd, FALSE);
494fc16838fSAlex Hornung } while (c != NOKEY);
495fc16838fSAlex Hornung }
496fc16838fSAlex Hornung
497fc16838fSAlex Hornung return (0);
498fc16838fSAlex Hornung }
499fc16838fSAlex Hornung
500fc16838fSAlex Hornung /*
501fc16838fSAlex Hornung * Test the interface to the device
502fc16838fSAlex Hornung */
503fc16838fSAlex Hornung static int
kbdmux_test_if(keyboard_t * kbd)504fc16838fSAlex Hornung kbdmux_test_if(keyboard_t *kbd)
505fc16838fSAlex Hornung {
506fc16838fSAlex Hornung return (0);
507fc16838fSAlex Hornung }
508fc16838fSAlex Hornung
509fc16838fSAlex Hornung /*
510fc16838fSAlex Hornung * Enable the access to the device; until this function is called,
511fc16838fSAlex Hornung * the client cannot read from the keyboard.
512fc16838fSAlex Hornung */
513fc16838fSAlex Hornung static int
kbdmux_enable(keyboard_t * kbd)514fc16838fSAlex Hornung kbdmux_enable(keyboard_t *kbd)
515fc16838fSAlex Hornung {
516fc16838fSAlex Hornung KBD_ACTIVATE(kbd);
517fc16838fSAlex Hornung return (0);
518fc16838fSAlex Hornung }
519fc16838fSAlex Hornung
520fc16838fSAlex Hornung /*
521fc16838fSAlex Hornung * Disallow the access to the device
522fc16838fSAlex Hornung */
523fc16838fSAlex Hornung static int
kbdmux_disable(keyboard_t * kbd)524fc16838fSAlex Hornung kbdmux_disable(keyboard_t *kbd)
525fc16838fSAlex Hornung {
526fc16838fSAlex Hornung KBD_DEACTIVATE(kbd);
527fc16838fSAlex Hornung return (0);
528fc16838fSAlex Hornung }
529fc16838fSAlex Hornung
530fc16838fSAlex Hornung /*
531fc16838fSAlex Hornung * Read one byte from the keyboard if it's allowed
532fc16838fSAlex Hornung */
533fc16838fSAlex Hornung static int
kbdmux_read(keyboard_t * kbd,int wait)534fc16838fSAlex Hornung kbdmux_read(keyboard_t *kbd, int wait)
535fc16838fSAlex Hornung {
536fc16838fSAlex Hornung kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
53722ff886eSAlex Hornung int c, ret;
538fc16838fSAlex Hornung
539786d7861SMatthew Dillon do {
540fc16838fSAlex Hornung c = kbdmux_kbd_getc(state);
541786d7861SMatthew Dillon } while (c == -1 && wait);
542fc16838fSAlex Hornung
543fc16838fSAlex Hornung if (c != -1)
544fc16838fSAlex Hornung kbd->kb_count++;
545fc16838fSAlex Hornung
54622ff886eSAlex Hornung ret = (KBD_IS_ACTIVE(kbd)? c : -1);
54722ff886eSAlex Hornung
54822ff886eSAlex Hornung return ret;
549fc16838fSAlex Hornung }
550fc16838fSAlex Hornung
551fc16838fSAlex Hornung /*
552fc16838fSAlex Hornung * Check if data is waiting
553fc16838fSAlex Hornung */
554fc16838fSAlex Hornung static int
kbdmux_check(keyboard_t * kbd)555fc16838fSAlex Hornung kbdmux_check(keyboard_t *kbd)
556fc16838fSAlex Hornung {
557fc16838fSAlex Hornung kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
558fc16838fSAlex Hornung int ready;
559fc16838fSAlex Hornung
560fc9700a1SMatthew Dillon if (!KBD_IS_ACTIVE(kbd))
561fc16838fSAlex Hornung return (FALSE);
562fc16838fSAlex Hornung
563fc16838fSAlex Hornung ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
564fc16838fSAlex Hornung
565fc16838fSAlex Hornung return (ready);
566fc16838fSAlex Hornung }
567fc16838fSAlex Hornung
568fc16838fSAlex Hornung /*
569fc16838fSAlex Hornung * Read char from the keyboard (stolen from atkbd.c)
570786d7861SMatthew Dillon *
571786d7861SMatthew Dillon * Note: We do not attempt to detect the case where no keyboards are
572786d7861SMatthew Dillon * present in the wait case. If the kernel is sitting at the
573786d7861SMatthew Dillon * debugger prompt we want someone to be able to plug in a keyboard
574786d7861SMatthew Dillon * and have it work, and not just panic or fall through or do
575786d7861SMatthew Dillon * something equally nasty.
576fc16838fSAlex Hornung */
577fc16838fSAlex Hornung static u_int
kbdmux_read_char(keyboard_t * kbd,int wait)578fc16838fSAlex Hornung kbdmux_read_char(keyboard_t *kbd, int wait)
579fc16838fSAlex Hornung {
580fc16838fSAlex Hornung kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
581fc16838fSAlex Hornung u_int action;
582fc16838fSAlex Hornung int scancode, keycode;
583fc16838fSAlex Hornung
584fc16838fSAlex Hornung next_code:
585fc16838fSAlex Hornung
586fc16838fSAlex Hornung /* do we have a composed char to return? */
587fc16838fSAlex Hornung if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
588fc16838fSAlex Hornung action = state->ks_composed_char;
589fc16838fSAlex Hornung state->ks_composed_char = 0;
590fc16838fSAlex Hornung if (action > UCHAR_MAX) {
591fc16838fSAlex Hornung return (ERRKEY);
592fc16838fSAlex Hornung }
593fc16838fSAlex Hornung return (action);
594fc16838fSAlex Hornung }
595fc16838fSAlex Hornung
596786d7861SMatthew Dillon /*
597786d7861SMatthew Dillon * See if there is something in the keyboard queue
598786d7861SMatthew Dillon */
599fc16838fSAlex Hornung scancode = kbdmux_kbd_getc(state);
600786d7861SMatthew Dillon
601fc16838fSAlex Hornung if (scancode == -1) {
602fc16838fSAlex Hornung if (state->ks_flags & POLLING) {
603fc16838fSAlex Hornung kbdmux_kbd_t *k;
604fc16838fSAlex Hornung
605fc16838fSAlex Hornung SLIST_FOREACH(k, &state->ks_kbds, next) {
606bcc53404SAlex Hornung while (kbd_check_char(k->kbd)) {
607bcc53404SAlex Hornung scancode = kbd_read_char(k->kbd, 0);
608fc16838fSAlex Hornung if (scancode == ERRKEY)
609fc16838fSAlex Hornung continue;
610786d7861SMatthew Dillon if (scancode == NOKEY)
611786d7861SMatthew Dillon break;
612fc16838fSAlex Hornung if (!KBD_IS_BUSY(k->kbd))
613fc16838fSAlex Hornung continue;
614fc16838fSAlex Hornung kbdmux_kbd_putc(state, scancode);
615fc16838fSAlex Hornung }
616fc16838fSAlex Hornung }
617fc16838fSAlex Hornung
618fc16838fSAlex Hornung if (state->ks_inq_length > 0)
619fc16838fSAlex Hornung goto next_code;
620786d7861SMatthew Dillon if (wait)
621786d7861SMatthew Dillon goto next_code;
622786d7861SMatthew Dillon } else {
623786d7861SMatthew Dillon if (wait) {
624*f57dbfa8SMatthew Dillon if (kbd->kb_flags & KB_POLLED) {
625*f57dbfa8SMatthew Dillon tsleep(&state->ks_task, PCATCH,
6262d57b795SSascha Wildner "kbdwai", hz/10);
627*f57dbfa8SMatthew Dillon } else {
628*f57dbfa8SMatthew Dillon lksleep(&state->ks_task,
629*f57dbfa8SMatthew Dillon &kbd->kb_lock, PCATCH,
630*f57dbfa8SMatthew Dillon "kbdwai", hz/10);
631*f57dbfa8SMatthew Dillon }
632786d7861SMatthew Dillon goto next_code;
633786d7861SMatthew Dillon }
634fc16838fSAlex Hornung }
635fc16838fSAlex Hornung return (NOKEY);
636fc16838fSAlex Hornung }
637fc16838fSAlex Hornung
638fc16838fSAlex Hornung kbd->kb_count++;
639fc16838fSAlex Hornung
6403d1294c7SPeeter Must #ifdef EVDEV_SUPPORT
6413d1294c7SPeeter Must /* push evdev event */
6423d1294c7SPeeter Must if (evdev_rcpt_mask & EVDEV_RCPT_KBDMUX && state->ks_evdev != NULL) {
6433d1294c7SPeeter Must uint16_t key = evdev_scancode2key(&state->ks_evdev_state,
6443d1294c7SPeeter Must scancode);
6453d1294c7SPeeter Must
6463d1294c7SPeeter Must if (key != KEY_RESERVED) {
6473d1294c7SPeeter Must evdev_push_event(state->ks_evdev, EV_KEY,
6483d1294c7SPeeter Must key, scancode & 0x80 ? 0 : 1);
6493d1294c7SPeeter Must evdev_sync(state->ks_evdev);
6503d1294c7SPeeter Must }
6513d1294c7SPeeter Must }
6523d1294c7SPeeter Must #endif
6533d1294c7SPeeter Must
654fc16838fSAlex Hornung /* return the byte as is for the K_RAW mode */
655fc9700a1SMatthew Dillon if (state->ks_mode == K_RAW)
656fc16838fSAlex Hornung return (scancode);
657fc16838fSAlex Hornung
658fc16838fSAlex Hornung /* translate the scan code into a keycode */
659fc16838fSAlex Hornung keycode = scancode & 0x7F;
660fc16838fSAlex Hornung switch (state->ks_prefix) {
661fc16838fSAlex Hornung case 0x00: /* normal scancode */
662fc16838fSAlex Hornung switch(scancode) {
663fc16838fSAlex Hornung case 0xB8: /* left alt (compose key) released */
664fc16838fSAlex Hornung if (state->ks_flags & COMPOSE) {
665fc16838fSAlex Hornung state->ks_flags &= ~COMPOSE;
666fc16838fSAlex Hornung if (state->ks_composed_char > UCHAR_MAX)
667fc16838fSAlex Hornung state->ks_composed_char = 0;
668fc16838fSAlex Hornung }
669fc16838fSAlex Hornung break;
670fc16838fSAlex Hornung case 0x38: /* left alt (compose key) pressed */
671fc16838fSAlex Hornung if (!(state->ks_flags & COMPOSE)) {
672fc16838fSAlex Hornung state->ks_flags |= COMPOSE;
673fc16838fSAlex Hornung state->ks_composed_char = 0;
674fc16838fSAlex Hornung }
675fc16838fSAlex Hornung break;
676fc16838fSAlex Hornung case 0xE0:
677fc16838fSAlex Hornung case 0xE1:
678fc16838fSAlex Hornung state->ks_prefix = scancode;
679fc16838fSAlex Hornung goto next_code;
680fc16838fSAlex Hornung }
681fc16838fSAlex Hornung break;
682fc16838fSAlex Hornung case 0xE0: /* 0xE0 prefix */
683fc16838fSAlex Hornung state->ks_prefix = 0;
684fc16838fSAlex Hornung switch (keycode) {
685fc16838fSAlex Hornung case 0x1C: /* right enter key */
686fc16838fSAlex Hornung keycode = 0x59;
687fc16838fSAlex Hornung break;
688fc16838fSAlex Hornung case 0x1D: /* right ctrl key */
689fc16838fSAlex Hornung keycode = 0x5A;
690fc16838fSAlex Hornung break;
691fc16838fSAlex Hornung case 0x35: /* keypad divide key */
692fc16838fSAlex Hornung keycode = 0x5B;
693fc16838fSAlex Hornung break;
694fc16838fSAlex Hornung case 0x37: /* print scrn key */
695fc16838fSAlex Hornung keycode = 0x5C;
696fc16838fSAlex Hornung break;
697fc16838fSAlex Hornung case 0x38: /* right alt key (alt gr) */
698fc16838fSAlex Hornung keycode = 0x5D;
699fc16838fSAlex Hornung break;
700fc16838fSAlex Hornung case 0x46: /* ctrl-pause/break on AT 101 (see below) */
701fc16838fSAlex Hornung keycode = 0x68;
702fc16838fSAlex Hornung break;
703fc16838fSAlex Hornung case 0x47: /* grey home key */
704fc16838fSAlex Hornung keycode = 0x5E;
705fc16838fSAlex Hornung break;
706fc16838fSAlex Hornung case 0x48: /* grey up arrow key */
707fc16838fSAlex Hornung keycode = 0x5F;
708fc16838fSAlex Hornung break;
709fc16838fSAlex Hornung case 0x49: /* grey page up key */
710fc16838fSAlex Hornung keycode = 0x60;
711fc16838fSAlex Hornung break;
712fc16838fSAlex Hornung case 0x4B: /* grey left arrow key */
713fc16838fSAlex Hornung keycode = 0x61;
714fc16838fSAlex Hornung break;
715fc16838fSAlex Hornung case 0x4D: /* grey right arrow key */
716fc16838fSAlex Hornung keycode = 0x62;
717fc16838fSAlex Hornung break;
718fc16838fSAlex Hornung case 0x4F: /* grey end key */
719fc16838fSAlex Hornung keycode = 0x63;
720fc16838fSAlex Hornung break;
721fc16838fSAlex Hornung case 0x50: /* grey down arrow key */
722fc16838fSAlex Hornung keycode = 0x64;
723fc16838fSAlex Hornung break;
724fc16838fSAlex Hornung case 0x51: /* grey page down key */
725fc16838fSAlex Hornung keycode = 0x65;
726fc16838fSAlex Hornung break;
727fc16838fSAlex Hornung case 0x52: /* grey insert key */
728fc16838fSAlex Hornung keycode = 0x66;
729fc16838fSAlex Hornung break;
730fc16838fSAlex Hornung case 0x53: /* grey delete key */
731fc16838fSAlex Hornung keycode = 0x67;
732fc16838fSAlex Hornung break;
733fc16838fSAlex Hornung /* the following 3 are only used on the MS "Natural" keyboard */
734fc16838fSAlex Hornung case 0x5b: /* left Window key */
735fc16838fSAlex Hornung keycode = 0x69;
736fc16838fSAlex Hornung break;
737fc16838fSAlex Hornung case 0x5c: /* right Window key */
738fc16838fSAlex Hornung keycode = 0x6a;
739fc16838fSAlex Hornung break;
740fc16838fSAlex Hornung case 0x5d: /* menu key */
741fc16838fSAlex Hornung keycode = 0x6b;
742fc16838fSAlex Hornung break;
743fc16838fSAlex Hornung case 0x5e: /* power key */
744fc16838fSAlex Hornung keycode = 0x6d;
745fc16838fSAlex Hornung break;
746fc16838fSAlex Hornung case 0x5f: /* sleep key */
747fc16838fSAlex Hornung keycode = 0x6e;
748fc16838fSAlex Hornung break;
749fc16838fSAlex Hornung case 0x63: /* wake key */
750fc16838fSAlex Hornung keycode = 0x6f;
751fc16838fSAlex Hornung break;
752fc16838fSAlex Hornung case 0x64: /* [JP106USB] backslash, underscore */
753fc16838fSAlex Hornung keycode = 0x73;
754fc16838fSAlex Hornung break;
755fc16838fSAlex Hornung default: /* ignore everything else */
756fc16838fSAlex Hornung goto next_code;
757fc16838fSAlex Hornung }
758fc16838fSAlex Hornung break;
759fc16838fSAlex Hornung case 0xE1: /* 0xE1 prefix */
760fc16838fSAlex Hornung /*
761fc16838fSAlex Hornung * The pause/break key on the 101 keyboard produces:
762fc16838fSAlex Hornung * E1-1D-45 E1-9D-C5
763fc16838fSAlex Hornung * Ctrl-pause/break produces:
764fc16838fSAlex Hornung * E0-46 E0-C6 (See above.)
765fc16838fSAlex Hornung */
766fc16838fSAlex Hornung state->ks_prefix = 0;
767fc16838fSAlex Hornung if (keycode == 0x1D)
768fc16838fSAlex Hornung state->ks_prefix = 0x1D;
769fc16838fSAlex Hornung goto next_code;
770fc16838fSAlex Hornung /* NOT REACHED */
771fc16838fSAlex Hornung case 0x1D: /* pause / break */
772fc16838fSAlex Hornung state->ks_prefix = 0;
773fc16838fSAlex Hornung if (keycode != 0x45)
774fc16838fSAlex Hornung goto next_code;
775fc16838fSAlex Hornung keycode = 0x68;
776fc16838fSAlex Hornung break;
777fc16838fSAlex Hornung }
778fc16838fSAlex Hornung
779fc16838fSAlex Hornung /* XXX assume 101/102 keys AT keyboard */
780fc16838fSAlex Hornung switch (keycode) {
781fc16838fSAlex Hornung case 0x5c: /* print screen */
782fc16838fSAlex Hornung if (state->ks_flags & ALTS)
783fc16838fSAlex Hornung keycode = 0x54; /* sysrq */
784fc16838fSAlex Hornung break;
785fc16838fSAlex Hornung case 0x68: /* pause/break */
786fc16838fSAlex Hornung if (state->ks_flags & CTLS)
787fc16838fSAlex Hornung keycode = 0x6c; /* break */
788fc16838fSAlex Hornung break;
789fc16838fSAlex Hornung }
790fc16838fSAlex Hornung
791fc16838fSAlex Hornung /* return the key code in the K_CODE mode */
792fc9700a1SMatthew Dillon if (state->ks_mode == K_CODE)
793fc16838fSAlex Hornung return (keycode | (scancode & 0x80));
794fc16838fSAlex Hornung
795fc16838fSAlex Hornung /* compose a character code */
796fc16838fSAlex Hornung if (state->ks_flags & COMPOSE) {
797fc16838fSAlex Hornung switch (keycode | (scancode & 0x80)) {
798fc16838fSAlex Hornung /* key pressed, process it */
799fc16838fSAlex Hornung case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
800fc16838fSAlex Hornung state->ks_composed_char *= 10;
801fc16838fSAlex Hornung state->ks_composed_char += keycode - 0x40;
802fc9700a1SMatthew Dillon if (state->ks_composed_char > UCHAR_MAX)
803fc16838fSAlex Hornung return (ERRKEY);
804fc16838fSAlex Hornung goto next_code;
805fc16838fSAlex Hornung case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
806fc16838fSAlex Hornung state->ks_composed_char *= 10;
807fc16838fSAlex Hornung state->ks_composed_char += keycode - 0x47;
808fc9700a1SMatthew Dillon if (state->ks_composed_char > UCHAR_MAX)
809fc16838fSAlex Hornung return (ERRKEY);
810fc16838fSAlex Hornung goto next_code;
811fc16838fSAlex Hornung case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
812fc16838fSAlex Hornung state->ks_composed_char *= 10;
813fc16838fSAlex Hornung state->ks_composed_char += keycode - 0x4E;
814fc9700a1SMatthew Dillon if (state->ks_composed_char > UCHAR_MAX)
815fc16838fSAlex Hornung return (ERRKEY);
816fc16838fSAlex Hornung goto next_code;
817fc16838fSAlex Hornung case 0x52: /* keypad 0 */
818fc16838fSAlex Hornung state->ks_composed_char *= 10;
819fc9700a1SMatthew Dillon if (state->ks_composed_char > UCHAR_MAX)
820fc16838fSAlex Hornung return (ERRKEY);
821fc16838fSAlex Hornung goto next_code;
822fc16838fSAlex Hornung
823fc16838fSAlex Hornung /* key released, no interest here */
824fc16838fSAlex Hornung case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
825fc16838fSAlex Hornung case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
826fc16838fSAlex Hornung case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
827fc16838fSAlex Hornung case 0xD2: /* keypad 0 */
828fc16838fSAlex Hornung goto next_code;
829fc16838fSAlex Hornung
830fc16838fSAlex Hornung case 0x38: /* left alt key */
831fc16838fSAlex Hornung break;
832fc16838fSAlex Hornung
833fc16838fSAlex Hornung default:
834fc16838fSAlex Hornung if (state->ks_composed_char > 0) {
835fc16838fSAlex Hornung state->ks_flags &= ~COMPOSE;
836fc16838fSAlex Hornung state->ks_composed_char = 0;
837fc16838fSAlex Hornung return (ERRKEY);
838fc16838fSAlex Hornung }
839fc16838fSAlex Hornung break;
840fc16838fSAlex Hornung }
841fc16838fSAlex Hornung }
842fc16838fSAlex Hornung
843fc16838fSAlex Hornung /* keycode to key action */
844fc16838fSAlex Hornung action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
845fc16838fSAlex Hornung &state->ks_state, &state->ks_accents);
846fc16838fSAlex Hornung if (action == NOKEY)
847fc16838fSAlex Hornung goto next_code;
848fc16838fSAlex Hornung
849fc16838fSAlex Hornung return (action);
850fc16838fSAlex Hornung }
851fc16838fSAlex Hornung
852fc16838fSAlex Hornung /*
853fc16838fSAlex Hornung * Check if char is waiting
854fc16838fSAlex Hornung */
855fc16838fSAlex Hornung static int
kbdmux_check_char(keyboard_t * kbd)856fc16838fSAlex Hornung kbdmux_check_char(keyboard_t *kbd)
857fc16838fSAlex Hornung {
858fc16838fSAlex Hornung kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
859fc16838fSAlex Hornung int ready;
860fc16838fSAlex Hornung
861fc9700a1SMatthew Dillon if (!KBD_IS_ACTIVE(kbd))
862fc16838fSAlex Hornung return (FALSE);
863fc16838fSAlex Hornung
864fc16838fSAlex Hornung if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
865fc16838fSAlex Hornung ready = TRUE;
866fc16838fSAlex Hornung else
867fc16838fSAlex Hornung ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
868fc16838fSAlex Hornung
869fc16838fSAlex Hornung return (ready);
870fc16838fSAlex Hornung }
871fc16838fSAlex Hornung
872fc16838fSAlex Hornung /*
873fc16838fSAlex Hornung * Keyboard ioctl's
874fc16838fSAlex Hornung */
875fc16838fSAlex Hornung static int
kbdmux_ioctl(keyboard_t * kbd,u_long cmd,caddr_t arg)876fc16838fSAlex Hornung kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
877fc16838fSAlex Hornung {
878fc16838fSAlex Hornung static int delays[] = {
879fc16838fSAlex Hornung 250, 500, 750, 1000
880fc16838fSAlex Hornung };
881fc16838fSAlex Hornung
882fc16838fSAlex Hornung static int rates[] = {
883fc16838fSAlex Hornung 34, 38, 42, 46, 50, 55, 59, 63,
884fc16838fSAlex Hornung 68, 76, 84, 92, 100, 110, 118, 126,
885fc16838fSAlex Hornung 136, 152, 168, 184, 200, 220, 236, 252,
886fc16838fSAlex Hornung 272, 304, 336, 368, 400, 440, 472, 504
887fc16838fSAlex Hornung };
888fc16838fSAlex Hornung
889fc16838fSAlex Hornung kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
890fc16838fSAlex Hornung kbdmux_kbd_t *k;
891fc16838fSAlex Hornung keyboard_info_t *ki;
89227332c1bSImre Vadász int error = 0, mode, i;
893fc16838fSAlex Hornung
894fc9700a1SMatthew Dillon if (state == NULL)
895fc16838fSAlex Hornung return (ENXIO);
896fc16838fSAlex Hornung
897fc16838fSAlex Hornung switch (cmd) {
898fc16838fSAlex Hornung case KBADDKBD: /* add keyboard to the mux */
899fc16838fSAlex Hornung ki = (keyboard_info_t *) arg;
900fc16838fSAlex Hornung
901fc16838fSAlex Hornung if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
90222ff886eSAlex Hornung strcmp(ki->kb_name, "*") == 0) {
903fc16838fSAlex Hornung return (EINVAL); /* bad input */
90422ff886eSAlex Hornung }
905fc16838fSAlex Hornung
906fc16838fSAlex Hornung SLIST_FOREACH(k, &state->ks_kbds, next)
907fc16838fSAlex Hornung if (k->kbd->kb_unit == ki->kb_unit &&
908fc16838fSAlex Hornung strcmp(k->kbd->kb_name, ki->kb_name) == 0)
909fc16838fSAlex Hornung break;
910fc16838fSAlex Hornung
911fc9700a1SMatthew Dillon if (k != NULL)
912fc16838fSAlex Hornung return (0); /* keyboard already in the mux */
913fc16838fSAlex Hornung
914bcc53404SAlex Hornung k = kmalloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
915fc9700a1SMatthew Dillon if (k == NULL)
916fc16838fSAlex Hornung return (ENOMEM); /* out of memory */
917fc16838fSAlex Hornung
918fc16838fSAlex Hornung k->kbd = kbd_get_keyboard(
919fc16838fSAlex Hornung kbd_allocate(
920fc16838fSAlex Hornung ki->kb_name,
921fc16838fSAlex Hornung ki->kb_unit,
922fc16838fSAlex Hornung (void *) &k->kbd,
923fc16838fSAlex Hornung kbdmux_kbd_event, (void *) state));
924fc16838fSAlex Hornung if (k->kbd == NULL) {
925bcc53404SAlex Hornung kfree(k, M_KBDMUX);
926fc16838fSAlex Hornung return (EINVAL); /* bad keyboard */
927fc16838fSAlex Hornung }
928fc16838fSAlex Hornung
929bcc53404SAlex Hornung kbd_enable(k->kbd);
930bcc53404SAlex Hornung kbd_clear_state(k->kbd);
931fc16838fSAlex Hornung
932fc16838fSAlex Hornung /* set K_RAW mode on slave keyboard */
933fc16838fSAlex Hornung mode = K_RAW;
934bcc53404SAlex Hornung error = kbd_ioctl(k->kbd, KDSKBMODE, (caddr_t)&mode);
935fc16838fSAlex Hornung if (error == 0) {
936fc16838fSAlex Hornung /* set lock keys state on slave keyboard */
937fc16838fSAlex Hornung mode = state->ks_state & LOCK_MASK;
938bcc53404SAlex Hornung error = kbd_ioctl(k->kbd, KDSKBSTATE, (caddr_t)&mode);
939fc16838fSAlex Hornung }
940fc16838fSAlex Hornung
941fc16838fSAlex Hornung if (error != 0) {
942fc16838fSAlex Hornung kbd_release(k->kbd, &k->kbd);
943fc16838fSAlex Hornung k->kbd = NULL;
944bcc53404SAlex Hornung kfree(k, M_KBDMUX);
945fc16838fSAlex Hornung return (error); /* could not set mode */
946fc16838fSAlex Hornung }
947fc16838fSAlex Hornung
948fc16838fSAlex Hornung SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
949fc16838fSAlex Hornung break;
950fc16838fSAlex Hornung
951fc16838fSAlex Hornung case KBRELKBD: /* release keyboard from the mux */
952fc16838fSAlex Hornung ki = (keyboard_info_t *) arg;
953fc16838fSAlex Hornung
954fc16838fSAlex Hornung if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
95522ff886eSAlex Hornung strcmp(ki->kb_name, "*") == 0) {
956fc16838fSAlex Hornung return (EINVAL); /* bad input */
95722ff886eSAlex Hornung }
958fc16838fSAlex Hornung
959fc16838fSAlex Hornung SLIST_FOREACH(k, &state->ks_kbds, next)
960fc16838fSAlex Hornung if (k->kbd->kb_unit == ki->kb_unit &&
961fc16838fSAlex Hornung strcmp(k->kbd->kb_name, ki->kb_name) == 0)
962fc16838fSAlex Hornung break;
963fc16838fSAlex Hornung
964fc16838fSAlex Hornung if (k != NULL) {
965fc16838fSAlex Hornung error = kbd_release(k->kbd, &k->kbd);
966fc16838fSAlex Hornung if (error == 0) {
967fc16838fSAlex Hornung SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
968fc16838fSAlex Hornung
969fc16838fSAlex Hornung k->kbd = NULL;
970fc16838fSAlex Hornung
971bcc53404SAlex Hornung kfree(k, M_KBDMUX);
972fc16838fSAlex Hornung }
973fc16838fSAlex Hornung } else
974fc16838fSAlex Hornung error = ENXIO; /* keyboard is not in the mux */
975fc16838fSAlex Hornung
976fc16838fSAlex Hornung break;
977fc16838fSAlex Hornung
978fc16838fSAlex Hornung case KDGKBMODE: /* get kyboard mode */
979fc16838fSAlex Hornung *(int *)arg = state->ks_mode;
980fc16838fSAlex Hornung break;
981fc16838fSAlex Hornung
982fc16838fSAlex Hornung case KDSKBMODE: /* set keyboard mode */
983fc16838fSAlex Hornung switch (*(int *)arg) {
984fc16838fSAlex Hornung case K_XLATE:
985fc16838fSAlex Hornung if (state->ks_mode != K_XLATE) {
986fc16838fSAlex Hornung /* make lock key state and LED state match */
987fc16838fSAlex Hornung state->ks_state &= ~LOCK_MASK;
988fc16838fSAlex Hornung state->ks_state |= KBD_LED_VAL(kbd);
989fc16838fSAlex Hornung }
990fc16838fSAlex Hornung /* FALLTHROUGH */
991fc16838fSAlex Hornung
992fc16838fSAlex Hornung case K_RAW:
993fc16838fSAlex Hornung case K_CODE:
994fc16838fSAlex Hornung if (state->ks_mode != *(int *)arg) {
995fc9700a1SMatthew Dillon kbdmux_clear_state(kbd);
996fc16838fSAlex Hornung state->ks_mode = *(int *)arg;
997fc16838fSAlex Hornung }
998fc16838fSAlex Hornung break;
999fc16838fSAlex Hornung
1000fc16838fSAlex Hornung default:
1001fc16838fSAlex Hornung error = EINVAL;
1002fc16838fSAlex Hornung break;
1003fc16838fSAlex Hornung }
1004fc16838fSAlex Hornung break;
1005fc16838fSAlex Hornung
1006fc16838fSAlex Hornung case KDGETLED: /* get keyboard LED */
1007fc16838fSAlex Hornung *(int *)arg = KBD_LED_VAL(kbd);
1008fc16838fSAlex Hornung break;
1009fc16838fSAlex Hornung
1010fc16838fSAlex Hornung case KDSETLED: /* set keyboard LED */
1011fc16838fSAlex Hornung /* NOTE: lock key state in ks_state won't be changed */
1012fc9700a1SMatthew Dillon if (*(int *)arg & ~LOCK_MASK)
1013fc16838fSAlex Hornung return (EINVAL);
1014fc16838fSAlex Hornung
1015fc16838fSAlex Hornung KBD_LED_VAL(kbd) = *(int *)arg;
10163d1294c7SPeeter Must #ifdef EVDEV_SUPPORT
10173d1294c7SPeeter Must if (state->ks_evdev != NULL &&
10183d1294c7SPeeter Must evdev_rcpt_mask & EVDEV_RCPT_KBDMUX)
10193d1294c7SPeeter Must evdev_push_leds(state->ks_evdev, *(int *)arg);
10203d1294c7SPeeter Must #endif
1021fc16838fSAlex Hornung /* KDSETLED on all slave keyboards */
1022fc16838fSAlex Hornung SLIST_FOREACH(k, &state->ks_kbds, next)
1023bcc53404SAlex Hornung kbd_ioctl(k->kbd, KDSETLED, arg);
1024fc16838fSAlex Hornung break;
1025fc16838fSAlex Hornung
1026fc16838fSAlex Hornung case KDGKBSTATE: /* get lock key state */
1027fc16838fSAlex Hornung *(int *)arg = state->ks_state & LOCK_MASK;
1028fc16838fSAlex Hornung break;
1029fc16838fSAlex Hornung
1030fc16838fSAlex Hornung case KDSKBSTATE: /* set lock key state */
1031fc9700a1SMatthew Dillon if (*(int *)arg & ~LOCK_MASK)
1032fc16838fSAlex Hornung return (EINVAL);
1033fc16838fSAlex Hornung
1034fc16838fSAlex Hornung state->ks_state &= ~LOCK_MASK;
1035fc16838fSAlex Hornung state->ks_state |= *(int *)arg;
1036fc16838fSAlex Hornung
1037fc16838fSAlex Hornung /* KDSKBSTATE on all slave keyboards */
1038fc16838fSAlex Hornung SLIST_FOREACH(k, &state->ks_kbds, next)
1039bcc53404SAlex Hornung kbd_ioctl(k->kbd, KDSKBSTATE, arg);
1040fc16838fSAlex Hornung
1041fc16838fSAlex Hornung return (kbdmux_ioctl(kbd, KDSETLED, arg));
1042fc16838fSAlex Hornung /* NOT REACHED */
1043fc16838fSAlex Hornung
1044fc16838fSAlex Hornung case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1045fc16838fSAlex Hornung /* lookup delay */
1046c157ff7aSSascha Wildner for (i = NELEM(delays) - 1; i > 0; i --)
1047fc16838fSAlex Hornung if (((int *)arg)[0] >= delays[i])
1048fc16838fSAlex Hornung break;
1049fc16838fSAlex Hornung mode = i << 5;
1050fc16838fSAlex Hornung
1051fc16838fSAlex Hornung /* lookup rate */
1052c157ff7aSSascha Wildner for (i = NELEM(rates) - 1; i > 0; i --)
1053fc16838fSAlex Hornung if (((int *)arg)[1] >= rates[i])
1054fc16838fSAlex Hornung break;
1055fc16838fSAlex Hornung mode |= i;
1056fc16838fSAlex Hornung
1057fc9700a1SMatthew Dillon if (mode & ~0x7f)
1058fc16838fSAlex Hornung return (EINVAL);
1059fc16838fSAlex Hornung
1060fc16838fSAlex Hornung kbd->kb_delay1 = delays[(mode >> 5) & 3];
1061fc16838fSAlex Hornung kbd->kb_delay2 = rates[mode & 0x1f];
10623d1294c7SPeeter Must #ifdef EVDEV_SUPPORT
10633d1294c7SPeeter Must if (state->ks_evdev != NULL &&
10643d1294c7SPeeter Must evdev_rcpt_mask & EVDEV_RCPT_KBDMUX)
10653d1294c7SPeeter Must evdev_push_repeats(state->ks_evdev, kbd);
10663d1294c7SPeeter Must #endif
1067fc16838fSAlex Hornung /* perform command on all slave keyboards */
1068fc16838fSAlex Hornung SLIST_FOREACH(k, &state->ks_kbds, next)
1069bcc53404SAlex Hornung kbd_ioctl(k->kbd, cmd, arg);
1070fc16838fSAlex Hornung break;
1071fc16838fSAlex Hornung
1072fc16838fSAlex Hornung case PIO_KEYMAP: /* set keyboard translation table */
1073fc16838fSAlex Hornung case PIO_KEYMAPENT: /* set keyboard translation table entry */
1074fc16838fSAlex Hornung case PIO_DEADKEYMAP: /* set accent key translation table */
1075fc16838fSAlex Hornung state->ks_accents = 0;
1076fc16838fSAlex Hornung
1077fc16838fSAlex Hornung /* perform command on all slave keyboards */
1078fc16838fSAlex Hornung SLIST_FOREACH(k, &state->ks_kbds, next)
1079bcc53404SAlex Hornung kbd_ioctl(k->kbd, cmd, arg);
1080fc16838fSAlex Hornung /* FALLTHROUGH */
1081fc16838fSAlex Hornung
1082fc16838fSAlex Hornung default:
1083fc16838fSAlex Hornung error = genkbd_commonioctl(kbd, cmd, arg);
1084fc16838fSAlex Hornung break;
1085fc16838fSAlex Hornung }
1086fc16838fSAlex Hornung return (error);
1087fc16838fSAlex Hornung }
1088fc16838fSAlex Hornung
1089fc16838fSAlex Hornung /*
1090fc16838fSAlex Hornung * Lock the access to the keyboard
1091fc16838fSAlex Hornung */
1092fc16838fSAlex Hornung static int
kbdmux_lock(keyboard_t * kbd,int lock)1093fc16838fSAlex Hornung kbdmux_lock(keyboard_t *kbd, int lock)
1094fc16838fSAlex Hornung {
1095fc16838fSAlex Hornung return (1); /* XXX */
1096fc16838fSAlex Hornung }
1097fc16838fSAlex Hornung
1098fc16838fSAlex Hornung /*
1099fc16838fSAlex Hornung * Clear the internal state of the keyboard
1100fc9700a1SMatthew Dillon *
1101fc9700a1SMatthew Dillon * NOTE: May be called unlocked from init
1102fc16838fSAlex Hornung */
1103fc16838fSAlex Hornung static void
kbdmux_clear_state(keyboard_t * kbd)1104fc9700a1SMatthew Dillon kbdmux_clear_state(keyboard_t *kbd)
1105fc16838fSAlex Hornung {
1106fc9700a1SMatthew Dillon kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1107fc16838fSAlex Hornung
1108fc16838fSAlex Hornung state->ks_flags &= ~(COMPOSE|POLLING);
1109fc16838fSAlex Hornung state->ks_state &= LOCK_MASK; /* preserve locking key state */
1110fc16838fSAlex Hornung state->ks_accents = 0;
1111fc16838fSAlex Hornung state->ks_composed_char = 0;
1112fc16838fSAlex Hornung /* state->ks_prefix = 0; XXX */
1113fc16838fSAlex Hornung state->ks_inq_length = 0;
1114fc16838fSAlex Hornung }
1115fc16838fSAlex Hornung
1116fc16838fSAlex Hornung /*
1117fc16838fSAlex Hornung * Save the internal state
1118fc16838fSAlex Hornung */
1119fc16838fSAlex Hornung static int
kbdmux_get_state(keyboard_t * kbd,void * buf,size_t len)1120fc16838fSAlex Hornung kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1121fc16838fSAlex Hornung {
1122fc16838fSAlex Hornung if (len == 0)
1123fc16838fSAlex Hornung return (sizeof(kbdmux_state_t));
1124fc16838fSAlex Hornung if (len < sizeof(kbdmux_state_t))
1125fc16838fSAlex Hornung return (-1);
1126fc16838fSAlex Hornung
1127fc16838fSAlex Hornung bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1128fc16838fSAlex Hornung
1129fc16838fSAlex Hornung return (0);
1130fc16838fSAlex Hornung }
1131fc16838fSAlex Hornung
1132fc16838fSAlex Hornung /*
1133fc16838fSAlex Hornung * Set the internal state
1134fc16838fSAlex Hornung */
1135fc16838fSAlex Hornung static int
kbdmux_set_state(keyboard_t * kbd,void * buf,size_t len)1136fc16838fSAlex Hornung kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1137fc16838fSAlex Hornung {
1138fc16838fSAlex Hornung if (len < sizeof(kbdmux_state_t))
1139fc16838fSAlex Hornung return (ENOMEM);
1140fc16838fSAlex Hornung
1141fc16838fSAlex Hornung bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1142fc16838fSAlex Hornung
1143fc16838fSAlex Hornung return (0);
1144fc16838fSAlex Hornung }
1145fc16838fSAlex Hornung
1146fc16838fSAlex Hornung /*
1147fc16838fSAlex Hornung * Set polling
1148fc9700a1SMatthew Dillon *
1149fc9700a1SMatthew Dillon * Caller interlocks all keyboard calls. We must not lock here.
1150fc16838fSAlex Hornung */
1151fc16838fSAlex Hornung static int
kbdmux_poll(keyboard_t * kbd,int on)1152fc16838fSAlex Hornung kbdmux_poll(keyboard_t *kbd, int on)
1153fc16838fSAlex Hornung {
1154fc16838fSAlex Hornung kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1155fc16838fSAlex Hornung kbdmux_kbd_t *k;
1156fc16838fSAlex Hornung
1157fc16838fSAlex Hornung if (on)
1158fc16838fSAlex Hornung state->ks_flags |= POLLING;
1159fc16838fSAlex Hornung else
1160fc16838fSAlex Hornung state->ks_flags &= ~POLLING;
1161fc16838fSAlex Hornung
1162fc16838fSAlex Hornung /* set poll on slave keyboards */
1163fc16838fSAlex Hornung SLIST_FOREACH(k, &state->ks_kbds, next)
1164bcc53404SAlex Hornung kbd_poll(k->kbd, on);
1165fc16838fSAlex Hornung
1166fc16838fSAlex Hornung return (0);
1167fc16838fSAlex Hornung }
1168fc16838fSAlex Hornung
1169fc16838fSAlex Hornung /*****************************************************************************
1170fc16838fSAlex Hornung *****************************************************************************
1171fc16838fSAlex Hornung ** Module
1172fc16838fSAlex Hornung *****************************************************************************
1173fc16838fSAlex Hornung *****************************************************************************/
1174fc16838fSAlex Hornung
1175fc16838fSAlex Hornung KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1176fc16838fSAlex Hornung
1177fc16838fSAlex Hornung static int
kbdmux_modevent(module_t mod,int type,void * data)1178fc16838fSAlex Hornung kbdmux_modevent(module_t mod, int type, void *data)
1179fc16838fSAlex Hornung {
1180fc16838fSAlex Hornung keyboard_switch_t *sw;
1181fc16838fSAlex Hornung keyboard_t *kbd;
1182fc16838fSAlex Hornung int error;
1183fc16838fSAlex Hornung
1184fc16838fSAlex Hornung switch (type) {
1185fc16838fSAlex Hornung case MOD_LOAD:
1186fc16838fSAlex Hornung if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1187fc16838fSAlex Hornung break;
1188fc16838fSAlex Hornung
1189fc16838fSAlex Hornung if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1190fc16838fSAlex Hornung kbd_delete_driver(&kbdmux_kbd_driver);
1191fc16838fSAlex Hornung error = ENXIO;
1192fc16838fSAlex Hornung break;
1193fc16838fSAlex Hornung }
1194fc16838fSAlex Hornung
1195fc16838fSAlex Hornung kbd = NULL;
1196fc16838fSAlex Hornung
1197fc16838fSAlex Hornung if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
1198fc16838fSAlex Hornung (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) {
1199fc16838fSAlex Hornung kbd_delete_driver(&kbdmux_kbd_driver);
1200fc16838fSAlex Hornung break;
1201fc16838fSAlex Hornung }
1202fc16838fSAlex Hornung
1203fc16838fSAlex Hornung #ifdef KBD_INSTALL_CDEV
1204fc16838fSAlex Hornung if ((error = kbd_attach(kbd)) != 0) {
1205fc16838fSAlex Hornung (*sw->term)(kbd);
1206fc16838fSAlex Hornung kbd_delete_driver(&kbdmux_kbd_driver);
1207fc16838fSAlex Hornung break;
1208fc16838fSAlex Hornung }
1209fc16838fSAlex Hornung #endif
1210fc16838fSAlex Hornung
1211fc16838fSAlex Hornung if ((error = (*sw->enable)(kbd)) != 0) {
1212fc16838fSAlex Hornung (*sw->disable)(kbd);
1213fc16838fSAlex Hornung #ifdef KBD_INSTALL_CDEV
1214fc16838fSAlex Hornung kbd_detach(kbd);
1215fc16838fSAlex Hornung #endif
1216fc16838fSAlex Hornung (*sw->term)(kbd);
1217fc16838fSAlex Hornung kbd_delete_driver(&kbdmux_kbd_driver);
1218fc16838fSAlex Hornung break;
1219fc16838fSAlex Hornung }
1220fc16838fSAlex Hornung break;
1221fc16838fSAlex Hornung
1222fc16838fSAlex Hornung case MOD_UNLOAD:
1223fc16838fSAlex Hornung if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
1224fc16838fSAlex Hornung panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
1225fc16838fSAlex Hornung
1226fc16838fSAlex Hornung kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1227fc16838fSAlex Hornung if (kbd != NULL) {
1228fc16838fSAlex Hornung (*sw->disable)(kbd);
1229fc16838fSAlex Hornung #ifdef KBD_INSTALL_CDEV
1230fc16838fSAlex Hornung kbd_detach(kbd);
1231fc16838fSAlex Hornung #endif
1232fc16838fSAlex Hornung (*sw->term)(kbd);
1233fc16838fSAlex Hornung kbd_delete_driver(&kbdmux_kbd_driver);
1234fc16838fSAlex Hornung }
1235fc16838fSAlex Hornung error = 0;
1236fc16838fSAlex Hornung break;
1237fc16838fSAlex Hornung
1238fc16838fSAlex Hornung default:
1239fc16838fSAlex Hornung error = EOPNOTSUPP;
1240fc16838fSAlex Hornung break;
1241fc16838fSAlex Hornung }
1242fc16838fSAlex Hornung return (error);
1243fc16838fSAlex Hornung }
1244fc16838fSAlex Hornung
1245fc16838fSAlex Hornung DEV_MODULE(kbdmux, kbdmux_modevent, NULL);
12463d1294c7SPeeter Must #ifdef EVDEV_SUPPORT
12473d1294c7SPeeter Must MODULE_DEPEND(kbdmux, evdev, 1, 1, 1);
12483d1294c7SPeeter Must #endif
1249