Home | History | Annotate | Line # | Download | only in dev
tctrl.c revision 1.5
      1 /*	$NetBSD: tctrl.c,v 1.5 1999/12/17 00:32:25 garbled Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Matt Thomas.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/ioctl.h>
     42 #include <sys/select.h>
     43 #include <sys/tty.h>
     44 #include <sys/proc.h>
     45 #include <sys/user.h>
     46 #include <sys/conf.h>
     47 #include <sys/file.h>
     48 #include <sys/uio.h>
     49 #include <sys/kernel.h>
     50 #include <sys/syslog.h>
     51 #include <sys/types.h>
     52 #include <sys/device.h>
     53 #include <sys/envsys.h>
     54 #include <sys/poll.h>
     55 
     56 #include <machine/apmvar.h>
     57 #include <machine/autoconf.h>
     58 #include <machine/cpu.h>
     59 #include <machine/bus.h>
     60 #include <machine/tctrl.h>
     61 
     62 #include <sparc/dev/ts102reg.h>
     63 #include <sparc/dev/tctrlvar.h>
     64 
     65 cdev_decl(tctrl);
     66 
     67 extern struct cfdriver tctrl_cd;
     68 
     69 static const char *tctrl_ext_statuses[16] = {
     70 	"main power available",
     71 	"internal battery attached",
     72 	"external battery attached",
     73 	"external VGA attached",
     74 	"external keyboard attached",
     75 	"external mouse attached",
     76 	"lid down",
     77 	"internal battery charging",
     78 	"external battery charging",
     79 	"internal battery discharging",
     80 	"external battery discharging",
     81 };
     82 
     83 struct tctrl_softc {
     84 	struct	device sc_dev;
     85 	bus_space_tag_t	sc_memt;
     86 	bus_space_handle_t	sc_memh;
     87 	unsigned int	sc_junk;
     88 	unsigned int	sc_ext_status;
     89 	unsigned int	sc_flags;
     90 #define TCTRL_SEND_REQUEST		0x0001
     91 #define TCTRL_APM_CTLOPEN		0x0002
     92 	unsigned int	sc_wantdata;
     93 	enum { TCTRL_IDLE, TCTRL_ARGS,
     94 		TCTRL_ACK, TCTRL_DATA } sc_state;
     95 	u_int8_t	sc_cmdbuf[16];
     96 	u_int8_t	sc_rspbuf[16];
     97 	u_int8_t	sc_bitport;
     98 	u_int8_t	sc_tft_on;
     99 	u_int8_t	sc_op;
    100 	u_int8_t	sc_cmdoff;
    101 	u_int8_t	sc_cmdlen;
    102 	u_int8_t	sc_rspoff;
    103 	u_int8_t	sc_rsplen;
    104 	/* APM stuff */
    105 #define APM_NEVENTS 16
    106 	struct	apm_event_info sc_event_list[APM_NEVENTS];
    107 	int	sc_event_count;
    108 	int	sc_event_ptr;
    109 	struct	selinfo sc_rsel;
    110 	/* ENVSYS stuff */
    111 #define ENVSYS_NUMSENSORS 3
    112 	struct	envsys_sensor sc_esensors[ENVSYS_NUMSENSORS];
    113 
    114 	struct	evcnt sc_intrcnt;	/* interrupt counting */
    115 };
    116 
    117 #define TCTRL_STD_DEV		0
    118 #define TCTRL_APMCTL_DEV	8
    119 
    120 static int tctrl_match __P((struct device *parent, struct cfdata *cf,
    121 	void *aux));
    122 static void tctrl_attach __P((struct device *parent, struct device *self,
    123 	void *aux));
    124 static void tctrl_write __P((struct tctrl_softc *sc, bus_size_t off,
    125 	u_int8_t v));
    126 static u_int8_t tctrl_read __P((struct tctrl_softc *sc, bus_size_t off));
    127 static void tctrl_write_data __P((struct tctrl_softc *sc, u_int8_t v));
    128 static u_int8_t tctrl_read_data __P((struct tctrl_softc *sc));
    129 static int tctrl_intr __P((void *arg));
    130 static void tctrl_setup_bitport __P((void));
    131 static void tctrl_setup_bitport_nop __P((void));
    132 static void tctrl_read_ext_status __P((void));
    133 static void tctrl_read_event_status __P((void *arg));
    134 static int tctrl_apm_record_event __P((struct tctrl_softc *sc,
    135 	u_int event_type));
    136 
    137 struct cfattach tctrl_ca = {
    138 	sizeof(struct tctrl_softc), tctrl_match, tctrl_attach
    139 };
    140 
    141 extern struct cfdriver tctrl_cd;
    142 /* XXX wtf is this? see i386/apm.c */
    143 int tctrl_apm_evindex;
    144 
    145 static int
    146 tctrl_match(parent, cf, aux)
    147 	struct device *parent;
    148 	struct cfdata *cf;
    149 	void *aux;
    150 {
    151 	union obio_attach_args *uoba = aux;
    152 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
    153 
    154 	if (uoba->uoba_isobio4 != 0) {
    155 		return (0);
    156 	}
    157 
    158 	/* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
    159 	 * (who's interface is off the TS102 PCMCIA controller but there
    160 	 * exists a OpenProm for microcontroller interface).
    161 	 */
    162 	return strcmp("uctrl", sa->sa_name) == 0;
    163 }
    164 
    165 static void
    166 tctrl_attach(parent, self, aux)
    167 	struct device *parent;
    168 	struct device *self;
    169 	void *aux;
    170 {
    171 	struct tctrl_softc *sc = (void *)self;
    172 	union obio_attach_args *uoba = aux;
    173 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
    174 	unsigned int i, v;
    175 #if 0
    176 	unsigned int ack, msb, lsb;
    177 #endif
    178 
    179 	/* We're living on a sbus slot that looks like an obio that
    180 	 * looks like an sbus slot.
    181 	 */
    182 	sc->sc_memt = sa->sa_bustag;
    183 	if (sbus_bus_map(sc->sc_memt, sa->sa_slot,
    184 			 sa->sa_offset - TS102_REG_UCTRL_INT, sa->sa_size,
    185 			 BUS_SPACE_MAP_LINEAR, 0,
    186 			 &sc->sc_memh) != 0) {
    187 		printf(": can't map registers\n");
    188 		return;
    189 	}
    190 
    191 	printf("\n");
    192 
    193 	sc->sc_tft_on = 1;
    194 
    195 	/* clear any pending data.
    196 	 */
    197 	for (i = 0; i < 10000; i++) {
    198 		if ((TS102_UCTRL_STS_RXNE_STA &
    199 		    tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
    200 			break;
    201 		}
    202 		v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
    203 		tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
    204 	}
    205 
    206 	if (sa->sa_nintr != 0) {
    207 		(void)bus_intr_establish(sc->sc_memt, sa->sa_pri,
    208 		    0, tctrl_intr, sc);
    209 		evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
    210 	}
    211 
    212 	/* See what the external status is
    213 	 */
    214 
    215 	tctrl_read_ext_status();
    216 	if (sc->sc_ext_status != 0) {
    217 		const char *sep;
    218 
    219 		printf("%s: ", sc->sc_dev.dv_xname);
    220 		v = sc->sc_ext_status;
    221 		for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
    222 			if (v & 1) {
    223 				printf("%s%s", sep, tctrl_ext_statuses[i]);
    224 				sep = ", ";
    225 			}
    226 		}
    227 		printf("\n");
    228 	}
    229 
    230 	/* Get a current of the control bitport;
    231 	 */
    232 	tctrl_setup_bitport_nop();
    233 	tctrl_write(sc, TS102_REG_UCTRL_INT,
    234 		    TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
    235 
    236 	sc->sc_wantdata = 0;
    237 	sc->sc_event_count = 0;
    238 
    239 	/* prime the sensor data */
    240 	sprintf(sc->sc_esensors[0].desc, "%s", "Internal Unit Temperature");
    241 	sc->sc_esensors[0].units = ENVSYS_STEMP;
    242 	sprintf(sc->sc_esensors[1].desc, "%s", "Internal Battery Voltage");
    243 	sc->sc_esensors[1].units = ENVSYS_SVOLTS_DC;
    244 	sprintf(sc->sc_esensors[2].desc, "%s", "DC-In Voltage");
    245 	sc->sc_esensors[2].units = ENVSYS_SVOLTS_DC;
    246 }
    247 
    248 static int
    249 tctrl_intr(arg)
    250 	void *arg;
    251 {
    252 	struct tctrl_softc *sc = arg;
    253 	unsigned int v, d;
    254 	int progress = 0;
    255 
    256     again:
    257 	/* find out the cause(s) of the interrupt */
    258 	v = tctrl_read(sc, TS102_REG_UCTRL_STS);
    259 
    260 	/* clear the cause(s) of the interrupt */
    261 	tctrl_write(sc, TS102_REG_UCTRL_STS, v);
    262 
    263 	v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
    264 	if (sc->sc_cmdoff >= sc->sc_cmdlen) {
    265 		v &= ~TS102_UCTRL_STS_TXNF_STA;
    266 		if (tctrl_read(sc, TS102_REG_UCTRL_INT) & TS102_UCTRL_INT_TXNF_REQ) {
    267 			tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
    268 			progress = 1;
    269 		}
    270 	}
    271 	if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
    272 	    sc->sc_state != TCTRL_IDLE)) {
    273 		wakeup(sc);
    274 		return progress;
    275 	}
    276 
    277 	progress = 1;
    278 	if (v & TS102_UCTRL_STS_RXNE_STA) {
    279 		d = tctrl_read_data(sc);
    280 		switch (sc->sc_state) {
    281 		case TCTRL_IDLE:
    282 			if (d == 0xfa) {
    283 				/* external event */
    284 				timeout(tctrl_read_event_status, (void *)0, 1);
    285 			} else {
    286 				printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
    287 					sc->sc_dev.dv_xname, sc->sc_op, d);
    288 			}
    289 			goto again;
    290 		case TCTRL_ACK:
    291 			if (d != 0xfe) {
    292 				printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
    293 					sc->sc_dev.dv_xname, sc->sc_op, d);
    294 			}
    295 #ifdef TCTRLDEBUG
    296 			printf(" ack=0x%02x", d);
    297 #endif
    298 			sc->sc_rsplen--;
    299 			sc->sc_rspoff = 0;
    300 			sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
    301 			sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
    302 #ifdef TCTRLDEBUG
    303 			if (sc->sc_rsplen > 0) {
    304 				printf(" [data(%u)]", sc->sc_rsplen);
    305 			} else {
    306 				printf(" [idle]\n");
    307 			}
    308 #endif
    309 			goto again;
    310 		case TCTRL_DATA:
    311 			sc->sc_rspbuf[sc->sc_rspoff++] = d;
    312 #ifdef TCTRLDEBUG
    313 			printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
    314 #endif
    315 			if (sc->sc_rspoff == sc->sc_rsplen) {
    316 #ifdef TCTRLDEBUG
    317 				printf(" [idle]\n");
    318 #endif
    319 				sc->sc_state = TCTRL_IDLE;
    320 				sc->sc_wantdata = 0;
    321 			}
    322 			goto again;
    323 		default:
    324 			printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
    325 			       sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
    326 			goto again;
    327 		}
    328 	}
    329 	if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
    330 	    sc->sc_flags & TCTRL_SEND_REQUEST) {
    331 		if (sc->sc_flags & TCTRL_SEND_REQUEST) {
    332 			sc->sc_flags &= ~TCTRL_SEND_REQUEST;
    333 			sc->sc_wantdata = 1;
    334 		}
    335 		if (sc->sc_cmdlen > 0) {
    336 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    337 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    338 				|TS102_UCTRL_INT_TXNF_MSK
    339 				|TS102_UCTRL_INT_TXNF_REQ);
    340 			v = tctrl_read(sc, TS102_REG_UCTRL_STS);
    341 		}
    342 	}
    343 	if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
    344 		tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
    345 #ifdef TCTRLDEBUG
    346 		if (sc->sc_cmdoff == 1) {
    347 			printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
    348 				sc->sc_cmdbuf[0], sc->sc_rsplen);
    349 		} else {
    350 			printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
    351 				sc->sc_cmdbuf[sc->sc_cmdoff-1]);
    352 		}
    353 #endif
    354 		if (sc->sc_cmdoff == sc->sc_cmdlen) {
    355 			sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
    356 #ifdef TCTRLDEBUG
    357 			printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
    358 #endif
    359 			if (sc->sc_cmdoff == 1) {
    360 				sc->sc_op = sc->sc_cmdbuf[0];
    361 			}
    362 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    363 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    364 				& (~TS102_UCTRL_INT_TXNF_MSK
    365 				   |TS102_UCTRL_INT_TXNF_REQ));
    366 		} else if (sc->sc_state == TCTRL_IDLE) {
    367 			sc->sc_op = sc->sc_cmdbuf[0];
    368 			sc->sc_state = TCTRL_ARGS;
    369 #ifdef TCTRLDEBUG
    370 			printf(" [args]");
    371 #endif
    372 		}
    373 	}
    374 	goto again;
    375 }
    376 
    377 static void
    378 tctrl_setup_bitport_nop(void)
    379 {
    380 	struct tctrl_softc *sc;
    381 	struct tctrl_req req;
    382 	int s;
    383 
    384 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    385 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    386 	req.cmdbuf[1] = 0xff;
    387 	req.cmdbuf[2] = 0;
    388 	req.cmdlen = 3;
    389 	req.rsplen = 2;
    390 	req.p = NULL;
    391 	tadpole_request(&req, 1);
    392 	s = splts102();
    393 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    394 	splx(s);
    395 }
    396 
    397 static void
    398 tctrl_setup_bitport(void)
    399 {
    400 	struct tctrl_softc *sc;
    401 	struct tctrl_req req;
    402 	int s;
    403 
    404 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    405 	s = splts102();
    406 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    407 	    || (!sc->sc_tft_on)) {
    408 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
    409 	} else {
    410 		req.cmdbuf[2] = 0;
    411 	}
    412 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    413 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    414 	req.cmdlen = 3;
    415 	req.rsplen = 2;
    416 	req.p = NULL;
    417 	tadpole_request(&req, 1);
    418 	s = splts102();
    419 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    420 	splx(s);
    421 }
    422 
    423 static void
    424 tctrl_read_ext_status(void)
    425 {
    426 	struct tctrl_softc *sc;
    427 	struct tctrl_req req;
    428 	int s;
    429 
    430 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    431 	req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
    432 	req.cmdlen = 1;
    433 	req.rsplen = 3;
    434 	req.p = NULL;
    435 #ifdef TCTRLDEBUG
    436 	printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
    437 #endif
    438 	tadpole_request(&req, 1);
    439 	s = splts102();
    440 	sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1];
    441 	splx(s);
    442 #ifdef TCTRLDEBUG
    443 	printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
    444 #endif
    445 }
    446 
    447 /*
    448  * return 0 if the user will notice and handle the event,
    449  * return 1 if the kernel driver should do so.
    450  */
    451 static int
    452 tctrl_apm_record_event(sc, event_type)
    453 	struct tctrl_softc *sc;
    454 	u_int event_type;
    455 {
    456 	struct apm_event_info *evp;
    457 
    458 	if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
    459 	    (sc->sc_event_count < APM_NEVENTS)) {
    460 		evp = &sc->sc_event_list[sc->sc_event_ptr];
    461 		sc->sc_event_count++;
    462 		sc->sc_event_ptr++;
    463 		sc->sc_event_ptr %= APM_NEVENTS;
    464 		evp->type = event_type;
    465 		evp->index = ++tctrl_apm_evindex;
    466 		selwakeup(&sc->sc_rsel);
    467 		return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
    468 	}
    469 	return(1);
    470 }
    471 
    472 static void
    473 tctrl_read_event_status(arg)
    474 	void *arg;
    475 {
    476 	struct tctrl_softc *sc;
    477 	struct tctrl_req req;
    478 	int s;
    479 	unsigned int v;
    480 
    481 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    482 	req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
    483 	req.cmdlen = 1;
    484 	req.rsplen = 3;
    485 	req.p = NULL;
    486 	tadpole_request(&req, 1);
    487 	s = splts102();
    488 	v = req.rspbuf[0] * 256 + req.rspbuf[1];
    489 	if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
    490 		printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
    491 	}
    492 	if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
    493 /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
    494 /* according to a tadpole header, and observation */
    495 #ifdef TCTRLDEBUG
    496 		printf("%s: Battery charge level change\n", sc->sc_dev.dv_xname);
    497 #endif
    498 	}
    499 	if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
    500 		if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
    501 			printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
    502 	}
    503 	if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
    504 		splx(s);
    505 		tctrl_read_ext_status();
    506 		s = splts102();
    507 		if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
    508 			printf("%s: main power %s\n", sc->sc_dev.dv_xname,
    509 			    (sc->sc_ext_status &
    510 			    TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
    511 			    "restored" : "removed");
    512 	}
    513 	if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
    514 		splx(s);
    515 		tctrl_read_ext_status();
    516 		tctrl_setup_bitport();
    517 #ifdef TCTRLDEBUG
    518 		printf("%s: lid %s\n", sc->sc_dev.dv_xname,
    519 		    (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    520 		    ? "closed" : "opened");
    521 #endif
    522 	}
    523 	splx(s);
    524 }
    525 
    526 void
    527 tadpole_request(req, spin)
    528 	struct tctrl_req *req;
    529 	int spin;
    530 {
    531 	struct tctrl_softc *sc;
    532 	int i, s;
    533 
    534 	if (tctrl_cd.cd_devs == NULL
    535 	    || tctrl_cd.cd_ndevs == 0
    536 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
    537 		return;
    538 	}
    539 
    540 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    541 	while (sc->sc_wantdata != 0) {
    542 		if (req->p != NULL)
    543 			tsleep(&sc->sc_wantdata, PLOCK, "tctrl_lock", 10);
    544 		else
    545 			DELAY(1);
    546 	}
    547 	if (spin)
    548 		s = splhigh();
    549 	else
    550 		s = splts102();
    551 	sc->sc_flags |= TCTRL_SEND_REQUEST;
    552 	memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
    553 	sc->sc_wantdata = 1;
    554 	sc->sc_rsplen = req->rsplen;
    555 	sc->sc_cmdlen = req->cmdlen;
    556 	sc->sc_cmdoff = sc->sc_rspoff = 0;
    557 
    558 	/* we spin for certain commands, like poweroffs */
    559 	if (spin) {
    560 		for (i = 0; i < 30000; i++) {
    561 			tctrl_intr(sc);
    562 			DELAY(1);
    563 		}
    564 	} else {
    565 		tctrl_intr(sc);
    566 		i = 0;
    567 		while (((sc->sc_rspoff != sc->sc_rsplen) ||
    568 		    (sc->sc_cmdoff != sc->sc_cmdlen)) &&
    569 		    (i < (5 * sc->sc_rsplen + sc->sc_cmdlen)))
    570 			if (req->p != NULL) {
    571 				tsleep(sc, PWAIT, "tctrl_data", 15);
    572 				i++;
    573 			}
    574 			else
    575 				DELAY(1);
    576 	}
    577 	/*
    578 	 * we give the user a reasonable amount of time for a command
    579 	 * to complete.  If it doesn't complete in time, we hand them
    580 	 * garbage.  This is here to stop things like setting the
    581 	 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
    582 	 */
    583 	sc->sc_wantdata = 0;
    584 	memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
    585 	splx(s);
    586 }
    587 
    588 void
    589 tadpole_powerdown(void)
    590 {
    591 	struct tctrl_req req;
    592 
    593 	req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
    594 	req.cmdlen = 1;
    595 	req.rsplen = 1;
    596 	req.p = NULL;
    597 	tadpole_request(&req, 1);
    598 }
    599 
    600 void
    601 tadpole_set_video(enabled)
    602 	int enabled;
    603 {
    604 	struct tctrl_softc *sc;
    605 	struct tctrl_req req;
    606 	int s;
    607 
    608 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    609 	while (sc->sc_wantdata != 0)
    610 		DELAY(1);
    611 	s = splts102();
    612 	req.p = NULL;
    613 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
    614 	    || (sc->sc_tft_on)) {
    615 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
    616 	} else {
    617 		req.cmdbuf[2] = 0;
    618 	}
    619 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    620 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    621 	req.cmdlen = 3;
    622 	req.rsplen = 2;
    623 
    624 	if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
    625 		sc->sc_tft_on = enabled;
    626 		if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
    627 			splx(s);
    628 			return;
    629 		}
    630 		tadpole_request(&req, 1);
    631 		sc->sc_bitport =
    632 		    (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    633 	}
    634 	splx(s);
    635 }
    636 
    637 static void
    638 tctrl_write_data(sc, v)
    639 	struct tctrl_softc *sc;
    640 	u_int8_t v;
    641 {
    642 	unsigned int i;
    643 
    644 	for (i = 0; i < 100; i++)  {
    645 		if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
    646 			break;
    647 	}
    648 	tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
    649 }
    650 
    651 static u_int8_t
    652 tctrl_read_data(sc)
    653 	struct tctrl_softc *sc;
    654 {
    655 	unsigned int i, v;
    656 
    657 	for (i = 0; i < 100000; i++) {
    658 		if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
    659 			break;
    660 		DELAY(1);
    661 	}
    662 
    663 	v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
    664 	tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
    665 	return v;
    666 }
    667 
    668 static u_int8_t
    669 tctrl_read(sc, off)
    670 	struct tctrl_softc *sc;
    671 	bus_size_t off;
    672 {
    673 
    674 	sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
    675 	return sc->sc_junk;
    676 }
    677 
    678 static void
    679 tctrl_write(sc, off, v)
    680 	struct tctrl_softc *sc;
    681 	bus_size_t off;
    682 	u_int8_t v;
    683 {
    684 
    685 	sc->sc_junk = v;
    686 	bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
    687 }
    688 
    689 int
    690 tctrlopen(dev, flags, mode, p)
    691 	dev_t dev;
    692 	int flags, mode;
    693 	struct proc *p;
    694 {
    695 	int unit = (minor(dev)&0xf0);
    696 	int ctl = (minor(dev)&0x0f);
    697 	struct tctrl_softc *sc;
    698 
    699 	if (unit >= tctrl_cd.cd_ndevs)
    700 		return(ENXIO);
    701 	sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
    702 	if (!sc)
    703 		return(ENXIO);
    704 
    705 	switch (ctl) {
    706 	case TCTRL_STD_DEV:
    707 		break;
    708 	case TCTRL_APMCTL_DEV:
    709 		if (!(flags & FWRITE))
    710 			return(EINVAL);
    711 		if (sc->sc_flags & TCTRL_APM_CTLOPEN)
    712 			return(EBUSY);
    713 		sc->sc_flags |= TCTRL_APM_CTLOPEN;
    714 		break;
    715 	default:
    716 		return(ENXIO);
    717 		break;
    718 	}
    719 
    720 	return(0);
    721 }
    722 
    723 int
    724 tctrlclose(dev, flags, mode, p)
    725 	dev_t dev;
    726 	int flags, mode;
    727 	struct proc *p;
    728 {
    729 	int ctl = (minor(dev)&0x0f);
    730 	struct tctrl_softc *sc;
    731 
    732 	sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
    733 	if (!sc)
    734 		return(ENXIO);
    735 
    736 	switch (ctl) {
    737 	case TCTRL_STD_DEV:
    738 		break;
    739 	case TCTRL_APMCTL_DEV:
    740 		sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
    741 		break;
    742 	}
    743 	return(0);
    744 }
    745 
    746 int
    747 tctrlioctl(dev, cmd, data, flags, p)
    748         dev_t dev;
    749         u_long cmd;
    750         caddr_t data;
    751         int flags;
    752         struct proc *p;
    753 {
    754 	struct tctrl_req req, *reqn;
    755 	envsys_range_t *envrange;
    756 	envsys_temp_data_t *envdata;
    757 	envsys_temp_info_t *envinfo;
    758 	struct apm_power_info *powerp;
    759 	struct apm_event_info *evp;
    760 	struct tctrl_softc *sc;
    761 	int i;
    762 	u_int j;
    763 	u_int16_t a;
    764 	u_int8_t c;
    765 
    766 	if (tctrl_cd.cd_devs == NULL
    767 	    || tctrl_cd.cd_ndevs == 0
    768 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
    769 		return ENXIO;
    770 	}
    771 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    772         switch (cmd) {
    773 
    774 	case APM_IOC_STANDBY:
    775 		return(EOPNOTSUPP); /* for now */
    776 
    777 	case APM_IOC_SUSPEND:
    778 		return(EOPNOTSUPP); /* for now */
    779 
    780 	case APM_IOC_GETPOWER:
    781 		powerp = (struct apm_power_info *)data;
    782 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
    783 		req.cmdlen = 1;
    784 		req.rsplen = 2;
    785 		req.p = p;
    786 		tadpole_request(&req, 0);
    787 		if (req.rspbuf[0] > 0x00)
    788 			powerp->battery_state = APM_BATT_CHARGING;
    789 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
    790 		req.cmdlen = 1;
    791 		req.rsplen = 3;
    792 		req.p = p;
    793 		tadpole_request(&req, 0);
    794 		c = req.rspbuf[0];
    795 		powerp->battery_life = c;
    796 		powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
    797 		if (powerp->battery_state != APM_BATT_CHARGING) {
    798 			if (c < 0x20)
    799 				powerp->battery_state = APM_BATT_CRITICAL;
    800 			else if (c < 0x40)
    801 				powerp->battery_state = APM_BATT_LOW;
    802 			else if (c < 0x66)
    803 				powerp->battery_state = APM_BATT_HIGH;
    804 			else
    805 				powerp->battery_state = APM_BATT_UNKNOWN;
    806 		}
    807 		req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
    808 		req.cmdlen = 1;
    809 		req.rsplen = 3;
    810 		req.p = p;
    811 		tadpole_request(&req, 0);
    812 		a = req.rspbuf[0] * 256 + req.rspbuf[1];
    813 		if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
    814 			powerp->ac_state = APM_AC_ON;
    815 		else
    816 			powerp->ac_state = APM_AC_OFF;
    817 		break;
    818 
    819 	case APM_IOC_NEXTEVENT:
    820 		if (!sc->sc_event_count)
    821 			return EAGAIN;
    822 
    823 		evp = (struct apm_event_info *)data;
    824 		i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
    825 		i %= APM_NEVENTS;
    826 		*evp = sc->sc_event_list[i];
    827 		sc->sc_event_count--;
    828 		return(0);
    829 
    830 	/* this ioctl assumes the caller knows exactly what he is doing */
    831 	case TCTRL_CMD_REQ:
    832 		reqn = (struct tctrl_req *)data;
    833 		if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 &&
    834 		    (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
    835 		    (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
    836 		    reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
    837 		    reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
    838 		    reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
    839 		    reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
    840 		    (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
    841 		    reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
    842 		    reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
    843 			return(i);
    844 		reqn->p = p;
    845 		tadpole_request(reqn, 0);
    846 		break;
    847 
    848 	case ENVSYS_VERSION:
    849 		*(int32_t *)data = 1000;
    850 		break;
    851 
    852 	case ENVSYS_GRANGE:
    853 		envrange = (envsys_range_t *)data;
    854 		i = 0;
    855 		envrange->high = envrange->low = 0;
    856 		for (j=0; j < ENVSYS_NUMSENSORS; j++) {
    857 			if (!i && envrange->units == sc->sc_esensors[j].units) {
    858 				envrange->low = j;
    859 				i++;
    860 			}
    861 			if (i && envrange->units == sc->sc_esensors[j].units)
    862 				envrange->high = j;
    863 		}
    864 		if (!i) {
    865 			envrange->high = 0;
    866 			envrange->low = 1;
    867 		}
    868 		break;
    869 
    870 	case ENVSYS_GTREDATA:
    871 		envdata = (envsys_temp_data_t *)data;
    872 		if (envdata->sensor >= ENVSYS_NUMSENSORS) {
    873 			envdata->validflags = 0;
    874 			break;
    875 		}
    876 		envdata->warnflags = ENVSYS_WARN_OK;
    877 		if (envdata->sensor == 0) {
    878 			envdata->validflags |= ENVSYS_FVALID;
    879 			req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
    880 			req.cmdlen = 1;
    881 			req.rsplen = 2;
    882 			req.p = p;
    883 			tadpole_request(&req, 0);
    884 			envdata->cur.data_us =             /* 273160? */
    885 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
    886 			envdata->validflags |= ENVSYS_FCURVALID;
    887 			req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
    888 			req.cmdlen = 1;
    889 			req.rsplen = 2;
    890 			req.p = p;
    891 			tadpole_request(&req, 0);
    892 			envdata->max.data_us =
    893 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
    894 			envdata->validflags |= ENVSYS_FMAXVALID;
    895 			req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
    896 			req.cmdlen = 1;
    897 			req.rsplen = 2;
    898 			req.p = p;
    899 			tadpole_request(&req, 0);
    900 			envdata->min.data_us =
    901 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
    902 			envdata->validflags |= ENVSYS_FMINVALID;
    903 			envdata->units = sc->sc_esensors[envdata->sensor].units;
    904 			break;
    905 		} else if (envdata->sensor == 1 || envdata->sensor == 2) {
    906 			envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
    907 			envdata->units = sc->sc_esensors[envdata->sensor].units;
    908 			if (envdata->sensor == 1)
    909 				req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
    910 			else
    911 				req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
    912 			req.cmdlen = 1;
    913 			req.rsplen = 2;
    914 			req.p = p;
    915 			tadpole_request(&req, 0);
    916 			envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000/11;
    917 			break;
    918 		}
    919 		break;
    920 
    921         case ENVSYS_GTREINFO:
    922 		envinfo = (envsys_temp_info_t *)data;
    923 		if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
    924 			envinfo->validflags = 0;
    925 			break;
    926 		}
    927 		envinfo->units = sc->sc_esensors[envinfo->sensor].units;
    928 		memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc,
    929 		    sizeof(sc->sc_esensors[envinfo->sensor].desc) >
    930 		    sizeof(envinfo->desc) ? sizeof(envinfo->desc) :
    931 		    sizeof(sc->sc_esensors[envinfo->sensor].desc));
    932 		if (envinfo->units == ENVSYS_STEMP) {
    933 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
    934 			    ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
    935 		} else if (envinfo->units == ENVSYS_SVOLTS_DC) {
    936 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
    937 		} else
    938 			envinfo->validflags = 0;
    939                 break;
    940 
    941         case ENVSYS_STREINFO:
    942 		envinfo = (envsys_temp_info_t *)data;
    943 		if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
    944 			envinfo->validflags = 0;
    945 			break;
    946 		}
    947 		if (envinfo->units == sc->sc_esensors[envinfo->sensor].units)
    948 			memcpy(sc->sc_esensors[envinfo->sensor].desc,
    949 			    envinfo->desc,
    950 			    sizeof(envinfo->desc) > sizeof(char)*32 ?
    951 			    sizeof(char)*32 : sizeof(envinfo->desc) );
    952 		if (envinfo->units == ENVSYS_STEMP) {
    953 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
    954 			    ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
    955 		} else if (envinfo->units == ENVSYS_SVOLTS_DC) {
    956 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
    957 		} else
    958 			envinfo->validflags = 0;
    959                 break;
    960 
    961 
    962         default:
    963                 return (ENOTTY);
    964         }
    965         return (0);
    966 }
    967 
    968 int
    969 tctrlpoll(dev, events, p)
    970 	dev_t dev;
    971 	int events;
    972 	struct proc *p;
    973 {
    974 	struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
    975 	int revents = 0;
    976 
    977 	if (events & (POLLIN | POLLRDNORM)) {
    978 		if (sc->sc_event_count)
    979 			revents |= events & (POLLIN | POLLRDNORM);
    980 		else
    981 			selrecord(p, &sc->sc_rsel);
    982 	}
    983 
    984 	return (revents);
    985 }
    986