atkbdc.c revision 69781
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 *
3050477Speter * $FreeBSD: head/sys/dev/atkbdc/atkbdc.c 69781 2000-12-08 21:51:06Z dwmalone $
3142421Syokota * from kbdio.c,v 1.13 1998/09/25 11:55:46 yokota Exp
3242421Syokota */
3342421Syokota
3442421Syokota#include "atkbdc.h"
3542421Syokota#include "opt_kbd.h"
3642421Syokota
3742421Syokota#include <sys/param.h>
3842421Syokota#include <sys/systm.h>
3958271Syokota#include <sys/bus.h>
4042421Syokota#include <sys/malloc.h>
4142421Syokota#include <sys/syslog.h>
4258271Syokota#include <machine/bus_pio.h>
4358271Syokota#include <machine/bus.h>
4458271Syokota#include <machine/resource.h>
4558271Syokota#include <sys/rman.h>
4642421Syokota
4742421Syokota
4842421Syokota#include <dev/kbd/atkbdcreg.h>
4942421Syokota
5042421Syokota#include <isa/isareg.h>
5142421Syokota
5242421Syokota/* constants */
5342421Syokota
5456836Speter#define MAXKBDC		MAX(NATKBDC, 1)		/* XXX */
5542421Syokota
5642421Syokota/* macros */
5742421Syokota
5842421Syokota#ifndef MAX
5942421Syokota#define MAX(x, y)	((x) > (y) ? (x) : (y))
6042421Syokota#endif
6142421Syokota
6242421Syokota#define kbdcp(p)	((atkbdc_softc_t *)(p))
6342421Syokota#define nextq(i)	(((i) + 1) % KBDQ_BUFSIZE)
6442421Syokota#define availq(q)	((q)->head != (q)->tail)
6542421Syokota#if KBDIO_DEBUG >= 2
6642421Syokota#define emptyq(q)	((q)->tail = (q)->head = (q)->qcount = 0)
6742421Syokota#else
6842421Syokota#define emptyq(q)	((q)->tail = (q)->head = 0)
6942421Syokota#endif
7042421Syokota
7158271Syokota#define read_data(k)	(bus_space_read_1((k)->iot, (k)->ioh0, 0))
7258271Syokota#define read_status(k)	(bus_space_read_1((k)->iot, (k)->ioh1, 0))
7358271Syokota#define write_data(k, d)	\
7458271Syokota			(bus_space_write_1((k)->iot, (k)->ioh0, 0, (d)))
7558271Syokota#define write_command(k, d)	\
7658271Syokota			(bus_space_write_1((k)->iot, (k)->ioh1, 0, (d)))
7758271Syokota
7842421Syokota/* local variables */
7942421Syokota
8042421Syokota/*
8142421Syokota * We always need at least one copy of the kbdc_softc struct for the
8242421Syokota * low-level console.  As the low-level console accesses the keyboard
8342421Syokota * controller before kbdc, and all other devices, is probed, we
8442421Syokota * statically allocate one entry. XXX
8542421Syokota */
8642421Syokotastatic atkbdc_softc_t default_kbdc;
8742421Syokotastatic atkbdc_softc_t *atkbdc_softc[MAXKBDC] = { &default_kbdc };
8842421Syokota
8942421Syokotastatic int verbose = KBDIO_DEBUG;
9042421Syokota
9142421Syokota/* function prototypes */
9242421Syokota
9358271Syokotastatic int atkbdc_setup(atkbdc_softc_t *sc, bus_space_tag_t tag,
9458271Syokota			bus_space_handle_t h0, bus_space_handle_t h1);
9542421Syokotastatic int addq(kqueue *q, int c);
9642421Syokotastatic int removeq(kqueue *q);
9742421Syokotastatic int wait_while_controller_busy(atkbdc_softc_t *kbdc);
9842421Syokotastatic int wait_for_data(atkbdc_softc_t *kbdc);
9942421Syokotastatic int wait_for_kbd_data(atkbdc_softc_t *kbdc);
10042421Syokotastatic int wait_for_kbd_ack(atkbdc_softc_t *kbdc);
10142421Syokotastatic int wait_for_aux_data(atkbdc_softc_t *kbdc);
10242421Syokotastatic int wait_for_aux_ack(atkbdc_softc_t *kbdc);
10342421Syokota
10442421Syokotaatkbdc_softc_t
10542421Syokota*atkbdc_get_softc(int unit)
10642421Syokota{
10742421Syokota	atkbdc_softc_t *sc;
10842421Syokota
10942421Syokota	if (unit >= sizeof(atkbdc_softc)/sizeof(atkbdc_softc[0]))
11042421Syokota		return NULL;
11142421Syokota	sc = atkbdc_softc[unit];
11242421Syokota	if (sc == NULL) {
11342421Syokota		sc = atkbdc_softc[unit]
11469781Sdwmalone		   = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO);
11542421Syokota		if (sc == NULL)
11642421Syokota			return NULL;
11742421Syokota	}
11842421Syokota	return sc;
11942421Syokota}
12042421Syokota
12142421Syokotaint
12258271Syokotaatkbdc_probe_unit(int unit, struct resource *port0, struct resource *port1)
12342421Syokota{
12458271Syokota	if (rman_get_start(port0) <= 0)
12547296Syokota		return ENXIO;
12658271Syokota	if (rman_get_start(port1) <= 0)
12758271Syokota		return ENXIO;
12847296Syokota	return 0;
12947296Syokota}
13047296Syokota
13147296Syokotaint
13258271Syokotaatkbdc_attach_unit(int unit, atkbdc_softc_t *sc, struct resource *port0,
13358271Syokota		   struct resource *port1)
13447296Syokota{
13558271Syokota	return atkbdc_setup(sc, rman_get_bustag(port0),
13658271Syokota			    rman_get_bushandle(port0),
13758271Syokota			    rman_get_bushandle(port1));
13842421Syokota}
13942421Syokota
14042421Syokota/* the backdoor to the keyboard controller! XXX */
14142421Syokotaint
14242421Syokotaatkbdc_configure(void)
14342421Syokota{
14458271Syokota	bus_space_tag_t tag;
14558271Syokota	bus_space_handle_t h0;
14658271Syokota	bus_space_handle_t h1;
14758271Syokota	int port0;
14858271Syokota	int port1;
14958271Syokota
15058271Syokota	port0 = IO_KBD;
15158271Syokota	resource_int_value("atkbdc", 0, "port", &port0);
15258271Syokota	port1 = IO_KBD + KBD_STATUS_PORT;
15358271Syokota#if 0
15458271Syokota	resource_int_value("atkbdc", 0, "port", &port0);
15558271Syokota#endif
15658271Syokota
15758271Syokota	/* XXX: tag should be passed from the caller */
15858271Syokota#if defined(__i386__)
15958271Syokota	tag = I386_BUS_SPACE_IO;
16058271Syokota#elif defined(__alpha__)
16165176Sdfr	tag = busspace_isa_io;
16258271Syokota#endif
16358271Syokota
16458271Syokota#if notyet
16558271Syokota	bus_space_map(tag, port0, IO_KBDSIZE, 0, &h0);
16658271Syokota	bus_space_map(tag, port1, IO_KBDSIZE, 0, &h1);
16758271Syokota#else
16858271Syokota	h0 = (bus_space_handle_t)port0;
16958271Syokota	h1 = (bus_space_handle_t)port1;
17058271Syokota#endif
17158271Syokota	return atkbdc_setup(atkbdc_softc[0], tag, h0, h1);
17242421Syokota}
17342421Syokota
17442421Syokotastatic int
17558271Syokotaatkbdc_setup(atkbdc_softc_t *sc, bus_space_tag_t tag, bus_space_handle_t h0,
17658271Syokota	     bus_space_handle_t h1)
17742421Syokota{
17858271Syokota	if (sc->ioh0 == 0) {	/* XXX */
17942421Syokota	    sc->command_byte = -1;
18042421Syokota	    sc->command_mask = 0;
18142421Syokota	    sc->lock = FALSE;
18242421Syokota	    sc->kbd.head = sc->kbd.tail = 0;
18342421Syokota	    sc->aux.head = sc->aux.tail = 0;
18442421Syokota#if KBDIO_DEBUG >= 2
18542421Syokota	    sc->kbd.call_count = 0;
18642421Syokota	    sc->kbd.qcount = sc->kbd.max_qcount = 0;
18742421Syokota	    sc->aux.call_count = 0;
18842421Syokota	    sc->aux.qcount = sc->aux.max_qcount = 0;
18942421Syokota#endif
19042421Syokota	}
19158271Syokota	sc->iot = tag;
19258271Syokota	sc->ioh0 = h0;
19358271Syokota	sc->ioh1 = h1;
19442421Syokota	return 0;
19542421Syokota}
19642421Syokota
19758271Syokota/* open a keyboard controller */
19842421SyokotaKBDC
19958271Syokotaatkbdc_open(int unit)
20042421Syokota{
20158271Syokota    if (unit <= 0)
20258271Syokota	unit = 0;
20358271Syokota    if (unit >= MAXKBDC)
20458271Syokota	return NULL;
20558271Syokota    if ((atkbdc_softc[unit]->port0 != NULL)
20658271Syokota	|| (atkbdc_softc[unit]->ioh0 != 0))		/* XXX */
20758271Syokota	return (KBDC)atkbdc_softc[unit];
20842421Syokota    return NULL;
20942421Syokota}
21042421Syokota
21142421Syokota/*
21242421Syokota * I/O access arbitration in `kbdio'
21342421Syokota *
21442421Syokota * The `kbdio' module uses a simplistic convention to arbitrate
21542421Syokota * I/O access to the controller/keyboard/mouse. The convention requires
21642421Syokota * close cooperation of the calling device driver.
21742421Syokota *
21842421Syokota * The device driver which utilizes the `kbdio' module are assumed to
21942421Syokota * have the following set of routines.
22042421Syokota *    a. An interrupt handler (the bottom half of the driver).
22142421Syokota *    b. Timeout routines which may briefly polls the keyboard controller.
22242421Syokota *    c. Routines outside interrupt context (the top half of the driver).
22342421Syokota * They should follow the rules below:
22442421Syokota *    1. The interrupt handler may assume that it always has full access
22542421Syokota *       to the controller/keyboard/mouse.
22642421Syokota *    2. The other routines must issue `spltty()' if they wish to
22742421Syokota *       prevent the interrupt handler from accessing
22842421Syokota *       the controller/keyboard/mouse.
22942421Syokota *    3. The timeout routines and the top half routines of the device driver
23042421Syokota *       arbitrate I/O access by observing the lock flag in `kbdio'.
23142421Syokota *       The flag is manipulated via `kbdc_lock()'; when one wants to
23242421Syokota *       perform I/O, call `kbdc_lock(kbdc, TRUE)' and proceed only if
23342421Syokota *       the call returns with TRUE. Otherwise the caller must back off.
23442421Syokota *       Call `kbdc_lock(kbdc, FALSE)' when necessary I/O operaion
23542421Syokota *       is finished. This mechanism does not prevent the interrupt
23642421Syokota *       handler from being invoked at any time and carrying out I/O.
23742421Syokota *       Therefore, `spltty()' must be strategically placed in the device
23842421Syokota *       driver code. Also note that the timeout routine may interrupt
23942421Syokota *       `kbdc_lock()' called by the top half of the driver, but this
24042421Syokota *       interruption is OK so long as the timeout routine observes the
24142421Syokota *       the rule 4 below.
24242421Syokota *    4. The interrupt and timeout routines should not extend I/O operation
24342421Syokota *       across more than one interrupt or timeout; they must complete
24442421Syokota *       necessary I/O operation within one invokation of the routine.
24542421Syokota *       This measns that if the timeout routine acquires the lock flag,
24642421Syokota *       it must reset the flag to FALSE before it returns.
24742421Syokota */
24842421Syokota
24942421Syokota/* set/reset polling lock */
25042421Syokotaint
25142421Syokotakbdc_lock(KBDC p, int lock)
25242421Syokota{
25342421Syokota    int prevlock;
25442421Syokota
25542421Syokota    prevlock = kbdcp(p)->lock;
25642421Syokota    kbdcp(p)->lock = lock;
25742421Syokota
25842421Syokota    return (prevlock != lock);
25942421Syokota}
26042421Syokota
26142421Syokota/* check if any data is waiting to be processed */
26242421Syokotaint
26342421Syokotakbdc_data_ready(KBDC p)
26442421Syokota{
26542421Syokota    return (availq(&kbdcp(p)->kbd) || availq(&kbdcp(p)->aux)
26658271Syokota	|| (read_status(kbdcp(p)) & KBDS_ANY_BUFFER_FULL));
26742421Syokota}
26842421Syokota
26942421Syokota/* queuing functions */
27042421Syokota
27142421Syokotastatic int
27242421Syokotaaddq(kqueue *q, int c)
27342421Syokota{
27442421Syokota    if (nextq(q->tail) != q->head) {
27542421Syokota	q->q[q->tail] = c;
27642421Syokota	q->tail = nextq(q->tail);
27742421Syokota#if KBDIO_DEBUG >= 2
27842421Syokota        ++q->call_count;
27942421Syokota        ++q->qcount;
28042421Syokota	if (q->qcount > q->max_qcount)
28142421Syokota            q->max_qcount = q->qcount;
28242421Syokota#endif
28342421Syokota	return TRUE;
28442421Syokota    }
28542421Syokota    return FALSE;
28642421Syokota}
28742421Syokota
28842421Syokotastatic int
28942421Syokotaremoveq(kqueue *q)
29042421Syokota{
29142421Syokota    int c;
29242421Syokota
29342421Syokota    if (q->tail != q->head) {
29442421Syokota	c = q->q[q->head];
29542421Syokota	q->head = nextq(q->head);
29642421Syokota#if KBDIO_DEBUG >= 2
29742421Syokota        --q->qcount;
29842421Syokota#endif
29942421Syokota	return c;
30042421Syokota    }
30142421Syokota    return -1;
30242421Syokota}
30342421Syokota
30442421Syokota/*
30542421Syokota * device I/O routines
30642421Syokota */
30742421Syokotastatic int
30842421Syokotawait_while_controller_busy(struct atkbdc_softc *kbdc)
30942421Syokota{
31042421Syokota    /* CPU will stay inside the loop for 100msec at most */
31142421Syokota    int retry = 5000;
31242421Syokota    int f;
31342421Syokota
31458271Syokota    while ((f = read_status(kbdc)) & KBDS_INPUT_BUFFER_FULL) {
31542421Syokota	if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
31642421Syokota	    DELAY(KBDD_DELAYTIME);
31758271Syokota	    addq(&kbdc->kbd, read_data(kbdc));
31842421Syokota	} else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
31942421Syokota	    DELAY(KBDD_DELAYTIME);
32058271Syokota	    addq(&kbdc->aux, read_data(kbdc));
32142421Syokota	}
32242421Syokota        DELAY(KBDC_DELAYTIME);
32342421Syokota        if (--retry < 0)
32442421Syokota    	    return FALSE;
32542421Syokota    }
32642421Syokota    return TRUE;
32742421Syokota}
32842421Syokota
32942421Syokota/*
33042421Syokota * wait for any data; whether it's from the controller,
33142421Syokota * the keyboard, or the aux device.
33242421Syokota */
33342421Syokotastatic int
33442421Syokotawait_for_data(struct atkbdc_softc *kbdc)
33542421Syokota{
33642421Syokota    /* CPU will stay inside the loop for 200msec at most */
33742421Syokota    int retry = 10000;
33842421Syokota    int f;
33942421Syokota
34058271Syokota    while ((f = read_status(kbdc) & KBDS_ANY_BUFFER_FULL) == 0) {
34142421Syokota        DELAY(KBDC_DELAYTIME);
34242421Syokota        if (--retry < 0)
34342421Syokota    	    return 0;
34442421Syokota    }
34542421Syokota    DELAY(KBDD_DELAYTIME);
34642421Syokota    return f;
34742421Syokota}
34842421Syokota
34942421Syokota/* wait for data from the keyboard */
35042421Syokotastatic int
35142421Syokotawait_for_kbd_data(struct atkbdc_softc *kbdc)
35242421Syokota{
35342421Syokota    /* CPU will stay inside the loop for 200msec at most */
35442421Syokota    int retry = 10000;
35542421Syokota    int f;
35642421Syokota
35758271Syokota    while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
35842421Syokota	    != KBDS_KBD_BUFFER_FULL) {
35942421Syokota        if (f == KBDS_AUX_BUFFER_FULL) {
36042421Syokota	    DELAY(KBDD_DELAYTIME);
36158271Syokota	    addq(&kbdc->aux, read_data(kbdc));
36242421Syokota	}
36342421Syokota        DELAY(KBDC_DELAYTIME);
36442421Syokota        if (--retry < 0)
36542421Syokota    	    return 0;
36642421Syokota    }
36742421Syokota    DELAY(KBDD_DELAYTIME);
36842421Syokota    return f;
36942421Syokota}
37042421Syokota
37142421Syokota/*
37242421Syokota * wait for an ACK(FAh), RESEND(FEh), or RESET_FAIL(FCh) from the keyboard.
37342421Syokota * queue anything else.
37442421Syokota */
37542421Syokotastatic int
37642421Syokotawait_for_kbd_ack(struct atkbdc_softc *kbdc)
37742421Syokota{
37842421Syokota    /* CPU will stay inside the loop for 200msec at most */
37942421Syokota    int retry = 10000;
38042421Syokota    int f;
38142421Syokota    int b;
38242421Syokota
38342421Syokota    while (retry-- > 0) {
38458271Syokota        if ((f = read_status(kbdc)) & KBDS_ANY_BUFFER_FULL) {
38542421Syokota	    DELAY(KBDD_DELAYTIME);
38658271Syokota            b = read_data(kbdc);
38742421Syokota	    if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
38842421Syokota		if ((b == KBD_ACK) || (b == KBD_RESEND)
38942421Syokota		    || (b == KBD_RESET_FAIL))
39042421Syokota		    return b;
39142421Syokota		addq(&kbdc->kbd, b);
39242421Syokota	    } else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
39342421Syokota		addq(&kbdc->aux, b);
39442421Syokota	    }
39542421Syokota	}
39642421Syokota        DELAY(KBDC_DELAYTIME);
39742421Syokota    }
39842421Syokota    return -1;
39942421Syokota}
40042421Syokota
40142421Syokota/* wait for data from the aux device */
40242421Syokotastatic int
40342421Syokotawait_for_aux_data(struct atkbdc_softc *kbdc)
40442421Syokota{
40542421Syokota    /* CPU will stay inside the loop for 200msec at most */
40642421Syokota    int retry = 10000;
40742421Syokota    int f;
40842421Syokota
40958271Syokota    while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
41042421Syokota	    != KBDS_AUX_BUFFER_FULL) {
41142421Syokota        if (f == KBDS_KBD_BUFFER_FULL) {
41242421Syokota	    DELAY(KBDD_DELAYTIME);
41358271Syokota	    addq(&kbdc->kbd, read_data(kbdc));
41442421Syokota	}
41542421Syokota        DELAY(KBDC_DELAYTIME);
41642421Syokota        if (--retry < 0)
41742421Syokota    	    return 0;
41842421Syokota    }
41942421Syokota    DELAY(KBDD_DELAYTIME);
42042421Syokota    return f;
42142421Syokota}
42242421Syokota
42342421Syokota/*
42442421Syokota * wait for an ACK(FAh), RESEND(FEh), or RESET_FAIL(FCh) from the aux device.
42542421Syokota * queue anything else.
42642421Syokota */
42742421Syokotastatic int
42842421Syokotawait_for_aux_ack(struct atkbdc_softc *kbdc)
42942421Syokota{
43042421Syokota    /* CPU will stay inside the loop for 200msec at most */
43142421Syokota    int retry = 10000;
43242421Syokota    int f;
43342421Syokota    int b;
43442421Syokota
43542421Syokota    while (retry-- > 0) {
43658271Syokota        if ((f = read_status(kbdc)) & KBDS_ANY_BUFFER_FULL) {
43742421Syokota	    DELAY(KBDD_DELAYTIME);
43858271Syokota            b = read_data(kbdc);
43942421Syokota	    if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
44042421Syokota		if ((b == PSM_ACK) || (b == PSM_RESEND)
44142421Syokota		    || (b == PSM_RESET_FAIL))
44242421Syokota		    return b;
44342421Syokota		addq(&kbdc->aux, b);
44442421Syokota	    } else if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
44542421Syokota		addq(&kbdc->kbd, b);
44642421Syokota	    }
44742421Syokota	}
44842421Syokota        DELAY(KBDC_DELAYTIME);
44942421Syokota    }
45042421Syokota    return -1;
45142421Syokota}
45242421Syokota
45342421Syokota/* write a one byte command to the controller */
45442421Syokotaint
45542421Syokotawrite_controller_command(KBDC p, int c)
45642421Syokota{
45742421Syokota    if (!wait_while_controller_busy(kbdcp(p)))
45842421Syokota	return FALSE;
45958271Syokota    write_command(kbdcp(p), c);
46042421Syokota    return TRUE;
46142421Syokota}
46242421Syokota
46342421Syokota/* write a one byte data to the controller */
46442421Syokotaint
46542421Syokotawrite_controller_data(KBDC p, int c)
46642421Syokota{
46742421Syokota    if (!wait_while_controller_busy(kbdcp(p)))
46842421Syokota	return FALSE;
46958271Syokota    write_data(kbdcp(p), c);
47042421Syokota    return TRUE;
47142421Syokota}
47242421Syokota
47342421Syokota/* write a one byte keyboard command */
47442421Syokotaint
47542421Syokotawrite_kbd_command(KBDC p, int c)
47642421Syokota{
47742421Syokota    if (!wait_while_controller_busy(kbdcp(p)))
47842421Syokota	return FALSE;
47958271Syokota    write_data(kbdcp(p), c);
48042421Syokota    return TRUE;
48142421Syokota}
48242421Syokota
48342421Syokota/* write a one byte auxiliary device command */
48442421Syokotaint
48542421Syokotawrite_aux_command(KBDC p, int c)
48642421Syokota{
48742421Syokota    if (!write_controller_command(p, KBDC_WRITE_TO_AUX))
48842421Syokota	return FALSE;
48942421Syokota    return write_controller_data(p, c);
49042421Syokota}
49142421Syokota
49242421Syokota/* send a command to the keyboard and wait for ACK */
49342421Syokotaint
49442421Syokotasend_kbd_command(KBDC p, int c)
49542421Syokota{
49642421Syokota    int retry = KBD_MAXRETRY;
49742421Syokota    int res = -1;
49842421Syokota
49942421Syokota    while (retry-- > 0) {
50042421Syokota	if (!write_kbd_command(p, c))
50142421Syokota	    continue;
50242421Syokota        res = wait_for_kbd_ack(kbdcp(p));
50342421Syokota        if (res == KBD_ACK)
50442421Syokota    	    break;
50542421Syokota    }
50642421Syokota    return res;
50742421Syokota}
50842421Syokota
50942421Syokota/* send a command to the auxiliary device and wait for ACK */
51042421Syokotaint
51142421Syokotasend_aux_command(KBDC p, int c)
51242421Syokota{
51342421Syokota    int retry = KBD_MAXRETRY;
51442421Syokota    int res = -1;
51542421Syokota
51642421Syokota    while (retry-- > 0) {
51742421Syokota	if (!write_aux_command(p, c))
51842421Syokota	    continue;
51942421Syokota	/*
52042421Syokota	 * FIXME: XXX
52142421Syokota	 * The aux device may have already sent one or two bytes of
52242421Syokota	 * status data, when a command is received. It will immediately
52342421Syokota	 * stop data transmission, thus, leaving an incomplete data
52442421Syokota	 * packet in our buffer. We have to discard any unprocessed
52542421Syokota	 * data in order to remove such packets. Well, we may remove
52642421Syokota	 * unprocessed, but necessary data byte as well...
52742421Syokota	 */
52842421Syokota	emptyq(&kbdcp(p)->aux);
52942421Syokota        res = wait_for_aux_ack(kbdcp(p));
53042421Syokota        if (res == PSM_ACK)
53142421Syokota    	    break;
53242421Syokota    }
53342421Syokota    return res;
53442421Syokota}
53542421Syokota
53642421Syokota/* send a command and a data to the keyboard, wait for ACKs */
53742421Syokotaint
53842421Syokotasend_kbd_command_and_data(KBDC p, int c, int d)
53942421Syokota{
54042421Syokota    int retry;
54142421Syokota    int res = -1;
54242421Syokota
54342421Syokota    for (retry = KBD_MAXRETRY; retry > 0; --retry) {
54442421Syokota	if (!write_kbd_command(p, c))
54542421Syokota	    continue;
54642421Syokota        res = wait_for_kbd_ack(kbdcp(p));
54742421Syokota        if (res == KBD_ACK)
54842421Syokota    	    break;
54942421Syokota        else if (res != KBD_RESEND)
55042421Syokota    	    return res;
55142421Syokota    }
55242421Syokota    if (retry <= 0)
55342421Syokota	return res;
55442421Syokota
55542421Syokota    for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) {
55642421Syokota	if (!write_kbd_command(p, d))
55742421Syokota	    continue;
55842421Syokota        res = wait_for_kbd_ack(kbdcp(p));
55942421Syokota        if (res != KBD_RESEND)
56042421Syokota    	    break;
56142421Syokota    }
56242421Syokota    return res;
56342421Syokota}
56442421Syokota
56542421Syokota/* send a command and a data to the auxiliary device, wait for ACKs */
56642421Syokotaint
56742421Syokotasend_aux_command_and_data(KBDC p, int c, int d)
56842421Syokota{
56942421Syokota    int retry;
57042421Syokota    int res = -1;
57142421Syokota
57242421Syokota    for (retry = KBD_MAXRETRY; retry > 0; --retry) {
57342421Syokota	if (!write_aux_command(p, c))
57442421Syokota	    continue;
57542421Syokota	emptyq(&kbdcp(p)->aux);
57642421Syokota        res = wait_for_aux_ack(kbdcp(p));
57742421Syokota        if (res == PSM_ACK)
57842421Syokota    	    break;
57942421Syokota        else if (res != PSM_RESEND)
58042421Syokota    	    return res;
58142421Syokota    }
58242421Syokota    if (retry <= 0)
58342421Syokota	return res;
58442421Syokota
58542421Syokota    for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) {
58642421Syokota	if (!write_aux_command(p, d))
58742421Syokota	    continue;
58842421Syokota        res = wait_for_aux_ack(kbdcp(p));
58942421Syokota        if (res != PSM_RESEND)
59042421Syokota    	    break;
59142421Syokota    }
59242421Syokota    return res;
59342421Syokota}
59442421Syokota
59542421Syokota/*
59642421Syokota * read one byte from any source; whether from the controller,
59742421Syokota * the keyboard, or the aux device
59842421Syokota */
59942421Syokotaint
60042421Syokotaread_controller_data(KBDC p)
60142421Syokota{
60242421Syokota    if (availq(&kbdcp(p)->kbd))
60342421Syokota        return removeq(&kbdcp(p)->kbd);
60442421Syokota    if (availq(&kbdcp(p)->aux))
60542421Syokota        return removeq(&kbdcp(p)->aux);
60642421Syokota    if (!wait_for_data(kbdcp(p)))
60742421Syokota        return -1;		/* timeout */
60858271Syokota    return read_data(kbdcp(p));
60942421Syokota}
61042421Syokota
61142421Syokota#if KBDIO_DEBUG >= 2
61242421Syokotastatic int call = 0;
61342421Syokota#endif
61442421Syokota
61542421Syokota/* read one byte from the keyboard */
61642421Syokotaint
61742421Syokotaread_kbd_data(KBDC p)
61842421Syokota{
61942421Syokota#if KBDIO_DEBUG >= 2
62042421Syokota    if (++call > 2000) {
62142421Syokota	call = 0;
62242421Syokota	log(LOG_DEBUG, "kbdc: kbd q: %d calls, max %d chars, "
62342421Syokota			     "aux q: %d calls, max %d chars\n",
62442421Syokota		       kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount,
62542421Syokota		       kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount);
62642421Syokota    }
62742421Syokota#endif
62842421Syokota
62942421Syokota    if (availq(&kbdcp(p)->kbd))
63042421Syokota        return removeq(&kbdcp(p)->kbd);
63142421Syokota    if (!wait_for_kbd_data(kbdcp(p)))
63242421Syokota        return -1;		/* timeout */
63358271Syokota    return read_data(kbdcp(p));
63442421Syokota}
63542421Syokota
63642421Syokota/* read one byte from the keyboard, but return immediately if
63742421Syokota * no data is waiting
63842421Syokota */
63942421Syokotaint
64042421Syokotaread_kbd_data_no_wait(KBDC p)
64142421Syokota{
64242421Syokota    int f;
64342421Syokota
64442421Syokota#if KBDIO_DEBUG >= 2
64542421Syokota    if (++call > 2000) {
64642421Syokota	call = 0;
64742421Syokota	log(LOG_DEBUG, "kbdc: kbd q: %d calls, max %d chars, "
64842421Syokota			     "aux q: %d calls, max %d chars\n",
64942421Syokota		       kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount,
65042421Syokota		       kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount);
65142421Syokota    }
65242421Syokota#endif
65342421Syokota
65442421Syokota    if (availq(&kbdcp(p)->kbd))
65542421Syokota        return removeq(&kbdcp(p)->kbd);
65658271Syokota    f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
65742421Syokota    if (f == KBDS_AUX_BUFFER_FULL) {
65842421Syokota        DELAY(KBDD_DELAYTIME);
65958271Syokota        addq(&kbdcp(p)->aux, read_data(kbdcp(p)));
66058271Syokota        f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
66142421Syokota    }
66242421Syokota    if (f == KBDS_KBD_BUFFER_FULL) {
66342421Syokota        DELAY(KBDD_DELAYTIME);
66458271Syokota        return read_data(kbdcp(p));
66542421Syokota    }
66642421Syokota    return -1;		/* no data */
66742421Syokota}
66842421Syokota
66942421Syokota/* read one byte from the aux device */
67042421Syokotaint
67142421Syokotaread_aux_data(KBDC p)
67242421Syokota{
67342421Syokota    if (availq(&kbdcp(p)->aux))
67442421Syokota        return removeq(&kbdcp(p)->aux);
67542421Syokota    if (!wait_for_aux_data(kbdcp(p)))
67642421Syokota        return -1;		/* timeout */
67758271Syokota    return read_data(kbdcp(p));
67842421Syokota}
67942421Syokota
68042421Syokota/* read one byte from the aux device, but return immediately if
68142421Syokota * no data is waiting
68242421Syokota */
68342421Syokotaint
68442421Syokotaread_aux_data_no_wait(KBDC p)
68542421Syokota{
68642421Syokota    int f;
68742421Syokota
68842421Syokota    if (availq(&kbdcp(p)->aux))
68942421Syokota        return removeq(&kbdcp(p)->aux);
69058271Syokota    f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
69142421Syokota    if (f == KBDS_KBD_BUFFER_FULL) {
69242421Syokota        DELAY(KBDD_DELAYTIME);
69358271Syokota        addq(&kbdcp(p)->kbd, read_data(kbdcp(p)));
69458271Syokota        f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
69542421Syokota    }
69642421Syokota    if (f == KBDS_AUX_BUFFER_FULL) {
69742421Syokota        DELAY(KBDD_DELAYTIME);
69858271Syokota        return read_data(kbdcp(p));
69942421Syokota    }
70042421Syokota    return -1;		/* no data */
70142421Syokota}
70242421Syokota
70342421Syokota/* discard data from the keyboard */
70442421Syokotavoid
70542421Syokotaempty_kbd_buffer(KBDC p, int wait)
70642421Syokota{
70742421Syokota    int t;
70842421Syokota    int b;
70942421Syokota    int f;
71042421Syokota#if KBDIO_DEBUG >= 2
71142421Syokota    int c1 = 0;
71242421Syokota    int c2 = 0;
71342421Syokota#endif
71442421Syokota    int delta = 2;
71542421Syokota
71642421Syokota    for (t = wait; t > 0; ) {
71758271Syokota        if ((f = read_status(kbdcp(p))) & KBDS_ANY_BUFFER_FULL) {
71842421Syokota	    DELAY(KBDD_DELAYTIME);
71958271Syokota            b = read_data(kbdcp(p));
72042421Syokota	    if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
72142421Syokota		addq(&kbdcp(p)->aux, b);
72242421Syokota#if KBDIO_DEBUG >= 2
72342421Syokota		++c2;
72442421Syokota            } else {
72542421Syokota		++c1;
72642421Syokota#endif
72742421Syokota	    }
72842421Syokota	    t = wait;
72942421Syokota	} else {
73042421Syokota	    t -= delta;
73142421Syokota	}
73242421Syokota        DELAY(delta*1000);
73342421Syokota    }
73442421Syokota#if KBDIO_DEBUG >= 2
73542421Syokota    if ((c1 > 0) || (c2 > 0))
73642421Syokota        log(LOG_DEBUG, "kbdc: %d:%d char read (empty_kbd_buffer)\n", c1, c2);
73742421Syokota#endif
73842421Syokota
73942421Syokota    emptyq(&kbdcp(p)->kbd);
74042421Syokota}
74142421Syokota
74242421Syokota/* discard data from the aux device */
74342421Syokotavoid
74442421Syokotaempty_aux_buffer(KBDC p, int wait)
74542421Syokota{
74642421Syokota    int t;
74742421Syokota    int b;
74842421Syokota    int f;
74942421Syokota#if KBDIO_DEBUG >= 2
75042421Syokota    int c1 = 0;
75142421Syokota    int c2 = 0;
75242421Syokota#endif
75342421Syokota    int delta = 2;
75442421Syokota
75542421Syokota    for (t = wait; t > 0; ) {
75658271Syokota        if ((f = read_status(kbdcp(p))) & KBDS_ANY_BUFFER_FULL) {
75742421Syokota	    DELAY(KBDD_DELAYTIME);
75858271Syokota            b = read_data(kbdcp(p));
75942421Syokota	    if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
76042421Syokota		addq(&kbdcp(p)->kbd, b);
76142421Syokota#if KBDIO_DEBUG >= 2
76242421Syokota		++c1;
76342421Syokota            } else {
76442421Syokota		++c2;
76542421Syokota#endif
76642421Syokota	    }
76742421Syokota	    t = wait;
76842421Syokota	} else {
76942421Syokota	    t -= delta;
77042421Syokota	}
77142421Syokota	DELAY(delta*1000);
77242421Syokota    }
77342421Syokota#if KBDIO_DEBUG >= 2
77442421Syokota    if ((c1 > 0) || (c2 > 0))
77542421Syokota        log(LOG_DEBUG, "kbdc: %d:%d char read (empty_aux_buffer)\n", c1, c2);
77642421Syokota#endif
77742421Syokota
77842421Syokota    emptyq(&kbdcp(p)->aux);
77942421Syokota}
78042421Syokota
78142421Syokota/* discard any data from the keyboard or the aux device */
78242421Syokotavoid
78342421Syokotaempty_both_buffers(KBDC p, int wait)
78442421Syokota{
78542421Syokota    int t;
78642421Syokota    int f;
78742421Syokota#if KBDIO_DEBUG >= 2
78842421Syokota    int c1 = 0;
78942421Syokota    int c2 = 0;
79042421Syokota#endif
79142421Syokota    int delta = 2;
79242421Syokota
79342421Syokota    for (t = wait; t > 0; ) {
79458271Syokota        if ((f = read_status(kbdcp(p))) & KBDS_ANY_BUFFER_FULL) {
79542421Syokota	    DELAY(KBDD_DELAYTIME);
79658271Syokota            (void)read_data(kbdcp(p));
79742421Syokota#if KBDIO_DEBUG >= 2
79842421Syokota	    if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL)
79942421Syokota		++c1;
80042421Syokota            else
80142421Syokota		++c2;
80242421Syokota#endif
80342421Syokota	    t = wait;
80442421Syokota	} else {
80542421Syokota	    t -= delta;
80642421Syokota	}
80742421Syokota	DELAY(delta*1000);
80842421Syokota    }
80942421Syokota#if KBDIO_DEBUG >= 2
81042421Syokota    if ((c1 > 0) || (c2 > 0))
81142421Syokota        log(LOG_DEBUG, "kbdc: %d:%d char read (empty_both_buffers)\n", c1, c2);
81242421Syokota#endif
81342421Syokota
81442421Syokota    emptyq(&kbdcp(p)->kbd);
81542421Syokota    emptyq(&kbdcp(p)->aux);
81642421Syokota}
81742421Syokota
81842421Syokota/* keyboard and mouse device control */
81942421Syokota
82042421Syokota/* NOTE: enable the keyboard port but disable the keyboard
82142421Syokota * interrupt before calling "reset_kbd()".
82242421Syokota */
82342421Syokotaint
82442421Syokotareset_kbd(KBDC p)
82542421Syokota{
82642421Syokota    int retry = KBD_MAXRETRY;
82742421Syokota    int again = KBD_MAXWAIT;
82842421Syokota    int c = KBD_RESEND;		/* keep the compiler happy */
82942421Syokota
83042421Syokota    while (retry-- > 0) {
83142421Syokota        empty_both_buffers(p, 10);
83242421Syokota        if (!write_kbd_command(p, KBDC_RESET_KBD))
83342421Syokota	    continue;
83442421Syokota	emptyq(&kbdcp(p)->kbd);
83542421Syokota        c = read_controller_data(p);
83642421Syokota	if (verbose || bootverbose)
83742421Syokota            log(LOG_DEBUG, "kbdc: RESET_KBD return code:%04x\n", c);
83842421Syokota        if (c == KBD_ACK)	/* keyboard has agreed to reset itself... */
83942421Syokota    	    break;
84042421Syokota    }
84142421Syokota    if (retry < 0)
84242421Syokota        return FALSE;
84342421Syokota
84442421Syokota    while (again-- > 0) {
84542421Syokota        /* wait awhile, well, in fact we must wait quite loooooooooooong */
84642421Syokota        DELAY(KBD_RESETDELAY*1000);
84742421Syokota        c = read_controller_data(p);	/* RESET_DONE/RESET_FAIL */
84842421Syokota        if (c != -1) 	/* wait again if the controller is not ready */
84942421Syokota    	    break;
85042421Syokota    }
85142421Syokota    if (verbose || bootverbose)
85242421Syokota        log(LOG_DEBUG, "kbdc: RESET_KBD status:%04x\n", c);
85342421Syokota    if (c != KBD_RESET_DONE)
85442421Syokota        return FALSE;
85542421Syokota    return TRUE;
85642421Syokota}
85742421Syokota
85842421Syokota/* NOTE: enable the aux port but disable the aux interrupt
85942421Syokota * before calling `reset_aux_dev()'.
86042421Syokota */
86142421Syokotaint
86242421Syokotareset_aux_dev(KBDC p)
86342421Syokota{
86442421Syokota    int retry = KBD_MAXRETRY;
86542421Syokota    int again = KBD_MAXWAIT;
86642421Syokota    int c = PSM_RESEND;		/* keep the compiler happy */
86742421Syokota
86842421Syokota    while (retry-- > 0) {
86942421Syokota        empty_both_buffers(p, 10);
87042421Syokota        if (!write_aux_command(p, PSMC_RESET_DEV))
87142421Syokota	    continue;
87242421Syokota	emptyq(&kbdcp(p)->aux);
87342421Syokota	/* NOTE: Compaq Armada laptops require extra delay here. XXX */
87442421Syokota	for (again = KBD_MAXWAIT; again > 0; --again) {
87542421Syokota            DELAY(KBD_RESETDELAY*1000);
87642421Syokota            c = read_aux_data_no_wait(p);
87742421Syokota	    if (c != -1)
87842421Syokota		break;
87942421Syokota	}
88042421Syokota        if (verbose || bootverbose)
88142421Syokota            log(LOG_DEBUG, "kbdc: RESET_AUX return code:%04x\n", c);
88242421Syokota        if (c == PSM_ACK)	/* aux dev is about to reset... */
88342421Syokota    	    break;
88442421Syokota    }
88542421Syokota    if (retry < 0)
88642421Syokota        return FALSE;
88742421Syokota
88842421Syokota    for (again = KBD_MAXWAIT; again > 0; --again) {
88942421Syokota        /* wait awhile, well, quite looooooooooooong */
89042421Syokota        DELAY(KBD_RESETDELAY*1000);
89142421Syokota        c = read_aux_data_no_wait(p);	/* RESET_DONE/RESET_FAIL */
89242421Syokota        if (c != -1) 	/* wait again if the controller is not ready */
89342421Syokota    	    break;
89442421Syokota    }
89542421Syokota    if (verbose || bootverbose)
89642421Syokota        log(LOG_DEBUG, "kbdc: RESET_AUX status:%04x\n", c);
89742421Syokota    if (c != PSM_RESET_DONE)	/* reset status */
89842421Syokota        return FALSE;
89942421Syokota
90042421Syokota    c = read_aux_data(p);	/* device ID */
90142421Syokota    if (verbose || bootverbose)
90242421Syokota        log(LOG_DEBUG, "kbdc: RESET_AUX ID:%04x\n", c);
90342421Syokota    /* NOTE: we could check the device ID now, but leave it later... */
90442421Syokota    return TRUE;
90542421Syokota}
90642421Syokota
90742421Syokota/* controller diagnostics and setup */
90842421Syokota
90942421Syokotaint
91042421Syokotatest_controller(KBDC p)
91142421Syokota{
91242421Syokota    int retry = KBD_MAXRETRY;
91342421Syokota    int again = KBD_MAXWAIT;
91442421Syokota    int c = KBD_DIAG_FAIL;
91542421Syokota
91642421Syokota    while (retry-- > 0) {
91742421Syokota        empty_both_buffers(p, 10);
91842421Syokota        if (write_controller_command(p, KBDC_DIAGNOSE))
91942421Syokota    	    break;
92042421Syokota    }
92142421Syokota    if (retry < 0)
92242421Syokota        return FALSE;
92342421Syokota
92442421Syokota    emptyq(&kbdcp(p)->kbd);
92542421Syokota    while (again-- > 0) {
92642421Syokota        /* wait awhile */
92742421Syokota        DELAY(KBD_RESETDELAY*1000);
92842421Syokota        c = read_controller_data(p);	/* DIAG_DONE/DIAG_FAIL */
92942421Syokota        if (c != -1) 	/* wait again if the controller is not ready */
93042421Syokota    	    break;
93142421Syokota    }
93242421Syokota    if (verbose || bootverbose)
93342421Syokota        log(LOG_DEBUG, "kbdc: DIAGNOSE status:%04x\n", c);
93442421Syokota    return (c == KBD_DIAG_DONE);
93542421Syokota}
93642421Syokota
93742421Syokotaint
93842421Syokotatest_kbd_port(KBDC p)
93942421Syokota{
94042421Syokota    int retry = KBD_MAXRETRY;
94142421Syokota    int again = KBD_MAXWAIT;
94242421Syokota    int c = -1;
94342421Syokota
94442421Syokota    while (retry-- > 0) {
94542421Syokota        empty_both_buffers(p, 10);
94642421Syokota        if (write_controller_command(p, KBDC_TEST_KBD_PORT))
94742421Syokota    	    break;
94842421Syokota    }
94942421Syokota    if (retry < 0)
95042421Syokota        return FALSE;
95142421Syokota
95242421Syokota    emptyq(&kbdcp(p)->kbd);
95342421Syokota    while (again-- > 0) {
95442421Syokota        c = read_controller_data(p);
95542421Syokota        if (c != -1) 	/* try again if the controller is not ready */
95642421Syokota    	    break;
95742421Syokota    }
95842421Syokota    if (verbose || bootverbose)
95942421Syokota        log(LOG_DEBUG, "kbdc: TEST_KBD_PORT status:%04x\n", c);
96042421Syokota    return c;
96142421Syokota}
96242421Syokota
96342421Syokotaint
96442421Syokotatest_aux_port(KBDC p)
96542421Syokota{
96642421Syokota    int retry = KBD_MAXRETRY;
96742421Syokota    int again = KBD_MAXWAIT;
96842421Syokota    int c = -1;
96942421Syokota
97042421Syokota    while (retry-- > 0) {
97142421Syokota        empty_both_buffers(p, 10);
97242421Syokota        if (write_controller_command(p, KBDC_TEST_AUX_PORT))
97342421Syokota    	    break;
97442421Syokota    }
97542421Syokota    if (retry < 0)
97642421Syokota        return FALSE;
97742421Syokota
97842421Syokota    emptyq(&kbdcp(p)->kbd);
97942421Syokota    while (again-- > 0) {
98042421Syokota        c = read_controller_data(p);
98142421Syokota        if (c != -1) 	/* try again if the controller is not ready */
98242421Syokota    	    break;
98342421Syokota    }
98442421Syokota    if (verbose || bootverbose)
98542421Syokota        log(LOG_DEBUG, "kbdc: TEST_AUX_PORT status:%04x\n", c);
98642421Syokota    return c;
98742421Syokota}
98842421Syokota
98942421Syokotaint
99042421Syokotakbdc_get_device_mask(KBDC p)
99142421Syokota{
99242421Syokota    return kbdcp(p)->command_mask;
99342421Syokota}
99442421Syokota
99542421Syokotavoid
99642421Syokotakbdc_set_device_mask(KBDC p, int mask)
99742421Syokota{
99842421Syokota    kbdcp(p)->command_mask =
99942421Syokota	mask & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS);
100042421Syokota}
100142421Syokota
100242421Syokotaint
100342421Syokotaget_controller_command_byte(KBDC p)
100442421Syokota{
100542421Syokota    if (kbdcp(p)->command_byte != -1)
100642421Syokota	return kbdcp(p)->command_byte;
100742421Syokota    if (!write_controller_command(p, KBDC_GET_COMMAND_BYTE))
100842421Syokota	return -1;
100942421Syokota    emptyq(&kbdcp(p)->kbd);
101042421Syokota    kbdcp(p)->command_byte = read_controller_data(p);
101142421Syokota    return kbdcp(p)->command_byte;
101242421Syokota}
101342421Syokota
101442421Syokotaint
101542421Syokotaset_controller_command_byte(KBDC p, int mask, int command)
101642421Syokota{
101742421Syokota    if (get_controller_command_byte(p) == -1)
101842421Syokota	return FALSE;
101942421Syokota
102042421Syokota    command = (kbdcp(p)->command_byte & ~mask) | (command & mask);
102142421Syokota    if (command & KBD_DISABLE_KBD_PORT) {
102242421Syokota	if (!write_controller_command(p, KBDC_DISABLE_KBD_PORT))
102342421Syokota	    return FALSE;
102442421Syokota    }
102542421Syokota    if (!write_controller_command(p, KBDC_SET_COMMAND_BYTE))
102642421Syokota	return FALSE;
102742421Syokota    if (!write_controller_data(p, command))
102842421Syokota	return FALSE;
102942421Syokota    kbdcp(p)->command_byte = command;
103042421Syokota
103142421Syokota    if (verbose)
103242421Syokota        log(LOG_DEBUG, "kbdc: new command byte:%04x (set_controller...)\n",
103342421Syokota	    command);
103442421Syokota
103542421Syokota    return TRUE;
103642421Syokota}
1037