kbdmux.c revision 156167
1/*
2 * kbdmux.c
3 */
4
5/*-
6 * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $
31 * $FreeBSD: head/sys/dev/kbdmux/kbdmux.c 156167 2006-03-01 18:34:48Z emax $
32 */
33
34#include "opt_kbd.h"
35
36#include <sys/param.h>
37#include <sys/bus.h>
38#include <sys/conf.h>
39#include <sys/consio.h>
40#include <sys/fcntl.h>
41#include <sys/kbio.h>
42#include <sys/kernel.h>
43#include <sys/limits.h>
44#include <sys/lock.h>
45#include <sys/malloc.h>
46#include <sys/module.h>
47#include <sys/mutex.h>
48#include <sys/poll.h>
49#include <sys/proc.h>
50#include <sys/queue.h>
51#include <sys/selinfo.h>
52#include <sys/systm.h>
53#include <sys/taskqueue.h>
54#include <sys/tty.h>
55#include <sys/uio.h>
56#include <dev/kbd/kbdreg.h>
57#include <dev/kbd/kbdtables.h>
58
59#define KEYBOARD_NAME	"kbdmux"
60
61MALLOC_DECLARE(M_KBDMUX);
62MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
63
64/*****************************************************************************
65 *****************************************************************************
66 **                             Keyboard state
67 *****************************************************************************
68 *****************************************************************************/
69
70#define	KBDMUX_Q_SIZE	512	/* input queue size */
71
72/*
73 * XXX
74 * For now rely on Giant mutex to protect our data structures.
75 * Just like the rest of keyboard drivers and syscons(4) do.
76 * Note that callout is initialized as not MP-safe to make sure
77 * Giant is held.
78 */
79
80#if 0 /* not yet */
81#define KBDMUX_LOCK_DECL_GLOBAL \
82	struct mtx ks_lock
83#define KBDMUX_LOCK_INIT(s) \
84	mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE)
85#define KBDMUX_LOCK_DESTROY(s) \
86	mtx_destroy(&(s)->ks_lock)
87#define KBDMUX_LOCK(s) \
88	mtx_lock(&(s)->ks_lock)
89#define KBDMUX_UNLOCK(s) \
90	mtx_unlock(&(s)->ks_lock)
91#define KBDMUX_LOCK_ASSERT(s, w) \
92	mtx_assert(&(s)->ks_lock, (w))
93#define KBDMUX_SLEEP(s, f, d, t) \
94	msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), (d), (t))
95#define KBDMUX_CALLOUT_INIT(s) \
96	callout_init_mtx(&(s)->ks_timo, &(s)->ks_lock, 0)
97#define KBDMUX_QUEUE_INTR(s) \
98	taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
99#else
100#define KBDMUX_LOCK_DECL_GLOBAL
101
102#define KBDMUX_LOCK_INIT(s)
103
104#define KBDMUX_LOCK_DESTROY(s)
105
106#define KBDMUX_LOCK(s)
107
108#define KBDMUX_UNLOCK(s)
109
110#define KBDMUX_LOCK_ASSERT(s, w)
111
112#define KBDMUX_SLEEP(s, f, d, t) \
113	tsleep(&(s)->f, PCATCH | (PZERO + 1), (d), (t))
114#define KBDMUX_CALLOUT_INIT(s) \
115	callout_init(&(s)->ks_timo, 0)
116#define KBDMUX_QUEUE_INTR(s) \
117	taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
118#endif /* not yet */
119
120#define	KBDMUX_INTR(kbd, arg) \
121	(*kbdsw[(kbd)->kb_index]->intr)((kbd), (arg))
122
123#define	KBDMUX_IOCTL(kbd, cmd, arg) \
124	(*kbdsw[(kbd)->kb_index]->ioctl)((kbd), (cmd), (caddr_t) (arg))
125
126#define	KBDMUX_CHECK_CHAR(kbd) \
127	(*kbdsw[(kbd)->kb_index]->check_char)((kbd))
128
129#define	KBDMUX_READ_CHAR(kbd, wait) \
130	(*kbdsw[(kbd)->kb_index]->read_char)((kbd), (wait))
131
132#define	KBDMUX_ENABLE(kbd) \
133	(*kbdsw[(kbd)->kb_index]->enable)((kbd))
134
135#define	KBDMUX_POLL(kbd, on) \
136	(*kbdsw[(kbd)->kb_index]->poll)((kbd), (on))
137
138#define	KBDMUX_CLEAR_STATE(kbd) \
139	(*kbdsw[(kbd)->kb_index]->clear_state)((kbd))
140
141/*
142 * kbdmux keyboard
143 */
144struct kbdmux_kbd
145{
146	keyboard_t		*kbd;	/* keyboard */
147	SLIST_ENTRY(kbdmux_kbd)	 next;	/* link to next */
148};
149
150typedef struct kbdmux_kbd	kbdmux_kbd_t;
151
152/*
153 * kbdmux state
154 */
155struct kbdmux_state
156{
157	struct clist		 ks_inq;	/* input chars queue */
158	struct task		 ks_task;	/* interrupt task */
159	struct callout		 ks_timo;	/* timeout handler */
160#define TICKS			(hz)		/* rate */
161
162	int			 ks_flags;	/* flags */
163#define COMPOSE			(1 << 0)	/* compose char flag */
164#define POLLING			(1 << 1)	/* polling */
165#define TASK			(1 << 2)	/* interrupt task queued */
166
167	int			 ks_mode;	/* K_XLATE, K_RAW, K_CODE */
168	int			 ks_state;	/* state */
169	int			 ks_accents;	/* accent key index (> 0) */
170	u_int			 ks_composed_char; /* composed char code */
171	u_char			 ks_prefix;	/* AT scan code prefix */
172
173	SLIST_HEAD(, kbdmux_kbd) ks_kbds;	/* keyboards */
174
175	KBDMUX_LOCK_DECL_GLOBAL;
176};
177
178typedef struct kbdmux_state	kbdmux_state_t;
179
180/*****************************************************************************
181 *****************************************************************************
182 **                             Helper functions
183 *****************************************************************************
184 *****************************************************************************/
185
186static task_fn_t		kbdmux_kbd_intr;
187static timeout_t		kbdmux_kbd_intr_timo;
188static kbd_callback_func_t	kbdmux_kbd_event;
189
190/*
191 * Interrupt handler task
192 */
193void
194kbdmux_kbd_intr(void *xkbd, int pending)
195{
196	keyboard_t	*kbd = (keyboard_t *) xkbd;
197	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
198
199	KBDMUX_INTR(kbd, NULL);
200
201	KBDMUX_LOCK(state);
202
203	state->ks_flags &= ~TASK;
204	wakeup(&state->ks_task);
205
206	KBDMUX_UNLOCK(state);
207}
208
209/*
210 * Schedule interrupt handler on timeout. Called with locked state.
211 */
212void
213kbdmux_kbd_intr_timo(void *xstate)
214{
215	kbdmux_state_t	*state = (kbdmux_state_t *) xstate;
216
217	KBDMUX_LOCK_ASSERT(state, MA_OWNED);
218
219	if (callout_pending(&state->ks_timo))
220		return; /* callout was reset */
221
222	if (!callout_active(&state->ks_timo))
223		return; /* callout was stopped */
224
225	callout_deactivate(&state->ks_timo);
226
227	/* queue interrupt task if needed */
228	if (state->ks_inq.c_cc > 0 && !(state->ks_flags & TASK) &&
229	    KBDMUX_QUEUE_INTR(state) == 0)
230		state->ks_flags |= TASK;
231
232	/* re-schedule timeout */
233	callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
234}
235
236/*
237 * Process event from one of our keyboards
238 */
239static int
240kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
241{
242	kbdmux_state_t	*state = (kbdmux_state_t *) arg;
243
244	switch (event) {
245	case KBDIO_KEYINPUT: {
246		int	c;
247
248		KBDMUX_LOCK(state);
249
250		/*
251		 * Read all chars from the keyboard
252		 *
253		 * Turns out that atkbd(4) check_char() method may return
254		 * "true" while read_char() method returns NOKEY. If this
255		 * happens we could stuck in the loop below. Avoid this
256		 * by breaking out of the loop if read_char() method returns
257		 * NOKEY.
258		 */
259
260		while (KBDMUX_CHECK_CHAR(kbd)) {
261			c = KBDMUX_READ_CHAR(kbd, 0);
262			if (c == NOKEY)
263				break;
264			if (c == ERRKEY)
265				continue; /* XXX ring bell */
266			if (!KBD_IS_BUSY(kbd))
267				continue; /* not open - discard the input */
268
269			putc(c, &state->ks_inq);
270		}
271
272		/* queue interrupt task if needed */
273		if (state->ks_inq.c_cc > 0 && !(state->ks_flags & TASK) &&
274		    KBDMUX_QUEUE_INTR(state) == 0)
275			state->ks_flags |= TASK;
276
277		KBDMUX_UNLOCK(state);
278		} break;
279
280	case KBDIO_UNLOADING: {
281		kbdmux_kbd_t	*k;
282
283		KBDMUX_LOCK(state);
284
285		SLIST_FOREACH(k, &state->ks_kbds, next)
286			if (k->kbd == kbd)
287				break;
288
289		if (k != NULL) {
290			kbd_release(k->kbd, &k->kbd);
291			SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
292
293			k->kbd = NULL;
294
295			free(k, M_KBDMUX);
296		}
297
298		KBDMUX_UNLOCK(state);
299		} break;
300
301	default:
302		return (EINVAL);
303		/* NOT REACHED */
304	}
305
306	return (0);
307}
308
309/****************************************************************************
310 ****************************************************************************
311 **                              Keyboard driver
312 ****************************************************************************
313 ****************************************************************************/
314
315static int		kbdmux_configure(int flags);
316static kbd_probe_t	kbdmux_probe;
317static kbd_init_t	kbdmux_init;
318static kbd_term_t	kbdmux_term;
319static kbd_intr_t	kbdmux_intr;
320static kbd_test_if_t	kbdmux_test_if;
321static kbd_enable_t	kbdmux_enable;
322static kbd_disable_t	kbdmux_disable;
323static kbd_read_t	kbdmux_read;
324static kbd_check_t	kbdmux_check;
325static kbd_read_char_t	kbdmux_read_char;
326static kbd_check_char_t	kbdmux_check_char;
327static kbd_ioctl_t	kbdmux_ioctl;
328static kbd_lock_t	kbdmux_lock;
329static void		kbdmux_clear_state_locked(kbdmux_state_t *state);
330static kbd_clear_state_t kbdmux_clear_state;
331static kbd_get_state_t	kbdmux_get_state;
332static kbd_set_state_t	kbdmux_set_state;
333static kbd_poll_mode_t	kbdmux_poll;
334
335static keyboard_switch_t kbdmuxsw = {
336	.probe =	kbdmux_probe,
337	.init =		kbdmux_init,
338	.term =		kbdmux_term,
339	.intr =		kbdmux_intr,
340	.test_if =	kbdmux_test_if,
341	.enable =	kbdmux_enable,
342	.disable =	kbdmux_disable,
343	.read =		kbdmux_read,
344	.check =	kbdmux_check,
345	.read_char =	kbdmux_read_char,
346	.check_char =	kbdmux_check_char,
347	.ioctl =	kbdmux_ioctl,
348	.lock =		kbdmux_lock,
349	.clear_state =	kbdmux_clear_state,
350	.get_state =	kbdmux_get_state,
351	.set_state =	kbdmux_set_state,
352	.get_fkeystr =	genkbd_get_fkeystr,
353	.poll =		kbdmux_poll,
354	.diag =		genkbd_diag,
355};
356
357/*
358 * Return the number of found keyboards
359 */
360static int
361kbdmux_configure(int flags)
362{
363	return (1);
364}
365
366/*
367 * Detect a keyboard
368 */
369static int
370kbdmux_probe(int unit, void *arg, int flags)
371{
372	if (resource_disabled(KEYBOARD_NAME, unit))
373		return (ENXIO);
374
375	return (0);
376}
377
378/*
379 * Reset and initialize the keyboard (stolen from atkbd.c)
380 */
381static int
382kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
383{
384	keyboard_t	*kbd = NULL;
385	kbdmux_state_t	*state = NULL;
386	keymap_t	*keymap = NULL;
387        accentmap_t	*accmap = NULL;
388        fkeytab_t	*fkeymap = NULL;
389	int		 error, needfree, fkeymap_size, delay[2];
390
391	if (*kbdp == NULL) {
392		*kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
393		state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
394		keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
395		accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
396		fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
397		fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
398		needfree = 1;
399
400		if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
401		    (accmap == NULL) || (fkeymap == NULL)) {
402			error = ENOMEM;
403			goto bad;
404		}
405
406		KBDMUX_LOCK_INIT(state);
407		clist_alloc_cblocks(&state->ks_inq,
408				KBDMUX_Q_SIZE, KBDMUX_Q_SIZE / 2);
409		TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
410		KBDMUX_CALLOUT_INIT(state);
411		SLIST_INIT(&state->ks_kbds);
412	} else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
413		return (0);
414	} else {
415		kbd = *kbdp;
416		state = (kbdmux_state_t *) kbd->kb_data;
417		keymap = kbd->kb_keymap;
418		accmap = kbd->kb_accentmap;
419		fkeymap = kbd->kb_fkeytab;
420		fkeymap_size = kbd->kb_fkeytab_size;
421		needfree = 0;
422	}
423
424	if (!KBD_IS_PROBED(kbd)) {
425		/* XXX assume 101/102 keys keyboard */
426		kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0);
427		bcopy(&key_map, keymap, sizeof(key_map));
428		bcopy(&accent_map, accmap, sizeof(accent_map));
429		bcopy(fkey_tab, fkeymap,
430			imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
431		kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
432		kbd->kb_data = (void *)state;
433
434		KBD_FOUND_DEVICE(kbd);
435		KBD_PROBE_DONE(kbd);
436
437		KBDMUX_LOCK(state);
438		kbdmux_clear_state_locked(state);
439		state->ks_mode = K_XLATE;
440		KBDMUX_UNLOCK(state);
441	}
442
443	if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
444		kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
445
446		kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
447
448		delay[0] = kbd->kb_delay1;
449		delay[1] = kbd->kb_delay2;
450		kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
451
452		KBD_INIT_DONE(kbd);
453	}
454
455	if (!KBD_IS_CONFIGURED(kbd)) {
456		if (kbd_register(kbd) < 0) {
457			error = ENXIO;
458			goto bad;
459		}
460
461		KBD_CONFIG_DONE(kbd);
462
463		KBDMUX_LOCK(state);
464		callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
465		KBDMUX_UNLOCK(state);
466	}
467
468	return (0);
469bad:
470	if (needfree) {
471		if (state != NULL) {
472			clist_free_cblocks(&state->ks_inq);
473			free(state, M_KBDMUX);
474		}
475		if (keymap != NULL)
476			free(keymap, M_KBDMUX);
477		if (accmap != NULL)
478			free(accmap, M_KBDMUX);
479		if (fkeymap != NULL)
480			free(fkeymap, M_KBDMUX);
481		if (kbd != NULL) {
482			free(kbd, M_KBDMUX);
483			*kbdp = NULL;	/* insure ref doesn't leak to caller */
484		}
485	}
486
487	return (error);
488}
489
490/*
491 * Finish using this keyboard
492 */
493static int
494kbdmux_term(keyboard_t *kbd)
495{
496	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
497	kbdmux_kbd_t	*k;
498
499	KBDMUX_LOCK(state);
500
501	/* kill callout */
502	callout_stop(&state->ks_timo);
503
504	/* wait for interrupt task */
505	while (state->ks_flags & TASK)
506		KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0);
507
508	/* release all keyboards from the mux */
509	while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
510		kbd_release(k->kbd, &k->kbd);
511		SLIST_REMOVE_HEAD(&state->ks_kbds, next);
512
513		k->kbd = NULL;
514
515		free(k, M_KBDMUX);
516	}
517
518	/* flush input queue */
519	ndflush(&state->ks_inq, state->ks_inq.c_cc);
520	clist_free_cblocks(&state->ks_inq);
521
522	KBDMUX_UNLOCK(state);
523
524	kbd_unregister(kbd);
525
526	KBDMUX_LOCK_DESTROY(state);
527	bzero(state, sizeof(*state));
528	free(state, M_KBDMUX);
529
530	free(kbd->kb_keymap, M_KBDMUX);
531	free(kbd->kb_accentmap, M_KBDMUX);
532	free(kbd->kb_fkeytab, M_KBDMUX);
533	free(kbd, M_KBDMUX);
534
535	return (0);
536}
537
538/*
539 * Keyboard interrupt routine
540 */
541static int
542kbdmux_intr(keyboard_t *kbd, void *arg)
543{
544	int	c;
545
546	if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
547		/* let the callback function to process the input */
548		(*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
549					    kbd->kb_callback.kc_arg);
550	} else {
551		/* read and discard the input; no one is waiting for input */
552		do {
553			c = kbdmux_read_char(kbd, FALSE);
554		} while (c != NOKEY);
555	}
556
557	return (0);
558}
559
560/*
561 * Test the interface to the device
562 */
563static int
564kbdmux_test_if(keyboard_t *kbd)
565{
566	return (0);
567}
568
569/*
570 * Enable the access to the device; until this function is called,
571 * the client cannot read from the keyboard.
572 */
573static int
574kbdmux_enable(keyboard_t *kbd)
575{
576	KBD_ACTIVATE(kbd);
577	return (0);
578}
579
580/*
581 * Disallow the access to the device
582 */
583static int
584kbdmux_disable(keyboard_t *kbd)
585{
586	KBD_DEACTIVATE(kbd);
587	return (0);
588}
589
590/*
591 * Read one byte from the keyboard if it's allowed
592 */
593static int
594kbdmux_read(keyboard_t *kbd, int wait)
595{
596	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
597	int		 c;
598
599	KBDMUX_LOCK(state);
600	c = getc(&state->ks_inq);
601	KBDMUX_UNLOCK(state);
602
603	if (c != -1)
604		kbd->kb_count ++;
605
606	return (KBD_IS_ACTIVE(kbd)? c : -1);
607}
608
609/*
610 * Check if data is waiting
611 */
612static int
613kbdmux_check(keyboard_t *kbd)
614{
615	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
616	int		 ready;
617
618	if (!KBD_IS_ACTIVE(kbd))
619		return (FALSE);
620
621	KBDMUX_LOCK(state);
622	ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE;
623	KBDMUX_UNLOCK(state);
624
625	return (ready);
626}
627
628/*
629 * Read char from the keyboard (stolen from atkbd.c)
630 */
631static u_int
632kbdmux_read_char(keyboard_t *kbd, int wait)
633{
634	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
635	u_int		 action;
636	int		 scancode, keycode;
637
638	KBDMUX_LOCK(state);
639
640next_code:
641
642	/* do we have a composed char to return? */
643	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
644		action = state->ks_composed_char;
645		state->ks_composed_char = 0;
646		if (action > UCHAR_MAX) {
647			KBDMUX_UNLOCK(state);
648
649			return (ERRKEY);
650		}
651
652		KBDMUX_UNLOCK(state);
653
654		return (action);
655	}
656
657	/* see if there is something in the keyboard queue */
658	scancode = getc(&state->ks_inq);
659	if (scancode == -1) {
660		KBDMUX_UNLOCK(state);
661		return (NOKEY);
662	}
663	/* XXX FIXME: check for -1 if wait == 1! */
664
665	kbd->kb_count ++;
666
667	/* return the byte as is for the K_RAW mode */
668	if (state->ks_mode == K_RAW) {
669		KBDMUX_UNLOCK(state);
670		return (scancode);
671	}
672
673	/* translate the scan code into a keycode */
674	keycode = scancode & 0x7F;
675	switch (state->ks_prefix) {
676	case 0x00:	/* normal scancode */
677		switch(scancode) {
678		case 0xB8:	/* left alt (compose key) released */
679			if (state->ks_flags & COMPOSE) {
680				state->ks_flags &= ~COMPOSE;
681				if (state->ks_composed_char > UCHAR_MAX)
682					state->ks_composed_char = 0;
683			}
684			break;
685		case 0x38:	/* left alt (compose key) pressed */
686			if (!(state->ks_flags & COMPOSE)) {
687				state->ks_flags |= COMPOSE;
688				state->ks_composed_char = 0;
689			}
690			break;
691		case 0xE0:
692		case 0xE1:
693			state->ks_prefix = scancode;
694			goto next_code;
695		}
696		break;
697	case 0xE0:      /* 0xE0 prefix */
698		state->ks_prefix = 0;
699		switch (keycode) {
700		case 0x1C:	/* right enter key */
701			keycode = 0x59;
702			break;
703		case 0x1D:	/* right ctrl key */
704			keycode = 0x5A;
705			break;
706		case 0x35:	/* keypad divide key */
707			keycode = 0x5B;
708			break;
709		case 0x37:	/* print scrn key */
710			keycode = 0x5C;
711			break;
712		case 0x38:	/* right alt key (alt gr) */
713			keycode = 0x5D;
714			break;
715		case 0x46:	/* ctrl-pause/break on AT 101 (see below) */
716			keycode = 0x68;
717			break;
718		case 0x47:	/* grey home key */
719			keycode = 0x5E;
720			break;
721		case 0x48:	/* grey up arrow key */
722			keycode = 0x5F;
723			break;
724		case 0x49:	/* grey page up key */
725			keycode = 0x60;
726			break;
727		case 0x4B:	/* grey left arrow key */
728			keycode = 0x61;
729			break;
730		case 0x4D:	/* grey right arrow key */
731			keycode = 0x62;
732			break;
733		case 0x4F:	/* grey end key */
734			keycode = 0x63;
735			break;
736		case 0x50:	/* grey down arrow key */
737			keycode = 0x64;
738			break;
739		case 0x51:	/* grey page down key */
740			keycode = 0x65;
741			break;
742		case 0x52:	/* grey insert key */
743			keycode = 0x66;
744			break;
745		case 0x53:	/* grey delete key */
746			keycode = 0x67;
747			break;
748		/* the following 3 are only used on the MS "Natural" keyboard */
749		case 0x5b:	/* left Window key */
750			keycode = 0x69;
751			break;
752		case 0x5c:	/* right Window key */
753			keycode = 0x6a;
754			break;
755		case 0x5d:	/* menu key */
756			keycode = 0x6b;
757			break;
758		case 0x5e:	/* power key */
759			keycode = 0x6d;
760			break;
761		case 0x5f:	/* sleep key */
762			keycode = 0x6e;
763			break;
764		case 0x63:	/* wake key */
765			keycode = 0x6f;
766			break;
767		default:	/* ignore everything else */
768			goto next_code;
769		}
770		break;
771	case 0xE1:	/* 0xE1 prefix */
772		/*
773		 * The pause/break key on the 101 keyboard produces:
774		 * E1-1D-45 E1-9D-C5
775		 * Ctrl-pause/break produces:
776		 * E0-46 E0-C6 (See above.)
777		 */
778		state->ks_prefix = 0;
779		if (keycode == 0x1D)
780			state->ks_prefix = 0x1D;
781		goto next_code;
782		/* NOT REACHED */
783	case 0x1D:	/* pause / break */
784		state->ks_prefix = 0;
785		if (keycode != 0x45)
786			goto next_code;
787		keycode = 0x68;
788		break;
789	}
790
791	/* XXX assume 101/102 keys AT keyboard */
792	switch (keycode) {
793	case 0x5c:	/* print screen */
794		if (state->ks_flags & ALTS)
795			keycode = 0x54;	/* sysrq */
796		break;
797	case 0x68:	/* pause/break */
798		if (state->ks_flags & CTLS)
799			keycode = 0x6c;	/* break */
800		break;
801	}
802
803	/* return the key code in the K_CODE mode */
804	if (state->ks_mode == K_CODE) {
805		KBDMUX_UNLOCK(state);
806		return (keycode | (scancode & 0x80));
807	}
808
809	/* compose a character code */
810	if (state->ks_flags & COMPOSE) {
811		switch (keycode | (scancode & 0x80)) {
812		/* key pressed, process it */
813		case 0x47: case 0x48: case 0x49:	/* keypad 7,8,9 */
814			state->ks_composed_char *= 10;
815			state->ks_composed_char += keycode - 0x40;
816			if (state->ks_composed_char > UCHAR_MAX) {
817				KBDMUX_UNLOCK(state);
818				return (ERRKEY);
819			}
820			goto next_code;
821		case 0x4B: case 0x4C: case 0x4D:	/* keypad 4,5,6 */
822			state->ks_composed_char *= 10;
823			state->ks_composed_char += keycode - 0x47;
824			if (state->ks_composed_char > UCHAR_MAX) {
825				KBDMUX_UNLOCK(state);
826				return (ERRKEY);
827			}
828			goto next_code;
829		case 0x4F: case 0x50: case 0x51:	/* keypad 1,2,3 */
830			state->ks_composed_char *= 10;
831			state->ks_composed_char += keycode - 0x4E;
832			if (state->ks_composed_char > UCHAR_MAX) {
833				KBDMUX_UNLOCK(state);
834				return (ERRKEY);
835			}
836			goto next_code;
837		case 0x52:	/* keypad 0 */
838			state->ks_composed_char *= 10;
839			if (state->ks_composed_char > UCHAR_MAX) {
840				KBDMUX_UNLOCK(state);
841				return (ERRKEY);
842			}
843			goto next_code;
844
845		/* key released, no interest here */
846		case 0xC7: case 0xC8: case 0xC9:	/* keypad 7,8,9 */
847		case 0xCB: case 0xCC: case 0xCD:	/* keypad 4,5,6 */
848		case 0xCF: case 0xD0: case 0xD1:	/* keypad 1,2,3 */
849		case 0xD2:				/* keypad 0 */
850			goto next_code;
851
852		case 0x38:				/* left alt key */
853			break;
854
855		default:
856			if (state->ks_composed_char > 0) {
857				state->ks_flags &= ~COMPOSE;
858				state->ks_composed_char = 0;
859				KBDMUX_UNLOCK(state);
860				return (ERRKEY);
861			}
862			break;
863		}
864	}
865
866	/* keycode to key action */
867	action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
868			&state->ks_state, &state->ks_accents);
869	if (action == NOKEY)
870		goto next_code;
871
872	KBDMUX_UNLOCK(state);
873
874	return (action);
875}
876
877/*
878 * Check if char is waiting
879 */
880static int
881kbdmux_check_char(keyboard_t *kbd)
882{
883	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
884	int		 ready;
885
886	if (!KBD_IS_ACTIVE(kbd))
887		return (FALSE);
888
889	KBDMUX_LOCK(state);
890
891	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
892		ready = TRUE;
893	else
894		ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE;
895
896	KBDMUX_UNLOCK(state);
897
898	return (ready);
899}
900
901/*
902 * Keyboard ioctl's
903 */
904static int
905kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
906{
907	static int	 delays[] = {
908		250, 500, 750, 1000
909	};
910
911	static int	 rates[]  =  {
912		34,  38,  42,  46,  50,   55,  59,  63,
913		68,  76,  84,  92,  100, 110, 118, 126,
914		136, 152, 168, 184, 200, 220, 236, 252,
915		272, 304, 336, 368, 400, 440, 472, 504
916	};
917
918	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
919	kbdmux_kbd_t	*k;
920	keyboard_info_t	*ki;
921	int		 error = 0, mode;
922
923	if (state == NULL)
924		return (ENXIO);
925
926	switch (cmd) {
927	case KBADDKBD: /* add keyboard to the mux */
928		ki = (keyboard_info_t *) arg;
929
930		if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
931		    strcmp(ki->kb_name, "*") == 0)
932			return (EINVAL); /* bad input */
933
934		KBDMUX_LOCK(state);
935
936		SLIST_FOREACH(k, &state->ks_kbds, next)
937			if (k->kbd->kb_unit == ki->kb_unit &&
938			    strcmp(k->kbd->kb_name, ki->kb_name) == 0)
939				break;
940
941		if (k != NULL) {
942			KBDMUX_UNLOCK(state);
943
944			return (0); /* keyboard already in the mux */
945		}
946
947		k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
948		if (k == NULL) {
949			KBDMUX_UNLOCK(state);
950
951			return (ENOMEM); /* out of memory */
952		}
953
954		k->kbd = kbd_get_keyboard(
955				kbd_allocate(
956					ki->kb_name,
957					ki->kb_unit,
958					(void *) &k->kbd,
959					kbdmux_kbd_event, (void *) state));
960		if (k->kbd == NULL) {
961			KBDMUX_UNLOCK(state);
962			free(k, M_KBDMUX);
963
964			return (EINVAL); /* bad keyboard */
965		}
966
967		KBDMUX_ENABLE(k->kbd);
968		KBDMUX_CLEAR_STATE(k->kbd);
969
970		/* set K_RAW mode on slave keyboard */
971		mode = K_RAW;
972		error = KBDMUX_IOCTL(k->kbd, KDSKBMODE, &mode);
973		if (error == 0) {
974			/* set lock keys state on slave keyboard */
975			mode = state->ks_state & LOCK_MASK;
976			error = KBDMUX_IOCTL(k->kbd, KDSKBSTATE, &mode);
977		}
978
979		if (error != 0) {
980			KBDMUX_UNLOCK(state);
981
982			kbd_release(k->kbd, &k->kbd);
983			k->kbd = NULL;
984
985			free(k, M_KBDMUX);
986
987			return (error); /* could not set mode */
988		}
989
990		SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
991
992		KBDMUX_UNLOCK(state);
993		break;
994
995	case KBRELKBD: /* release keyboard from the mux */
996		ki = (keyboard_info_t *) arg;
997
998		if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
999		    strcmp(ki->kb_name, "*") == 0)
1000			return (EINVAL); /* bad input */
1001
1002		KBDMUX_LOCK(state);
1003
1004		SLIST_FOREACH(k, &state->ks_kbds, next)
1005			if (k->kbd->kb_unit == ki->kb_unit &&
1006			    strcmp(k->kbd->kb_name, ki->kb_name) == 0)
1007				break;
1008
1009		if (k != NULL) {
1010			error = kbd_release(k->kbd, &k->kbd);
1011			if (error == 0) {
1012				SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
1013
1014				k->kbd = NULL;
1015
1016				free(k, M_KBDMUX);
1017			}
1018		} else
1019			error = ENXIO; /* keyboard is not in the mux */
1020
1021		KBDMUX_UNLOCK(state);
1022		break;
1023
1024	case KDGKBMODE: /* get kyboard mode */
1025		KBDMUX_LOCK(state);
1026		*((int *) arg) = state->ks_mode;
1027		KBDMUX_UNLOCK(state);
1028		break;
1029
1030	case KDSKBMODE: /* set keyboard mode */
1031		KBDMUX_LOCK(state);
1032
1033		switch (*((int *) arg)) {
1034		case K_XLATE:
1035			if (state->ks_mode != K_XLATE) {
1036				/* make lock key state and LED state match */
1037				state->ks_state &= ~LOCK_MASK;
1038				state->ks_state |= KBD_LED_VAL(kbd);
1039                        }
1040                        /* FALLTHROUGH */
1041
1042		case K_RAW:
1043		case K_CODE:
1044			if (state->ks_mode != *((int *) arg)) {
1045				kbdmux_clear_state_locked(state);
1046				state->ks_mode = *((int *) arg);
1047			}
1048			break;
1049
1050                default:
1051			error = EINVAL;
1052			break;
1053		}
1054
1055		KBDMUX_UNLOCK(state);
1056		break;
1057
1058	case KDGETLED: /* get keyboard LED */
1059		KBDMUX_LOCK(state);
1060		*((int *) arg) = KBD_LED_VAL(kbd);
1061		KBDMUX_UNLOCK(state);
1062		break;
1063
1064	case KDSETLED: /* set keyboard LED */
1065		KBDMUX_LOCK(state);
1066
1067		/* NOTE: lock key state in ks_state won't be changed */
1068		if (*((int *) arg) & ~LOCK_MASK) {
1069			KBDMUX_UNLOCK(state);
1070
1071			return (EINVAL);
1072		}
1073
1074		KBD_LED_VAL(kbd) = *((int *) arg);
1075
1076		/* KDSETLED on all slave keyboards */
1077		SLIST_FOREACH(k, &state->ks_kbds, next)
1078			KBDMUX_IOCTL(k->kbd, KDSETLED, arg);
1079
1080		KBDMUX_UNLOCK(state);
1081		break;
1082
1083	case KDGKBSTATE: /* get lock key state */
1084		KBDMUX_LOCK(state);
1085		*((int *) arg) = state->ks_state & LOCK_MASK;
1086		KBDMUX_UNLOCK(state);
1087		break;
1088
1089	case KDSKBSTATE: /* set lock key state */
1090		KBDMUX_LOCK(state);
1091
1092		if (*((int *) arg) & ~LOCK_MASK) {
1093			KBDMUX_UNLOCK(state);
1094
1095			return (EINVAL);
1096		}
1097
1098		state->ks_state &= ~LOCK_MASK;
1099		state->ks_state |= *((int *) arg);
1100
1101		/* KDSKBSTATE on all slave keyboards */
1102		SLIST_FOREACH(k, &state->ks_kbds, next)
1103			KBDMUX_IOCTL(k->kbd, KDSKBSTATE, arg);
1104
1105		KBDMUX_UNLOCK(state);
1106
1107		return (kbdmux_ioctl(kbd, KDSETLED, arg));
1108		/* NOT REACHED */
1109
1110	case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1111	case KDSETRAD: /* set keyboard repeat rate (old interface) */
1112		KBDMUX_LOCK(state);
1113
1114		if (cmd == KDSETREPEAT) {
1115			int	i;
1116
1117			/* lookup delay */
1118			for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --)
1119				if (((int *) arg)[0] >= delays[i])
1120					break;
1121			mode = i << 5;
1122
1123			/* lookup rate */
1124			for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --)
1125				if (((int *) arg)[1] >= rates[i])
1126					break;
1127			mode |= i;
1128		} else
1129			mode = *((int *) arg);
1130
1131		if (mode & ~0x7f) {
1132			KBDMUX_UNLOCK(state);
1133
1134			return (EINVAL);
1135		}
1136
1137		kbd->kb_delay1 = delays[(mode >> 5) & 3];
1138		kbd->kb_delay2 = rates[mode & 0x1f];
1139
1140		/* perform command on all slave keyboards */
1141		SLIST_FOREACH(k, &state->ks_kbds, next)
1142			KBDMUX_IOCTL(k->kbd, cmd, arg);
1143
1144		KBDMUX_UNLOCK(state);
1145		break;
1146
1147	case PIO_KEYMAP:	/* set keyboard translation table */
1148	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
1149	case PIO_DEADKEYMAP:	/* set accent key translation table */
1150		KBDMUX_LOCK(state);
1151                state->ks_accents = 0;
1152
1153		/* perform command on all slave keyboards */
1154		SLIST_FOREACH(k, &state->ks_kbds, next)
1155			KBDMUX_IOCTL(k->kbd, cmd, arg);
1156
1157		KBDMUX_UNLOCK(state);
1158                /* FALLTHROUGH */
1159
1160	default:
1161		error = genkbd_commonioctl(kbd, cmd, arg);
1162		break;
1163	}
1164
1165	return (error);
1166}
1167
1168/*
1169 * Lock the access to the keyboard
1170 */
1171static int
1172kbdmux_lock(keyboard_t *kbd, int lock)
1173{
1174	return (1); /* XXX */
1175}
1176
1177/*
1178 * Clear the internal state of the keyboard
1179 */
1180static void
1181kbdmux_clear_state_locked(kbdmux_state_t *state)
1182{
1183	KBDMUX_LOCK_ASSERT(state, MA_OWNED);
1184
1185	state->ks_flags &= ~(COMPOSE|POLLING);
1186	state->ks_state &= LOCK_MASK;	/* preserve locking key state */
1187	state->ks_accents = 0;
1188	state->ks_composed_char = 0;
1189/*	state->ks_prefix = 0;		XXX */
1190
1191	ndflush(&state->ks_inq, state->ks_inq.c_cc);
1192}
1193
1194static void
1195kbdmux_clear_state(keyboard_t *kbd)
1196{
1197	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
1198
1199	KBDMUX_LOCK(state);
1200	kbdmux_clear_state_locked(state);
1201	KBDMUX_UNLOCK(state);
1202}
1203
1204/*
1205 * Save the internal state
1206 */
1207static int
1208kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1209{
1210	if (len == 0)
1211		return (sizeof(kbdmux_state_t));
1212	if (len < sizeof(kbdmux_state_t))
1213		return (-1);
1214
1215	bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1216
1217	return (0);
1218}
1219
1220/*
1221 * Set the internal state
1222 */
1223static int
1224kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1225{
1226	if (len < sizeof(kbdmux_state_t))
1227		return (ENOMEM);
1228
1229	bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1230
1231	return (0);
1232}
1233
1234/*
1235 * Set polling
1236 */
1237static int
1238kbdmux_poll(keyboard_t *kbd, int on)
1239{
1240	kbdmux_state_t	*state = (kbdmux_state_t *) kbd->kb_data;
1241	kbdmux_kbd_t	*k;
1242
1243	KBDMUX_LOCK(state);
1244
1245	if (on)
1246		state->ks_flags |= POLLING;
1247	else
1248		state->ks_flags &= ~POLLING;
1249
1250	/* set poll on slave keyboards */
1251	SLIST_FOREACH(k, &state->ks_kbds, next)
1252		KBDMUX_POLL(k->kbd, on);
1253
1254	KBDMUX_UNLOCK(state);
1255
1256	return (0);
1257}
1258
1259/*****************************************************************************
1260 *****************************************************************************
1261 **                                    Module
1262 *****************************************************************************
1263 *****************************************************************************/
1264
1265KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1266
1267static int
1268kbdmux_modevent(module_t mod, int type, void *data)
1269{
1270	keyboard_switch_t	*sw;
1271	keyboard_t		*kbd;
1272	int			 error;
1273
1274	switch (type) {
1275	case MOD_LOAD:
1276		if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1277			break;
1278
1279		if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1280			kbd_delete_driver(&kbdmux_kbd_driver);
1281			error = ENXIO;
1282			break;
1283		}
1284
1285		kbd = NULL;
1286
1287		if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
1288		    (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) {
1289			kbd_delete_driver(&kbdmux_kbd_driver);
1290			break;
1291		}
1292
1293#ifdef KBD_INSTALL_CDEV
1294		if ((error = kbd_attach(kbd)) != 0) {
1295			(*sw->term)(kbd);
1296			kbd_delete_driver(&kbdmux_kbd_driver);
1297			break;
1298		}
1299#endif
1300
1301		if ((error = (*sw->enable)(kbd)) != 0) {
1302			(*sw->disable)(kbd);
1303#ifdef KBD_INSTALL_CDEV
1304			kbd_detach(kbd);
1305#endif
1306			(*sw->term)(kbd);
1307			kbd_delete_driver(&kbdmux_kbd_driver);
1308			break;
1309		}
1310		break;
1311
1312	case MOD_UNLOAD:
1313		if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
1314			panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
1315
1316		kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1317		if (kbd == NULL)
1318			 panic("kbd_get_keyboard(kbd_find_keyboard(" KEYBOARD_NAME ", 0)) == NULL");
1319
1320		(*sw->disable)(kbd);
1321#ifdef KBD_INSTALL_CDEV
1322		kbd_detach(kbd);
1323#endif
1324		(*sw->term)(kbd);
1325		kbd_delete_driver(&kbdmux_kbd_driver);
1326		error = 0;
1327		break;
1328
1329	default:
1330		error = EOPNOTSUPP;
1331		break;
1332	}
1333
1334	return (0);
1335}
1336
1337DEV_MODULE(kbdmux, kbdmux_modevent, NULL);
1338
1339