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