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