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