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