Home | History | Annotate | Line # | Download | only in dev
tctrl.c revision 1.14.4.1
      1 /*	$NetBSD: tctrl.c,v 1.14.4.1 2002/05/17 15:40:51 gehenna 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 
     74 const struct cdevsw tctrl_cdevsw = {
     75 	tctrlopen, tctrlclose, noread, nowrite, tctrlioctl,
     76 	nostop, notty, tctrlpoll, nommap,
     77 };
     78 
     79 static const char *tctrl_ext_statuses[16] = {
     80 	"main power available",
     81 	"internal battery attached",
     82 	"external battery attached",
     83 	"external VGA attached",
     84 	"external keyboard attached",
     85 	"external mouse attached",
     86 	"lid down",
     87 	"internal battery charging",
     88 	"external battery charging",
     89 	"internal battery discharging",
     90 	"external battery discharging",
     91 };
     92 
     93 struct tctrl_softc {
     94 	struct	device sc_dev;
     95 	bus_space_tag_t	sc_memt;
     96 	bus_space_handle_t	sc_memh;
     97 	unsigned int	sc_junk;
     98 	unsigned int	sc_ext_status;
     99 	unsigned int	sc_flags;
    100 #define TCTRL_SEND_REQUEST		0x0001
    101 #define TCTRL_APM_CTLOPEN		0x0002
    102 	unsigned int	sc_wantdata;
    103 	volatile unsigned short	sc_lcdstate;
    104 	enum { TCTRL_IDLE, TCTRL_ARGS,
    105 		TCTRL_ACK, TCTRL_DATA } sc_state;
    106 	u_int8_t	sc_cmdbuf[16];
    107 	u_int8_t	sc_rspbuf[16];
    108 	u_int8_t	sc_bitport;
    109 	u_int8_t	sc_tft_on;
    110 	u_int8_t	sc_op;
    111 	u_int8_t	sc_cmdoff;
    112 	u_int8_t	sc_cmdlen;
    113 	u_int8_t	sc_rspoff;
    114 	u_int8_t	sc_rsplen;
    115 	/* APM stuff */
    116 #define APM_NEVENTS 16
    117 	struct	apm_event_info sc_event_list[APM_NEVENTS];
    118 	int	sc_event_count;
    119 	int	sc_event_ptr;
    120 	struct	selinfo sc_rsel;
    121 	/* ENVSYS stuff */
    122 #define ENVSYS_NUMSENSORS 3
    123 	struct	envsys_sensor sc_esensors[ENVSYS_NUMSENSORS];
    124 
    125 	struct	evcnt sc_intrcnt;	/* interrupt counting */
    126 };
    127 
    128 #define TCTRL_STD_DEV		0
    129 #define TCTRL_APMCTL_DEV	8
    130 
    131 static struct callout tctrl_event_ch = CALLOUT_INITIALIZER;
    132 
    133 static int tctrl_match __P((struct device *parent, struct cfdata *cf,
    134 	void *aux));
    135 static void tctrl_attach __P((struct device *parent, struct device *self,
    136 	void *aux));
    137 static void tctrl_write __P((struct tctrl_softc *sc, bus_size_t off,
    138 	u_int8_t v));
    139 static u_int8_t tctrl_read __P((struct tctrl_softc *sc, bus_size_t off));
    140 static void tctrl_write_data __P((struct tctrl_softc *sc, u_int8_t v));
    141 static u_int8_t tctrl_read_data __P((struct tctrl_softc *sc));
    142 static int tctrl_intr __P((void *arg));
    143 static void tctrl_setup_bitport __P((void));
    144 static void tctrl_setup_bitport_nop __P((void));
    145 static void tctrl_read_ext_status __P((void));
    146 static void tctrl_read_event_status __P((void *arg));
    147 static int tctrl_apm_record_event __P((struct tctrl_softc *sc,
    148 	u_int event_type));
    149 static void tctrl_init_lcd __P((void));
    150 
    151 struct cfattach tctrl_ca = {
    152 	sizeof(struct tctrl_softc), tctrl_match, tctrl_attach
    153 };
    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 		    0, 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 		selwakeup(&sc->sc_rsel);
    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, p)
    901 	dev_t dev;
    902 	int flags, mode;
    903 	struct proc *p;
    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, p)
    935 	dev_t dev;
    936 	int flags, mode;
    937 	struct proc *p;
    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, p)
    958         dev_t dev;
    959         u_long cmd;
    960         caddr_t data;
    961         int flags;
    962         struct proc *p;
    963 {
    964 	struct tctrl_req req, *reqn;
    965 	struct tctrl_pwr *pwrreq;
    966 	envsys_range_t *envrange;
    967 	envsys_temp_data_t *envdata;
    968 	envsys_temp_info_t *envinfo;
    969 	struct apm_power_info *powerp;
    970 	struct apm_event_info *evp;
    971 	struct tctrl_softc *sc;
    972 	int i;
    973 	u_int j;
    974 	u_int16_t a;
    975 	u_int8_t c;
    976 
    977 	if (tctrl_cd.cd_devs == NULL
    978 	    || tctrl_cd.cd_ndevs == 0
    979 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
    980 		return ENXIO;
    981 	}
    982 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    983         switch (cmd) {
    984 
    985 	case APM_IOC_STANDBY:
    986 		return(EOPNOTSUPP); /* for now */
    987 
    988 	case APM_IOC_SUSPEND:
    989 		return(EOPNOTSUPP); /* for now */
    990 
    991 	case APM_IOC_GETPOWER:
    992 		powerp = (struct apm_power_info *)data;
    993 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
    994 		req.cmdlen = 1;
    995 		req.rsplen = 2;
    996 		req.p = p;
    997 		tadpole_request(&req, 0);
    998 		if (req.rspbuf[0] > 0x00)
    999 			powerp->battery_state = APM_BATT_CHARGING;
   1000 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
   1001 		req.cmdlen = 1;
   1002 		req.rsplen = 3;
   1003 		req.p = p;
   1004 		tadpole_request(&req, 0);
   1005 		c = req.rspbuf[0];
   1006 		powerp->battery_life = c;
   1007 		if (c > 0x70)	/* the tadpole sometimes dips below zero, and */
   1008 			c = 0;	/* into the 255 range. */
   1009 		powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
   1010 		if (powerp->battery_state != APM_BATT_CHARGING) {
   1011 			if (c < 0x20)
   1012 				powerp->battery_state = APM_BATT_CRITICAL;
   1013 			else if (c < 0x40)
   1014 				powerp->battery_state = APM_BATT_LOW;
   1015 			else if (c < 0x66)
   1016 				powerp->battery_state = APM_BATT_HIGH;
   1017 			else
   1018 				powerp->battery_state = APM_BATT_UNKNOWN;
   1019 		}
   1020 		req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
   1021 		req.cmdlen = 1;
   1022 		req.rsplen = 3;
   1023 		req.p = p;
   1024 		tadpole_request(&req, 0);
   1025 		a = req.rspbuf[0] * 256 + req.rspbuf[1];
   1026 		if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
   1027 			powerp->ac_state = APM_AC_ON;
   1028 		else
   1029 			powerp->ac_state = APM_AC_OFF;
   1030 		break;
   1031 
   1032 	case APM_IOC_NEXTEVENT:
   1033 		if (!sc->sc_event_count)
   1034 			return EAGAIN;
   1035 
   1036 		evp = (struct apm_event_info *)data;
   1037 		i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
   1038 		i %= APM_NEVENTS;
   1039 		*evp = sc->sc_event_list[i];
   1040 		sc->sc_event_count--;
   1041 		return(0);
   1042 
   1043 	/* this ioctl assumes the caller knows exactly what he is doing */
   1044 	case TCTRL_CMD_REQ:
   1045 		reqn = (struct tctrl_req *)data;
   1046 		if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 &&
   1047 		    (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
   1048 		    (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
   1049 		    reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
   1050 		    reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
   1051 		    reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
   1052 		    reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
   1053 		    (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
   1054 		    reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
   1055 		    reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
   1056 			return(i);
   1057 		reqn->p = p;
   1058 		tadpole_request(reqn, 0);
   1059 		break;
   1060 
   1061 	case ENVSYS_VERSION:
   1062 		*(int32_t *)data = 1000;
   1063 		break;
   1064 
   1065 	case ENVSYS_GRANGE:
   1066 		envrange = (envsys_range_t *)data;
   1067 		i = 0;
   1068 		envrange->high = envrange->low = 0;
   1069 		for (j=0; j < ENVSYS_NUMSENSORS; j++) {
   1070 			if (!i && envrange->units == sc->sc_esensors[j].units) {
   1071 				envrange->low = j;
   1072 				i++;
   1073 			}
   1074 			if (i && envrange->units == sc->sc_esensors[j].units)
   1075 				envrange->high = j;
   1076 		}
   1077 		if (!i) {
   1078 			envrange->high = 0;
   1079 			envrange->low = 1;
   1080 		}
   1081 		break;
   1082 
   1083 	case ENVSYS_GTREDATA:
   1084 		envdata = (envsys_temp_data_t *)data;
   1085 		if (envdata->sensor >= ENVSYS_NUMSENSORS) {
   1086 			envdata->validflags = 0;
   1087 			break;
   1088 		}
   1089 		envdata->warnflags = ENVSYS_WARN_OK;
   1090 		if (envdata->sensor == 0) {
   1091 			envdata->validflags |= ENVSYS_FVALID;
   1092 			req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
   1093 			req.cmdlen = 1;
   1094 			req.rsplen = 2;
   1095 			req.p = p;
   1096 			tadpole_request(&req, 0);
   1097 			envdata->cur.data_us =             /* 273160? */
   1098 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
   1099 			envdata->validflags |= ENVSYS_FCURVALID;
   1100 			req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
   1101 			req.cmdlen = 1;
   1102 			req.rsplen = 2;
   1103 			req.p = p;
   1104 			tadpole_request(&req, 0);
   1105 			envdata->max.data_us =
   1106 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
   1107 			envdata->validflags |= ENVSYS_FMAXVALID;
   1108 			req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
   1109 			req.cmdlen = 1;
   1110 			req.rsplen = 2;
   1111 			req.p = p;
   1112 			tadpole_request(&req, 0);
   1113 			envdata->min.data_us =
   1114 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
   1115 			envdata->validflags |= ENVSYS_FMINVALID;
   1116 			envdata->units = sc->sc_esensors[envdata->sensor].units;
   1117 			break;
   1118 		} else if (envdata->sensor == 1 || envdata->sensor == 2) {
   1119 			envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
   1120 			envdata->units = sc->sc_esensors[envdata->sensor].units;
   1121 			if (envdata->sensor == 1)
   1122 				req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
   1123 			else
   1124 				req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
   1125 			req.cmdlen = 1;
   1126 			req.rsplen = 2;
   1127 			req.p = p;
   1128 			tadpole_request(&req, 0);
   1129 			envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000000/11;
   1130 			break;
   1131 		}
   1132 		break;
   1133 
   1134         case ENVSYS_GTREINFO:
   1135 		envinfo = (envsys_temp_info_t *)data;
   1136 		if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
   1137 			envinfo->validflags = 0;
   1138 			break;
   1139 		}
   1140 		envinfo->units = sc->sc_esensors[envinfo->sensor].units;
   1141 		memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc,
   1142 		    sizeof(sc->sc_esensors[envinfo->sensor].desc) >
   1143 		    sizeof(envinfo->desc) ? sizeof(envinfo->desc) :
   1144 		    sizeof(sc->sc_esensors[envinfo->sensor].desc));
   1145 		if (envinfo->units == ENVSYS_STEMP) {
   1146 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
   1147 			    ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
   1148 		} else if (envinfo->units == ENVSYS_SVOLTS_DC) {
   1149 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
   1150 		} else
   1151 			envinfo->validflags = 0;
   1152                 break;
   1153 
   1154         case ENVSYS_STREINFO:
   1155 		envinfo = (envsys_temp_info_t *)data;
   1156 		if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
   1157 			envinfo->validflags = 0;
   1158 			break;
   1159 		}
   1160 		if (envinfo->units == sc->sc_esensors[envinfo->sensor].units)
   1161 			memcpy(sc->sc_esensors[envinfo->sensor].desc,
   1162 			    envinfo->desc,
   1163 			    sizeof(envinfo->desc) > sizeof(char)*32 ?
   1164 			    sizeof(char)*32 : sizeof(envinfo->desc) );
   1165 		if (envinfo->units == ENVSYS_STEMP) {
   1166 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
   1167 			    ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
   1168 		} else if (envinfo->units == ENVSYS_SVOLTS_DC) {
   1169 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
   1170 		} else
   1171 			envinfo->validflags = 0;
   1172                 break;
   1173 
   1174 	/* serial power mode (via auxiotwo) */
   1175 	case TCTRL_SERIAL_PWR:
   1176 		pwrreq = (struct tctrl_pwr *)data;
   1177 		if (pwrreq->rw)
   1178 			pwrreq->state = auxiotwoserialgetapm();
   1179 		else
   1180 			auxiotwoserialsetapm(pwrreq->state);
   1181 		break;
   1182 
   1183 	/* modem power mode (via auxio) */
   1184 	case TCTRL_MODEM_PWR:
   1185 		return(EOPNOTSUPP); /* for now */
   1186 		break;
   1187 
   1188 
   1189         default:
   1190                 return (ENOTTY);
   1191         }
   1192         return (0);
   1193 }
   1194 
   1195 int
   1196 tctrlpoll(dev, events, p)
   1197 	dev_t dev;
   1198 	int events;
   1199 	struct proc *p;
   1200 {
   1201 	struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
   1202 	int revents = 0;
   1203 
   1204 	if (events & (POLLIN | POLLRDNORM)) {
   1205 		if (sc->sc_event_count)
   1206 			revents |= events & (POLLIN | POLLRDNORM);
   1207 		else
   1208 			selrecord(p, &sc->sc_rsel);
   1209 	}
   1210 
   1211 	return (revents);
   1212 }
   1213 /* DO NOT SET THIS OPTION */
   1214 #ifdef TADPOLE_BLINK
   1215 void
   1216 cpu_disk_unbusy(busy)
   1217         int busy;
   1218 {
   1219 	static struct timeval tctrl_ds_timestamp;
   1220         struct timeval dv_time, diff_time;
   1221 	struct tctrl_softc *sc;
   1222 
   1223 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
   1224 
   1225 	/* quickly bail */
   1226 	if (!(sc->sc_lcdstate & TS102_LCD_DISK_ACTIVE) || busy > 0)
   1227 		return;
   1228 
   1229         /* we aren't terribly concerned with precision here */
   1230         dv_time = mono_time;
   1231         timersub(&dv_time, &tctrl_ds_timestamp, &diff_time);
   1232 
   1233 	if (diff_time.tv_sec > 0) {
   1234                 tctrl_set_lcd(0, TS102_LCD_DISK_ACTIVE);
   1235 		tctrl_ds_timestamp = mono_time;
   1236 	}
   1237 }
   1238 #endif
   1239