142421Syokota/*-
242421Syokota * Copyright (c) 1996-1999
342421Syokota * Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
442421Syokota * All rights reserved.
542421Syokota *
642421Syokota * Redistribution and use in source and binary forms, with or without
742421Syokota * modification, are permitted provided that the following conditions
842421Syokota * are met:
942421Syokota * 1. Redistributions of source code must retain the above copyright
1042421Syokota *    notice, this list of conditions and the following disclaimer.
1142421Syokota * 2. Redistributions in binary form must reproduce the above copyright
1242421Syokota *    notice, this list of conditions and the following disclaimer in the
1342421Syokota *    documentation and/or other materials provided with the distribution.
1442421Syokota * 3. The name of the author may not be used to endorse or promote
1542421Syokota *    products derived from this software without specific prior written
1642421Syokota *    permission.
1742421Syokota *
1842421Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1942421Syokota * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2042421Syokota * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2142421Syokota * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2242421Syokota * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2342421Syokota * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2442421Syokota * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2542421Syokota * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2642421Syokota * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2742421Syokota * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2842421Syokota * SUCH DAMAGE.
2942421Syokota *
3042421Syokota * from kbdio.c,v 1.13 1998/09/25 11:55:46 yokota Exp
3142421Syokota */
3242421Syokota
33119418Sobrien#include <sys/cdefs.h>
34119418Sobrien__FBSDID("$FreeBSD$");
35119418Sobrien
3642421Syokota#include "opt_kbd.h"
3742421Syokota
3842421Syokota#include <sys/param.h>
3942421Syokota#include <sys/systm.h>
4058271Syokota#include <sys/bus.h>
4142421Syokota#include <sys/malloc.h>
4242421Syokota#include <sys/syslog.h>
4358271Syokota#include <machine/bus.h>
4458271Syokota#include <machine/resource.h>
4558271Syokota#include <sys/rman.h>
4642421Syokota
47207354Ssobomax#if defined(__amd64__)
48207354Ssobomax#include <machine/clock.h>
49207354Ssobomax#endif
50207354Ssobomax
51147271Smarius#include <dev/atkbdc/atkbdcreg.h>
5242421Syokota
53147271Smarius#ifdef __sparc64__
54147271Smarius#include <dev/ofw/openfirm.h>
55147271Smarius#include <machine/bus_private.h>
56147271Smarius#include <machine/ofw_machdep.h>
57147271Smarius#else
5842421Syokota#include <isa/isareg.h>
59147271Smarius#endif
6042421Syokota
6142421Syokota/* constants */
6242421Syokota
63102149Speter#define MAXKBDC		1		/* XXX */
6442421Syokota
6542421Syokota/* macros */
6642421Syokota
6742421Syokota#ifndef MAX
6842421Syokota#define MAX(x, y)	((x) > (y) ? (x) : (y))
6942421Syokota#endif
7042421Syokota
7142421Syokota#define kbdcp(p)	((atkbdc_softc_t *)(p))
7242421Syokota#define nextq(i)	(((i) + 1) % KBDQ_BUFSIZE)
7342421Syokota#define availq(q)	((q)->head != (q)->tail)
7442421Syokota#if KBDIO_DEBUG >= 2
7542421Syokota#define emptyq(q)	((q)->tail = (q)->head = (q)->qcount = 0)
7642421Syokota#else
7742421Syokota#define emptyq(q)	((q)->tail = (q)->head = 0)
7842421Syokota#endif
7942421Syokota
8058271Syokota#define read_data(k)	(bus_space_read_1((k)->iot, (k)->ioh0, 0))
8158271Syokota#define read_status(k)	(bus_space_read_1((k)->iot, (k)->ioh1, 0))
8258271Syokota#define write_data(k, d)	\
8358271Syokota			(bus_space_write_1((k)->iot, (k)->ioh0, 0, (d)))
8458271Syokota#define write_command(k, d)	\
8558271Syokota			(bus_space_write_1((k)->iot, (k)->ioh1, 0, (d)))
8658271Syokota
8742421Syokota/* local variables */
8842421Syokota
8942421Syokota/*
9042421Syokota * We always need at least one copy of the kbdc_softc struct for the
9142421Syokota * low-level console.  As the low-level console accesses the keyboard
9242421Syokota * controller before kbdc, and all other devices, is probed, we
9342421Syokota * statically allocate one entry. XXX
9442421Syokota */
9542421Syokotastatic atkbdc_softc_t default_kbdc;
9642421Syokotastatic atkbdc_softc_t *atkbdc_softc[MAXKBDC] = { &default_kbdc };
9742421Syokota
9842421Syokotastatic int verbose = KBDIO_DEBUG;
9942421Syokota
100147271Smarius#ifdef __sparc64__
101147271Smariusstatic struct bus_space_tag atkbdc_bst_store[MAXKBDC];
102147271Smarius#endif
103147271Smarius
10442421Syokota/* function prototypes */
10542421Syokota
10658271Syokotastatic int atkbdc_setup(atkbdc_softc_t *sc, bus_space_tag_t tag,
10758271Syokota			bus_space_handle_t h0, bus_space_handle_t h1);
10842421Syokotastatic int addq(kqueue *q, int c);
10942421Syokotastatic int removeq(kqueue *q);
11042421Syokotastatic int wait_while_controller_busy(atkbdc_softc_t *kbdc);
11142421Syokotastatic int wait_for_data(atkbdc_softc_t *kbdc);
11242421Syokotastatic int wait_for_kbd_data(atkbdc_softc_t *kbdc);
11342421Syokotastatic int wait_for_kbd_ack(atkbdc_softc_t *kbdc);
11442421Syokotastatic int wait_for_aux_data(atkbdc_softc_t *kbdc);
11542421Syokotastatic int wait_for_aux_ack(atkbdc_softc_t *kbdc);
11642421Syokota
11742421Syokotaatkbdc_softc_t
11842421Syokota*atkbdc_get_softc(int unit)
11942421Syokota{
12042421Syokota	atkbdc_softc_t *sc;
12142421Syokota
12242421Syokota	if (unit >= sizeof(atkbdc_softc)/sizeof(atkbdc_softc[0]))
12342421Syokota		return NULL;
12442421Syokota	sc = atkbdc_softc[unit];
12542421Syokota	if (sc == NULL) {
12642421Syokota		sc = atkbdc_softc[unit]
12769781Sdwmalone		   = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO);
12842421Syokota		if (sc == NULL)
12942421Syokota			return NULL;
13042421Syokota	}
13142421Syokota	return sc;
13242421Syokota}
13342421Syokota
13442421Syokotaint
13558271Syokotaatkbdc_probe_unit(int unit, struct resource *port0, struct resource *port1)
13642421Syokota{
13758271Syokota	if (rman_get_start(port0) <= 0)
13847296Syokota		return ENXIO;
13958271Syokota	if (rman_get_start(port1) <= 0)
14058271Syokota		return ENXIO;
14147296Syokota	return 0;
14247296Syokota}
14347296Syokota
14447296Syokotaint
14558271Syokotaatkbdc_attach_unit(int unit, atkbdc_softc_t *sc, struct resource *port0,
14658271Syokota		   struct resource *port1)
14747296Syokota{
14858271Syokota	return atkbdc_setup(sc, rman_get_bustag(port0),
14958271Syokota			    rman_get_bushandle(port0),
15058271Syokota			    rman_get_bushandle(port1));
15142421Syokota}
15242421Syokota
15342421Syokota/* the backdoor to the keyboard controller! XXX */
15442421Syokotaint
15542421Syokotaatkbdc_configure(void)
15642421Syokota{
15758271Syokota	bus_space_tag_t tag;
15858271Syokota	bus_space_handle_t h0;
15958271Syokota	bus_space_handle_t h1;
160207354Ssobomax#if defined(__i386__) || defined(__amd64__)
161158041Ssobomax	volatile int i;
162158041Ssobomax	register_t flags;
163158041Ssobomax#endif
164147271Smarius#ifdef __sparc64__
165147271Smarius	char name[32];
166147271Smarius	phandle_t chosen, node;
167147271Smarius	ihandle_t stdin;
168147271Smarius	bus_addr_t port0;
169147271Smarius	bus_addr_t port1;
170147271Smarius	int space;
171147271Smarius#else
17258271Syokota	int port0;
17358271Syokota	int port1;
17458271Syokota#endif
17558271Syokota
17658271Syokota	/* XXX: tag should be passed from the caller */
177216592Stijl#if defined(__amd64__) || defined(__i386__)
178216592Stijl	tag = X86_BUS_SPACE_IO;
17992661Speter#elif defined(__ia64__)
18092661Speter	tag = IA64_BUS_SPACE_IO;
181147271Smarius#elif defined(__sparc64__)
182147271Smarius	tag = &atkbdc_bst_store[0];
18392661Speter#else
18492661Speter#error "define tag!"
18558271Syokota#endif
18658271Syokota
187147271Smarius#ifdef __sparc64__
188147271Smarius	if ((chosen = OF_finddevice("/chosen")) == -1)
189147271Smarius		return 0;
190147271Smarius	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1)
191147271Smarius		return 0;
192147271Smarius	if ((node = OF_instance_to_package(stdin)) == -1)
193147271Smarius		return 0;
194147271Smarius	if (OF_getprop(node, "name", name, sizeof(name)) == -1)
195147271Smarius		return 0;
196147271Smarius	name[sizeof(name) - 1] = '\0';
197147271Smarius	if (strcmp(name, "kb_ps2") != 0)
198147271Smarius		return 0;
199147271Smarius	/*
200147271Smarius	 * The stdin handle points to an instance of a PS/2 keyboard
201147271Smarius	 * package but we want the 8042 controller, which is the parent
202147271Smarius	 * of that keyboard node.
203147271Smarius	 */
204147271Smarius	if ((node = OF_parent(node)) == 0)
205147271Smarius		return 0;
206147271Smarius	if (OF_decode_addr(node, 0, &space, &port0) != 0)
207147271Smarius		return 0;
208147271Smarius	h0 = sparc64_fake_bustag(space, port0, tag);
209147271Smarius	bus_space_subregion(tag, h0, KBD_DATA_PORT, 1, &h0);
210147271Smarius	if (OF_decode_addr(node, 1, &space, &port1) != 0)
211147271Smarius		return 0;
212147271Smarius	h1 = sparc64_fake_bustag(space, port1, tag);
213147271Smarius	bus_space_subregion(tag, h1, KBD_STATUS_PORT, 1, &h1);
214147271Smarius#else
215147271Smarius	port0 = IO_KBD;
216147271Smarius	resource_int_value("atkbdc", 0, "port", &port0);
217147271Smarius	port1 = IO_KBD + KBD_STATUS_PORT;
218153072Sru#ifdef notyet
21958271Syokota	bus_space_map(tag, port0, IO_KBDSIZE, 0, &h0);
22058271Syokota	bus_space_map(tag, port1, IO_KBDSIZE, 0, &h1);
22158271Syokota#else
22258271Syokota	h0 = (bus_space_handle_t)port0;
22358271Syokota	h1 = (bus_space_handle_t)port1;
22458271Syokota#endif
225147271Smarius#endif
226158041Ssobomax
227207354Ssobomax#if defined(__i386__) || defined(__amd64__)
228158041Ssobomax	/*
229158041Ssobomax	 * Check if we really have AT keyboard controller. Poll status
230158041Ssobomax	 * register until we get "all clear" indication. If no such
231158041Ssobomax	 * indication comes, it probably means that there is no AT
232158041Ssobomax	 * keyboard controller present. Give up in such case. Check relies
233158041Ssobomax	 * on the fact that reading from non-existing in/out port returns
234158041Ssobomax	 * 0xff on i386. May or may not be true on other platforms.
235158041Ssobomax	 */
236158041Ssobomax	flags = intr_disable();
237158041Ssobomax	for (i = 0; i != 65535; i++) {
238158041Ssobomax		if ((bus_space_read_1(tag, h1, 0) & 0x2) == 0)
239158041Ssobomax			break;
240158041Ssobomax	}
241158041Ssobomax	intr_restore(flags);
242158041Ssobomax	if (i == 65535)
243158041Ssobomax                return ENXIO;
244158041Ssobomax#endif
245158041Ssobomax
24658271Syokota	return atkbdc_setup(atkbdc_softc[0], tag, h0, h1);
24742421Syokota}
24842421Syokota
24942421Syokotastatic int
25058271Syokotaatkbdc_setup(atkbdc_softc_t *sc, bus_space_tag_t tag, bus_space_handle_t h0,
25158271Syokota	     bus_space_handle_t h1)
25242421Syokota{
253207354Ssobomax#if defined(__amd64__)
254207354Ssobomax	u_int64_t tscval[3], read_delay;
255207354Ssobomax	register_t flags;
256207354Ssobomax#endif
257207354Ssobomax
25858271Syokota	if (sc->ioh0 == 0) {	/* XXX */
25942421Syokota	    sc->command_byte = -1;
26042421Syokota	    sc->command_mask = 0;
26142421Syokota	    sc->lock = FALSE;
26242421Syokota	    sc->kbd.head = sc->kbd.tail = 0;
26342421Syokota	    sc->aux.head = sc->aux.tail = 0;
26442421Syokota#if KBDIO_DEBUG >= 2
26542421Syokota	    sc->kbd.call_count = 0;
26642421Syokota	    sc->kbd.qcount = sc->kbd.max_qcount = 0;
26742421Syokota	    sc->aux.call_count = 0;
26842421Syokota	    sc->aux.qcount = sc->aux.max_qcount = 0;
26942421Syokota#endif
27042421Syokota	}
27158271Syokota	sc->iot = tag;
27258271Syokota	sc->ioh0 = h0;
27358271Syokota	sc->ioh1 = h1;
274207354Ssobomax
275207354Ssobomax#if defined(__amd64__)
276207354Ssobomax	/*
277207354Ssobomax	 * On certain chipsets AT keyboard controller isn't present and is
278207354Ssobomax	 * emulated by BIOS using SMI interrupt. On those chipsets reading
279207354Ssobomax	 * from the status port may be thousand times slower than usually.
280207354Ssobomax	 * Sometimes this emilation is not working properly resulting in
281207354Ssobomax	 * commands timing our and since we assume that inb() operation
282207354Ssobomax	 * takes very little time to complete we need to adjust number of
283207354Ssobomax	 * retries to keep waiting time within a designed limits (100ms).
284207354Ssobomax	 * Measure time it takes to make read_status() call and adjust
285207354Ssobomax	 * number of retries accordingly.
286207354Ssobomax	 */
287207354Ssobomax	flags = intr_disable();
288207354Ssobomax	tscval[0] = rdtsc();
289207354Ssobomax	read_status(sc);
290207354Ssobomax	tscval[1] = rdtsc();
291207354Ssobomax	DELAY(1000);
292207354Ssobomax	tscval[2] = rdtsc();
293207354Ssobomax	intr_restore(flags);
294207354Ssobomax	read_delay = tscval[1] - tscval[0];
295207354Ssobomax	read_delay /= (tscval[2] - tscval[1]) / 1000;
296207354Ssobomax	sc->retry = 100000 / ((KBDD_DELAYTIME * 2) + read_delay);
297207354Ssobomax#else
298207354Ssobomax	sc->retry = 5000;
299207354Ssobomax#endif
300207354Ssobomax
30142421Syokota	return 0;
30242421Syokota}
30342421Syokota
30458271Syokota/* open a keyboard controller */
30542421SyokotaKBDC
30658271Syokotaatkbdc_open(int unit)
30742421Syokota{
30858271Syokota    if (unit <= 0)
30958271Syokota	unit = 0;
31058271Syokota    if (unit >= MAXKBDC)
31158271Syokota	return NULL;
31258271Syokota    if ((atkbdc_softc[unit]->port0 != NULL)
31358271Syokota	|| (atkbdc_softc[unit]->ioh0 != 0))		/* XXX */
31458271Syokota	return (KBDC)atkbdc_softc[unit];
31542421Syokota    return NULL;
31642421Syokota}
31742421Syokota
31842421Syokota/*
31942421Syokota * I/O access arbitration in `kbdio'
32042421Syokota *
32142421Syokota * The `kbdio' module uses a simplistic convention to arbitrate
32242421Syokota * I/O access to the controller/keyboard/mouse. The convention requires
32342421Syokota * close cooperation of the calling device driver.
32442421Syokota *
32593279Smurray * The device drivers which utilize the `kbdio' module are assumed to
32642421Syokota * have the following set of routines.
32742421Syokota *    a. An interrupt handler (the bottom half of the driver).
32893279Smurray *    b. Timeout routines which may briefly poll the keyboard controller.
32942421Syokota *    c. Routines outside interrupt context (the top half of the driver).
33042421Syokota * They should follow the rules below:
33142421Syokota *    1. The interrupt handler may assume that it always has full access
33242421Syokota *       to the controller/keyboard/mouse.
33342421Syokota *    2. The other routines must issue `spltty()' if they wish to
33442421Syokota *       prevent the interrupt handler from accessing
33542421Syokota *       the controller/keyboard/mouse.
33642421Syokota *    3. The timeout routines and the top half routines of the device driver
33742421Syokota *       arbitrate I/O access by observing the lock flag in `kbdio'.
33842421Syokota *       The flag is manipulated via `kbdc_lock()'; when one wants to
33942421Syokota *       perform I/O, call `kbdc_lock(kbdc, TRUE)' and proceed only if
34042421Syokota *       the call returns with TRUE. Otherwise the caller must back off.
34142421Syokota *       Call `kbdc_lock(kbdc, FALSE)' when necessary I/O operaion
34242421Syokota *       is finished. This mechanism does not prevent the interrupt
34342421Syokota *       handler from being invoked at any time and carrying out I/O.
34442421Syokota *       Therefore, `spltty()' must be strategically placed in the device
34542421Syokota *       driver code. Also note that the timeout routine may interrupt
34642421Syokota *       `kbdc_lock()' called by the top half of the driver, but this
34793279Smurray *       interruption is OK so long as the timeout routine observes
34893279Smurray *       rule 4 below.
34942421Syokota *    4. The interrupt and timeout routines should not extend I/O operation
35093279Smurray *       across more than one interrupt or timeout; they must complete any
35193279Smurray *       necessary I/O operation within one invocation of the routine.
35293279Smurray *       This means that if the timeout routine acquires the lock flag,
35342421Syokota *       it must reset the flag to FALSE before it returns.
35442421Syokota */
35542421Syokota
35642421Syokota/* set/reset polling lock */
35742421Syokotaint
35842421Syokotakbdc_lock(KBDC p, int lock)
35942421Syokota{
36042421Syokota    int prevlock;
36142421Syokota
36242421Syokota    prevlock = kbdcp(p)->lock;
36342421Syokota    kbdcp(p)->lock = lock;
36442421Syokota
36542421Syokota    return (prevlock != lock);
36642421Syokota}
36742421Syokota
36842421Syokota/* check if any data is waiting to be processed */
36942421Syokotaint
37042421Syokotakbdc_data_ready(KBDC p)
37142421Syokota{
37242421Syokota    return (availq(&kbdcp(p)->kbd) || availq(&kbdcp(p)->aux)
37358271Syokota	|| (read_status(kbdcp(p)) & KBDS_ANY_BUFFER_FULL));
37442421Syokota}
37542421Syokota
37642421Syokota/* queuing functions */
37742421Syokota
37842421Syokotastatic int
37942421Syokotaaddq(kqueue *q, int c)
38042421Syokota{
38142421Syokota    if (nextq(q->tail) != q->head) {
38242421Syokota	q->q[q->tail] = c;
38342421Syokota	q->tail = nextq(q->tail);
38442421Syokota#if KBDIO_DEBUG >= 2
38542421Syokota        ++q->call_count;
38642421Syokota        ++q->qcount;
38742421Syokota	if (q->qcount > q->max_qcount)
38842421Syokota            q->max_qcount = q->qcount;
38942421Syokota#endif
39042421Syokota	return TRUE;
39142421Syokota    }
39242421Syokota    return FALSE;
39342421Syokota}
39442421Syokota
39542421Syokotastatic int
39642421Syokotaremoveq(kqueue *q)
39742421Syokota{
39842421Syokota    int c;
39942421Syokota
40042421Syokota    if (q->tail != q->head) {
40142421Syokota	c = q->q[q->head];
40242421Syokota	q->head = nextq(q->head);
40342421Syokota#if KBDIO_DEBUG >= 2
40442421Syokota        --q->qcount;
40542421Syokota#endif
40642421Syokota	return c;
40742421Syokota    }
40842421Syokota    return -1;
40942421Syokota}
41042421Syokota
41142421Syokota/*
41242421Syokota * device I/O routines
41342421Syokota */
41442421Syokotastatic int
41542421Syokotawait_while_controller_busy(struct atkbdc_softc *kbdc)
41642421Syokota{
417207354Ssobomax    int retry;
41842421Syokota    int f;
41942421Syokota
420207354Ssobomax    /* CPU will stay inside the loop for 100msec at most */
421207354Ssobomax    retry = kbdc->retry;
422207354Ssobomax
42358271Syokota    while ((f = read_status(kbdc)) & KBDS_INPUT_BUFFER_FULL) {
42442421Syokota	if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
42542421Syokota	    DELAY(KBDD_DELAYTIME);
42658271Syokota	    addq(&kbdc->kbd, read_data(kbdc));
42742421Syokota	} else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
42842421Syokota	    DELAY(KBDD_DELAYTIME);
42958271Syokota	    addq(&kbdc->aux, read_data(kbdc));
43042421Syokota	}
43142421Syokota        DELAY(KBDC_DELAYTIME);
43242421Syokota        if (--retry < 0)
43342421Syokota    	    return FALSE;
43442421Syokota    }
43542421Syokota    return TRUE;
43642421Syokota}
43742421Syokota
43842421Syokota/*
43942421Syokota * wait for any data; whether it's from the controller,
44042421Syokota * the keyboard, or the aux device.
44142421Syokota */
44242421Syokotastatic int
44342421Syokotawait_for_data(struct atkbdc_softc *kbdc)
44442421Syokota{
445207354Ssobomax    int retry;
44642421Syokota    int f;
44742421Syokota
448207354Ssobomax    /* CPU will stay inside the loop for 200msec at most */
449207354Ssobomax    retry = kbdc->retry * 2;
450207354Ssobomax
45158271Syokota    while ((f = read_status(kbdc) & KBDS_ANY_BUFFER_FULL) == 0) {
45242421Syokota        DELAY(KBDC_DELAYTIME);
45342421Syokota        if (--retry < 0)
45442421Syokota    	    return 0;
45542421Syokota    }
45642421Syokota    DELAY(KBDD_DELAYTIME);
45742421Syokota    return f;
45842421Syokota}
45942421Syokota
46042421Syokota/* wait for data from the keyboard */
46142421Syokotastatic int
46242421Syokotawait_for_kbd_data(struct atkbdc_softc *kbdc)
46342421Syokota{
464207354Ssobomax    int retry;
46542421Syokota    int f;
46642421Syokota
467207354Ssobomax    /* CPU will stay inside the loop for 200msec at most */
468207354Ssobomax    retry = kbdc->retry * 2;
469207354Ssobomax
47058271Syokota    while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
47142421Syokota	    != KBDS_KBD_BUFFER_FULL) {
47242421Syokota        if (f == KBDS_AUX_BUFFER_FULL) {
47342421Syokota	    DELAY(KBDD_DELAYTIME);
47458271Syokota	    addq(&kbdc->aux, read_data(kbdc));
47542421Syokota	}
47642421Syokota        DELAY(KBDC_DELAYTIME);
47742421Syokota        if (--retry < 0)
47842421Syokota    	    return 0;
47942421Syokota    }
48042421Syokota    DELAY(KBDD_DELAYTIME);
48142421Syokota    return f;
48242421Syokota}
48342421Syokota
48442421Syokota/*
48542421Syokota * wait for an ACK(FAh), RESEND(FEh), or RESET_FAIL(FCh) from the keyboard.
48642421Syokota * queue anything else.
48742421Syokota */
48842421Syokotastatic int
48942421Syokotawait_for_kbd_ack(struct atkbdc_softc *kbdc)
49042421Syokota{
491207354Ssobomax    int retry;
49242421Syokota    int f;
49342421Syokota    int b;
49442421Syokota
495207354Ssobomax    /* CPU will stay inside the loop for 200msec at most */
496207354Ssobomax    retry = kbdc->retry * 2;
497207354Ssobomax
49842421Syokota    while (retry-- > 0) {
49958271Syokota        if ((f = read_status(kbdc)) & KBDS_ANY_BUFFER_FULL) {
50042421Syokota	    DELAY(KBDD_DELAYTIME);
50158271Syokota            b = read_data(kbdc);
50242421Syokota	    if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
50342421Syokota		if ((b == KBD_ACK) || (b == KBD_RESEND)
50442421Syokota		    || (b == KBD_RESET_FAIL))
50542421Syokota		    return b;
50642421Syokota		addq(&kbdc->kbd, b);
50742421Syokota	    } else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
50842421Syokota		addq(&kbdc->aux, b);
50942421Syokota	    }
51042421Syokota	}
51142421Syokota        DELAY(KBDC_DELAYTIME);
51242421Syokota    }
51342421Syokota    return -1;
51442421Syokota}
51542421Syokota
51642421Syokota/* wait for data from the aux device */
51742421Syokotastatic int
51842421Syokotawait_for_aux_data(struct atkbdc_softc *kbdc)
51942421Syokota{
520207354Ssobomax    int retry;
52142421Syokota    int f;
52242421Syokota
523207354Ssobomax    /* CPU will stay inside the loop for 200msec at most */
524207354Ssobomax    retry = kbdc->retry * 2;
525207354Ssobomax
52658271Syokota    while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
52742421Syokota	    != KBDS_AUX_BUFFER_FULL) {
52842421Syokota        if (f == KBDS_KBD_BUFFER_FULL) {
52942421Syokota	    DELAY(KBDD_DELAYTIME);
53058271Syokota	    addq(&kbdc->kbd, read_data(kbdc));
53142421Syokota	}
53242421Syokota        DELAY(KBDC_DELAYTIME);
53342421Syokota        if (--retry < 0)
53442421Syokota    	    return 0;
53542421Syokota    }
53642421Syokota    DELAY(KBDD_DELAYTIME);
53742421Syokota    return f;
53842421Syokota}
53942421Syokota
54042421Syokota/*
54142421Syokota * wait for an ACK(FAh), RESEND(FEh), or RESET_FAIL(FCh) from the aux device.
54242421Syokota * queue anything else.
54342421Syokota */
54442421Syokotastatic int
54542421Syokotawait_for_aux_ack(struct atkbdc_softc *kbdc)
54642421Syokota{
547207354Ssobomax    int retry;
54842421Syokota    int f;
54942421Syokota    int b;
55042421Syokota
551207354Ssobomax    /* CPU will stay inside the loop for 200msec at most */
552207354Ssobomax    retry = kbdc->retry * 2;
553207354Ssobomax
55442421Syokota    while (retry-- > 0) {
55558271Syokota        if ((f = read_status(kbdc)) & KBDS_ANY_BUFFER_FULL) {
55642421Syokota	    DELAY(KBDD_DELAYTIME);
55758271Syokota            b = read_data(kbdc);
55842421Syokota	    if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
55942421Syokota		if ((b == PSM_ACK) || (b == PSM_RESEND)
56042421Syokota		    || (b == PSM_RESET_FAIL))
56142421Syokota		    return b;
56242421Syokota		addq(&kbdc->aux, b);
56342421Syokota	    } else if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
56442421Syokota		addq(&kbdc->kbd, b);
56542421Syokota	    }
56642421Syokota	}
56742421Syokota        DELAY(KBDC_DELAYTIME);
56842421Syokota    }
56942421Syokota    return -1;
57042421Syokota}
57142421Syokota
57242421Syokota/* write a one byte command to the controller */
57342421Syokotaint
57442421Syokotawrite_controller_command(KBDC p, int c)
57542421Syokota{
57642421Syokota    if (!wait_while_controller_busy(kbdcp(p)))
57742421Syokota	return FALSE;
57858271Syokota    write_command(kbdcp(p), c);
57942421Syokota    return TRUE;
58042421Syokota}
58142421Syokota
58242421Syokota/* write a one byte data to the controller */
58342421Syokotaint
58442421Syokotawrite_controller_data(KBDC p, int c)
58542421Syokota{
58642421Syokota    if (!wait_while_controller_busy(kbdcp(p)))
58742421Syokota	return FALSE;
58858271Syokota    write_data(kbdcp(p), c);
58942421Syokota    return TRUE;
59042421Syokota}
59142421Syokota
59242421Syokota/* write a one byte keyboard command */
59342421Syokotaint
59442421Syokotawrite_kbd_command(KBDC p, int c)
59542421Syokota{
59642421Syokota    if (!wait_while_controller_busy(kbdcp(p)))
59742421Syokota	return FALSE;
59858271Syokota    write_data(kbdcp(p), c);
59942421Syokota    return TRUE;
60042421Syokota}
60142421Syokota
60242421Syokota/* write a one byte auxiliary device command */
60342421Syokotaint
60442421Syokotawrite_aux_command(KBDC p, int c)
60542421Syokota{
60642421Syokota    if (!write_controller_command(p, KBDC_WRITE_TO_AUX))
60742421Syokota	return FALSE;
60842421Syokota    return write_controller_data(p, c);
60942421Syokota}
61042421Syokota
61142421Syokota/* send a command to the keyboard and wait for ACK */
61242421Syokotaint
61342421Syokotasend_kbd_command(KBDC p, int c)
61442421Syokota{
61542421Syokota    int retry = KBD_MAXRETRY;
61642421Syokota    int res = -1;
61742421Syokota
61842421Syokota    while (retry-- > 0) {
61942421Syokota	if (!write_kbd_command(p, c))
62042421Syokota	    continue;
62142421Syokota        res = wait_for_kbd_ack(kbdcp(p));
62242421Syokota        if (res == KBD_ACK)
62342421Syokota    	    break;
62442421Syokota    }
62542421Syokota    return res;
62642421Syokota}
62742421Syokota
62842421Syokota/* send a command to the auxiliary device and wait for ACK */
62942421Syokotaint
63042421Syokotasend_aux_command(KBDC p, int c)
63142421Syokota{
63242421Syokota    int retry = KBD_MAXRETRY;
63342421Syokota    int res = -1;
63442421Syokota
63542421Syokota    while (retry-- > 0) {
63642421Syokota	if (!write_aux_command(p, c))
63742421Syokota	    continue;
63842421Syokota	/*
63942421Syokota	 * FIXME: XXX
64042421Syokota	 * The aux device may have already sent one or two bytes of
64142421Syokota	 * status data, when a command is received. It will immediately
64242421Syokota	 * stop data transmission, thus, leaving an incomplete data
64342421Syokota	 * packet in our buffer. We have to discard any unprocessed
64442421Syokota	 * data in order to remove such packets. Well, we may remove
64542421Syokota	 * unprocessed, but necessary data byte as well...
64642421Syokota	 */
64742421Syokota	emptyq(&kbdcp(p)->aux);
64842421Syokota        res = wait_for_aux_ack(kbdcp(p));
64942421Syokota        if (res == PSM_ACK)
65042421Syokota    	    break;
65142421Syokota    }
65242421Syokota    return res;
65342421Syokota}
65442421Syokota
65542421Syokota/* send a command and a data to the keyboard, wait for ACKs */
65642421Syokotaint
65742421Syokotasend_kbd_command_and_data(KBDC p, int c, int d)
65842421Syokota{
65942421Syokota    int retry;
66042421Syokota    int res = -1;
66142421Syokota
66242421Syokota    for (retry = KBD_MAXRETRY; retry > 0; --retry) {
66342421Syokota	if (!write_kbd_command(p, c))
66442421Syokota	    continue;
66542421Syokota        res = wait_for_kbd_ack(kbdcp(p));
66642421Syokota        if (res == KBD_ACK)
66742421Syokota    	    break;
66842421Syokota        else if (res != KBD_RESEND)
66942421Syokota    	    return res;
67042421Syokota    }
67142421Syokota    if (retry <= 0)
67242421Syokota	return res;
67342421Syokota
67442421Syokota    for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) {
67542421Syokota	if (!write_kbd_command(p, d))
67642421Syokota	    continue;
67742421Syokota        res = wait_for_kbd_ack(kbdcp(p));
67842421Syokota        if (res != KBD_RESEND)
67942421Syokota    	    break;
68042421Syokota    }
68142421Syokota    return res;
68242421Syokota}
68342421Syokota
68442421Syokota/* send a command and a data to the auxiliary device, wait for ACKs */
68542421Syokotaint
68642421Syokotasend_aux_command_and_data(KBDC p, int c, int d)
68742421Syokota{
68842421Syokota    int retry;
68942421Syokota    int res = -1;
69042421Syokota
69142421Syokota    for (retry = KBD_MAXRETRY; retry > 0; --retry) {
69242421Syokota	if (!write_aux_command(p, c))
69342421Syokota	    continue;
69442421Syokota	emptyq(&kbdcp(p)->aux);
69542421Syokota        res = wait_for_aux_ack(kbdcp(p));
69642421Syokota        if (res == PSM_ACK)
69742421Syokota    	    break;
69842421Syokota        else if (res != PSM_RESEND)
69942421Syokota    	    return res;
70042421Syokota    }
70142421Syokota    if (retry <= 0)
70242421Syokota	return res;
70342421Syokota
70442421Syokota    for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) {
70542421Syokota	if (!write_aux_command(p, d))
70642421Syokota	    continue;
70742421Syokota        res = wait_for_aux_ack(kbdcp(p));
70842421Syokota        if (res != PSM_RESEND)
70942421Syokota    	    break;
71042421Syokota    }
71142421Syokota    return res;
71242421Syokota}
71342421Syokota
71442421Syokota/*
71542421Syokota * read one byte from any source; whether from the controller,
71642421Syokota * the keyboard, or the aux device
71742421Syokota */
71842421Syokotaint
71942421Syokotaread_controller_data(KBDC p)
72042421Syokota{
72142421Syokota    if (availq(&kbdcp(p)->kbd))
72242421Syokota        return removeq(&kbdcp(p)->kbd);
72342421Syokota    if (availq(&kbdcp(p)->aux))
72442421Syokota        return removeq(&kbdcp(p)->aux);
72542421Syokota    if (!wait_for_data(kbdcp(p)))
72642421Syokota        return -1;		/* timeout */
72758271Syokota    return read_data(kbdcp(p));
72842421Syokota}
72942421Syokota
73042421Syokota#if KBDIO_DEBUG >= 2
73142421Syokotastatic int call = 0;
73242421Syokota#endif
73342421Syokota
73442421Syokota/* read one byte from the keyboard */
73542421Syokotaint
73642421Syokotaread_kbd_data(KBDC p)
73742421Syokota{
73842421Syokota#if KBDIO_DEBUG >= 2
73942421Syokota    if (++call > 2000) {
74042421Syokota	call = 0;
74142421Syokota	log(LOG_DEBUG, "kbdc: kbd q: %d calls, max %d chars, "
74242421Syokota			     "aux q: %d calls, max %d chars\n",
74342421Syokota		       kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount,
74442421Syokota		       kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount);
74542421Syokota    }
74642421Syokota#endif
74742421Syokota
74842421Syokota    if (availq(&kbdcp(p)->kbd))
74942421Syokota        return removeq(&kbdcp(p)->kbd);
75042421Syokota    if (!wait_for_kbd_data(kbdcp(p)))
75142421Syokota        return -1;		/* timeout */
75258271Syokota    return read_data(kbdcp(p));
75342421Syokota}
75442421Syokota
75542421Syokota/* read one byte from the keyboard, but return immediately if
75642421Syokota * no data is waiting
75742421Syokota */
75842421Syokotaint
75942421Syokotaread_kbd_data_no_wait(KBDC p)
76042421Syokota{
76142421Syokota    int f;
76242421Syokota
76342421Syokota#if KBDIO_DEBUG >= 2
76442421Syokota    if (++call > 2000) {
76542421Syokota	call = 0;
76642421Syokota	log(LOG_DEBUG, "kbdc: kbd q: %d calls, max %d chars, "
76742421Syokota			     "aux q: %d calls, max %d chars\n",
76842421Syokota		       kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount,
76942421Syokota		       kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount);
77042421Syokota    }
77142421Syokota#endif
77242421Syokota
77342421Syokota    if (availq(&kbdcp(p)->kbd))
77442421Syokota        return removeq(&kbdcp(p)->kbd);
77558271Syokota    f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
77642421Syokota    if (f == KBDS_AUX_BUFFER_FULL) {
77742421Syokota        DELAY(KBDD_DELAYTIME);
77858271Syokota        addq(&kbdcp(p)->aux, read_data(kbdcp(p)));
77958271Syokota        f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
78042421Syokota    }
78142421Syokota    if (f == KBDS_KBD_BUFFER_FULL) {
78242421Syokota        DELAY(KBDD_DELAYTIME);
78358271Syokota        return read_data(kbdcp(p));
78442421Syokota    }
78542421Syokota    return -1;		/* no data */
78642421Syokota}
78742421Syokota
78842421Syokota/* read one byte from the aux device */
78942421Syokotaint
79042421Syokotaread_aux_data(KBDC p)
79142421Syokota{
79242421Syokota    if (availq(&kbdcp(p)->aux))
79342421Syokota        return removeq(&kbdcp(p)->aux);
79442421Syokota    if (!wait_for_aux_data(kbdcp(p)))
79542421Syokota        return -1;		/* timeout */
79658271Syokota    return read_data(kbdcp(p));
79742421Syokota}
79842421Syokota
79942421Syokota/* read one byte from the aux device, but return immediately if
80042421Syokota * no data is waiting
80142421Syokota */
80242421Syokotaint
80342421Syokotaread_aux_data_no_wait(KBDC p)
80442421Syokota{
80542421Syokota    int f;
80642421Syokota
80742421Syokota    if (availq(&kbdcp(p)->aux))
80842421Syokota        return removeq(&kbdcp(p)->aux);
80958271Syokota    f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
81042421Syokota    if (f == KBDS_KBD_BUFFER_FULL) {
81142421Syokota        DELAY(KBDD_DELAYTIME);
81258271Syokota        addq(&kbdcp(p)->kbd, read_data(kbdcp(p)));
81358271Syokota        f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
81442421Syokota    }
81542421Syokota    if (f == KBDS_AUX_BUFFER_FULL) {
81642421Syokota        DELAY(KBDD_DELAYTIME);
81758271Syokota        return read_data(kbdcp(p));
81842421Syokota    }
81942421Syokota    return -1;		/* no data */
82042421Syokota}
82142421Syokota
82242421Syokota/* discard data from the keyboard */
82342421Syokotavoid
82442421Syokotaempty_kbd_buffer(KBDC p, int wait)
82542421Syokota{
82642421Syokota    int t;
82742421Syokota    int b;
82842421Syokota    int f;
82942421Syokota#if KBDIO_DEBUG >= 2
83042421Syokota    int c1 = 0;
83142421Syokota    int c2 = 0;
83242421Syokota#endif
83342421Syokota    int delta = 2;
83442421Syokota
83542421Syokota    for (t = wait; t > 0; ) {
83658271Syokota        if ((f = read_status(kbdcp(p))) & KBDS_ANY_BUFFER_FULL) {
83742421Syokota	    DELAY(KBDD_DELAYTIME);
83858271Syokota            b = read_data(kbdcp(p));
83942421Syokota	    if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
84042421Syokota		addq(&kbdcp(p)->aux, b);
84142421Syokota#if KBDIO_DEBUG >= 2
84242421Syokota		++c2;
84342421Syokota            } else {
84442421Syokota		++c1;
84542421Syokota#endif
84642421Syokota	    }
84742421Syokota	    t = wait;
84842421Syokota	} else {
84942421Syokota	    t -= delta;
85042421Syokota	}
85142421Syokota        DELAY(delta*1000);
85242421Syokota    }
85342421Syokota#if KBDIO_DEBUG >= 2
85442421Syokota    if ((c1 > 0) || (c2 > 0))
85542421Syokota        log(LOG_DEBUG, "kbdc: %d:%d char read (empty_kbd_buffer)\n", c1, c2);
85642421Syokota#endif
85742421Syokota
85842421Syokota    emptyq(&kbdcp(p)->kbd);
85942421Syokota}
86042421Syokota
86142421Syokota/* discard data from the aux device */
86242421Syokotavoid
86342421Syokotaempty_aux_buffer(KBDC p, int wait)
86442421Syokota{
86542421Syokota    int t;
86642421Syokota    int b;
86742421Syokota    int f;
86842421Syokota#if KBDIO_DEBUG >= 2
86942421Syokota    int c1 = 0;
87042421Syokota    int c2 = 0;
87142421Syokota#endif
87242421Syokota    int delta = 2;
87342421Syokota
87442421Syokota    for (t = wait; t > 0; ) {
87558271Syokota        if ((f = read_status(kbdcp(p))) & KBDS_ANY_BUFFER_FULL) {
87642421Syokota	    DELAY(KBDD_DELAYTIME);
87758271Syokota            b = read_data(kbdcp(p));
87842421Syokota	    if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
87942421Syokota		addq(&kbdcp(p)->kbd, b);
88042421Syokota#if KBDIO_DEBUG >= 2
88142421Syokota		++c1;
88242421Syokota            } else {
88342421Syokota		++c2;
88442421Syokota#endif
88542421Syokota	    }
88642421Syokota	    t = wait;
88742421Syokota	} else {
88842421Syokota	    t -= delta;
88942421Syokota	}
89042421Syokota	DELAY(delta*1000);
89142421Syokota    }
89242421Syokota#if KBDIO_DEBUG >= 2
89342421Syokota    if ((c1 > 0) || (c2 > 0))
89442421Syokota        log(LOG_DEBUG, "kbdc: %d:%d char read (empty_aux_buffer)\n", c1, c2);
89542421Syokota#endif
89642421Syokota
89742421Syokota    emptyq(&kbdcp(p)->aux);
89842421Syokota}
89942421Syokota
90042421Syokota/* discard any data from the keyboard or the aux device */
90142421Syokotavoid
90242421Syokotaempty_both_buffers(KBDC p, int wait)
90342421Syokota{
90442421Syokota    int t;
90542421Syokota    int f;
906161969Sdwhite    int waited = 0;
90742421Syokota#if KBDIO_DEBUG >= 2
90842421Syokota    int c1 = 0;
90942421Syokota    int c2 = 0;
91042421Syokota#endif
91142421Syokota    int delta = 2;
91242421Syokota
91342421Syokota    for (t = wait; t > 0; ) {
91458271Syokota        if ((f = read_status(kbdcp(p))) & KBDS_ANY_BUFFER_FULL) {
91542421Syokota	    DELAY(KBDD_DELAYTIME);
91658271Syokota            (void)read_data(kbdcp(p));
91742421Syokota#if KBDIO_DEBUG >= 2
91842421Syokota	    if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL)
91942421Syokota		++c1;
92042421Syokota            else
92142421Syokota		++c2;
92242421Syokota#endif
92342421Syokota	    t = wait;
92442421Syokota	} else {
92542421Syokota	    t -= delta;
92642421Syokota	}
927161969Sdwhite
928161969Sdwhite	/*
929161969Sdwhite	 * Some systems (Intel/IBM blades) do not have keyboard devices and
930161969Sdwhite	 * will thus hang in this procedure. Time out after delta seconds to
931161969Sdwhite	 * avoid this hang -- the keyboard attach will fail later on.
932161969Sdwhite	 */
933161969Sdwhite        waited += (delta * 1000);
934161969Sdwhite        if (waited == (delta * 1000000))
935161969Sdwhite	    return;
936161969Sdwhite
93742421Syokota	DELAY(delta*1000);
93842421Syokota    }
93942421Syokota#if KBDIO_DEBUG >= 2
94042421Syokota    if ((c1 > 0) || (c2 > 0))
94142421Syokota        log(LOG_DEBUG, "kbdc: %d:%d char read (empty_both_buffers)\n", c1, c2);
94242421Syokota#endif
94342421Syokota
94442421Syokota    emptyq(&kbdcp(p)->kbd);
94542421Syokota    emptyq(&kbdcp(p)->aux);
94642421Syokota}
94742421Syokota
94842421Syokota/* keyboard and mouse device control */
94942421Syokota
95042421Syokota/* NOTE: enable the keyboard port but disable the keyboard
95142421Syokota * interrupt before calling "reset_kbd()".
95242421Syokota */
95342421Syokotaint
95442421Syokotareset_kbd(KBDC p)
95542421Syokota{
95642421Syokota    int retry = KBD_MAXRETRY;
95742421Syokota    int again = KBD_MAXWAIT;
95842421Syokota    int c = KBD_RESEND;		/* keep the compiler happy */
95942421Syokota
96042421Syokota    while (retry-- > 0) {
96142421Syokota        empty_both_buffers(p, 10);
96242421Syokota        if (!write_kbd_command(p, KBDC_RESET_KBD))
96342421Syokota	    continue;
96442421Syokota	emptyq(&kbdcp(p)->kbd);
96542421Syokota        c = read_controller_data(p);
96642421Syokota	if (verbose || bootverbose)
96742421Syokota            log(LOG_DEBUG, "kbdc: RESET_KBD return code:%04x\n", c);
96842421Syokota        if (c == KBD_ACK)	/* keyboard has agreed to reset itself... */
96942421Syokota    	    break;
97042421Syokota    }
97142421Syokota    if (retry < 0)
97242421Syokota        return FALSE;
97342421Syokota
97442421Syokota    while (again-- > 0) {
97542421Syokota        /* wait awhile, well, in fact we must wait quite loooooooooooong */
97642421Syokota        DELAY(KBD_RESETDELAY*1000);
97742421Syokota        c = read_controller_data(p);	/* RESET_DONE/RESET_FAIL */
97842421Syokota        if (c != -1) 	/* wait again if the controller is not ready */
97942421Syokota    	    break;
98042421Syokota    }
98142421Syokota    if (verbose || bootverbose)
98242421Syokota        log(LOG_DEBUG, "kbdc: RESET_KBD status:%04x\n", c);
98342421Syokota    if (c != KBD_RESET_DONE)
98442421Syokota        return FALSE;
98542421Syokota    return TRUE;
98642421Syokota}
98742421Syokota
98842421Syokota/* NOTE: enable the aux port but disable the aux interrupt
98942421Syokota * before calling `reset_aux_dev()'.
99042421Syokota */
99142421Syokotaint
99242421Syokotareset_aux_dev(KBDC p)
99342421Syokota{
99442421Syokota    int retry = KBD_MAXRETRY;
99542421Syokota    int again = KBD_MAXWAIT;
99642421Syokota    int c = PSM_RESEND;		/* keep the compiler happy */
99742421Syokota
99842421Syokota    while (retry-- > 0) {
99942421Syokota        empty_both_buffers(p, 10);
100042421Syokota        if (!write_aux_command(p, PSMC_RESET_DEV))
100142421Syokota	    continue;
100242421Syokota	emptyq(&kbdcp(p)->aux);
100342421Syokota	/* NOTE: Compaq Armada laptops require extra delay here. XXX */
100442421Syokota	for (again = KBD_MAXWAIT; again > 0; --again) {
100542421Syokota            DELAY(KBD_RESETDELAY*1000);
100642421Syokota            c = read_aux_data_no_wait(p);
100742421Syokota	    if (c != -1)
100842421Syokota		break;
100942421Syokota	}
101042421Syokota        if (verbose || bootverbose)
101142421Syokota            log(LOG_DEBUG, "kbdc: RESET_AUX return code:%04x\n", c);
101242421Syokota        if (c == PSM_ACK)	/* aux dev is about to reset... */
101342421Syokota    	    break;
101442421Syokota    }
101542421Syokota    if (retry < 0)
101642421Syokota        return FALSE;
101742421Syokota
101842421Syokota    for (again = KBD_MAXWAIT; again > 0; --again) {
101942421Syokota        /* wait awhile, well, quite looooooooooooong */
102042421Syokota        DELAY(KBD_RESETDELAY*1000);
102142421Syokota        c = read_aux_data_no_wait(p);	/* RESET_DONE/RESET_FAIL */
102242421Syokota        if (c != -1) 	/* wait again if the controller is not ready */
102342421Syokota    	    break;
102442421Syokota    }
102542421Syokota    if (verbose || bootverbose)
102642421Syokota        log(LOG_DEBUG, "kbdc: RESET_AUX status:%04x\n", c);
102742421Syokota    if (c != PSM_RESET_DONE)	/* reset status */
102842421Syokota        return FALSE;
102942421Syokota
103042421Syokota    c = read_aux_data(p);	/* device ID */
103142421Syokota    if (verbose || bootverbose)
103242421Syokota        log(LOG_DEBUG, "kbdc: RESET_AUX ID:%04x\n", c);
103342421Syokota    /* NOTE: we could check the device ID now, but leave it later... */
103442421Syokota    return TRUE;
103542421Syokota}
103642421Syokota
103742421Syokota/* controller diagnostics and setup */
103842421Syokota
103942421Syokotaint
104042421Syokotatest_controller(KBDC p)
104142421Syokota{
104242421Syokota    int retry = KBD_MAXRETRY;
104342421Syokota    int again = KBD_MAXWAIT;
104442421Syokota    int c = KBD_DIAG_FAIL;
104542421Syokota
104642421Syokota    while (retry-- > 0) {
104742421Syokota        empty_both_buffers(p, 10);
104842421Syokota        if (write_controller_command(p, KBDC_DIAGNOSE))
104942421Syokota    	    break;
105042421Syokota    }
105142421Syokota    if (retry < 0)
105242421Syokota        return FALSE;
105342421Syokota
105442421Syokota    emptyq(&kbdcp(p)->kbd);
105542421Syokota    while (again-- > 0) {
105642421Syokota        /* wait awhile */
105742421Syokota        DELAY(KBD_RESETDELAY*1000);
105842421Syokota        c = read_controller_data(p);	/* DIAG_DONE/DIAG_FAIL */
105942421Syokota        if (c != -1) 	/* wait again if the controller is not ready */
106042421Syokota    	    break;
106142421Syokota    }
106242421Syokota    if (verbose || bootverbose)
106342421Syokota        log(LOG_DEBUG, "kbdc: DIAGNOSE status:%04x\n", c);
106442421Syokota    return (c == KBD_DIAG_DONE);
106542421Syokota}
106642421Syokota
106742421Syokotaint
106842421Syokotatest_kbd_port(KBDC p)
106942421Syokota{
107042421Syokota    int retry = KBD_MAXRETRY;
107142421Syokota    int again = KBD_MAXWAIT;
107242421Syokota    int c = -1;
107342421Syokota
107442421Syokota    while (retry-- > 0) {
107542421Syokota        empty_both_buffers(p, 10);
107642421Syokota        if (write_controller_command(p, KBDC_TEST_KBD_PORT))
107742421Syokota    	    break;
107842421Syokota    }
107942421Syokota    if (retry < 0)
108042421Syokota        return FALSE;
108142421Syokota
108242421Syokota    emptyq(&kbdcp(p)->kbd);
108342421Syokota    while (again-- > 0) {
108442421Syokota        c = read_controller_data(p);
108542421Syokota        if (c != -1) 	/* try again if the controller is not ready */
108642421Syokota    	    break;
108742421Syokota    }
108842421Syokota    if (verbose || bootverbose)
108942421Syokota        log(LOG_DEBUG, "kbdc: TEST_KBD_PORT status:%04x\n", c);
109042421Syokota    return c;
109142421Syokota}
109242421Syokota
109342421Syokotaint
109442421Syokotatest_aux_port(KBDC p)
109542421Syokota{
109642421Syokota    int retry = KBD_MAXRETRY;
109742421Syokota    int again = KBD_MAXWAIT;
109842421Syokota    int c = -1;
109942421Syokota
110042421Syokota    while (retry-- > 0) {
110142421Syokota        empty_both_buffers(p, 10);
110242421Syokota        if (write_controller_command(p, KBDC_TEST_AUX_PORT))
110342421Syokota    	    break;
110442421Syokota    }
110542421Syokota    if (retry < 0)
110642421Syokota        return FALSE;
110742421Syokota
110842421Syokota    emptyq(&kbdcp(p)->kbd);
110942421Syokota    while (again-- > 0) {
111042421Syokota        c = read_controller_data(p);
111142421Syokota        if (c != -1) 	/* try again if the controller is not ready */
111242421Syokota    	    break;
111342421Syokota    }
111442421Syokota    if (verbose || bootverbose)
111542421Syokota        log(LOG_DEBUG, "kbdc: TEST_AUX_PORT status:%04x\n", c);
111642421Syokota    return c;
111742421Syokota}
111842421Syokota
111942421Syokotaint
112042421Syokotakbdc_get_device_mask(KBDC p)
112142421Syokota{
112242421Syokota    return kbdcp(p)->command_mask;
112342421Syokota}
112442421Syokota
112542421Syokotavoid
112642421Syokotakbdc_set_device_mask(KBDC p, int mask)
112742421Syokota{
112842421Syokota    kbdcp(p)->command_mask =
112942421Syokota	mask & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS);
113042421Syokota}
113142421Syokota
113242421Syokotaint
113342421Syokotaget_controller_command_byte(KBDC p)
113442421Syokota{
113542421Syokota    if (kbdcp(p)->command_byte != -1)
113642421Syokota	return kbdcp(p)->command_byte;
113742421Syokota    if (!write_controller_command(p, KBDC_GET_COMMAND_BYTE))
113842421Syokota	return -1;
113942421Syokota    emptyq(&kbdcp(p)->kbd);
114042421Syokota    kbdcp(p)->command_byte = read_controller_data(p);
114142421Syokota    return kbdcp(p)->command_byte;
114242421Syokota}
114342421Syokota
114442421Syokotaint
114542421Syokotaset_controller_command_byte(KBDC p, int mask, int command)
114642421Syokota{
114742421Syokota    if (get_controller_command_byte(p) == -1)
114842421Syokota	return FALSE;
114942421Syokota
115042421Syokota    command = (kbdcp(p)->command_byte & ~mask) | (command & mask);
115142421Syokota    if (command & KBD_DISABLE_KBD_PORT) {
115242421Syokota	if (!write_controller_command(p, KBDC_DISABLE_KBD_PORT))
115342421Syokota	    return FALSE;
115442421Syokota    }
115542421Syokota    if (!write_controller_command(p, KBDC_SET_COMMAND_BYTE))
115642421Syokota	return FALSE;
115742421Syokota    if (!write_controller_data(p, command))
115842421Syokota	return FALSE;
115942421Syokota    kbdcp(p)->command_byte = command;
116042421Syokota
116142421Syokota    if (verbose)
116242421Syokota        log(LOG_DEBUG, "kbdc: new command byte:%04x (set_controller...)\n",
116342421Syokota	    command);
116442421Syokota
116542421Syokota    return TRUE;
116642421Syokota}
1167