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