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