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