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: releng/10.2/sys/dev/atkbdc/atkbdc.c 216592 2010-12-20 16:39:43Z tijl $"); 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