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