Home | History | Annotate | Line # | Download | only in dev
tctrl.c revision 1.21
      1 /*	$NetBSD: tctrl.c,v 1.21 2002/11/26 19:50:29 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Matt Thomas.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/callout.h>
     42 #include <sys/ioctl.h>
     43 #include <sys/select.h>
     44 #include <sys/tty.h>
     45 #include <sys/proc.h>
     46 #include <sys/user.h>
     47 #include <sys/conf.h>
     48 #include <sys/file.h>
     49 #include <sys/uio.h>
     50 #include <sys/kernel.h>
     51 #include <sys/syslog.h>
     52 #include <sys/types.h>
     53 #include <sys/device.h>
     54 #include <sys/envsys.h>
     55 #include <sys/poll.h>
     56 
     57 #include <machine/apmvar.h>
     58 #include <machine/autoconf.h>
     59 #include <machine/bus.h>
     60 #include <machine/intr.h>
     61 #include <machine/tctrl.h>
     62 
     63 #include <sparc/dev/ts102reg.h>
     64 #include <sparc/dev/tctrlvar.h>
     65 #include <sparc/sparc/auxiotwo.h>
     66 
     67 extern struct cfdriver tctrl_cd;
     68 
     69 dev_type_open(tctrlopen);
     70 dev_type_close(tctrlclose);
     71 dev_type_ioctl(tctrlioctl);
     72 dev_type_poll(tctrlpoll);
     73 dev_type_kqfilter(tctrlkqfilter);
     74 
     75 const struct cdevsw tctrl_cdevsw = {
     76 	tctrlopen, tctrlclose, noread, nowrite, tctrlioctl,
     77 	nostop, notty, tctrlpoll, nommap, tctrlkqfilter,
     78 };
     79 
     80 static const char *tctrl_ext_statuses[16] = {
     81 	"main power available",
     82 	"internal battery attached",
     83 	"external battery attached",
     84 	"external VGA attached",
     85 	"external keyboard attached",
     86 	"external mouse attached",
     87 	"lid down",
     88 	"internal battery charging",
     89 	"external battery charging",
     90 	"internal battery discharging",
     91 	"external battery discharging",
     92 };
     93 
     94 struct tctrl_softc {
     95 	struct	device sc_dev;
     96 	bus_space_tag_t	sc_memt;
     97 	bus_space_handle_t	sc_memh;
     98 	unsigned int	sc_junk;
     99 	unsigned int	sc_ext_status;
    100 	unsigned int	sc_flags;
    101 #define TCTRL_SEND_REQUEST		0x0001
    102 #define TCTRL_APM_CTLOPEN		0x0002
    103 	unsigned int	sc_wantdata;
    104 	volatile unsigned short	sc_lcdstate;
    105 	enum { TCTRL_IDLE, TCTRL_ARGS,
    106 		TCTRL_ACK, TCTRL_DATA } sc_state;
    107 	u_int8_t	sc_cmdbuf[16];
    108 	u_int8_t	sc_rspbuf[16];
    109 	u_int8_t	sc_bitport;
    110 	u_int8_t	sc_tft_on;
    111 	u_int8_t	sc_op;
    112 	u_int8_t	sc_cmdoff;
    113 	u_int8_t	sc_cmdlen;
    114 	u_int8_t	sc_rspoff;
    115 	u_int8_t	sc_rsplen;
    116 	/* APM stuff */
    117 #define APM_NEVENTS 16
    118 	struct	apm_event_info sc_event_list[APM_NEVENTS];
    119 	int	sc_event_count;
    120 	int	sc_event_ptr;
    121 	struct	selinfo sc_rsel;
    122 	/* ENVSYS stuff */
    123 #define ENVSYS_NUMSENSORS 3
    124 	struct	envsys_sensor sc_esensors[ENVSYS_NUMSENSORS];
    125 
    126 	struct	evcnt sc_intrcnt;	/* interrupt counting */
    127 };
    128 
    129 #define TCTRL_STD_DEV		0
    130 #define TCTRL_APMCTL_DEV	8
    131 
    132 static struct callout tctrl_event_ch = CALLOUT_INITIALIZER;
    133 
    134 static int tctrl_match __P((struct device *parent, struct cfdata *cf,
    135 	void *aux));
    136 static void tctrl_attach __P((struct device *parent, struct device *self,
    137 	void *aux));
    138 static void tctrl_write __P((struct tctrl_softc *sc, bus_size_t off,
    139 	u_int8_t v));
    140 static u_int8_t tctrl_read __P((struct tctrl_softc *sc, bus_size_t off));
    141 static void tctrl_write_data __P((struct tctrl_softc *sc, u_int8_t v));
    142 static u_int8_t tctrl_read_data __P((struct tctrl_softc *sc));
    143 static int tctrl_intr __P((void *arg));
    144 static void tctrl_setup_bitport __P((void));
    145 static void tctrl_setup_bitport_nop __P((void));
    146 static void tctrl_read_ext_status __P((void));
    147 static void tctrl_read_event_status __P((void *arg));
    148 static int tctrl_apm_record_event __P((struct tctrl_softc *sc,
    149 	u_int event_type));
    150 static void tctrl_init_lcd __P((void));
    151 
    152 CFATTACH_DECL(tctrl, sizeof(struct tctrl_softc),
    153     tctrl_match, tctrl_attach, NULL, NULL);
    154 
    155 extern struct cfdriver tctrl_cd;
    156 /* XXX wtf is this? see i386/apm.c */
    157 int tctrl_apm_evindex;
    158 
    159 static int
    160 tctrl_match(parent, cf, aux)
    161 	struct device *parent;
    162 	struct cfdata *cf;
    163 	void *aux;
    164 {
    165 	union obio_attach_args *uoba = aux;
    166 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
    167 
    168 	if (uoba->uoba_isobio4 != 0) {
    169 		return (0);
    170 	}
    171 
    172 	/* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
    173 	 * (who's interface is off the TS102 PCMCIA controller but there
    174 	 * exists a OpenProm for microcontroller interface).
    175 	 */
    176 	return strcmp("uctrl", sa->sa_name) == 0;
    177 }
    178 
    179 static void
    180 tctrl_attach(parent, self, aux)
    181 	struct device *parent;
    182 	struct device *self;
    183 	void *aux;
    184 {
    185 	struct tctrl_softc *sc = (void *)self;
    186 	union obio_attach_args *uoba = aux;
    187 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
    188 	unsigned int i, v;
    189 #if 0
    190 	unsigned int ack, msb, lsb;
    191 #endif
    192 
    193 	/* We're living on a sbus slot that looks like an obio that
    194 	 * looks like an sbus slot.
    195 	 */
    196 	sc->sc_memt = sa->sa_bustag;
    197 	if (sbus_bus_map(sc->sc_memt,
    198 			 sa->sa_slot,
    199 			 sa->sa_offset - TS102_REG_UCTRL_INT,
    200 			 sa->sa_size,
    201 			 BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) {
    202 		printf(": can't map registers\n");
    203 		return;
    204 	}
    205 
    206 	printf("\n");
    207 
    208 	sc->sc_tft_on = 1;
    209 
    210 	/* clear any pending data.
    211 	 */
    212 	for (i = 0; i < 10000; i++) {
    213 		if ((TS102_UCTRL_STS_RXNE_STA &
    214 		    tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
    215 			break;
    216 		}
    217 		v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
    218 		tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
    219 	}
    220 
    221 	if (sa->sa_nintr != 0) {
    222 		(void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE,
    223 		    0, tctrl_intr, sc);
    224 		evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
    225 		    sc->sc_dev.dv_xname, "intr");
    226 	}
    227 
    228 	/* See what the external status is
    229 	 */
    230 
    231 	tctrl_read_ext_status();
    232 	if (sc->sc_ext_status != 0) {
    233 		const char *sep;
    234 
    235 		printf("%s: ", sc->sc_dev.dv_xname);
    236 		v = sc->sc_ext_status;
    237 		for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
    238 			if (v & 1) {
    239 				printf("%s%s", sep, tctrl_ext_statuses[i]);
    240 				sep = ", ";
    241 			}
    242 		}
    243 		printf("\n");
    244 	}
    245 
    246 	/* Get a current of the control bitport;
    247 	 */
    248 	tctrl_setup_bitport_nop();
    249 	tctrl_write(sc, TS102_REG_UCTRL_INT,
    250 		    TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
    251 
    252 	sc->sc_wantdata = 0;
    253 	sc->sc_event_count = 0;
    254 
    255 	/* prime the sensor data */
    256 	sprintf(sc->sc_esensors[0].desc, "%s", "Internal Unit Temperature");
    257 	sc->sc_esensors[0].units = ENVSYS_STEMP;
    258 	sprintf(sc->sc_esensors[1].desc, "%s", "Internal Battery Voltage");
    259 	sc->sc_esensors[1].units = ENVSYS_SVOLTS_DC;
    260 	sprintf(sc->sc_esensors[2].desc, "%s", "DC-In Voltage");
    261 	sc->sc_esensors[2].units = ENVSYS_SVOLTS_DC;
    262 
    263 	/* initialize the LCD */
    264 	tctrl_init_lcd();
    265 
    266 	/* initialize sc_lcdstate */
    267 	sc->sc_lcdstate = 0;
    268 	tctrl_set_lcd(2, 0);
    269 }
    270 
    271 static int
    272 tctrl_intr(arg)
    273 	void *arg;
    274 {
    275 	struct tctrl_softc *sc = arg;
    276 	unsigned int v, d;
    277 	int progress = 0;
    278 
    279     again:
    280 	/* find out the cause(s) of the interrupt */
    281 	v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK;
    282 
    283 	/* clear the cause(s) of the interrupt */
    284 	tctrl_write(sc, TS102_REG_UCTRL_STS, v);
    285 
    286 	v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
    287 	if (sc->sc_cmdoff >= sc->sc_cmdlen) {
    288 		v &= ~TS102_UCTRL_STS_TXNF_STA;
    289 		if (tctrl_read(sc, TS102_REG_UCTRL_INT) & TS102_UCTRL_INT_TXNF_REQ) {
    290 			tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
    291 			progress = 1;
    292 		}
    293 	}
    294 	if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
    295 	    sc->sc_state != TCTRL_IDLE)) {
    296 		wakeup(sc);
    297 		return progress;
    298 	}
    299 
    300 	progress = 1;
    301 	if (v & TS102_UCTRL_STS_RXNE_STA) {
    302 		d = tctrl_read_data(sc);
    303 		switch (sc->sc_state) {
    304 		case TCTRL_IDLE:
    305 			if (d == 0xfa) {
    306 				/* external event */
    307 				callout_reset(&tctrl_event_ch, 1,
    308 				    tctrl_read_event_status, NULL);
    309 			} else {
    310 				printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
    311 					sc->sc_dev.dv_xname, sc->sc_op, d);
    312 			}
    313 			goto again;
    314 		case TCTRL_ACK:
    315 			if (d != 0xfe) {
    316 				printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
    317 					sc->sc_dev.dv_xname, sc->sc_op, d);
    318 			}
    319 #ifdef TCTRLDEBUG
    320 			printf(" ack=0x%02x", d);
    321 #endif
    322 			sc->sc_rsplen--;
    323 			sc->sc_rspoff = 0;
    324 			sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
    325 			sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
    326 #ifdef TCTRLDEBUG
    327 			if (sc->sc_rsplen > 0) {
    328 				printf(" [data(%u)]", sc->sc_rsplen);
    329 			} else {
    330 				printf(" [idle]\n");
    331 			}
    332 #endif
    333 			goto again;
    334 		case TCTRL_DATA:
    335 			sc->sc_rspbuf[sc->sc_rspoff++] = d;
    336 #ifdef TCTRLDEBUG
    337 			printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
    338 #endif
    339 			if (sc->sc_rspoff == sc->sc_rsplen) {
    340 #ifdef TCTRLDEBUG
    341 				printf(" [idle]\n");
    342 #endif
    343 				sc->sc_state = TCTRL_IDLE;
    344 				sc->sc_wantdata = 0;
    345 			}
    346 			goto again;
    347 		default:
    348 			printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
    349 			       sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
    350 			goto again;
    351 		}
    352 	}
    353 	if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
    354 	    sc->sc_flags & TCTRL_SEND_REQUEST) {
    355 		if (sc->sc_flags & TCTRL_SEND_REQUEST) {
    356 			sc->sc_flags &= ~TCTRL_SEND_REQUEST;
    357 			sc->sc_wantdata = 1;
    358 		}
    359 		if (sc->sc_cmdlen > 0) {
    360 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    361 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    362 				|TS102_UCTRL_INT_TXNF_MSK
    363 				|TS102_UCTRL_INT_TXNF_REQ);
    364 			v = tctrl_read(sc, TS102_REG_UCTRL_STS);
    365 		}
    366 	}
    367 	if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
    368 		tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
    369 #ifdef TCTRLDEBUG
    370 		if (sc->sc_cmdoff == 1) {
    371 			printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
    372 				sc->sc_cmdbuf[0], sc->sc_rsplen);
    373 		} else {
    374 			printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
    375 				sc->sc_cmdbuf[sc->sc_cmdoff-1]);
    376 		}
    377 #endif
    378 		if (sc->sc_cmdoff == sc->sc_cmdlen) {
    379 			sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
    380 #ifdef TCTRLDEBUG
    381 			printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
    382 #endif
    383 			if (sc->sc_cmdoff == 1) {
    384 				sc->sc_op = sc->sc_cmdbuf[0];
    385 			}
    386 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    387 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    388 				& (~TS102_UCTRL_INT_TXNF_MSK
    389 				   |TS102_UCTRL_INT_TXNF_REQ));
    390 		} else if (sc->sc_state == TCTRL_IDLE) {
    391 			sc->sc_op = sc->sc_cmdbuf[0];
    392 			sc->sc_state = TCTRL_ARGS;
    393 #ifdef TCTRLDEBUG
    394 			printf(" [args]");
    395 #endif
    396 		}
    397 	}
    398 	goto again;
    399 }
    400 
    401 static void
    402 tctrl_setup_bitport_nop(void)
    403 {
    404 	struct tctrl_softc *sc;
    405 	struct tctrl_req req;
    406 	int s;
    407 
    408 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    409 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    410 	req.cmdbuf[1] = 0xff;
    411 	req.cmdbuf[2] = 0;
    412 	req.cmdlen = 3;
    413 	req.rsplen = 2;
    414 	req.p = NULL;
    415 	tadpole_request(&req, 1);
    416 	s = splts102();
    417 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    418 	splx(s);
    419 }
    420 
    421 static void
    422 tctrl_setup_bitport(void)
    423 {
    424 	struct tctrl_softc *sc;
    425 	struct tctrl_req req;
    426 	int s;
    427 
    428 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    429 	s = splts102();
    430 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    431 	    || (!sc->sc_tft_on)) {
    432 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
    433 	} else {
    434 		req.cmdbuf[2] = 0;
    435 	}
    436 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    437 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    438 	req.cmdlen = 3;
    439 	req.rsplen = 2;
    440 	req.p = NULL;
    441 	tadpole_request(&req, 1);
    442 	s = splts102();
    443 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    444 	splx(s);
    445 }
    446 
    447 /*
    448  * The tadpole microcontroller is not preprogrammed with icon
    449  * representations.  The machine boots with the DC-IN light as
    450  * a blank (all 0x00) and the other lights, as 4 rows of horizontal
    451  * bars.  The below code initializes the icons in the system to
    452  * sane values.  Some of these icons could be used for any purpose
    453  * desired, namely the pcmcia, LAN and WAN lights.  For the disk spinner,
    454  * only the backslash is unprogrammed.  (sigh)
    455  *
    456  * programming the icons is simple.  It is a 5x8 matrix, which each row a
    457  * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
    458  */
    459 
    460 static void
    461 tctrl_init_lcd(void)
    462 {
    463 	struct tctrl_req req;
    464 
    465 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    466 	req.cmdlen = 11;
    467 	req.rsplen = 1;
    468 	req.cmdbuf[1] = 0x08;	/*len*/
    469 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD;
    470 	req.cmdbuf[3] =  0x00;	/* ..... */
    471 	req.cmdbuf[4] =  0x00;	/* ..... */
    472 	req.cmdbuf[5] =  0x1f;	/* XXXXX */
    473 	req.cmdbuf[6] =  0x00;	/* ..... */
    474 	req.cmdbuf[7] =  0x15;	/* X.X.X */
    475 	req.cmdbuf[8] =  0x00;	/* ..... */
    476 	req.cmdbuf[9] =  0x00;	/* ..... */
    477 	req.cmdbuf[10] = 0x00;	/* ..... */
    478 	req.p = NULL;
    479 	tadpole_request(&req, 1);
    480 
    481 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    482 	req.cmdlen = 11;
    483 	req.rsplen = 1;
    484 	req.cmdbuf[1] = 0x08;	/*len*/
    485 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH;
    486 	req.cmdbuf[3] =  0x00;	/* ..... */
    487 	req.cmdbuf[4] =  0x10;	/* X.... */
    488 	req.cmdbuf[5] =  0x08;	/* .X... */
    489 	req.cmdbuf[6] =  0x04;	/* ..X.. */
    490 	req.cmdbuf[7] =  0x02;	/* ...X. */
    491 	req.cmdbuf[8] =  0x01;	/* ....X */
    492 	req.cmdbuf[9] =  0x00;	/* ..... */
    493 	req.cmdbuf[10] = 0x00;	/* ..... */
    494 	req.p = NULL;
    495 	tadpole_request(&req, 1);
    496 
    497 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    498 	req.cmdlen = 11;
    499 	req.rsplen = 1;
    500 	req.cmdbuf[1] = 0x08;	/*len*/
    501 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1;
    502 	req.cmdbuf[3] =  0x0c;	/* .XXX. */
    503 	req.cmdbuf[4] =  0x16;	/* X.XX. */
    504 	req.cmdbuf[5] =  0x10;	/* X.... */
    505 	req.cmdbuf[6] =  0x15;	/* X.X.X */
    506 	req.cmdbuf[7] =  0x10;	/* X.... */
    507 	req.cmdbuf[8] =  0x16;	/* X.XX. */
    508 	req.cmdbuf[9] =  0x0c;	/* .XXX. */
    509 	req.cmdbuf[10] = 0x00;	/* ..... */
    510 	req.p = NULL;
    511 	tadpole_request(&req, 1);
    512 
    513 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    514 	req.cmdlen = 11;
    515 	req.rsplen = 1;
    516 	req.cmdbuf[1] = 0x08;	/*len*/
    517 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2;
    518 	req.cmdbuf[3] =  0x0c;	/* .XXX. */
    519 	req.cmdbuf[4] =  0x0d;	/* .XX.X */
    520 	req.cmdbuf[5] =  0x01;	/* ....X */
    521 	req.cmdbuf[6] =  0x15;	/* X.X.X */
    522 	req.cmdbuf[7] =  0x01;	/* ....X */
    523 	req.cmdbuf[8] =  0x0d;	/* .XX.X */
    524 	req.cmdbuf[9] =  0x0c;	/* .XXX. */
    525 	req.cmdbuf[10] = 0x00;	/* ..... */
    526 	req.p = NULL;
    527 	tadpole_request(&req, 1);
    528 
    529 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    530 	req.cmdlen = 11;
    531 	req.rsplen = 1;
    532 	req.cmdbuf[1] = 0x08;	/*len*/
    533 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1;
    534 	req.cmdbuf[3] =  0x00;	/* ..... */
    535 	req.cmdbuf[4] =  0x04;	/* ..X.. */
    536 	req.cmdbuf[5] =  0x08;	/* .X... */
    537 	req.cmdbuf[6] =  0x13;	/* X..XX */
    538 	req.cmdbuf[7] =  0x08;	/* .X... */
    539 	req.cmdbuf[8] =  0x04;	/* ..X.. */
    540 	req.cmdbuf[9] =  0x00;	/* ..... */
    541 	req.cmdbuf[10] = 0x00;	/* ..... */
    542 	req.p = NULL;
    543 	tadpole_request(&req, 1);
    544 
    545 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    546 	req.cmdlen = 11;
    547 	req.rsplen = 1;
    548 	req.cmdbuf[1] = 0x08;	/*len*/
    549 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2;
    550 	req.cmdbuf[3] =  0x00;	/* ..... */
    551 	req.cmdbuf[4] =  0x04;	/* ..X.. */
    552 	req.cmdbuf[5] =  0x02;	/* ...X. */
    553 	req.cmdbuf[6] =  0x19;	/* XX..X */
    554 	req.cmdbuf[7] =  0x02;	/* ...X. */
    555 	req.cmdbuf[8] =  0x04;	/* ..X.. */
    556 	req.cmdbuf[9] =  0x00;	/* ..... */
    557 	req.cmdbuf[10] = 0x00;	/* ..... */
    558 	req.p = NULL;
    559 	tadpole_request(&req, 1);
    560 
    561 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    562 	req.cmdlen = 11;
    563 	req.rsplen = 1;
    564 	req.cmdbuf[1] = 0x08;	/*len*/
    565 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA;
    566 	req.cmdbuf[3] =  0x00;	/* ..... */
    567 	req.cmdbuf[4] =  0x0c;	/* .XXX. */
    568 	req.cmdbuf[5] =  0x1f;	/* XXXXX */
    569 	req.cmdbuf[6] =  0x1f;	/* XXXXX */
    570 	req.cmdbuf[7] =  0x1f;	/* XXXXX */
    571 	req.cmdbuf[8] =  0x1f;	/* XXXXX */
    572 	req.cmdbuf[9] =  0x00;	/* ..... */
    573 	req.cmdbuf[10] = 0x00;	/* ..... */
    574 	req.p = NULL;
    575 	tadpole_request(&req, 1);
    576 }
    577 
    578 
    579 
    580 /*
    581  * set the blinken-lights on the lcd.  what:
    582  * what = 0 off,  what = 1 on,  what = 2 toggle
    583  */
    584 
    585 void
    586 tctrl_set_lcd(what, which)
    587 	int what;
    588 	unsigned short which;
    589 {
    590 	struct tctrl_softc *sc;
    591 	struct tctrl_req req;
    592 	int s;
    593 
    594 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    595 	s = splts102();
    596 
    597 	/* provide a quick exit to save cpu time */
    598 	if ((what == 1 && sc->sc_lcdstate & which) ||
    599 	    (what == 0 && !(sc->sc_lcdstate & which))) {
    600 		splx(s);
    601 		return;
    602 	}
    603 	/*
    604 	 * the mask setup on this particular command is *very* bizzare
    605 	 * and totally undocumented.
    606 	 */
    607 	if ((what == 1) || (what == 2 && !(sc->sc_lcdstate & which))) {
    608 		req.cmdbuf[2] = (u_int8_t)(which&0xff);
    609 		req.cmdbuf[3] = (u_int8_t)(which>>8);
    610 	} else {
    611 		req.cmdbuf[2] = 0;
    612 		req.cmdbuf[3] = 0;
    613 	}
    614 	req.cmdbuf[0] = TS102_OP_CTL_LCD;
    615 	req.cmdbuf[4] = (u_int8_t)(~which>>8);
    616 	req.cmdbuf[1] = (u_int8_t)(~which&0xff);
    617 
    618 	/* XXX this thing is weird.... */
    619 	req.cmdlen = 3;
    620 	req.rsplen = 2;
    621 #if 0
    622 	req.cmdlen = 5;
    623 	req.rsplen = 4;
    624 #endif
    625 	req.p = NULL;
    626 	tadpole_request(&req, 1);
    627 	s = splts102();
    628 	sc->sc_lcdstate = (unsigned short)req.rspbuf[0];
    629 	splx(s);
    630 }
    631 
    632 static void
    633 tctrl_read_ext_status(void)
    634 {
    635 	struct tctrl_softc *sc;
    636 	struct tctrl_req req;
    637 	int s;
    638 
    639 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    640 	req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
    641 	req.cmdlen = 1;
    642 	req.rsplen = 3;
    643 	req.p = NULL;
    644 #ifdef TCTRLDEBUG
    645 	printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
    646 #endif
    647 	tadpole_request(&req, 1);
    648 	s = splts102();
    649 	sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1];
    650 	splx(s);
    651 #ifdef TCTRLDEBUG
    652 	printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
    653 #endif
    654 }
    655 
    656 /*
    657  * return 0 if the user will notice and handle the event,
    658  * return 1 if the kernel driver should do so.
    659  */
    660 static int
    661 tctrl_apm_record_event(sc, event_type)
    662 	struct tctrl_softc *sc;
    663 	u_int event_type;
    664 {
    665 	struct apm_event_info *evp;
    666 
    667 	if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
    668 	    (sc->sc_event_count < APM_NEVENTS)) {
    669 		evp = &sc->sc_event_list[sc->sc_event_ptr];
    670 		sc->sc_event_count++;
    671 		sc->sc_event_ptr++;
    672 		sc->sc_event_ptr %= APM_NEVENTS;
    673 		evp->type = event_type;
    674 		evp->index = ++tctrl_apm_evindex;
    675 		selnotify(&sc->sc_rsel, 0);
    676 		return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
    677 	}
    678 	return(1);
    679 }
    680 
    681 static void
    682 tctrl_read_event_status(arg)
    683 	void *arg;
    684 {
    685 	struct tctrl_softc *sc;
    686 	struct tctrl_req req;
    687 	int s;
    688 	unsigned int v;
    689 
    690 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    691 	req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
    692 	req.cmdlen = 1;
    693 	req.rsplen = 3;
    694 	req.p = NULL;
    695 	tadpole_request(&req, 1);
    696 	s = splts102();
    697 	v = req.rspbuf[0] * 256 + req.rspbuf[1];
    698 	if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
    699 		printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
    700 	}
    701 	if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
    702 /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
    703 /* according to a tadpole header, and observation */
    704 #ifdef TCTRLDEBUG
    705 		printf("%s: Battery charge level change\n", sc->sc_dev.dv_xname);
    706 #endif
    707 	}
    708 	if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
    709 		if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
    710 			printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
    711 	}
    712 	if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
    713 		splx(s);
    714 		tctrl_read_ext_status();
    715 		s = splts102();
    716 		if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
    717 			printf("%s: main power %s\n", sc->sc_dev.dv_xname,
    718 			    (sc->sc_ext_status &
    719 			    TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
    720 			    "restored" : "removed");
    721 	}
    722 	if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
    723 		splx(s);
    724 		tctrl_read_ext_status();
    725 		tctrl_setup_bitport();
    726 #ifdef TCTRLDEBUG
    727 		printf("%s: lid %s\n", sc->sc_dev.dv_xname,
    728 		    (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    729 		    ? "closed" : "opened");
    730 #endif
    731 	}
    732 	splx(s);
    733 }
    734 
    735 void
    736 tadpole_request(req, spin)
    737 	struct tctrl_req *req;
    738 	int spin;
    739 {
    740 	struct tctrl_softc *sc;
    741 	int i, s;
    742 
    743 	if (tctrl_cd.cd_devs == NULL
    744 	    || tctrl_cd.cd_ndevs == 0
    745 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
    746 		return;
    747 	}
    748 
    749 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    750 	while (sc->sc_wantdata != 0) {
    751 		if (req->p != NULL)
    752 			tsleep(&sc->sc_wantdata, PLOCK, "tctrl_lock", 10);
    753 		else
    754 			DELAY(1);
    755 	}
    756 	if (spin)
    757 		s = splhigh();
    758 	else
    759 		s = splts102();
    760 	sc->sc_flags |= TCTRL_SEND_REQUEST;
    761 	memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
    762 	sc->sc_wantdata = 1;
    763 	sc->sc_rsplen = req->rsplen;
    764 	sc->sc_cmdlen = req->cmdlen;
    765 	sc->sc_cmdoff = sc->sc_rspoff = 0;
    766 
    767 	/* we spin for certain commands, like poweroffs */
    768 	if (spin) {
    769 /*		for (i = 0; i < 30000; i++) {*/
    770 		while (sc->sc_wantdata == 1) {
    771 			tctrl_intr(sc);
    772 			DELAY(1);
    773 		}
    774 	} else {
    775 		tctrl_intr(sc);
    776 		i = 0;
    777 		while (((sc->sc_rspoff != sc->sc_rsplen) ||
    778 		    (sc->sc_cmdoff != sc->sc_cmdlen)) &&
    779 		    (i < (5 * sc->sc_rsplen + sc->sc_cmdlen)))
    780 			if (req->p != NULL) {
    781 				tsleep(sc, PWAIT, "tctrl_data", 15);
    782 				i++;
    783 			}
    784 			else
    785 				DELAY(1);
    786 	}
    787 	/*
    788 	 * we give the user a reasonable amount of time for a command
    789 	 * to complete.  If it doesn't complete in time, we hand them
    790 	 * garbage.  This is here to stop things like setting the
    791 	 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
    792 	 */
    793 	sc->sc_wantdata = 0;
    794 	memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
    795 	splx(s);
    796 }
    797 
    798 void
    799 tadpole_powerdown(void)
    800 {
    801 	struct tctrl_req req;
    802 
    803 	req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
    804 	req.cmdlen = 1;
    805 	req.rsplen = 1;
    806 	req.p = NULL;
    807 	tadpole_request(&req, 1);
    808 }
    809 
    810 void
    811 tadpole_set_video(enabled)
    812 	int enabled;
    813 {
    814 	struct tctrl_softc *sc;
    815 	struct tctrl_req req;
    816 	int s;
    817 
    818 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    819 	while (sc->sc_wantdata != 0)
    820 		DELAY(1);
    821 	s = splts102();
    822 	req.p = NULL;
    823 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
    824 	    || (sc->sc_tft_on)) {
    825 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
    826 	} else {
    827 		req.cmdbuf[2] = 0;
    828 	}
    829 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    830 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    831 	req.cmdlen = 3;
    832 	req.rsplen = 2;
    833 
    834 	if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
    835 		sc->sc_tft_on = enabled;
    836 		if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
    837 			splx(s);
    838 			return;
    839 		}
    840 		tadpole_request(&req, 1);
    841 		sc->sc_bitport =
    842 		    (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    843 	}
    844 	splx(s);
    845 }
    846 
    847 static void
    848 tctrl_write_data(sc, v)
    849 	struct tctrl_softc *sc;
    850 	u_int8_t v;
    851 {
    852 	unsigned int i;
    853 
    854 	for (i = 0; i < 100; i++)  {
    855 		if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
    856 			break;
    857 	}
    858 	tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
    859 }
    860 
    861 static u_int8_t
    862 tctrl_read_data(sc)
    863 	struct tctrl_softc *sc;
    864 {
    865 	unsigned int i, v;
    866 
    867 	for (i = 0; i < 100000; i++) {
    868 		if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
    869 			break;
    870 		DELAY(1);
    871 	}
    872 
    873 	v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
    874 	tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
    875 	return v;
    876 }
    877 
    878 static u_int8_t
    879 tctrl_read(sc, off)
    880 	struct tctrl_softc *sc;
    881 	bus_size_t off;
    882 {
    883 
    884 	sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
    885 	return sc->sc_junk;
    886 }
    887 
    888 static void
    889 tctrl_write(sc, off, v)
    890 	struct tctrl_softc *sc;
    891 	bus_size_t off;
    892 	u_int8_t v;
    893 {
    894 
    895 	sc->sc_junk = v;
    896 	bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
    897 }
    898 
    899 int
    900 tctrlopen(dev, flags, mode, p)
    901 	dev_t dev;
    902 	int flags, mode;
    903 	struct proc *p;
    904 {
    905 	int unit = (minor(dev)&0xf0);
    906 	int ctl = (minor(dev)&0x0f);
    907 	struct tctrl_softc *sc;
    908 
    909 	if (unit >= tctrl_cd.cd_ndevs)
    910 		return(ENXIO);
    911 	sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
    912 	if (!sc)
    913 		return(ENXIO);
    914 
    915 	switch (ctl) {
    916 	case TCTRL_STD_DEV:
    917 		break;
    918 	case TCTRL_APMCTL_DEV:
    919 		if (!(flags & FWRITE))
    920 			return(EINVAL);
    921 		if (sc->sc_flags & TCTRL_APM_CTLOPEN)
    922 			return(EBUSY);
    923 		sc->sc_flags |= TCTRL_APM_CTLOPEN;
    924 		break;
    925 	default:
    926 		return(ENXIO);
    927 		break;
    928 	}
    929 
    930 	return(0);
    931 }
    932 
    933 int
    934 tctrlclose(dev, flags, mode, p)
    935 	dev_t dev;
    936 	int flags, mode;
    937 	struct proc *p;
    938 {
    939 	int ctl = (minor(dev)&0x0f);
    940 	struct tctrl_softc *sc;
    941 
    942 	sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
    943 	if (!sc)
    944 		return(ENXIO);
    945 
    946 	switch (ctl) {
    947 	case TCTRL_STD_DEV:
    948 		break;
    949 	case TCTRL_APMCTL_DEV:
    950 		sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
    951 		break;
    952 	}
    953 	return(0);
    954 }
    955 
    956 int
    957 tctrlioctl(dev, cmd, data, flags, p)
    958         dev_t dev;
    959         u_long cmd;
    960         caddr_t data;
    961         int flags;
    962         struct proc *p;
    963 {
    964 	struct tctrl_req req, *reqn;
    965 	struct tctrl_pwr *pwrreq;
    966 	envsys_range_t *envrange;
    967 	envsys_temp_data_t *envdata;
    968 	envsys_temp_info_t *envinfo;
    969 	struct apm_power_info *powerp;
    970 	struct apm_event_info *evp;
    971 	struct tctrl_softc *sc;
    972 	int i;
    973 	u_int j;
    974 	u_int16_t a;
    975 	u_int8_t c;
    976 
    977 	if (tctrl_cd.cd_devs == NULL
    978 	    || tctrl_cd.cd_ndevs == 0
    979 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
    980 		return ENXIO;
    981 	}
    982 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    983         switch (cmd) {
    984 
    985 	case APM_IOC_STANDBY:
    986 		return(EOPNOTSUPP); /* for now */
    987 
    988 	case APM_IOC_SUSPEND:
    989 		return(EOPNOTSUPP); /* for now */
    990 
    991 	case OAPM_IOC_GETPOWER:
    992 	case APM_IOC_GETPOWER:
    993 		powerp = (struct apm_power_info *)data;
    994 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
    995 		req.cmdlen = 1;
    996 		req.rsplen = 2;
    997 		req.p = p;
    998 		tadpole_request(&req, 0);
    999 		if (req.rspbuf[0] > 0x00)
   1000 			powerp->battery_state = APM_BATT_CHARGING;
   1001 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
   1002 		req.cmdlen = 1;
   1003 		req.rsplen = 3;
   1004 		req.p = p;
   1005 		tadpole_request(&req, 0);
   1006 		c = req.rspbuf[0];
   1007 		powerp->battery_life = c;
   1008 		if (c > 0x70)	/* the tadpole sometimes dips below zero, and */
   1009 			c = 0;	/* into the 255 range. */
   1010 		powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
   1011 		if (powerp->battery_state != APM_BATT_CHARGING) {
   1012 			if (c < 0x20)
   1013 				powerp->battery_state = APM_BATT_CRITICAL;
   1014 			else if (c < 0x40)
   1015 				powerp->battery_state = APM_BATT_LOW;
   1016 			else if (c < 0x66)
   1017 				powerp->battery_state = APM_BATT_HIGH;
   1018 			else
   1019 				powerp->battery_state = APM_BATT_UNKNOWN;
   1020 		}
   1021 		req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
   1022 		req.cmdlen = 1;
   1023 		req.rsplen = 3;
   1024 		req.p = p;
   1025 		tadpole_request(&req, 0);
   1026 		a = req.rspbuf[0] * 256 + req.rspbuf[1];
   1027 		if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
   1028 			powerp->ac_state = APM_AC_ON;
   1029 		else
   1030 			powerp->ac_state = APM_AC_OFF;
   1031 		break;
   1032 
   1033 	case APM_IOC_NEXTEVENT:
   1034 		if (!sc->sc_event_count)
   1035 			return EAGAIN;
   1036 
   1037 		evp = (struct apm_event_info *)data;
   1038 		i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
   1039 		i %= APM_NEVENTS;
   1040 		*evp = sc->sc_event_list[i];
   1041 		sc->sc_event_count--;
   1042 		return(0);
   1043 
   1044 	/* this ioctl assumes the caller knows exactly what he is doing */
   1045 	case TCTRL_CMD_REQ:
   1046 		reqn = (struct tctrl_req *)data;
   1047 		if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 &&
   1048 		    (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
   1049 		    (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
   1050 		    reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
   1051 		    reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
   1052 		    reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
   1053 		    reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
   1054 		    (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
   1055 		    reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
   1056 		    reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
   1057 			return(i);
   1058 		reqn->p = p;
   1059 		tadpole_request(reqn, 0);
   1060 		break;
   1061 
   1062 	case ENVSYS_VERSION:
   1063 		*(int32_t *)data = 1000;
   1064 		break;
   1065 
   1066 	case ENVSYS_GRANGE:
   1067 		envrange = (envsys_range_t *)data;
   1068 		i = 0;
   1069 		envrange->high = envrange->low = 0;
   1070 		for (j=0; j < ENVSYS_NUMSENSORS; j++) {
   1071 			if (!i && envrange->units == sc->sc_esensors[j].units) {
   1072 				envrange->low = j;
   1073 				i++;
   1074 			}
   1075 			if (i && envrange->units == sc->sc_esensors[j].units)
   1076 				envrange->high = j;
   1077 		}
   1078 		if (!i) {
   1079 			envrange->high = 0;
   1080 			envrange->low = 1;
   1081 		}
   1082 		break;
   1083 
   1084 	case ENVSYS_GTREDATA:
   1085 		envdata = (envsys_temp_data_t *)data;
   1086 		if (envdata->sensor >= ENVSYS_NUMSENSORS) {
   1087 			envdata->validflags = 0;
   1088 			break;
   1089 		}
   1090 		envdata->warnflags = ENVSYS_WARN_OK;
   1091 		if (envdata->sensor == 0) {
   1092 			envdata->validflags |= ENVSYS_FVALID;
   1093 			req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
   1094 			req.cmdlen = 1;
   1095 			req.rsplen = 2;
   1096 			req.p = p;
   1097 			tadpole_request(&req, 0);
   1098 			envdata->cur.data_us =             /* 273160? */
   1099 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
   1100 			envdata->validflags |= ENVSYS_FCURVALID;
   1101 			req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
   1102 			req.cmdlen = 1;
   1103 			req.rsplen = 2;
   1104 			req.p = p;
   1105 			tadpole_request(&req, 0);
   1106 			envdata->max.data_us =
   1107 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
   1108 			envdata->validflags |= ENVSYS_FMAXVALID;
   1109 			req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
   1110 			req.cmdlen = 1;
   1111 			req.rsplen = 2;
   1112 			req.p = p;
   1113 			tadpole_request(&req, 0);
   1114 			envdata->min.data_us =
   1115 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
   1116 			envdata->validflags |= ENVSYS_FMINVALID;
   1117 			envdata->units = sc->sc_esensors[envdata->sensor].units;
   1118 			break;
   1119 		} else if (envdata->sensor == 1 || envdata->sensor == 2) {
   1120 			envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
   1121 			envdata->units = sc->sc_esensors[envdata->sensor].units;
   1122 			if (envdata->sensor == 1)
   1123 				req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
   1124 			else
   1125 				req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
   1126 			req.cmdlen = 1;
   1127 			req.rsplen = 2;
   1128 			req.p = p;
   1129 			tadpole_request(&req, 0);
   1130 			envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000000/11;
   1131 			break;
   1132 		}
   1133 		break;
   1134 
   1135         case ENVSYS_GTREINFO:
   1136 		envinfo = (envsys_temp_info_t *)data;
   1137 		if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
   1138 			envinfo->validflags = 0;
   1139 			break;
   1140 		}
   1141 		envinfo->units = sc->sc_esensors[envinfo->sensor].units;
   1142 		memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc,
   1143 		    sizeof(sc->sc_esensors[envinfo->sensor].desc) >
   1144 		    sizeof(envinfo->desc) ? sizeof(envinfo->desc) :
   1145 		    sizeof(sc->sc_esensors[envinfo->sensor].desc));
   1146 		if (envinfo->units == ENVSYS_STEMP) {
   1147 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
   1148 			    ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
   1149 		} else if (envinfo->units == ENVSYS_SVOLTS_DC) {
   1150 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
   1151 		} else
   1152 			envinfo->validflags = 0;
   1153                 break;
   1154 
   1155         case ENVSYS_STREINFO:
   1156 		envinfo = (envsys_temp_info_t *)data;
   1157 		if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
   1158 			envinfo->validflags = 0;
   1159 			break;
   1160 		}
   1161 		if (envinfo->units == sc->sc_esensors[envinfo->sensor].units)
   1162 			memcpy(sc->sc_esensors[envinfo->sensor].desc,
   1163 			    envinfo->desc,
   1164 			    sizeof(envinfo->desc) > sizeof(char)*32 ?
   1165 			    sizeof(char)*32 : sizeof(envinfo->desc) );
   1166 		if (envinfo->units == ENVSYS_STEMP) {
   1167 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
   1168 			    ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
   1169 		} else if (envinfo->units == ENVSYS_SVOLTS_DC) {
   1170 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
   1171 		} else
   1172 			envinfo->validflags = 0;
   1173                 break;
   1174 
   1175 	/* serial power mode (via auxiotwo) */
   1176 	case TCTRL_SERIAL_PWR:
   1177 		pwrreq = (struct tctrl_pwr *)data;
   1178 		if (pwrreq->rw)
   1179 			pwrreq->state = auxiotwoserialgetapm();
   1180 		else
   1181 			auxiotwoserialsetapm(pwrreq->state);
   1182 		break;
   1183 
   1184 	/* modem power mode (via auxio) */
   1185 	case TCTRL_MODEM_PWR:
   1186 		return(EOPNOTSUPP); /* for now */
   1187 		break;
   1188 
   1189 
   1190         default:
   1191                 return (ENOTTY);
   1192         }
   1193         return (0);
   1194 }
   1195 
   1196 int
   1197 tctrlpoll(dev, events, p)
   1198 	dev_t dev;
   1199 	int events;
   1200 	struct proc *p;
   1201 {
   1202 	struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
   1203 	int revents = 0;
   1204 
   1205 	if (events & (POLLIN | POLLRDNORM)) {
   1206 		if (sc->sc_event_count)
   1207 			revents |= events & (POLLIN | POLLRDNORM);
   1208 		else
   1209 			selrecord(p, &sc->sc_rsel);
   1210 	}
   1211 
   1212 	return (revents);
   1213 }
   1214 
   1215 static void
   1216 filt_tctrlrdetach(struct knote *kn)
   1217 {
   1218 	struct tctrl_softc *sc = kn->kn_hook;
   1219 	int s;
   1220 
   1221 	s = splts102();
   1222 	SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
   1223 	splx(s);
   1224 }
   1225 
   1226 static int
   1227 filt_tctrlread(struct knote *kn, long hint)
   1228 {
   1229 	struct tctrl_softc *sc = kn->kn_hook;
   1230 
   1231 	kn->kn_data = sc->sc_event_count;
   1232 	return (kn->kn_data > 0);
   1233 }
   1234 
   1235 static const struct filterops tctrlread_filtops =
   1236 	{ 1, NULL, filt_tctrlrdetach, filt_tctrlread };
   1237 
   1238 int
   1239 tctrlkqfilter(dev_t dev, struct knote *kn)
   1240 {
   1241 	struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
   1242 	struct klist *klist;
   1243 	int s;
   1244 
   1245 	switch (kn->kn_filter) {
   1246 	case EVFILT_READ:
   1247 		klist = &sc->sc_rsel.sel_klist;
   1248 		kn->kn_fop = &tctrlread_filtops;
   1249 		break;
   1250 
   1251 	default:
   1252 		return (1);
   1253 	}
   1254 
   1255 	kn->kn_hook = sc;
   1256 
   1257 	s = splts102();
   1258 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
   1259 	splx(s);
   1260 
   1261 	return (0);
   1262 }
   1263 
   1264 /* DO NOT SET THIS OPTION */
   1265 #ifdef TADPOLE_BLINK
   1266 void
   1267 cpu_disk_unbusy(busy)
   1268         int busy;
   1269 {
   1270 	static struct timeval tctrl_ds_timestamp;
   1271         struct timeval dv_time, diff_time;
   1272 	struct tctrl_softc *sc;
   1273 
   1274 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
   1275 
   1276 	/* quickly bail */
   1277 	if (!(sc->sc_lcdstate & TS102_LCD_DISK_ACTIVE) || busy > 0)
   1278 		return;
   1279 
   1280         /* we aren't terribly concerned with precision here */
   1281         dv_time = mono_time;
   1282         timersub(&dv_time, &tctrl_ds_timestamp, &diff_time);
   1283 
   1284 	if (diff_time.tv_sec > 0) {
   1285                 tctrl_set_lcd(0, TS102_LCD_DISK_ACTIVE);
   1286 		tctrl_ds_timestamp = mono_time;
   1287 	}
   1288 }
   1289 #endif
   1290