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