pckbd.c revision 117167
142805Skato/*
242805Skato * Copyright (c) 1999 FreeBSD(98) port team.
342805Skato * All rights reserved.
442805Skato *
542805Skato * Redistribution and use in source and binary forms, with or without
642805Skato * modification, are permitted provided that the following conditions
742805Skato * are met:
842805Skato * 1. Redistributions of source code must retain the above copyright
942805Skato *    notice, this list of conditions and the following disclaimer as
1042805Skato *    the first lines of this file unmodified.
1142805Skato * 2. Redistributions in binary form must reproduce the above copyright
1242805Skato *    notice, this list of conditions and the following disclaimer in the
1342805Skato *    documentation and/or other materials provided with the distribution.
1442805Skato * 3. The name of the author may not be used to endorse or promote products
1542805Skato *    derived from this software without specific prior written permission.
1642805Skato *
1742805Skato * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1842805Skato * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1942805Skato * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2042805Skato * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2142805Skato * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2242805Skato * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2342805Skato * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2442805Skato * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2542805Skato * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2642805Skato * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2742805Skato *
2850477Speter * $FreeBSD: head/sys/pc98/cbus/pckbd.c 117167 2003-07-02 16:09:02Z jhb $
2942795Skato */
3042795Skato
3142795Skato#include "opt_kbd.h"
3242795Skato
3342795Skato#include <sys/param.h>
3442795Skato#include <sys/systm.h>
3542795Skato#include <sys/kernel.h>
3645783Skato#include <sys/module.h>
3742795Skato#include <sys/bus.h>
3845783Skato#include <machine/bus.h>
3945783Skato#include <sys/rman.h>
4067370Skato#include <sys/kbio.h>
4142795Skato
4242795Skato#include <machine/resource.h>
4342795Skato
4442795Skato#include <dev/kbd/kbdreg.h>
4542795Skato
4642795Skato#include <pc98/pc98/pc98.h>
4742795Skato
4845783Skato#include <isa/isavar.h>
4945783Skato
5042795Skato#define DRIVER_NAME		"pckbd"
5142795Skato
5242795Skato/* device configuration flags */
5342795Skato#define KB_CONF_FAIL_IF_NO_KBD	(1 << 0) /* don't install if no kbd is found */
5442795Skato
5545783Skatostatic devclass_t	pckbd_devclass;
5642795Skato
5745783Skatostatic int		pckbdprobe(device_t dev);
5845783Skatostatic int		pckbdattach(device_t dev);
5979702Snyanstatic int		pckbdresume(device_t dev);
6045783Skatostatic void		pckbd_isa_intr(void *arg);
6142795Skato
6245783Skatostatic device_method_t pckbd_methods[] = {
6345783Skato	/* Device interface */
6445783Skato	DEVMETHOD(device_probe,		pckbdprobe),
6545783Skato	DEVMETHOD(device_attach,	pckbdattach),
6679702Snyan	DEVMETHOD(device_resume,	pckbdresume),
6745783Skato	{ 0, 0 }
6845783Skato};
6942795Skato
7045783Skatostatic driver_t pckbd_driver = {
7142795Skato	DRIVER_NAME,
7245783Skato	pckbd_methods,
7350236Skato	1,
7442795Skato};
7542795Skato
7645783SkatoDRIVER_MODULE(pckbd, isa, pckbd_driver, pckbd_devclass, 0, 0);
7745783Skato
7878385Snyanstatic bus_addr_t pckbd_iat[] = {0, 2};
7978385Snyan
8044635Skatostatic int		pckbd_probe_unit(int unit, int port, int irq,
8144635Skato					 int flags);
8250236Skatostatic int		pckbd_attach_unit(int unit, keyboard_t **kbd,
8344635Skato					  int port, int irq, int flags);
8442795Skatostatic timeout_t	pckbd_timeout;
8542795Skato
8642795Skato
8742795Skatostatic int
8845783Skatopckbdprobe(device_t dev)
8942795Skato{
9078385Snyan	struct resource *res;
9178385Snyan	int error, rid;
9278385Snyan
9351276Snyan	/* Check isapnp ids */
9451276Snyan	if (isa_get_vendorid(dev))
9551276Snyan		return (ENXIO);
9651276Snyan
9745783Skato	device_set_desc(dev, "PC-98 Keyboard");
9845783Skato
9978385Snyan	rid = 0;
10078385Snyan	res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, pckbd_iat, 2,
10178385Snyan				  RF_ACTIVE);
10278385Snyan	if (res == NULL)
10378385Snyan		return ENXIO;
10478385Snyan	isa_load_resourcev(res, pckbd_iat, 2);
10578385Snyan
10678385Snyan	error = pckbd_probe_unit(device_get_unit(dev),
10778385Snyan				 isa_get_port(dev),
10878385Snyan				 (1 << isa_get_irq(dev)),
10978385Snyan				 device_get_flags(dev));
11078385Snyan
11178385Snyan	bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
11278385Snyan
11378385Snyan	return (error);
11442795Skato}
11542795Skato
11642795Skatostatic int
11745783Skatopckbdattach(device_t dev)
11842795Skato{
11950236Skato	keyboard_t	*kbd;
12045783Skato	void		*ih;
12145783Skato	struct resource	*res;
12278385Snyan	int		error, rid;
12342795Skato
12478385Snyan	rid = 0;
12578385Snyan	res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, pckbd_iat, 2,
12678385Snyan				  RF_ACTIVE);
12778385Snyan	if (res == NULL)
12878385Snyan		return ENXIO;
12978385Snyan	isa_load_resourcev(res, pckbd_iat, 2);
13045783Skato
13178385Snyan	error = pckbd_attach_unit(device_get_unit(dev), &kbd,
13278385Snyan				  isa_get_port(dev),
13378385Snyan				  (1 << isa_get_irq(dev)),
13478385Snyan				  device_get_flags(dev));
13578385Snyan
13678385Snyan	rid = 0;
13778385Snyan	res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE);
13878385Snyan	if (res == NULL)
13978385Snyan		return ENXIO;
14046759Skato	BUS_SETUP_INTR(device_get_parent(dev), dev, res, INTR_TYPE_TTY,
14178385Snyan		       pckbd_isa_intr, kbd, &ih);
14245783Skato
14379702Snyan	return 0;
14479702Snyan}
14579702Snyan
14679702Snyanstatic int
14779702Snyanpckbdresume(device_t dev)
14879702Snyan{
14979702Snyan	keyboard_t *kbd;
15079702Snyan
15179702Snyan	kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME,
15279702Snyan						 device_get_unit(dev)));
15379702Snyan	if (kbd)
15479702Snyan		(*kbdsw[kbd->kb_index]->clear_state)(kbd);
15579702Snyan
15645783Skato	return (0);
15742795Skato}
15842795Skato
15942795Skatostatic void
16045783Skatopckbd_isa_intr(void *arg)
16142795Skato{
16250236Skato        keyboard_t	*kbd = arg;
16342795Skato
16444635Skato	(*kbdsw[kbd->kb_index]->intr)(kbd, NULL);
16542795Skato}
16642795Skato
16742795Skatostatic int
16844635Skatopckbd_probe_unit(int unit, int port, int irq, int flags)
16942795Skato{
17042795Skato	keyboard_switch_t *sw;
17142795Skato	int args[2];
17244635Skato	int error;
17342795Skato
17442795Skato	sw = kbd_get_switch(DRIVER_NAME);
17542795Skato	if (sw == NULL)
17642795Skato		return ENXIO;
17742795Skato
17842795Skato	args[0] = port;
17942795Skato	args[1] = irq;
18044635Skato	error = (*sw->probe)(unit, args, flags);
18144635Skato	if (error)
18244635Skato		return error;
18344635Skato	return 0;
18442795Skato}
18542795Skato
18642795Skatostatic int
18750236Skatopckbd_attach_unit(int unit, keyboard_t **kbd, int port, int irq, int flags)
18842795Skato{
18942795Skato	keyboard_switch_t *sw;
19044635Skato	int args[2];
19142795Skato	int error;
19242795Skato
19342795Skato	sw = kbd_get_switch(DRIVER_NAME);
19442795Skato	if (sw == NULL)
19542795Skato		return ENXIO;
19642795Skato
19742795Skato	/* reset, initialize and enable the device */
19844635Skato	args[0] = port;
19944635Skato	args[1] = irq;
20050236Skato	*kbd = NULL;
20144635Skato	error = (*sw->probe)(unit, args, flags);
20242795Skato	if (error)
20344635Skato		return error;
20450236Skato	error = (*sw->init)(unit, kbd, args, flags);
20544635Skato	if (error)
20644635Skato		return error;
20750236Skato	(*sw->enable)(*kbd);
20842795Skato
20942795Skato#ifdef KBD_INSTALL_CDEV
21042795Skato	/* attach a virtual keyboard cdev */
21150236Skato	error = kbd_attach(*kbd);
21242795Skato	if (error)
21342795Skato		return error;
21442795Skato#endif /* KBD_INSTALL_CDEV */
21542795Skato
21642795Skato	/*
21742795Skato	 * This is a kludge to compensate for lost keyboard interrupts.
21842795Skato	 * A similar code used to be in syscons. See below. XXX
21942795Skato	 */
22050236Skato	pckbd_timeout(*kbd);
22142795Skato
22242795Skato	if (bootverbose)
22350236Skato		(*sw->diag)(*kbd, bootverbose);
22442795Skato
22542795Skato	return 0;
22642795Skato}
22742795Skato
22842795Skatostatic void
22942795Skatopckbd_timeout(void *arg)
23042795Skato{
23142795Skato	keyboard_t *kbd;
23242795Skato	int s;
23342795Skato
23442795Skato	/* The following comments are extracted from syscons.c (1.287) */
23542795Skato	/*
23642795Skato	 * With release 2.1 of the Xaccel server, the keyboard is left
23742795Skato	 * hanging pretty often. Apparently an interrupt from the
23842795Skato	 * keyboard is lost, and I don't know why (yet).
23942795Skato	 * This ugly hack calls scintr if input is ready for the keyboard
24042795Skato	 * and conveniently hides the problem.			XXX
24142795Skato	 */
24242795Skato	/*
24342795Skato	 * Try removing anything stuck in the keyboard controller; whether
24442795Skato	 * it's a keyboard scan code or mouse data. `scintr()' doesn't
24542795Skato	 * read the mouse data directly, but `kbdio' routines will, as a
24642795Skato	 * side effect.
24742795Skato	 */
24842795Skato	s = spltty();
24942795Skato	kbd = (keyboard_t *)arg;
25042795Skato	if ((*kbdsw[kbd->kb_index]->lock)(kbd, TRUE)) {
25142795Skato		/*
25242795Skato		 * We have seen the lock flag is not set. Let's reset
25342795Skato		 * the flag early, otherwise the LED update routine fails
25442795Skato		 * which may want the lock during the interrupt routine.
25542795Skato		 */
25642795Skato		(*kbdsw[kbd->kb_index]->lock)(kbd, FALSE);
25742795Skato		if ((*kbdsw[kbd->kb_index]->check_char)(kbd))
25844635Skato			(*kbdsw[kbd->kb_index]->intr)(kbd, NULL);
25942795Skato	}
26042795Skato	splx(s);
26142795Skato	timeout(pckbd_timeout, arg, hz/10);
26242795Skato}
26342795Skato
26442795Skato/* LOW-LEVEL */
26542795Skato
266114216Skan#include <sys/limits.h>
26742795Skato
26842795Skato#define PC98KBD_DEFAULT	0
26942795Skato
27042795Skatotypedef caddr_t		KBDC;
27142795Skato
27242795Skatotypedef struct pckbd_state {
27342795Skato	KBDC		kbdc;		/* keyboard controller */
27442795Skato	int		ks_mode;	/* input mode (K_XLATE,K_RAW,K_CODE) */
27542795Skato	int		ks_flags;	/* flags */
27642795Skato#define COMPOSE		(1 << 0)
27742795Skato	int		ks_state;	/* shift/lock key state */
27842795Skato	int		ks_accents;	/* accent key index (> 0) */
27942795Skato	u_int		ks_composed_char; /* composed char code (> 0) */
28042795Skato} pckbd_state_t;
28142795Skato
28242795Skato/* keyboard driver declaration */
28342795Skatostatic int		pckbd_configure(int flags);
28442795Skatostatic kbd_probe_t	pckbd_probe;
28542795Skatostatic kbd_init_t	pckbd_init;
28642795Skatostatic kbd_term_t	pckbd_term;
28742795Skatostatic kbd_intr_t	pckbd_intr;
28842795Skatostatic kbd_test_if_t	pckbd_test_if;
28942795Skatostatic kbd_enable_t	pckbd_enable;
29042795Skatostatic kbd_disable_t	pckbd_disable;
29142795Skatostatic kbd_read_t	pckbd_read;
29242795Skatostatic kbd_check_t	pckbd_check;
29342795Skatostatic kbd_read_char_t	pckbd_read_char;
29442795Skatostatic kbd_check_char_t	pckbd_check_char;
29542795Skatostatic kbd_ioctl_t	pckbd_ioctl;
29642795Skatostatic kbd_lock_t	pckbd_lock;
29742795Skatostatic kbd_clear_state_t pckbd_clear_state;
29842795Skatostatic kbd_get_state_t	pckbd_get_state;
29942795Skatostatic kbd_set_state_t	pckbd_set_state;
30044635Skatostatic kbd_poll_mode_t	pckbd_poll;
30142795Skato
30242795Skatokeyboard_switch_t pckbdsw = {
30342795Skato	pckbd_probe,
30442795Skato	pckbd_init,
30542795Skato	pckbd_term,
30642795Skato	pckbd_intr,
30742795Skato	pckbd_test_if,
30842795Skato	pckbd_enable,
30942795Skato	pckbd_disable,
31042795Skato	pckbd_read,
31142795Skato	pckbd_check,
31242795Skato	pckbd_read_char,
31342795Skato	pckbd_check_char,
31442795Skato	pckbd_ioctl,
31542795Skato	pckbd_lock,
31642795Skato	pckbd_clear_state,
31742795Skato	pckbd_get_state,
31842795Skato	pckbd_set_state,
31942795Skato	genkbd_get_fkeystr,
32044635Skato	pckbd_poll,
32142795Skato	genkbd_diag,
32242795Skato};
32342795Skato
32442795SkatoKEYBOARD_DRIVER(pckbd, pckbdsw, pckbd_configure);
32542795Skato
32642795Skatostruct kbdc_softc {
32742795Skato    int port;			/* base port address */
32842795Skato    int lock;			/* FIXME: XXX not quite a semaphore... */
32942795Skato};
33042795Skato
33142795Skato/* local functions */
33242795Skatostatic int		probe_keyboard(KBDC kbdc, int flags);
33342795Skatostatic int		init_keyboard(KBDC kbdc, int *type, int flags);
33442795Skatostatic KBDC		kbdc_open(int port);
33542795Skatostatic int		kbdc_lock(KBDC kbdc, int lock);
33642795Skatostatic int		kbdc_data_ready(KBDC kbdc);
33742795Skatostatic int		read_kbd_data(KBDC kbdc);
33842795Skatostatic int		read_kbd_data_no_wait(KBDC kbdc);
33942795Skatostatic int		wait_for_kbd_data(struct kbdc_softc *kbdc);
34042795Skato
34142795Skato/* local variables */
34242795Skato
34342795Skato/* the initial key map, accent map and fkey strings */
34442833Skato#include <dev/kbd/kbdtables.h>
34542795Skato
34642795Skato/* structures for the default keyboard */
34742795Skatostatic keyboard_t	default_kbd;
34842795Skatostatic pckbd_state_t	default_kbd_state;
34942795Skatostatic keymap_t		default_keymap;
35042795Skatostatic accentmap_t	default_accentmap;
35142795Skatostatic fkeytab_t	default_fkeytab[NUM_FKEYS];
35242795Skato
35342795Skato/*
35442795Skato * The back door to the keyboard driver!
35542795Skato * This function is called by the console driver, via the kbdio module,
35642795Skato * to tickle keyboard drivers when the low-level console is being initialized.
35742795Skato * Almost nothing in the kernel has been initialied yet.  Try to probe
35842795Skato * keyboards if possible.
35942795Skato * NOTE: because of the way the low-level conole is initialized, this routine
36042795Skato * may be called more than once!!
36142795Skato */
36242795Skatostatic int
36342795Skatopckbd_configure(int flags)
36442795Skato{
36542795Skato	keyboard_t *kbd;
36642795Skato	int arg[2];
36744635Skato	int i;
36842795Skato
36942795Skato	/* XXX: a kludge to obtain the device configuration flags */
37045783Skato	if (resource_int_value(DRIVER_NAME, 0, "flags", &i) == 0) {
37145783Skato		flags |= i;
37244635Skato		/* if the driver is disabled, unregister the keyboard if any */
373117167Sjhb		if (resource_disabled(DRIVER_NAME, 0)) {
37444635Skato			i = kbd_find_keyboard(DRIVER_NAME, PC98KBD_DEFAULT);
37544635Skato			if (i >= 0) {
37644635Skato				kbd = kbd_get_keyboard(i);
37744635Skato				kbd_unregister(kbd);
37844635Skato				kbd->kb_flags &= ~KB_REGISTERED;
37944635Skato				return 0;
38044635Skato			}
38144635Skato		}
38244635Skato	}
38342795Skato
38442795Skato	/* probe the default keyboard */
38542795Skato	arg[0] = -1;
38642795Skato	arg[1] = -1;
38744635Skato	kbd = NULL;
38844635Skato	if (pckbd_probe(PC98KBD_DEFAULT, arg, flags))
38942795Skato		return 0;
39044635Skato	if (pckbd_init(PC98KBD_DEFAULT, &kbd, arg, flags))
39144635Skato		return 0;
39242795Skato
39344635Skato	/* return the number of found keyboards */
39444635Skato	return 1;
39542795Skato}
39642795Skato
39742795Skato/* low-level functions */
39842795Skato
39944635Skato/* detect a keyboard */
40042795Skatostatic int
40144635Skatopckbd_probe(int unit, void *arg, int flags)
40242795Skato{
40342795Skato	KBDC kbdc;
40442795Skato	int *data = (int *)arg;
40542795Skato
40642795Skato	if (unit != PC98KBD_DEFAULT)
40742795Skato		return ENXIO;
40844635Skato	if (KBD_IS_PROBED(&default_kbd))
40942795Skato		return 0;
41042795Skato
41144635Skato	kbdc = kbdc_open(data[0]);
41242795Skato	if (kbdc == NULL)
41342795Skato		return ENXIO;
41442795Skato	if (probe_keyboard(kbdc, flags)) {
41542795Skato		if (flags & KB_CONF_FAIL_IF_NO_KBD)
41642795Skato			return ENXIO;
41742795Skato	}
41842795Skato	return 0;
41942795Skato}
42042795Skato
42142795Skato/* reset and initialize the device */
42242795Skatostatic int
42344635Skatopckbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
42442795Skato{
42544635Skato	keyboard_t *kbd;
42644635Skato	pckbd_state_t *state;
42744635Skato	keymap_t *keymap;
42844635Skato	accentmap_t *accmap;
42944635Skato	fkeytab_t *fkeymap;
43044635Skato	int fkeymap_size;
43144635Skato	int *data = (int *)arg;
43242795Skato
43344635Skato	if (unit != PC98KBD_DEFAULT)			/* shouldn't happen */
43444635Skato		return ENXIO;
43542795Skato
43644635Skato	*kbdp = kbd = &default_kbd;
43744635Skato	state = &default_kbd_state;
43844635Skato	if (!KBD_IS_PROBED(kbd)) {
43944635Skato		keymap = &default_keymap;
44044635Skato		accmap = &default_accentmap;
44144635Skato		fkeymap = default_fkeytab;
44244635Skato		fkeymap_size =
44344635Skato			sizeof(default_fkeytab)/sizeof(default_fkeytab[0]);
44444635Skato
44544635Skato		state->kbdc = kbdc_open(data[0]);
44644635Skato		if (state->kbdc == NULL)
44744635Skato			return ENXIO;
44844635Skato		kbd_init_struct(kbd, DRIVER_NAME, KB_OTHER, unit, flags,
44944635Skato				data[0], IO_KBDSIZE);
45044635Skato		bcopy(&key_map, keymap, sizeof(key_map));
45144635Skato		bcopy(&accent_map, accmap, sizeof(accent_map));
45244635Skato		bcopy(fkey_tab, fkeymap,
45344635Skato		      imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
45444635Skato		kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
45544635Skato		kbd->kb_data = (void *)state;
45644635Skato
45744635Skato		if (probe_keyboard(state->kbdc, flags)) {/* shouldn't happen */
45844635Skato			if (flags & KB_CONF_FAIL_IF_NO_KBD)
45944635Skato				return ENXIO;
46044635Skato		} else {
46144635Skato			KBD_FOUND_DEVICE(kbd);
46244635Skato		}
46344635Skato		pckbd_clear_state(kbd);
46444635Skato		state->ks_mode = K_XLATE;
46544635Skato		KBD_PROBE_DONE(kbd);
46644635Skato	}
46744635Skato	if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
46842795Skato		if (KBD_HAS_DEVICE(kbd)
46944635Skato		    && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config)
47042795Skato		    && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD))
47142795Skato			return ENXIO;
47244635Skato		pckbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
47342795Skato		KBD_INIT_DONE(kbd);
47442795Skato	}
47542795Skato	if (!KBD_IS_CONFIGURED(kbd)) {
47642795Skato		if (kbd_register(kbd) < 0)
47742795Skato			return ENXIO;
47842795Skato		KBD_CONFIG_DONE(kbd);
47942795Skato	}
48042795Skato
48142795Skato	return 0;
48242795Skato}
48342795Skato
48442795Skato/* finish using this keyboard */
48542795Skatostatic int
48642795Skatopckbd_term(keyboard_t *kbd)
48742795Skato{
48842795Skato	kbd_unregister(kbd);
48942795Skato	return 0;
49042795Skato}
49142795Skato
49242795Skato/* keyboard interrupt routine */
49342795Skatostatic int
49444635Skatopckbd_intr(keyboard_t *kbd, void *arg)
49542795Skato{
49642795Skato	int c;
49742795Skato
49842795Skato	if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
49942795Skato		/* let the callback function to process the input */
50042795Skato		(*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
50142795Skato					    kbd->kb_callback.kc_arg);
50242795Skato	} else {
50342795Skato		/* read and discard the input; no one is waiting for input */
50442795Skato		do {
50542795Skato			c = pckbd_read_char(kbd, FALSE);
50642795Skato		} while (c != NOKEY);
50742795Skato	}
50842795Skato	return 0;
50942795Skato}
51042795Skato
51142795Skato/* test the interface to the device */
51242795Skatostatic int
51342795Skatopckbd_test_if(keyboard_t *kbd)
51442795Skato{
51542795Skato	return 0;
51642795Skato}
51742795Skato
51842795Skato/*
51942795Skato * Enable the access to the device; until this function is called,
52042795Skato * the client cannot read from the keyboard.
52142795Skato */
52242795Skatostatic int
52342795Skatopckbd_enable(keyboard_t *kbd)
52442795Skato{
52542795Skato	int s;
52642795Skato
52742795Skato	s = spltty();
52842795Skato	KBD_ACTIVATE(kbd);
52942795Skato	splx(s);
53042795Skato	return 0;
53142795Skato}
53242795Skato
53342795Skato/* disallow the access to the device */
53442795Skatostatic int
53542795Skatopckbd_disable(keyboard_t *kbd)
53642795Skato{
53742795Skato	int s;
53842795Skato
53942795Skato	s = spltty();
54042795Skato	KBD_DEACTIVATE(kbd);
54142795Skato	splx(s);
54242795Skato	return 0;
54342795Skato}
54442795Skato
54542795Skato/* read one byte from the keyboard if it's allowed */
54642795Skatostatic int
54742795Skatopckbd_read(keyboard_t *kbd, int wait)
54842795Skato{
54942795Skato	int c;
55042795Skato
55142795Skato	if (wait)
55242795Skato		c = read_kbd_data(((pckbd_state_t *)kbd->kb_data)->kbdc);
55342795Skato	else
55442795Skato		c = read_kbd_data_no_wait(((pckbd_state_t *)kbd->kb_data)->kbdc);
55554551Skato	if (c != -1)
55654551Skato		++kbd->kb_count;
55742795Skato	return (KBD_IS_ACTIVE(kbd) ? c : -1);
55842795Skato}
55942795Skato
56042795Skato/* check if data is waiting */
56142795Skatostatic int
56242795Skatopckbd_check(keyboard_t *kbd)
56342795Skato{
56442795Skato	if (!KBD_IS_ACTIVE(kbd))
56542795Skato		return FALSE;
56642795Skato	return kbdc_data_ready(((pckbd_state_t *)kbd->kb_data)->kbdc);
56742795Skato}
56842795Skato
56942795Skato/* read char from the keyboard */
57042795Skatostatic u_int
57142795Skatopckbd_read_char(keyboard_t *kbd, int wait)
57242795Skato{
57342795Skato	pckbd_state_t *state;
57442795Skato	u_int action;
57542795Skato	int scancode;
57642795Skato	int keycode;
57742795Skato
57842795Skato	state = (pckbd_state_t *)kbd->kb_data;
57942795Skatonext_code:
58042795Skato	/* do we have a composed char to return? */
58142795Skato	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
58242795Skato		action = state->ks_composed_char;
58342795Skato		state->ks_composed_char = 0;
58442795Skato		if (action > UCHAR_MAX)
58542795Skato			return ERRKEY;
58642795Skato		return action;
58742795Skato	}
58842795Skato
58942795Skato	/* see if there is something in the keyboard port */
59042795Skato	if (wait) {
59142795Skato		do {
59242795Skato			scancode = read_kbd_data(state->kbdc);
59342795Skato		} while (scancode == -1);
59442795Skato	} else {
59542795Skato		scancode = read_kbd_data_no_wait(state->kbdc);
59642795Skato		if (scancode == -1)
59742795Skato			return NOKEY;
59842795Skato	}
59954551Skato	++kbd->kb_count;
60042795Skato
60154551Skato#if 0
60254551Skato	printf("pckbd_read_char(): scancode:0x%x\n", scancode);
60354551Skato#endif
60454551Skato
60542795Skato	/* return the byte as is for the K_RAW mode */
60642795Skato	if (state->ks_mode == K_RAW)
60742795Skato		return scancode;
60842795Skato
60942795Skato	/* translate the scan code into a keycode */
61042795Skato	keycode = scancode & 0x7F;
61142795Skato	switch(scancode) {
61242795Skato	case 0xF3:	/* GRPH (compose key) released */
61342795Skato		if (state->ks_flags & COMPOSE) {
61442795Skato			state->ks_flags &= ~COMPOSE;
61542795Skato			if (state->ks_composed_char > UCHAR_MAX)
61642795Skato				state->ks_composed_char = 0;
61742795Skato		}
61842795Skato		break;
61942795Skato	case 0x73:	/* GRPH (compose key) pressed */
62042795Skato		if (!(state->ks_flags & COMPOSE)) {
62142795Skato			state->ks_flags |= COMPOSE;
62242795Skato			state->ks_composed_char = 0;
62342795Skato		}
62442795Skato		break;
62542795Skato	}
62642795Skato
62742795Skato	/* return the key code in the K_CODE mode */
62842795Skato	if (state->ks_mode == K_CODE)
62942795Skato		return (keycode | (scancode & 0x80));
63042795Skato
63142795Skato	/* compose a character code */
63242795Skato	if (state->ks_flags & COMPOSE) {
63342795Skato		switch (scancode) {
63442795Skato		/* key pressed, process it */
63542795Skato		case 0x42: case 0x43: case 0x44:	/* keypad 7,8,9 */
63642795Skato			state->ks_composed_char *= 10;
63742795Skato			state->ks_composed_char += scancode - 0x3B;
63842795Skato			if (state->ks_composed_char > UCHAR_MAX)
63942795Skato				return ERRKEY;
64042795Skato			goto next_code;
64142795Skato		case 0x46: case 0x47: case 0x48:	/* keypad 4,5,6 */
64242795Skato			state->ks_composed_char *= 10;
64342795Skato			state->ks_composed_char += scancode - 0x42;
64442795Skato			if (state->ks_composed_char > UCHAR_MAX)
64542795Skato				return ERRKEY;
64642795Skato			goto next_code;
64742795Skato		case 0x4A: case 0x4B: case 0x4C:	/* keypad 1,2,3 */
64842795Skato			state->ks_composed_char *= 10;
64942795Skato			state->ks_composed_char += scancode - 0x49;
65042795Skato			if (state->ks_composed_char > UCHAR_MAX)
65142795Skato				return ERRKEY;
65242795Skato			goto next_code;
65342795Skato		case 0x4E:				/* keypad 0 */
65442795Skato			state->ks_composed_char *= 10;
65542795Skato			if (state->ks_composed_char > UCHAR_MAX)
65642795Skato				return ERRKEY;
65742795Skato			goto next_code;
65842795Skato
65942795Skato		/* key released, no interest here */
66042795Skato		case 0xC2: case 0xC3: case 0xC4:	/* keypad 7,8,9 */
66142795Skato		case 0xC6: case 0xC7: case 0xC8:	/* keypad 4,5,6 */
66242795Skato		case 0xCA: case 0xCB: case 0xCC:	/* keypad 1,2,3 */
66342795Skato		case 0xCE:				/* keypad 0 */
66442795Skato			goto next_code;
66542795Skato
66642795Skato		case 0x73:				/* GRPH key */
66742795Skato			break;
66842795Skato
66942795Skato		default:
67042795Skato			if (state->ks_composed_char > 0) {
67142795Skato				state->ks_flags &= ~COMPOSE;
67242795Skato				state->ks_composed_char = 0;
67342795Skato				return ERRKEY;
67442795Skato			}
67542795Skato			break;
67642795Skato		}
67742795Skato	}
67842795Skato
67942795Skato	/* keycode to key action */
68042795Skato	action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
68142795Skato				  &state->ks_state, &state->ks_accents);
68242795Skato	if (action == NOKEY)
68342795Skato		goto next_code;
68442795Skato	else
68542795Skato		return action;
68642795Skato}
68742795Skato
68842795Skato/* check if char is waiting */
68942795Skatostatic int
69042795Skatopckbd_check_char(keyboard_t *kbd)
69142795Skato{
69242795Skato	pckbd_state_t *state;
69342795Skato
69442795Skato	if (!KBD_IS_ACTIVE(kbd))
69542795Skato		return FALSE;
69642795Skato	state = (pckbd_state_t *)kbd->kb_data;
69742795Skato	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0))
69842795Skato		return TRUE;
69942795Skato	return kbdc_data_ready(state->kbdc);
70042795Skato}
70142795Skato
70242795Skato/* some useful control functions */
70342795Skatostatic int
70442795Skatopckbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
70542795Skato{
70642795Skato	pckbd_state_t *state = kbd->kb_data;
70742795Skato	int s;
70842795Skato	int i;
70942795Skato
71042795Skato	s = spltty();
71142795Skato	switch (cmd) {
71242795Skato
71342795Skato	case KDGKBMODE:		/* get keyboard mode */
71442795Skato		*(int *)arg = state->ks_mode;
71542795Skato		break;
71642795Skato	case KDSKBMODE:		/* set keyboard mode */
71742795Skato		switch (*(int *)arg) {
71842795Skato		case K_XLATE:
71942795Skato			if (state->ks_mode != K_XLATE) {
72042795Skato				/* make lock key state and LED state match */
72142795Skato				state->ks_state &= ~LOCK_MASK;
72242795Skato				state->ks_state |= KBD_LED_VAL(kbd);
72342795Skato			}
724102412Scharnier			/* FALLTHROUGH */
72542795Skato		case K_RAW:
72642795Skato		case K_CODE:
72742795Skato			if (state->ks_mode != *(int *)arg) {
72842795Skato				pckbd_clear_state(kbd);
72942795Skato				state->ks_mode = *(int *)arg;
73042795Skato			}
73142795Skato			break;
73242795Skato		default:
73342795Skato			splx(s);
73442795Skato			return EINVAL;
73542795Skato		}
73642795Skato		break;
73742795Skato
73842795Skato	case KDGETLED:		/* get keyboard LED */
73942795Skato		*(int *)arg = KBD_LED_VAL(kbd);
74042795Skato		break;
74142795Skato	case KDSETLED:		/* set keyboard LED */
74242795Skato		/* NOTE: lock key state in ks_state won't be changed */
74342795Skato		if (*(int *)arg & ~LOCK_MASK) {
74442795Skato			splx(s);
74542795Skato			return EINVAL;
74642795Skato		}
74742795Skato		i = *(int *)arg;
74842795Skato		/* replace CAPS LED with ALTGR LED for ALTGR keyboards */
74942795Skato		if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
75042795Skato			if (i & ALKED)
75142795Skato				i |= CLKED;
75242795Skato			else
75342795Skato				i &= ~CLKED;
75442795Skato		}
75542795Skato		KBD_LED_VAL(kbd) = *(int *)arg;
75642795Skato		break;
75742795Skato
75842795Skato	case KDGKBSTATE:	/* get lock key state */
75942795Skato		*(int *)arg = state->ks_state & LOCK_MASK;
76042795Skato		break;
76142795Skato	case KDSKBSTATE:	/* set lock key state */
76242795Skato		if (*(int *)arg & ~LOCK_MASK) {
76342795Skato			splx(s);
76442795Skato			return EINVAL;
76542795Skato		}
76642795Skato		state->ks_state &= ~LOCK_MASK;
76742795Skato		state->ks_state |= *(int *)arg;
76842795Skato		splx(s);
76942795Skato		/* set LEDs and quit */
77042795Skato		return pckbd_ioctl(kbd, KDSETLED, arg);
77142795Skato
77244635Skato	case KDSETRAD:		/* set keyboard repeat rate (old interface)*/
77342795Skato		break;
77444635Skato	case KDSETREPEAT:	/* set keyboard repeat rate (new interface) */
77544635Skato		break;
77642795Skato
77742795Skato	case PIO_KEYMAP:	/* set keyboard translation table */
77842795Skato	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
77942795Skato	case PIO_DEADKEYMAP:	/* set accent key translation table */
78042795Skato		state->ks_accents = 0;
781102412Scharnier		/* FALLTHROUGH */
78242795Skato	default:
78342795Skato		splx(s);
78442795Skato		return genkbd_commonioctl(kbd, cmd, arg);
78542795Skato	}
78642795Skato
78742795Skato	splx(s);
78842795Skato	return 0;
78942795Skato}
79042795Skato
79142795Skato/* lock the access to the keyboard */
79242795Skatostatic int
79342795Skatopckbd_lock(keyboard_t *kbd, int lock)
79442795Skato{
79542795Skato	return kbdc_lock(((pckbd_state_t *)kbd->kb_data)->kbdc, lock);
79642795Skato}
79742795Skato
79842795Skato/* clear the internal state of the keyboard */
79942795Skatostatic void
80042795Skatopckbd_clear_state(keyboard_t *kbd)
80142795Skato{
80242795Skato	pckbd_state_t *state;
80342795Skato
80442795Skato	state = (pckbd_state_t *)kbd->kb_data;
80542795Skato	state->ks_flags = 0;
80642795Skato	state->ks_state &= LOCK_MASK;	/* preserve locking key state */
80742795Skato	state->ks_accents = 0;
80842795Skato	state->ks_composed_char = 0;
80942795Skato}
81042795Skato
81142795Skato/* save the internal state */
81242795Skatostatic int
81342795Skatopckbd_get_state(keyboard_t *kbd, void *buf, size_t len)
81442795Skato{
81542795Skato	if (len == 0)
81642795Skato		return sizeof(pckbd_state_t);
81742795Skato	if (len < sizeof(pckbd_state_t))
81842795Skato		return -1;
81942795Skato	bcopy(kbd->kb_data, buf, sizeof(pckbd_state_t));
82042795Skato	return 0;
82142795Skato}
82242795Skato
82342795Skato/* set the internal state */
82442795Skatostatic int
82542795Skatopckbd_set_state(keyboard_t *kbd, void *buf, size_t len)
82642795Skato{
82742795Skato	if (len < sizeof(pckbd_state_t))
82842795Skato		return ENOMEM;
82942795Skato	if (((pckbd_state_t *)kbd->kb_data)->kbdc
83042795Skato		!= ((pckbd_state_t *)buf)->kbdc)
83142795Skato		return ENOMEM;
83242795Skato	bcopy(buf, kbd->kb_data, sizeof(pckbd_state_t));
83342795Skato	return 0;
83442795Skato}
83542795Skato
83644635Skato/* set polling mode */
83744635Skatostatic int
83844635Skatopckbd_poll(keyboard_t *kbd, int on)
83944635Skato{
84044635Skato	return 0;
84144635Skato}
84244635Skato
84342795Skato/* local functions */
84442795Skato
84542795Skatostatic int
84642795Skatoprobe_keyboard(KBDC kbdc, int flags)
84742795Skato{
84842795Skato	return 0;
84942795Skato}
85042795Skato
85142795Skatostatic int
85242795Skatoinit_keyboard(KBDC kbdc, int *type, int flags)
85342795Skato{
85442795Skato	*type = KB_OTHER;
85542795Skato	return 0;
85642795Skato}
85742795Skato
85842795Skato/* keyboard I/O routines */
85942795Skato
86042795Skato/* retry count */
86142795Skato#ifndef KBD_MAXRETRY
86242795Skato#define KBD_MAXRETRY	3
86342795Skato#endif
86442795Skato
86542795Skato/* timing parameters */
86642795Skato#ifndef KBD_RESETDELAY
86742795Skato#define KBD_RESETDELAY  200     /* wait 200msec after kbd/mouse reset */
86842795Skato#endif
86942795Skato#ifndef KBD_MAXWAIT
87042795Skato#define KBD_MAXWAIT	5 	/* wait 5 times at most after reset */
87142795Skato#endif
87242795Skato
87342795Skato/* I/O recovery time */
87442795Skato#define KBDC_DELAYTIME	37
87542795Skato#define KBDD_DELAYTIME	37
87642795Skato
87742795Skato/* I/O ports */
87842795Skato#define KBD_STATUS_PORT 	2	/* status port, read */
87942795Skato#define KBD_DATA_PORT		0	/* data port, read */
88042795Skato
88142795Skato/* status bits (KBD_STATUS_PORT) */
88242795Skato#define KBDS_BUFFER_FULL	0x0002
88342795Skato
88442795Skato/* macros */
88542795Skato
88642795Skato#define kbdcp(p)		((struct kbdc_softc *)(p))
88742795Skato
88842795Skato/* local variables */
88942795Skato
890102151Speterstatic struct kbdc_softc kbdc_softc[1] = { { 0 }, };
89142795Skato
89242795Skato/* associate a port number with a KBDC */
89342795Skato
89442795Skatostatic KBDC
89542795Skatokbdc_open(int port)
89642795Skato{
89742795Skato	if (port <= 0)
89842795Skato		port = IO_KBD;
89942795Skato
900102151Speter	/* PC-98 has only one keyboard I/F */
901102151Speter	kbdc_softc[0].port = port;
902102151Speter	kbdc_softc[0].lock = FALSE;
903102151Speter	return (KBDC)&kbdc_softc[0];
90442795Skato}
90542795Skato
90642795Skato/* set/reset polling lock */
90742795Skatostatic int
90842795Skatokbdc_lock(KBDC p, int lock)
90942795Skato{
91042795Skato    int prevlock;
91142795Skato
91242795Skato    prevlock = kbdcp(p)->lock;
91342795Skato    kbdcp(p)->lock = lock;
91442795Skato
91542795Skato    return (prevlock != lock);
91642795Skato}
91742795Skato
91842795Skato/* check if any data is waiting to be processed */
91942795Skatostatic int
92042795Skatokbdc_data_ready(KBDC p)
92142795Skato{
92242795Skato	return (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL);
92342795Skato}
92442795Skato
92542795Skato/* wait for data from the keyboard */
92642795Skatostatic int
92742795Skatowait_for_kbd_data(struct kbdc_softc *kbdc)
92842795Skato{
92942795Skato    /* CPU will stay inside the loop for 200msec at most */
93042795Skato    int retry = 10000;
93142795Skato    int port = kbdc->port;
93242795Skato
93342795Skato    while (!(inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)) {
93442795Skato	DELAY(KBDD_DELAYTIME);
93542795Skato	DELAY(KBDC_DELAYTIME);
93642795Skato        if (--retry < 0)
93742795Skato    	    return 0;
93842795Skato    }
93942795Skato    DELAY(KBDD_DELAYTIME);
94042795Skato    return 1;
94142795Skato}
94242795Skato
94342795Skato/* read one byte from the keyboard */
94442795Skatostatic int
94542795Skatoread_kbd_data(KBDC p)
94642795Skato{
94742795Skato    if (!wait_for_kbd_data(kbdcp(p)))
94842795Skato        return -1;		/* timeout */
94942795Skato    DELAY(KBDC_DELAYTIME);
95042795Skato    return inb(kbdcp(p)->port + KBD_DATA_PORT);
95142795Skato}
95242795Skato
95342795Skato/* read one byte from the keyboard, but return immediately if
95442795Skato * no data is waiting
95542795Skato */
95642795Skatostatic int
95742795Skatoread_kbd_data_no_wait(KBDC p)
95842795Skato{
95942795Skato    if (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) {
96042795Skato        DELAY(KBDD_DELAYTIME);
96142795Skato        return inb(kbdcp(p)->port + KBD_DATA_PORT);
96242795Skato    }
96342795Skato    return -1;		/* no data */
96442795Skato}
965