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