atkbd.c revision 119418
1285612Sdelphij/*-
2285612Sdelphij * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3285612Sdelphij * All rights reserved.
4285612Sdelphij *
5285612Sdelphij * Redistribution and use in source and binary forms, with or without
6285612Sdelphij * modification, are permitted provided that the following conditions
7285612Sdelphij * are met:
8285612Sdelphij * 1. Redistributions of source code must retain the above copyright
9285612Sdelphij *    notice, this list of conditions and the following disclaimer as
1054359Sroberto *    the first lines of this file unmodified.
11285612Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
1254359Sroberto *    notice, this list of conditions and the following disclaimer in the
1354359Sroberto *    documentation and/or other materials provided with the distribution.
1454359Sroberto *
1554359Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1654359Sroberto * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1782498Sroberto * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1854359Sroberto * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1954359Sroberto * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2082498Sroberto * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2182498Sroberto * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22106163Sroberto * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23285612Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24106163Sroberto * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2582498Sroberto *
2682498Sroberto */
2782498Sroberto
2882498Sroberto#include <sys/cdefs.h>
29285612Sdelphij__FBSDID("$FreeBSD: head/sys/dev/atkbdc/atkbd.c 119418 2003-08-24 17:55:58Z obrien $");
30285612Sdelphij
31285612Sdelphij#include "opt_kbd.h"
3282498Sroberto#include "opt_atkbd.h"
33285612Sdelphij
34285612Sdelphij#include <sys/param.h>
3554359Sroberto#include <sys/systm.h>
36285612Sdelphij#include <sys/kernel.h>
37285612Sdelphij#include <sys/bus.h>
38285612Sdelphij#include <sys/proc.h>
39285612Sdelphij#include <sys/limits.h>
40285612Sdelphij#include <sys/malloc.h>
41285612Sdelphij
42285612Sdelphij#include <machine/bus.h>
43285612Sdelphij#include <machine/resource.h>
44285612Sdelphij
45285612Sdelphij#ifdef __i386__
46182007Sroberto#include <machine/md_var.h>
47182007Sroberto#include <machine/psl.h>
48182007Sroberto#include <machine/vm86.h>
49182007Sroberto#include <machine/pc/bios.h>
50182007Sroberto
51182007Sroberto#include <vm/vm.h>
52285612Sdelphij#include <vm/pmap.h>
53285612Sdelphij#endif /* __i386__ */
54285612Sdelphij
55182007Sroberto#include <sys/kbio.h>
56309008Sdelphij#include <dev/kbd/kbdreg.h>
57309008Sdelphij#include <dev/kbd/atkbdreg.h>
58309008Sdelphij#include <dev/kbd/atkbdcreg.h>
59309008Sdelphij
60309008Sdelphij#include <isa/isareg.h>
61309008Sdelphij
62294569Sdelphijstatic timeout_t	atkbd_timeout;
63294569Sdelphij
64289997Sglebiusint
65289997Sglebiusatkbd_probe_unit(int unit, int ctlr, int irq, int flags)
66289997Sglebius{
67289997Sglebius	keyboard_switch_t *sw;
6882498Sroberto	int args[2];
69285612Sdelphij	int error;
70285612Sdelphij
71285612Sdelphij	sw = kbd_get_switch(ATKBD_DRIVER_NAME);
7254359Sroberto	if (sw == NULL)
73289997Sglebius		return ENXIO;
74289997Sglebius
75289997Sglebius	args[0] = ctlr;
76289997Sglebius	args[1] = irq;
77289997Sglebius	error = (*sw->probe)(unit, args, flags);
78289997Sglebius	if (error)
7954359Sroberto		return error;
8054359Sroberto	return 0;
8154359Sroberto}
8254359Sroberto
8354359Srobertoint
84285612Sdelphijatkbd_attach_unit(int unit, keyboard_t **kbd, int ctlr, int irq, int flags)
85285612Sdelphij{
8654359Sroberto	keyboard_switch_t *sw;
8754359Sroberto	int args[2];
8854359Sroberto	int error;
89285612Sdelphij
90285612Sdelphij	sw = kbd_get_switch(ATKBD_DRIVER_NAME);
91285612Sdelphij	if (sw == NULL)
92285612Sdelphij		return ENXIO;
93285612Sdelphij
9454359Sroberto	/* reset, initialize and enable the device */
9554359Sroberto	args[0] = ctlr;
96285612Sdelphij	args[1] = irq;
97285612Sdelphij	*kbd = NULL;
98285612Sdelphij	error = (*sw->probe)(unit, args, flags);
99285612Sdelphij	if (error)
100285612Sdelphij		return error;
101285612Sdelphij	error = (*sw->init)(unit, kbd, args, flags);
102285612Sdelphij	if (error)
103285612Sdelphij		return error;
104285612Sdelphij	(*sw->enable)(*kbd);
105285612Sdelphij
106285612Sdelphij#ifdef KBD_INSTALL_CDEV
107285612Sdelphij	/* attach a virtual keyboard cdev */
108285612Sdelphij	error = kbd_attach(*kbd);
109285612Sdelphij	if (error)
110285612Sdelphij		return error;
111285612Sdelphij#endif
112285612Sdelphij
113285612Sdelphij	/*
11454359Sroberto	 * This is a kludge to compensate for lost keyboard interrupts.
11554359Sroberto	 * A similar code used to be in syscons. See below. XXX
11654359Sroberto	 */
11754359Sroberto	atkbd_timeout(*kbd);
118285612Sdelphij
11954359Sroberto	if (bootverbose)
12054359Sroberto		(*sw->diag)(*kbd, bootverbose);
121285612Sdelphij	return 0;
122285612Sdelphij}
123285612Sdelphij
124285612Sdelphijstatic void
125285612Sdelphijatkbd_timeout(void *arg)
126285612Sdelphij{
127285612Sdelphij	keyboard_t *kbd;
128285612Sdelphij	int s;
129285612Sdelphij
130285612Sdelphij	/*
131285612Sdelphij	 * The original text of the following comments are extracted
132285612Sdelphij	 * from syscons.c (1.287)
133285612Sdelphij	 *
134285612Sdelphij	 * With release 2.1 of the Xaccel server, the keyboard is left
135182007Sroberto	 * hanging pretty often. Apparently an interrupt from the
13654359Sroberto	 * keyboard is lost, and I don't know why (yet).
13754359Sroberto	 * This ugly hack calls the low-level interrupt routine if input
13854359Sroberto	 * is ready for the keyboard and conveniently hides the problem. XXX
13954359Sroberto	 *
14054359Sroberto	 * Try removing anything stuck in the keyboard controller; whether
14154359Sroberto	 * it's a keyboard scan code or mouse data. The low-level
14254359Sroberto	 * interrupt routine doesn't read the mouse data directly,
14354359Sroberto	 * but the keyboard controller driver will, as a side effect.
144285612Sdelphij	 */
14582498Sroberto	/*
14654359Sroberto	 * And here is bde's original comment about this:
14754359Sroberto	 *
14854359Sroberto	 * This is necessary to handle edge triggered interrupts - if we
149285612Sdelphij	 * returned when our IRQ is high due to unserviced input, then there
150285612Sdelphij	 * would be no more keyboard IRQs until the keyboard is reset by
151285612Sdelphij	 * external powers.
152330141Sdelphij	 *
153285612Sdelphij	 * The keyboard apparently unwedges the irq in most cases.
154330141Sdelphij	 */
155285612Sdelphij	s = spltty();
15654359Sroberto	kbd = (keyboard_t *)arg;
15754359Sroberto	if ((*kbdsw[kbd->kb_index]->lock)(kbd, TRUE)) {
15854359Sroberto		/*
15954359Sroberto		 * We have seen the lock flag is not set. Let's reset
16054359Sroberto		 * the flag early, otherwise the LED update routine fails
16182498Sroberto		 * which may want the lock during the interrupt routine.
162285612Sdelphij		 */
163285612Sdelphij		(*kbdsw[kbd->kb_index]->lock)(kbd, FALSE);
164285612Sdelphij		if ((*kbdsw[kbd->kb_index]->check_char)(kbd))
165285612Sdelphij			(*kbdsw[kbd->kb_index]->intr)(kbd, NULL);
166285612Sdelphij	}
167285612Sdelphij	splx(s);
168285612Sdelphij	timeout(atkbd_timeout, arg, hz/10);
16982498Sroberto}
170285612Sdelphij
171285612Sdelphij/* LOW-LEVEL */
17282498Sroberto
17382498Sroberto#define ATKBD_DEFAULT	0
174285612Sdelphij
175285612Sdelphijtypedef struct atkbd_state {
176285612Sdelphij	KBDC		kbdc;		/* keyboard controller */
177285612Sdelphij					/* XXX: don't move this field; pcvt
17882498Sroberto					 * expects `kbdc' to be the first
17954359Sroberto					 * field in this structure. */
18054359Sroberto	int		ks_mode;	/* input mode (K_XLATE,K_RAW,K_CODE) */
18154359Sroberto	int		ks_flags;	/* flags */
18254359Sroberto#define COMPOSE		(1 << 0)
18354359Sroberto	int		ks_polling;
18454359Sroberto	int		ks_state;	/* shift/lock key state */
18554359Sroberto	int		ks_accents;	/* accent key index (> 0) */
18654359Sroberto	u_int		ks_composed_char; /* composed char code (> 0) */
18754359Sroberto	u_char		ks_prefix;	/* AT scan code prefix */
18854359Sroberto} atkbd_state_t;
189285612Sdelphij
19054359Sroberto/* keyboard driver declaration */
19154359Srobertostatic int		atkbd_configure(int flags);
19254359Srobertostatic kbd_probe_t	atkbd_probe;
193285612Sdelphijstatic kbd_init_t	atkbd_init;
194285612Sdelphijstatic kbd_term_t	atkbd_term;
195285612Sdelphijstatic kbd_intr_t	atkbd_intr;
196285612Sdelphijstatic kbd_test_if_t	atkbd_test_if;
197285612Sdelphijstatic kbd_enable_t	atkbd_enable;
198285612Sdelphijstatic kbd_disable_t	atkbd_disable;
199285612Sdelphijstatic kbd_read_t	atkbd_read;
200285612Sdelphijstatic kbd_check_t	atkbd_check;
201285612Sdelphijstatic kbd_read_char_t	atkbd_read_char;
202285612Sdelphijstatic kbd_check_char_t	atkbd_check_char;
203285612Sdelphijstatic kbd_ioctl_t	atkbd_ioctl;
204285612Sdelphijstatic kbd_lock_t	atkbd_lock;
20554359Srobertostatic kbd_clear_state_t atkbd_clear_state;
206285612Sdelphijstatic kbd_get_state_t	atkbd_get_state;
20754359Srobertostatic kbd_set_state_t	atkbd_set_state;
208285612Sdelphijstatic kbd_poll_mode_t	atkbd_poll;
209285612Sdelphij
210285612Sdelphijstatic keyboard_switch_t atkbdsw = {
211285612Sdelphij	atkbd_probe,
212285612Sdelphij	atkbd_init,
213285612Sdelphij	atkbd_term,
214285612Sdelphij	atkbd_intr,
215285612Sdelphij	atkbd_test_if,
216285612Sdelphij	atkbd_enable,
217285612Sdelphij	atkbd_disable,
218285612Sdelphij	atkbd_read,
219285612Sdelphij	atkbd_check,
22054359Sroberto	atkbd_read_char,
221285612Sdelphij	atkbd_check_char,
222285612Sdelphij	atkbd_ioctl,
223285612Sdelphij	atkbd_lock,
224285612Sdelphij	atkbd_clear_state,
225285612Sdelphij	atkbd_get_state,
226285612Sdelphij	atkbd_set_state,
227285612Sdelphij	genkbd_get_fkeystr,
228285612Sdelphij	atkbd_poll,
229285612Sdelphij	genkbd_diag,
230285612Sdelphij};
231285612Sdelphij
232285612SdelphijKEYBOARD_DRIVER(atkbd, atkbdsw, atkbd_configure);
233285612Sdelphij
234285612Sdelphij/* local functions */
235285612Sdelphijstatic int		get_typematic(keyboard_t *kbd);
236285612Sdelphijstatic int		setup_kbd_port(KBDC kbdc, int port, int intr);
237285612Sdelphijstatic int		get_kbd_echo(KBDC kbdc);
238285612Sdelphijstatic int		probe_keyboard(KBDC kbdc, int flags);
239285612Sdelphijstatic int		init_keyboard(KBDC kbdc, int *type, int flags);
240285612Sdelphijstatic int		write_kbd(KBDC kbdc, int command, int data);
241285612Sdelphijstatic int		get_kbd_id(KBDC kbdc);
242285612Sdelphijstatic int		typematic(int delay, int rate);
243285612Sdelphijstatic int		typematic_delay(int delay);
244285612Sdelphijstatic int		typematic_rate(int rate);
245285612Sdelphij
246285612Sdelphij/* local variables */
247285612Sdelphij
248285612Sdelphij/* the initial key map, accent map and fkey strings */
249285612Sdelphij#ifdef ATKBD_DFLT_KEYMAP
250285612Sdelphij#define KBD_DFLT_KEYMAP
251285612Sdelphij#include "atkbdmap.h"
252285612Sdelphij#endif
253285612Sdelphij#include <dev/kbd/kbdtables.h>
254285612Sdelphij
255285612Sdelphij/* structures for the default keyboard */
256285612Sdelphijstatic keyboard_t	default_kbd;
257285612Sdelphijstatic atkbd_state_t	default_kbd_state;
258285612Sdelphijstatic keymap_t		default_keymap;
259285612Sdelphijstatic accentmap_t	default_accentmap;
260285612Sdelphijstatic fkeytab_t	default_fkeytab[NUM_FKEYS];
261285612Sdelphij
262285612Sdelphij/*
263285612Sdelphij * The back door to the keyboard driver!
264285612Sdelphij * This function is called by the console driver, via the kbdio module,
265285612Sdelphij * to tickle keyboard drivers when the low-level console is being initialized.
266285612Sdelphij * Almost nothing in the kernel has been initialied yet.  Try to probe
267285612Sdelphij * keyboards if possible.
268285612Sdelphij * NOTE: because of the way the low-level console is initialized, this routine
269285612Sdelphij * may be called more than once!!
270285612Sdelphij */
271285612Sdelphijstatic int
272285612Sdelphijatkbd_configure(int flags)
273285612Sdelphij{
274285612Sdelphij	keyboard_t *kbd;
275285612Sdelphij	int arg[2];
276285612Sdelphij	int i;
277285612Sdelphij
278285612Sdelphij	/* probe the keyboard controller */
279285612Sdelphij	atkbdc_configure();
280285612Sdelphij
281285612Sdelphij	/* if the driver is disabled, unregister the keyboard if any */
282285612Sdelphij	if (resource_disabled("atkbd", ATKBD_DEFAULT)) {
283285612Sdelphij		i = kbd_find_keyboard(ATKBD_DRIVER_NAME, ATKBD_DEFAULT);
284285612Sdelphij		if (i >= 0) {
285285612Sdelphij			kbd = kbd_get_keyboard(i);
286285612Sdelphij			kbd_unregister(kbd);
287285612Sdelphij			kbd->kb_flags &= ~KB_REGISTERED;
288285612Sdelphij		}
289285612Sdelphij		return 0;
290285612Sdelphij	}
291285612Sdelphij
292285612Sdelphij	/* XXX: a kludge to obtain the device configuration flags */
293285612Sdelphij	if (resource_int_value("atkbd", ATKBD_DEFAULT, "flags", &i) == 0)
294285612Sdelphij		flags |= i;
295285612Sdelphij
296285612Sdelphij	/* probe the default keyboard */
297285612Sdelphij	arg[0] = -1;
298285612Sdelphij	arg[1] = -1;
299285612Sdelphij	kbd = NULL;
300285612Sdelphij	if (atkbd_probe(ATKBD_DEFAULT, arg, flags))
301285612Sdelphij		return 0;
302285612Sdelphij	if (atkbd_init(ATKBD_DEFAULT, &kbd, arg, flags))
303285612Sdelphij		return 0;
304285612Sdelphij
305285612Sdelphij	/* return the number of found keyboards */
306285612Sdelphij	return 1;
307285612Sdelphij}
308285612Sdelphij
309285612Sdelphij/* low-level functions */
310285612Sdelphij
311285612Sdelphij/* detect a keyboard */
312285612Sdelphijstatic int
313285612Sdelphijatkbd_probe(int unit, void *arg, int flags)
314285612Sdelphij{
315330141Sdelphij	KBDC kbdc;
316285612Sdelphij	int *data = (int *)arg;	/* data[0]: controller, data[1]: irq */
317285612Sdelphij
318285612Sdelphij	/* XXX */
319285612Sdelphij	if (unit == ATKBD_DEFAULT) {
320285612Sdelphij		if (KBD_IS_PROBED(&default_kbd))
321285612Sdelphij			return 0;
322285612Sdelphij	}
323285612Sdelphij
324285612Sdelphij	kbdc = atkbdc_open(data[0]);
325285612Sdelphij	if (kbdc == NULL)
326285612Sdelphij		return ENXIO;
327285612Sdelphij	if (probe_keyboard(kbdc, flags)) {
328285612Sdelphij		if (flags & KB_CONF_FAIL_IF_NO_KBD)
329285612Sdelphij			return ENXIO;
330285612Sdelphij	}
331285612Sdelphij	return 0;
332285612Sdelphij}
333285612Sdelphij
334285612Sdelphij/* reset and initialize the device */
335285612Sdelphijstatic int
336285612Sdelphijatkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
337285612Sdelphij{
338285612Sdelphij	keyboard_t *kbd;
339285612Sdelphij	atkbd_state_t *state;
340285612Sdelphij	keymap_t *keymap;
341285612Sdelphij	accentmap_t *accmap;
342285612Sdelphij	fkeytab_t *fkeymap;
343285612Sdelphij	int fkeymap_size;
344285612Sdelphij	int delay[2];
345285612Sdelphij	int *data = (int *)arg;	/* data[0]: controller, data[1]: irq */
346285612Sdelphij
347285612Sdelphij	/* XXX */
348285612Sdelphij	if (unit == ATKBD_DEFAULT) {
349285612Sdelphij		*kbdp = kbd = &default_kbd;
350285612Sdelphij		if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd))
351285612Sdelphij			return 0;
352285612Sdelphij		state = &default_kbd_state;
353285612Sdelphij		keymap = &default_keymap;
354182007Sroberto		accmap = &default_accentmap;
355182007Sroberto		fkeymap = default_fkeytab;
356182007Sroberto		fkeymap_size =
357182007Sroberto			sizeof(default_fkeytab)/sizeof(default_fkeytab[0]);
358285612Sdelphij	} else if (*kbdp == NULL) {
35954359Sroberto		*kbdp = kbd = malloc(sizeof(*kbd), M_DEVBUF, M_NOWAIT | M_ZERO);
360285612Sdelphij		state = malloc(sizeof(*state), M_DEVBUF, M_NOWAIT | M_ZERO);
361285612Sdelphij		keymap = malloc(sizeof(key_map), M_DEVBUF, M_NOWAIT);
362285612Sdelphij		accmap = malloc(sizeof(accent_map), M_DEVBUF, M_NOWAIT);
363285612Sdelphij		fkeymap = malloc(sizeof(fkey_tab), M_DEVBUF, M_NOWAIT);
364285612Sdelphij		fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
365316069Sdelphij		if ((kbd == NULL) || (state == NULL) || (keymap == NULL)
366316069Sdelphij		     || (accmap == NULL) || (fkeymap == NULL)) {
367338531Sdelphij			if (state != NULL)
368316069Sdelphij				free(state, M_DEVBUF);
369330141Sdelphij			if (keymap != NULL)
370285612Sdelphij				free(keymap, M_DEVBUF);
371285612Sdelphij			if (accmap != NULL)
372285612Sdelphij				free(accmap, M_DEVBUF);
373285612Sdelphij			if (fkeymap != NULL)
374285612Sdelphij				free(fkeymap, M_DEVBUF);
375285612Sdelphij			if (kbd != NULL)
376316069Sdelphij				free(kbd, M_DEVBUF);
377316069Sdelphij			return ENOMEM;
378316069Sdelphij		}
379316069Sdelphij	} else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
380316069Sdelphij		return 0;
381316069Sdelphij	} else {
382316069Sdelphij		kbd = *kbdp;
383316069Sdelphij		state = (atkbd_state_t *)kbd->kb_data;
384316069Sdelphij		bzero(state, sizeof(*state));
385338531Sdelphij		keymap = kbd->kb_keymap;
386316069Sdelphij		accmap = kbd->kb_accentmap;
387316069Sdelphij		fkeymap = kbd->kb_fkeytab;
388316069Sdelphij		fkeymap_size = kbd->kb_fkeytab_size;
389316069Sdelphij	}
390316069Sdelphij
391285612Sdelphij	if (!KBD_IS_PROBED(kbd)) {
392338531Sdelphij		state->kbdc = atkbdc_open(data[0]);
393285612Sdelphij		if (state->kbdc == NULL)
394285612Sdelphij			return ENXIO;
39554359Sroberto		kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags,
396285612Sdelphij				0, 0);
397285612Sdelphij		bcopy(&key_map, keymap, sizeof(key_map));
398285612Sdelphij		bcopy(&accent_map, accmap, sizeof(accent_map));
399285612Sdelphij		bcopy(fkey_tab, fkeymap,
400285612Sdelphij		      imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
40154359Sroberto		kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
40254359Sroberto		kbd->kb_data = (void *)state;
403285612Sdelphij
404285612Sdelphij		if (probe_keyboard(state->kbdc, flags)) { /* shouldn't happen */
405285612Sdelphij			if (flags & KB_CONF_FAIL_IF_NO_KBD)
40654359Sroberto				return ENXIO;
407285612Sdelphij		} else {
408285612Sdelphij			KBD_FOUND_DEVICE(kbd);
409285612Sdelphij		}
410285612Sdelphij		atkbd_clear_state(kbd);
411285612Sdelphij		state->ks_mode = K_XLATE;
412285612Sdelphij		/*
413285612Sdelphij		 * FIXME: set the initial value for lock keys in ks_state
414285612Sdelphij		 * according to the BIOS data?
415285612Sdelphij		 */
416285612Sdelphij		KBD_PROBE_DONE(kbd);
41754359Sroberto	}
418285612Sdelphij	if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
41954359Sroberto		kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
420285612Sdelphij		if (KBD_HAS_DEVICE(kbd)
421285612Sdelphij	    	    && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config)
422285612Sdelphij	    	    && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) {
423285612Sdelphij			kbd_unregister(kbd);
42454359Sroberto			return ENXIO;
42554359Sroberto		}
426285612Sdelphij		atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
427285612Sdelphij		get_typematic(kbd);
428285612Sdelphij		delay[0] = kbd->kb_delay1;
429285612Sdelphij		delay[1] = kbd->kb_delay2;
430285612Sdelphij		atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
431285612Sdelphij		KBD_INIT_DONE(kbd);
432285612Sdelphij	}
433285612Sdelphij	if (!KBD_IS_CONFIGURED(kbd)) {
434285612Sdelphij		if (kbd_register(kbd) < 0)
435285612Sdelphij			return ENXIO;
436285612Sdelphij		KBD_CONFIG_DONE(kbd);
437285612Sdelphij	}
438285612Sdelphij
439285612Sdelphij	return 0;
440285612Sdelphij}
441285612Sdelphij
442285612Sdelphij/* finish using this keyboard */
443285612Sdelphijstatic int
44454359Srobertoatkbd_term(keyboard_t *kbd)
44554359Sroberto{
44654359Sroberto	kbd_unregister(kbd);
447285612Sdelphij	return 0;
448285612Sdelphij}
449285612Sdelphij
450285612Sdelphij/* keyboard interrupt routine */
45154359Srobertostatic int
45254359Srobertoatkbd_intr(keyboard_t *kbd, void *arg)
453285612Sdelphij{
454285612Sdelphij	atkbd_state_t *state;
455285612Sdelphij	int delay[2];
45654359Sroberto	int c;
457285612Sdelphij
458285612Sdelphij	if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
45954359Sroberto		/* let the callback function to process the input */
460285612Sdelphij		(*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
461285612Sdelphij					    kbd->kb_callback.kc_arg);
462285612Sdelphij	} else {
463285612Sdelphij		/* read and discard the input; no one is waiting for input */
464285612Sdelphij		do {
465285612Sdelphij			c = atkbd_read_char(kbd, FALSE);
466285612Sdelphij		} while (c != NOKEY);
467285612Sdelphij
468285612Sdelphij		if (!KBD_HAS_DEVICE(kbd)) {
469285612Sdelphij			/*
470285612Sdelphij			 * The keyboard was not detected before;
471285612Sdelphij			 * it must have been reconnected!
472285612Sdelphij			 */
473285612Sdelphij			state = (atkbd_state_t *)kbd->kb_data;
474285612Sdelphij			init_keyboard(state->kbdc, &kbd->kb_type,
475285612Sdelphij				      kbd->kb_config);
476285612Sdelphij			atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
477285612Sdelphij			get_typematic(kbd);
478285612Sdelphij			delay[0] = kbd->kb_delay1;
479285612Sdelphij			delay[1] = kbd->kb_delay2;
480285612Sdelphij			atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
481285612Sdelphij			KBD_FOUND_DEVICE(kbd);
482285612Sdelphij		}
48354359Sroberto	}
484285612Sdelphij	return 0;
485285612Sdelphij}
486285612Sdelphij
487285612Sdelphij/* test the interface to the device */
488285612Sdelphijstatic int
48954359Srobertoatkbd_test_if(keyboard_t *kbd)
490285612Sdelphij{
49154359Sroberto	int error;
49254359Sroberto	int s;
493285612Sdelphij
494285612Sdelphij	error = 0;
495285612Sdelphij	empty_both_buffers(((atkbd_state_t *)kbd->kb_data)->kbdc, 10);
496285612Sdelphij	s = spltty();
497285612Sdelphij	if (!test_controller(((atkbd_state_t *)kbd->kb_data)->kbdc))
498285612Sdelphij		error = EIO;
49954359Sroberto	else if (test_kbd_port(((atkbd_state_t *)kbd->kb_data)->kbdc) != 0)
50054359Sroberto		error = EIO;
501285612Sdelphij	splx(s);
502285612Sdelphij
50354359Sroberto	return error;
504285612Sdelphij}
505285612Sdelphij
506285612Sdelphij/*
507285612Sdelphij * Enable the access to the device; until this function is called,
508285612Sdelphij * the client cannot read from the keyboard.
509285612Sdelphij */
510285612Sdelphijstatic int
511285612Sdelphijatkbd_enable(keyboard_t *kbd)
512285612Sdelphij{
513285612Sdelphij	int s;
514285612Sdelphij
515285612Sdelphij	s = spltty();
516285612Sdelphij	KBD_ACTIVATE(kbd);
517285612Sdelphij	splx(s);
518285612Sdelphij	return 0;
519285612Sdelphij}
520285612Sdelphij
521285612Sdelphij/* disallow the access to the device */
522285612Sdelphijstatic int
523285612Sdelphijatkbd_disable(keyboard_t *kbd)
524285612Sdelphij{
525285612Sdelphij	int s;
526285612Sdelphij
527285612Sdelphij	s = spltty();
528285612Sdelphij	KBD_DEACTIVATE(kbd);
529285612Sdelphij	splx(s);
530285612Sdelphij	return 0;
531285612Sdelphij}
532285612Sdelphij
533285612Sdelphij/* read one byte from the keyboard if it's allowed */
534330141Sdelphijstatic int
535285612Sdelphijatkbd_read(keyboard_t *kbd, int wait)
536285612Sdelphij{
537285612Sdelphij	int c;
538285612Sdelphij
539285612Sdelphij	if (wait)
540285612Sdelphij		c = read_kbd_data(((atkbd_state_t *)kbd->kb_data)->kbdc);
541285612Sdelphij	else
542285612Sdelphij		c = read_kbd_data_no_wait(((atkbd_state_t *)kbd->kb_data)->kbdc);
543285612Sdelphij	if (c != -1)
544285612Sdelphij		++kbd->kb_count;
545285612Sdelphij	return (KBD_IS_ACTIVE(kbd) ? c : -1);
546285612Sdelphij}
547285612Sdelphij
548285612Sdelphij/* check if data is waiting */
549285612Sdelphijstatic int
550285612Sdelphijatkbd_check(keyboard_t *kbd)
551285612Sdelphij{
552285612Sdelphij	if (!KBD_IS_ACTIVE(kbd))
553285612Sdelphij		return FALSE;
554285612Sdelphij	return kbdc_data_ready(((atkbd_state_t *)kbd->kb_data)->kbdc);
555285612Sdelphij}
556285612Sdelphij
557285612Sdelphij/* read char from the keyboard */
55854359Srobertostatic u_int
55954359Srobertoatkbd_read_char(keyboard_t *kbd, int wait)
560330141Sdelphij{
561330141Sdelphij	atkbd_state_t *state;
562330141Sdelphij	u_int action;
563330141Sdelphij	int scancode;
564285612Sdelphij	int keycode;
565285612Sdelphij
566285612Sdelphij	state = (atkbd_state_t *)kbd->kb_data;
567285612Sdelphijnext_code:
568285612Sdelphij	/* do we have a composed char to return? */
569285612Sdelphij	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
570285612Sdelphij		action = state->ks_composed_char;
571285612Sdelphij		state->ks_composed_char = 0;
572285612Sdelphij		if (action > UCHAR_MAX)
573285612Sdelphij			return ERRKEY;
574285612Sdelphij		return action;
575285612Sdelphij	}
576285612Sdelphij
577285612Sdelphij	/* see if there is something in the keyboard port */
578285612Sdelphij	if (wait) {
579285612Sdelphij		do {
580285612Sdelphij			scancode = read_kbd_data(state->kbdc);
581285612Sdelphij		} while (scancode == -1);
582285612Sdelphij	} else {
583285612Sdelphij		scancode = read_kbd_data_no_wait(state->kbdc);
584285612Sdelphij		if (scancode == -1)
585285612Sdelphij			return NOKEY;
586285612Sdelphij	}
587285612Sdelphij	++kbd->kb_count;
588285612Sdelphij
589285612Sdelphij#if KBDIO_DEBUG >= 10
590285612Sdelphij	printf("atkbd_read_char(): scancode:0x%x\n", scancode);
591285612Sdelphij#endif
592285612Sdelphij
593285612Sdelphij	/* return the byte as is for the K_RAW mode */
594285612Sdelphij	if (state->ks_mode == K_RAW)
595285612Sdelphij		return scancode;
596285612Sdelphij
597285612Sdelphij	/* translate the scan code into a keycode */
598285612Sdelphij	keycode = scancode & 0x7F;
59954359Sroberto	switch (state->ks_prefix) {
60054359Sroberto	case 0x00:	/* normal scancode */
601285612Sdelphij		switch(scancode) {
602285612Sdelphij		case 0xB8:	/* left alt (compose key) released */
603285612Sdelphij			if (state->ks_flags & COMPOSE) {
604285612Sdelphij				state->ks_flags &= ~COMPOSE;
605285612Sdelphij				if (state->ks_composed_char > UCHAR_MAX)
606285612Sdelphij					state->ks_composed_char = 0;
607285612Sdelphij			}
60854359Sroberto			break;
609285612Sdelphij		case 0x38:	/* left alt (compose key) pressed */
610285612Sdelphij			if (!(state->ks_flags & COMPOSE)) {
61154359Sroberto				state->ks_flags |= COMPOSE;
612285612Sdelphij				state->ks_composed_char = 0;
613285612Sdelphij			}
614285612Sdelphij			break;
615285612Sdelphij		case 0xE0:
616285612Sdelphij		case 0xE1:
617285612Sdelphij			state->ks_prefix = scancode;
618285612Sdelphij			goto next_code;
61954359Sroberto		}
620285612Sdelphij		break;
621285612Sdelphij	case 0xE0:      /* 0xE0 prefix */
622285612Sdelphij		state->ks_prefix = 0;
623285612Sdelphij		switch (keycode) {
624285612Sdelphij		case 0x1C:	/* right enter key */
625285612Sdelphij			keycode = 0x59;
626285612Sdelphij			break;
627285612Sdelphij		case 0x1D:	/* right ctrl key */
628285612Sdelphij			keycode = 0x5A;
629285612Sdelphij			break;
630285612Sdelphij		case 0x35:	/* keypad divide key */
631285612Sdelphij	    		keycode = 0x5B;
632285612Sdelphij	    		break;
633285612Sdelphij		case 0x37:	/* print scrn key */
634285612Sdelphij	    		keycode = 0x5C;
635285612Sdelphij	    		break;
636285612Sdelphij		case 0x38:	/* right alt key (alt gr) */
637285612Sdelphij	    		keycode = 0x5D;
638285612Sdelphij	    		break;
639285612Sdelphij		case 0x46:	/* ctrl-pause/break on AT 101 (see below) */
640285612Sdelphij			keycode = 0x68;
64154359Sroberto	    		break;
642285612Sdelphij		case 0x47:	/* grey home key */
643285612Sdelphij	    		keycode = 0x5E;
644285612Sdelphij	    		break;
645285612Sdelphij		case 0x48:	/* grey up arrow key */
64654359Sroberto	    		keycode = 0x5F;
647285612Sdelphij	    		break;
648285612Sdelphij		case 0x49:	/* grey page up key */
649285612Sdelphij	    		keycode = 0x60;
650285612Sdelphij	    		break;
651285612Sdelphij		case 0x4B:	/* grey left arrow key */
652285612Sdelphij	    		keycode = 0x61;
653285612Sdelphij	    		break;
654285612Sdelphij		case 0x4D:	/* grey right arrow key */
655285612Sdelphij	    		keycode = 0x62;
65654359Sroberto	    		break;
657285612Sdelphij		case 0x4F:	/* grey end key */
658285612Sdelphij	    		keycode = 0x63;
659285612Sdelphij	    		break;
660285612Sdelphij		case 0x50:	/* grey down arrow key */
661285612Sdelphij	    		keycode = 0x64;
662285612Sdelphij	    		break;
663285612Sdelphij		case 0x51:	/* grey page down key */
664285612Sdelphij	    		keycode = 0x65;
665285612Sdelphij	    		break;
66654359Sroberto		case 0x52:	/* grey insert key */
667285612Sdelphij	    		keycode = 0x66;
668285612Sdelphij	    		break;
66954359Sroberto		case 0x53:	/* grey delete key */
670285612Sdelphij	    		keycode = 0x67;
671285612Sdelphij	    		break;
672285612Sdelphij		/* the following 3 are only used on the MS "Natural" keyboard */
673285612Sdelphij		case 0x5b:	/* left Window key */
674285612Sdelphij	    		keycode = 0x69;
675285612Sdelphij	    		break;
676285612Sdelphij		case 0x5c:	/* right Window key */
677285612Sdelphij	    		keycode = 0x6a;
678285612Sdelphij	    		break;
679285612Sdelphij		case 0x5d:	/* menu key */
680285612Sdelphij	    		keycode = 0x6b;
681285612Sdelphij	    		break;
682285612Sdelphij		default:	/* ignore everything else */
683285612Sdelphij	    		goto next_code;
684285612Sdelphij		}
685285612Sdelphij		break;
686285612Sdelphij    	case 0xE1:	/* 0xE1 prefix */
687285612Sdelphij		/*
688285612Sdelphij		 * The pause/break key on the 101 keyboard produces:
689285612Sdelphij		 * E1-1D-45 E1-9D-C5
690285612Sdelphij		 * Ctrl-pause/break produces:
691285612Sdelphij		 * E0-46 E0-C6 (See above.)
69254359Sroberto		 */
693285612Sdelphij		state->ks_prefix = 0;
69454359Sroberto		if (keycode == 0x1D)
69554359Sroberto	    		state->ks_prefix = 0x1D;
696285612Sdelphij		goto next_code;
697285612Sdelphij		/* NOT REACHED */
698260639Sdelphij    	case 0x1D:	/* pause / break */
699285612Sdelphij		state->ks_prefix = 0;
700285612Sdelphij		if (keycode != 0x45)
701285612Sdelphij			goto next_code;
702285612Sdelphij		keycode = 0x68;
703285612Sdelphij		break;
704285612Sdelphij	}
705285612Sdelphij
706285612Sdelphij	if (kbd->kb_type == KB_84) {
707285612Sdelphij		switch (keycode) {
708285612Sdelphij		case 0x37:	/* *(numpad)/print screen */
709285612Sdelphij			if (state->ks_flags & SHIFTS)
710285612Sdelphij	    			keycode = 0x5c;	/* print screen */
711285612Sdelphij			break;
712285612Sdelphij		case 0x45:	/* num lock/pause */
713285612Sdelphij			if (state->ks_flags & CTLS)
714285612Sdelphij				keycode = 0x68;	/* pause */
715285612Sdelphij			break;
716285612Sdelphij		case 0x46:	/* scroll lock/break */
717285612Sdelphij			if (state->ks_flags & CTLS)
718285612Sdelphij				keycode = 0x6c;	/* break */
719285612Sdelphij			break;
720285612Sdelphij		}
721285612Sdelphij	} else if (kbd->kb_type == KB_101) {
722285612Sdelphij		switch (keycode) {
723285612Sdelphij		case 0x5c:	/* print screen */
724285612Sdelphij			if (state->ks_flags & ALTS)
725285612Sdelphij				keycode = 0x54;	/* sysrq */
726285612Sdelphij			break;
727285612Sdelphij		case 0x68:	/* pause/break */
728285612Sdelphij			if (state->ks_flags & CTLS)
729285612Sdelphij				keycode = 0x6c;	/* break */
730285612Sdelphij			break;
731330141Sdelphij		}
732330141Sdelphij	}
733330141Sdelphij
734330141Sdelphij	/* return the key code in the K_CODE mode */
735330141Sdelphij	if (state->ks_mode == K_CODE)
736330141Sdelphij		return (keycode | (scancode & 0x80));
737330141Sdelphij
738330141Sdelphij	/* compose a character code */
739330141Sdelphij	if (state->ks_flags & COMPOSE) {
740330141Sdelphij		switch (keycode | (scancode & 0x80)) {
741330141Sdelphij		/* key pressed, process it */
742330141Sdelphij		case 0x47: case 0x48: case 0x49:	/* keypad 7,8,9 */
743330141Sdelphij			state->ks_composed_char *= 10;
744330141Sdelphij			state->ks_composed_char += keycode - 0x40;
745338531Sdelphij			if (state->ks_composed_char > UCHAR_MAX)
746285612Sdelphij				return ERRKEY;
747285612Sdelphij			goto next_code;
748285612Sdelphij		case 0x4B: case 0x4C: case 0x4D:	/* keypad 4,5,6 */
749285612Sdelphij			state->ks_composed_char *= 10;
750285612Sdelphij			state->ks_composed_char += keycode - 0x47;
751285612Sdelphij			if (state->ks_composed_char > UCHAR_MAX)
752285612Sdelphij				return ERRKEY;
753285612Sdelphij			goto next_code;
754285612Sdelphij		case 0x4F: case 0x50: case 0x51:	/* keypad 1,2,3 */
755285612Sdelphij			state->ks_composed_char *= 10;
756285612Sdelphij			state->ks_composed_char += keycode - 0x4E;
757285612Sdelphij			if (state->ks_composed_char > UCHAR_MAX)
758285612Sdelphij				return ERRKEY;
759285612Sdelphij			goto next_code;
760285612Sdelphij		case 0x52:				/* keypad 0 */
761285612Sdelphij			state->ks_composed_char *= 10;
762285612Sdelphij			if (state->ks_composed_char > UCHAR_MAX)
763285612Sdelphij				return ERRKEY;
764285612Sdelphij			goto next_code;
765285612Sdelphij
766285612Sdelphij		/* key released, no interest here */
767285612Sdelphij		case 0xC7: case 0xC8: case 0xC9:	/* keypad 7,8,9 */
768285612Sdelphij		case 0xCB: case 0xCC: case 0xCD:	/* keypad 4,5,6 */
769285612Sdelphij		case 0xCF: case 0xD0: case 0xD1:	/* keypad 1,2,3 */
770285612Sdelphij		case 0xD2:				/* keypad 0 */
771285612Sdelphij			goto next_code;
772285612Sdelphij
773285612Sdelphij		case 0x38:				/* left alt key */
774285612Sdelphij			break;
775285612Sdelphij
776285612Sdelphij		default:
777285612Sdelphij			if (state->ks_composed_char > 0) {
778285612Sdelphij				state->ks_flags &= ~COMPOSE;
779285612Sdelphij				state->ks_composed_char = 0;
780285612Sdelphij				return ERRKEY;
781285612Sdelphij			}
782285612Sdelphij			break;
783285612Sdelphij		}
784285612Sdelphij	}
785285612Sdelphij
786285612Sdelphij	/* keycode to key action */
787285612Sdelphij	action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
788285612Sdelphij				  &state->ks_state, &state->ks_accents);
789285612Sdelphij	if (action == NOKEY)
790285612Sdelphij		goto next_code;
791285612Sdelphij	else
792182007Sroberto		return action;
793285612Sdelphij}
794285612Sdelphij
795285612Sdelphij/* check if char is waiting */
79654359Srobertostatic int
797285612Sdelphijatkbd_check_char(keyboard_t *kbd)
798285612Sdelphij{
79982498Sroberto	atkbd_state_t *state;
800285612Sdelphij
801285612Sdelphij	if (!KBD_IS_ACTIVE(kbd))
802285612Sdelphij		return FALSE;
803285612Sdelphij	state = (atkbd_state_t *)kbd->kb_data;
80482498Sroberto	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0))
805285612Sdelphij		return TRUE;
80654359Sroberto	return kbdc_data_ready(state->kbdc);
807285612Sdelphij}
808285612Sdelphij
809285612Sdelphij/* some useful control functions */
810285612Sdelphijstatic int
811285612Sdelphijatkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
812285612Sdelphij{
813285612Sdelphij	/* trasnlate LED_XXX bits into the device specific bits */
814285612Sdelphij	static u_char ledmap[8] = {
815285612Sdelphij		0, 4, 2, 6, 1, 5, 3, 7,
816285612Sdelphij	};
81754359Sroberto	atkbd_state_t *state = kbd->kb_data;
818285612Sdelphij	int error;
819285612Sdelphij	int s;
82054359Sroberto	int i;
821285612Sdelphij
822285612Sdelphij	s = spltty();
82354359Sroberto	switch (cmd) {
824285612Sdelphij
825285612Sdelphij	case KDGKBMODE:		/* get keyboard mode */
826132451Sroberto		*(int *)arg = state->ks_mode;
827285612Sdelphij		break;
828285612Sdelphij	case KDSKBMODE:		/* set keyboard mode */
82954359Sroberto		switch (*(int *)arg) {
830285612Sdelphij		case K_XLATE:
831285612Sdelphij			if (state->ks_mode != K_XLATE) {
832285612Sdelphij				/* make lock key state and LED state match */
833285612Sdelphij				state->ks_state &= ~LOCK_MASK;
834285612Sdelphij				state->ks_state |= KBD_LED_VAL(kbd);
835285612Sdelphij			}
836285612Sdelphij			/* FALLTHROUGH */
837285612Sdelphij		case K_RAW:
838285612Sdelphij		case K_CODE:
839285612Sdelphij			if (state->ks_mode != *(int *)arg) {
840285612Sdelphij				atkbd_clear_state(kbd);
841285612Sdelphij				state->ks_mode = *(int *)arg;
842285612Sdelphij			}
843285612Sdelphij			break;
844285612Sdelphij		default:
845285612Sdelphij			splx(s);
846285612Sdelphij			return EINVAL;
847285612Sdelphij		}
848285612Sdelphij		break;
849285612Sdelphij
850285612Sdelphij	case KDGETLED:		/* get keyboard LED */
851285612Sdelphij		*(int *)arg = KBD_LED_VAL(kbd);
852285612Sdelphij		break;
853285612Sdelphij	case KDSETLED:		/* set keyboard LED */
854285612Sdelphij		/* NOTE: lock key state in ks_state won't be changed */
855285612Sdelphij		if (*(int *)arg & ~LOCK_MASK) {
856285612Sdelphij			splx(s);
857285612Sdelphij			return EINVAL;
858285612Sdelphij		}
859285612Sdelphij		i = *(int *)arg;
860285612Sdelphij		/* replace CAPS LED with ALTGR LED for ALTGR keyboards */
861285612Sdelphij		if (state->ks_mode == K_XLATE &&
862285612Sdelphij		    kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
863285612Sdelphij			if (i & ALKED)
86454359Sroberto				i |= CLKED;
865285612Sdelphij			else
866285612Sdelphij				i &= ~CLKED;
867285612Sdelphij		}
868285612Sdelphij		if (KBD_HAS_DEVICE(kbd)) {
86954359Sroberto			error = write_kbd(state->kbdc, KBDC_SET_LEDS,
870285612Sdelphij					  ledmap[i & LED_MASK]);
871285612Sdelphij			if (error) {
872285612Sdelphij				splx(s);
873285612Sdelphij				return error;
874285612Sdelphij			}
875285612Sdelphij		}
876285612Sdelphij		KBD_LED_VAL(kbd) = *(int *)arg;
877285612Sdelphij		break;
878285612Sdelphij
879285612Sdelphij	case KDGKBSTATE:	/* get lock key state */
880285612Sdelphij		*(int *)arg = state->ks_state & LOCK_MASK;
881285612Sdelphij		break;
88254359Sroberto	case KDSKBSTATE:	/* set lock key state */
883285612Sdelphij		if (*(int *)arg & ~LOCK_MASK) {
884285612Sdelphij			splx(s);
885285612Sdelphij			return EINVAL;
886285612Sdelphij		}
887285612Sdelphij		state->ks_state &= ~LOCK_MASK;
888285612Sdelphij		state->ks_state |= *(int *)arg;
889285612Sdelphij		splx(s);
890285612Sdelphij		/* set LEDs and quit */
891285612Sdelphij		return atkbd_ioctl(kbd, KDSETLED, arg);
892285612Sdelphij
893285612Sdelphij	case KDSETREPEAT:	/* set keyboard repeat rate (new interface) */
894285612Sdelphij		splx(s);
895285612Sdelphij		if (!KBD_HAS_DEVICE(kbd))
896285612Sdelphij			return 0;
897285612Sdelphij		i = typematic(((int *)arg)[0], ((int *)arg)[1]);
898285612Sdelphij		error = write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, i);
899285612Sdelphij		if (error == 0) {
900285612Sdelphij			kbd->kb_delay1 = typematic_delay(i);
901285612Sdelphij			kbd->kb_delay2 = typematic_rate(i);
902285612Sdelphij		}
903285612Sdelphij		return error;
904285612Sdelphij
905285612Sdelphij	case KDSETRAD:		/* set keyboard repeat rate (old interface) */
906285612Sdelphij		splx(s);
907285612Sdelphij		if (!KBD_HAS_DEVICE(kbd))
908285612Sdelphij			return 0;
909285612Sdelphij		error = write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, *(int *)arg);
910285612Sdelphij		if (error == 0) {
911285612Sdelphij			kbd->kb_delay1 = typematic_delay(*(int *)arg);
912285612Sdelphij			kbd->kb_delay2 = typematic_rate(*(int *)arg);
913285612Sdelphij		}
914285612Sdelphij		return error;
915285612Sdelphij
916285612Sdelphij	case PIO_KEYMAP:	/* set keyboard translation table */
917285612Sdelphij	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
918285612Sdelphij	case PIO_DEADKEYMAP:	/* set accent key translation table */
919285612Sdelphij		state->ks_accents = 0;
920285612Sdelphij		/* FALLTHROUGH */
921285612Sdelphij	default:
922285612Sdelphij		splx(s);
923285612Sdelphij		return genkbd_commonioctl(kbd, cmd, arg);
924285612Sdelphij	}
925285612Sdelphij
926285612Sdelphij	splx(s);
927285612Sdelphij	return 0;
928285612Sdelphij}
929285612Sdelphij
930285612Sdelphij/* lock the access to the keyboard */
931330141Sdelphijstatic int
932285612Sdelphijatkbd_lock(keyboard_t *kbd, int lock)
933285612Sdelphij{
934285612Sdelphij	return kbdc_lock(((atkbd_state_t *)kbd->kb_data)->kbdc, lock);
935330141Sdelphij}
936330141Sdelphij
937330141Sdelphij/* clear the internal state of the keyboard */
938330141Sdelphijstatic void
939285612Sdelphijatkbd_clear_state(keyboard_t *kbd)
940285612Sdelphij{
941338531Sdelphij	atkbd_state_t *state;
942330141Sdelphij
943285612Sdelphij	state = (atkbd_state_t *)kbd->kb_data;
944330141Sdelphij	state->ks_flags = 0;
945330141Sdelphij	state->ks_polling = 0;
946330141Sdelphij	state->ks_state &= LOCK_MASK;	/* preserve locking key state */
947330141Sdelphij	state->ks_accents = 0;
948330141Sdelphij	state->ks_composed_char = 0;
949330141Sdelphij#if 0
950330141Sdelphij	state->ks_prefix = 0; /* XXX */
951330141Sdelphij#endif
952330141Sdelphij}
953330141Sdelphij
954330141Sdelphij/* save the internal state */
955330141Sdelphijstatic int
956330141Sdelphijatkbd_get_state(keyboard_t *kbd, void *buf, size_t len)
957330141Sdelphij{
958330141Sdelphij	if (len == 0)
959330141Sdelphij		return sizeof(atkbd_state_t);
960330141Sdelphij	if (len < sizeof(atkbd_state_t))
961330141Sdelphij		return -1;
962330141Sdelphij	bcopy(kbd->kb_data, buf, sizeof(atkbd_state_t));
963330141Sdelphij	return 0;
964285612Sdelphij}
965285612Sdelphij
966330141Sdelphij/* set the internal state */
967285612Sdelphijstatic int
968285612Sdelphijatkbd_set_state(keyboard_t *kbd, void *buf, size_t len)
969330141Sdelphij{
970330141Sdelphij	if (len < sizeof(atkbd_state_t))
971330141Sdelphij		return ENOMEM;
972330141Sdelphij	if (((atkbd_state_t *)kbd->kb_data)->kbdc
973330141Sdelphij		!= ((atkbd_state_t *)buf)->kbdc)
974285612Sdelphij		return ENOMEM;
975285612Sdelphij	bcopy(buf, kbd->kb_data, sizeof(atkbd_state_t));
976285612Sdelphij	return 0;
977285612Sdelphij}
978285612Sdelphij
979285612Sdelphijstatic int
980285612Sdelphijatkbd_poll(keyboard_t *kbd, int on)
981285612Sdelphij{
982285612Sdelphij	atkbd_state_t *state;
983285612Sdelphij	int s;
984285612Sdelphij
985285612Sdelphij	state = (atkbd_state_t *)kbd->kb_data;
986285612Sdelphij	s = spltty();
987285612Sdelphij	if (on)
988285612Sdelphij		++state->ks_polling;
989285612Sdelphij	else
990285612Sdelphij		--state->ks_polling;
991285612Sdelphij	splx(s);
992285612Sdelphij	return 0;
993285612Sdelphij}
994285612Sdelphij
995285612Sdelphij/* local functions */
996285612Sdelphij
997285612Sdelphijstatic int
998285612Sdelphijget_typematic(keyboard_t *kbd)
999285612Sdelphij{
1000285612Sdelphij#ifdef __i386__
1001285612Sdelphij	/*
1002285612Sdelphij	 * Only some systems allow us to retrieve the keyboard repeat
1003285612Sdelphij	 * rate previously set via the BIOS...
1004285612Sdelphij	 */
1005285612Sdelphij	struct vm86frame vmf;
1006285612Sdelphij	u_int32_t p;
1007285612Sdelphij
1008285612Sdelphij	bzero(&vmf, sizeof(vmf));
1009285612Sdelphij	vmf.vmf_ax = 0xc000;
1010285612Sdelphij	vm86_intcall(0x15, &vmf);
1011285612Sdelphij	if ((vmf.vmf_eflags & PSL_C) || vmf.vmf_ah)
1012285612Sdelphij		return ENODEV;
1013285612Sdelphij        p = BIOS_PADDRTOVADDR(((u_int32_t)vmf.vmf_es << 4) + vmf.vmf_bx);
1014285612Sdelphij	if ((readb(p + 6) & 0x40) == 0)	/* int 16, function 0x09 supported? */
1015285612Sdelphij		return ENODEV;
1016285612Sdelphij	vmf.vmf_ax = 0x0900;
1017285612Sdelphij	vm86_intcall(0x16, &vmf);
1018285612Sdelphij	if ((vmf.vmf_al & 0x08) == 0)	/* int 16, function 0x0306 supported? */
1019285612Sdelphij		return ENODEV;
1020285612Sdelphij	vmf.vmf_ax = 0x0306;
1021285612Sdelphij	vm86_intcall(0x16, &vmf);
1022285612Sdelphij	kbd->kb_delay1 = typematic_delay(vmf.vmf_bh << 5);
1023285612Sdelphij	kbd->kb_delay2 = typematic_rate(vmf.vmf_bl);
1024285612Sdelphij	return 0;
1025285612Sdelphij#else
1026285612Sdelphij	return ENODEV;
1027285612Sdelphij#endif /* __i386__ */
1028132451Sroberto}
1029285612Sdelphij
1030285612Sdelphijstatic int
1031182007Srobertosetup_kbd_port(KBDC kbdc, int port, int intr)
1032182007Sroberto{
1033285612Sdelphij	if (!set_controller_command_byte(kbdc,
1034285612Sdelphij		KBD_KBD_CONTROL_BITS,
1035285612Sdelphij		((port) ? KBD_ENABLE_KBD_PORT : KBD_DISABLE_KBD_PORT)
1036285612Sdelphij		    | ((intr) ? KBD_ENABLE_KBD_INT : KBD_DISABLE_KBD_INT)))
1037285612Sdelphij		return 1;
1038285612Sdelphij	return 0;
1039285612Sdelphij}
1040285612Sdelphij
104154359Srobertostatic int
1042285612Sdelphijget_kbd_echo(KBDC kbdc)
1043285612Sdelphij{
1044285612Sdelphij	/* enable the keyboard port, but disable the keyboard intr. */
1045285612Sdelphij	if (setup_kbd_port(kbdc, TRUE, FALSE))
1046285612Sdelphij		/* CONTROLLER ERROR: there is very little we can do... */
1047285612Sdelphij		return ENXIO;
1048285612Sdelphij
1049285612Sdelphij	/* see if something is present */
105054359Sroberto	write_kbd_command(kbdc, KBDC_ECHO);
1051285612Sdelphij	if (read_kbd_data(kbdc) != KBD_ECHO) {
1052285612Sdelphij		empty_both_buffers(kbdc, 10);
1053285612Sdelphij		test_controller(kbdc);
105454359Sroberto		test_kbd_port(kbdc);
105554359Sroberto		return ENXIO;
1056182007Sroberto	}
1057285612Sdelphij
1058285612Sdelphij	/* enable the keyboard port and intr. */
1059285612Sdelphij	if (setup_kbd_port(kbdc, TRUE, TRUE)) {
1060285612Sdelphij		/*
1061285612Sdelphij		 * CONTROLLER ERROR
1062285612Sdelphij		 * This is serious; the keyboard intr is left disabled!
1063285612Sdelphij		 */
1064285612Sdelphij		return ENXIO;
1065285612Sdelphij	}
106654359Sroberto
1067285612Sdelphij	return 0;
1068285612Sdelphij}
1069285612Sdelphij
1070285612Sdelphijstatic int
1071285612Sdelphijprobe_keyboard(KBDC kbdc, int flags)
1072285612Sdelphij{
1073285612Sdelphij	/*
1074285612Sdelphij	 * Don't try to print anything in this function.  The low-level
1075285612Sdelphij	 * console may not have been initialized yet...
1076182007Sroberto	 */
1077285612Sdelphij	int err;
1078285612Sdelphij	int c;
107954359Sroberto	int m;
1080182007Sroberto
1081285612Sdelphij	if (!kbdc_lock(kbdc, TRUE)) {
1082285612Sdelphij		/* driver error? */
1083285612Sdelphij		return ENXIO;
1084285612Sdelphij	}
1085285612Sdelphij
1086285612Sdelphij	/* temporarily block data transmission from the keyboard */
1087285612Sdelphij	write_controller_command(kbdc, KBDC_DISABLE_KBD_PORT);
1088285612Sdelphij
1089182007Sroberto	/* flush any noise in the buffer */
1090285612Sdelphij	empty_both_buffers(kbdc, 100);
1091285612Sdelphij
1092285612Sdelphij	/* save the current keyboard controller command byte */
1093285612Sdelphij	m = kbdc_get_device_mask(kbdc) & ~KBD_KBD_CONTROL_BITS;
1094285612Sdelphij	c = get_controller_command_byte(kbdc);
1095285612Sdelphij	if (c == -1) {
109654359Sroberto		/* CONTROLLER ERROR */
1097285612Sdelphij		kbdc_set_device_mask(kbdc, m);
1098285612Sdelphij		kbdc_lock(kbdc, FALSE);
109954359Sroberto		return ENXIO;
1100285612Sdelphij	}
1101285612Sdelphij
110254359Sroberto	/*
1103330141Sdelphij	 * The keyboard may have been screwed up by the boot block.
1104330141Sdelphij	 * We may just be able to recover from error by testing the controller
1105330141Sdelphij	 * and the keyboard port. The controller command byte needs to be
1106330141Sdelphij	 * saved before this recovery operation, as some controllers seem
1107330141Sdelphij	 * to set the command byte to particular values.
1108330141Sdelphij	 */
1109330141Sdelphij	test_controller(kbdc);
1110330141Sdelphij	test_kbd_port(kbdc);
111154359Sroberto
1112330141Sdelphij	err = get_kbd_echo(kbdc);
1113330141Sdelphij
1114330141Sdelphij	/*
1115330141Sdelphij	 * Even if the keyboard doesn't seem to be present (err != 0),
1116330141Sdelphij	 * we shall enable the keyboard port and interrupt so that
1117330141Sdelphij	 * the driver will be operable when the keyboard is attached
1118330141Sdelphij	 * to the system later.  It is NOT recommended to hot-plug
1119330141Sdelphij	 * the AT keyboard, but many people do so...
1120330141Sdelphij	 */
1121330141Sdelphij	kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS);
1122330141Sdelphij	setup_kbd_port(kbdc, TRUE, TRUE);
1123330141Sdelphij#if 0
1124330141Sdelphij	if (err == 0) {
1125330141Sdelphij		kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS);
1126285612Sdelphij	} else {
1127285612Sdelphij		/* try to restore the command byte as before */
1128285612Sdelphij		set_controller_command_byte(kbdc, 0xff, c);
112954359Sroberto		kbdc_set_device_mask(kbdc, m);
1130330141Sdelphij	}
1131330141Sdelphij#endif
1132330141Sdelphij
1133330141Sdelphij	kbdc_lock(kbdc, FALSE);
1134330141Sdelphij	return err;
1135330141Sdelphij}
1136330141Sdelphij
1137330141Sdelphijstatic int
1138330141Sdelphijinit_keyboard(KBDC kbdc, int *type, int flags)
1139330141Sdelphij{
1140330141Sdelphij	int codeset;
1141330141Sdelphij	int id;
1142285612Sdelphij	int c;
1143285612Sdelphij
1144285612Sdelphij	if (!kbdc_lock(kbdc, TRUE)) {
1145285612Sdelphij		/* driver error? */
1146285612Sdelphij		return EIO;
1147285612Sdelphij	}
1148285612Sdelphij
114982498Sroberto	/* temporarily block data transmission from the keyboard */
1150285612Sdelphij	write_controller_command(kbdc, KBDC_DISABLE_KBD_PORT);
1151285612Sdelphij
1152285612Sdelphij	/* save the current controller command byte */
1153285612Sdelphij	empty_both_buffers(kbdc, 200);
115482498Sroberto	c = get_controller_command_byte(kbdc);
1155285612Sdelphij	if (c == -1) {
1156285612Sdelphij		/* CONTROLLER ERROR */
115754359Sroberto		kbdc_lock(kbdc, FALSE);
1158285612Sdelphij		printf("atkbd: unable to get the current command byte value.\n");
1159285612Sdelphij		return EIO;
1160285612Sdelphij	}
1161285612Sdelphij	if (bootverbose)
1162285612Sdelphij		printf("atkbd: the current kbd controller command byte %04x\n",
1163285612Sdelphij		       c);
1164285612Sdelphij#if 0
1165285612Sdelphij	/* override the keyboard lock switch */
1166285612Sdelphij	c |= KBD_OVERRIDE_KBD_LOCK;
1167285612Sdelphij#endif
1168285612Sdelphij
1169285612Sdelphij	/* enable the keyboard port, but disable the keyboard intr. */
1170285612Sdelphij	if (setup_kbd_port(kbdc, TRUE, FALSE)) {
1171285612Sdelphij		/* CONTROLLER ERROR: there is very little we can do... */
1172285612Sdelphij		printf("atkbd: unable to set the command byte.\n");
1173285612Sdelphij		kbdc_lock(kbdc, FALSE);
1174285612Sdelphij		return EIO;
1175285612Sdelphij	}
1176285612Sdelphij
1177285612Sdelphij	/*
1178285612Sdelphij	 * Check if we have an XT keyboard before we attempt to reset it.
1179285612Sdelphij	 * The procedure assumes that the keyboard and the controller have
1180285612Sdelphij	 * been set up properly by BIOS and have not been messed up
1181285612Sdelphij	 * during the boot process.
1182285612Sdelphij	 */
1183285612Sdelphij	codeset = -1;
1184285612Sdelphij	if (flags & KB_CONF_ALT_SCANCODESET)
1185285612Sdelphij		/* the user says there is a XT keyboard */
1186285612Sdelphij		codeset = 1;
1187285612Sdelphij#ifdef KBD_DETECT_XT_KEYBOARD
1188285612Sdelphij	else if ((c & KBD_TRANSLATION) == 0) {
1189285612Sdelphij		/* SET_SCANCODE_SET is not always supported; ignore error */
1190285612Sdelphij		if (send_kbd_command_and_data(kbdc, KBDC_SET_SCANCODE_SET, 0)
1191285612Sdelphij			== KBD_ACK)
1192285612Sdelphij			codeset = read_kbd_data(kbdc);
1193285612Sdelphij	}
1194285612Sdelphij	if (bootverbose)
1195285612Sdelphij		printf("atkbd: scancode set %d\n", codeset);
1196285612Sdelphij#endif /* KBD_DETECT_XT_KEYBOARD */
1197285612Sdelphij
1198285612Sdelphij	*type = KB_OTHER;
1199285612Sdelphij	id = get_kbd_id(kbdc);
1200285612Sdelphij	switch(id) {
1201285612Sdelphij	case 0x41ab:	/* 101/102/... Enhanced */
1202285612Sdelphij	case 0x83ab:	/* ditto */
1203285612Sdelphij	case 0x54ab:	/* SpaceSaver */
1204285612Sdelphij	case 0x84ab:	/* ditto */
1205285612Sdelphij#if 0
1206285612Sdelphij	case 0x90ab:	/* 'G' */
1207285612Sdelphij	case 0x91ab:	/* 'P' */
1208285612Sdelphij	case 0x92ab:	/* 'A' */
1209285612Sdelphij#endif
1210285612Sdelphij		*type = KB_101;
1211285612Sdelphij		break;
1212285612Sdelphij	case -1:	/* AT 84 keyboard doesn't return ID */
1213285612Sdelphij		*type = KB_84;
1214285612Sdelphij		break;
1215285612Sdelphij	default:
1216285612Sdelphij		break;
1217285612Sdelphij	}
1218285612Sdelphij	if (bootverbose)
1219285612Sdelphij		printf("atkbd: keyboard ID 0x%x (%d)\n", id, *type);
1220285612Sdelphij
1221285612Sdelphij	/* reset keyboard hardware */
1222285612Sdelphij	if (!(flags & KB_CONF_NO_RESET) && !reset_kbd(kbdc)) {
1223285612Sdelphij		/*
1224285612Sdelphij		 * KEYBOARD ERROR
1225285612Sdelphij		 * Keyboard reset may fail either because the keyboard
1226285612Sdelphij		 * doen't exist, or because the keyboard doesn't pass
1227285612Sdelphij		 * the self-test, or the keyboard controller on the
1228285612Sdelphij		 * motherboard and the keyboard somehow fail to shake hands.
1229285612Sdelphij		 * It is just possible, particularly in the last case,
1230285612Sdelphij		 * that the keyboard controller may be left in a hung state.
1231285612Sdelphij		 * test_controller() and test_kbd_port() appear to bring
1232285612Sdelphij		 * the keyboard controller back (I don't know why and how,
1233285612Sdelphij		 * though.)
1234285612Sdelphij		 */
1235285612Sdelphij		empty_both_buffers(kbdc, 10);
1236285612Sdelphij		test_controller(kbdc);
1237285612Sdelphij		test_kbd_port(kbdc);
1238285612Sdelphij		/*
1239285612Sdelphij		 * We could disable the keyboard port and interrupt... but,
1240285612Sdelphij		 * the keyboard may still exist (see above).
1241285612Sdelphij		 */
1242285612Sdelphij		set_controller_command_byte(kbdc, 0xff, c);
1243285612Sdelphij		kbdc_lock(kbdc, FALSE);
1244285612Sdelphij		if (bootverbose)
1245285612Sdelphij			printf("atkbd: failed to reset the keyboard.\n");
1246285612Sdelphij		return EIO;
1247285612Sdelphij	}
1248285612Sdelphij
1249285612Sdelphij	/*
1250285612Sdelphij	 * Allow us to set the XT_KEYBD flag so that keyboards
1251285612Sdelphij	 * such as those on the IBM ThinkPad laptop computers can be used
1252285612Sdelphij	 * with the standard console driver.
1253285612Sdelphij	 */
1254285612Sdelphij	if (codeset == 1) {
1255285612Sdelphij		if (send_kbd_command_and_data(kbdc,
1256285612Sdelphij			KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) {
1257285612Sdelphij			/* XT kbd doesn't need scan code translation */
1258285612Sdelphij			c &= ~KBD_TRANSLATION;
1259285612Sdelphij		} else {
1260285612Sdelphij			/*
1261285612Sdelphij			 * KEYBOARD ERROR
1262285612Sdelphij			 * The XT kbd isn't usable unless the proper scan
1263285612Sdelphij			 * code set is selected.
1264285612Sdelphij			 */
1265285612Sdelphij			set_controller_command_byte(kbdc, 0xff, c);
1266285612Sdelphij			kbdc_lock(kbdc, FALSE);
1267289997Sglebius			printf("atkbd: unable to set the XT keyboard mode.\n");
1268289997Sglebius			return EIO;
1269285612Sdelphij		}
1270285612Sdelphij	}
1271285612Sdelphij
1272285612Sdelphij#ifdef __alpha__
1273285612Sdelphij	if (send_kbd_command_and_data(
1274285612Sdelphij		kbdc, KBDC_SET_SCANCODE_SET, 2) != KBD_ACK) {
1275285612Sdelphij		printf("atkbd: can't set translation.\n");
1276285612Sdelphij
1277285612Sdelphij	}
1278285612Sdelphij	c |= KBD_TRANSLATION;
1279285612Sdelphij#endif
1280285612Sdelphij
1281285612Sdelphij	/* enable the keyboard port and intr. */
1282285612Sdelphij	if (!set_controller_command_byte(kbdc,
1283285612Sdelphij		KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK,
1284289997Sglebius		(c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK))
1285285612Sdelphij		    | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) {
1286285612Sdelphij		/*
1287285612Sdelphij		 * CONTROLLER ERROR
1288285612Sdelphij		 * This is serious; we are left with the disabled
1289285612Sdelphij		 * keyboard intr.
1290285612Sdelphij		 */
1291285612Sdelphij		set_controller_command_byte(kbdc, 0xff, c);
1292285612Sdelphij		kbdc_lock(kbdc, FALSE);
1293285612Sdelphij		printf("atkbd: unable to enable the keyboard port and intr.\n");
1294285612Sdelphij		return EIO;
1295285612Sdelphij	}
1296285612Sdelphij
1297285612Sdelphij	kbdc_lock(kbdc, FALSE);
1298285612Sdelphij	return 0;
1299285612Sdelphij}
1300285612Sdelphij
1301285612Sdelphijstatic int
1302285612Sdelphijwrite_kbd(KBDC kbdc, int command, int data)
1303285612Sdelphij{
1304285612Sdelphij    int s;
1305285612Sdelphij
1306285612Sdelphij    /* prevent the timeout routine from polling the keyboard */
1307285612Sdelphij    if (!kbdc_lock(kbdc, TRUE))
1308285612Sdelphij	return EBUSY;
1309285612Sdelphij
1310285612Sdelphij    /* disable the keyboard and mouse interrupt */
1311285612Sdelphij    s = spltty();
1312285612Sdelphij#if 0
1313285612Sdelphij    c = get_controller_command_byte(kbdc);
1314285612Sdelphij    if ((c == -1)
1315285612Sdelphij	|| !set_controller_command_byte(kbdc,
1316285612Sdelphij            kbdc_get_device_mask(kbdc),
1317285612Sdelphij            KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
1318285612Sdelphij                | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1319285612Sdelphij	/* CONTROLLER ERROR */
1320285612Sdelphij        kbdc_lock(kbdc, FALSE);
1321285612Sdelphij	splx(s);
1322285612Sdelphij	return EIO;
1323285612Sdelphij    }
1324285612Sdelphij    /*
132554359Sroberto     * Now that the keyboard controller is told not to generate
1326285612Sdelphij     * the keyboard and mouse interrupts, call `splx()' to allow
132754359Sroberto     * the other tty interrupts. The clock interrupt may also occur,
1328285612Sdelphij     * but the timeout routine (`scrn_timer()') will be blocked
1329285612Sdelphij     * by the lock flag set via `kbdc_lock()'
1330285612Sdelphij     */
133154359Sroberto    splx(s);
1332285612Sdelphij#endif
1333285612Sdelphij
1334285612Sdelphij    if (send_kbd_command_and_data(kbdc, command, data) != KBD_ACK)
1335285612Sdelphij        send_kbd_command(kbdc, KBDC_ENABLE_KBD);
133654359Sroberto
1337285612Sdelphij#if 0
1338285612Sdelphij    /* restore the interrupts */
1339285612Sdelphij    if (!set_controller_command_byte(kbdc,
1340285612Sdelphij            kbdc_get_device_mask(kbdc),
1341285612Sdelphij	    c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
1342285612Sdelphij	/* CONTROLLER ERROR */
1343285612Sdelphij    }
1344285612Sdelphij#else
1345285612Sdelphij    splx(s);
1346285612Sdelphij#endif
1347285612Sdelphij    kbdc_lock(kbdc, FALSE);
134854359Sroberto
134954359Sroberto    return 0;
135054359Sroberto}
1351285612Sdelphij
1352285612Sdelphijstatic int
1353285612Sdelphijget_kbd_id(KBDC kbdc)
1354285612Sdelphij{
1355285612Sdelphij	int id1, id2;
1356285612Sdelphij
1357285612Sdelphij	empty_both_buffers(kbdc, 10);
1358182007Sroberto	id1 = id2 = -1;
1359285612Sdelphij	if (send_kbd_command(kbdc, KBDC_SEND_DEV_ID) != KBD_ACK)
1360285612Sdelphij		return -1;
1361182007Sroberto
136254359Sroberto	DELAY(10000); 	/* 10 msec delay */
1363132451Sroberto	id1 = read_kbd_data(kbdc);
1364285612Sdelphij	if (id1 != -1)
1365316069Sdelphij		id2 = read_kbd_data(kbdc);
1366316069Sdelphij
1367316069Sdelphij	if ((id1 == -1) || (id2 == -1)) {
1368316069Sdelphij		empty_both_buffers(kbdc, 10);
1369285612Sdelphij		test_controller(kbdc);
1370285612Sdelphij		test_kbd_port(kbdc);
1371285612Sdelphij		return -1;
1372285612Sdelphij	}
1373285612Sdelphij	return ((id2 << 8) | id1);
1374285612Sdelphij}
1375132451Sroberto
1376285612Sdelphijstatic int delays[] = { 250, 500, 750, 1000 };
1377316069Sdelphijstatic int rates[] = {  34,  38,  42,  46,  50,  55,  59,  63,
1378316069Sdelphij			68,  76,  84,  92, 100, 110, 118, 126,
1379316069Sdelphij		       136, 152, 168, 184, 200, 220, 236, 252,
1380316069Sdelphij		       272, 304, 336, 368, 400, 440, 472, 504 };
1381316069Sdelphij
1382316069Sdelphijstatic int
138354359Srobertotypematic_delay(int i)
138454359Sroberto{
1385285612Sdelphij	return delays[(i >> 5) & 3];
1386285612Sdelphij}
1387285612Sdelphij
1388285612Sdelphijstatic int
1389285612Sdelphijtypematic_rate(int i)
1390285612Sdelphij{
1391285612Sdelphij	return rates[i & 0x1f];
139254359Sroberto}
1393132451Sroberto
139454359Srobertostatic int
1395285612Sdelphijtypematic(int delay, int rate)
1396285612Sdelphij{
1397285612Sdelphij	int value;
1398285612Sdelphij	int i;
1399285612Sdelphij
1400285612Sdelphij	for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; --i) {
1401285612Sdelphij		if (delay >= delays[i])
140254359Sroberto			break;
140354359Sroberto	}
140454359Sroberto	value = i << 5;
1405285612Sdelphij	for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; --i) {
1406285612Sdelphij		if (rate >= rates[i])
1407285612Sdelphij			break;
140882498Sroberto	}
1409285612Sdelphij	value |= i;
1410285612Sdelphij	return value;
1411285612Sdelphij}
1412285612Sdelphij