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