Home | History | Annotate | Line # | Download | only in dev
tctrl.c revision 1.62
      1 /*	$NetBSD: tctrl.c,v 1.62 2020/06/13 05:31:28 jdc 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.62 2020/06/13 05:31:28 jdc 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 	mutex_init(&sc->sc_requestlock, MUTEX_DEFAULT, IPL_NONE);
    264 
    265 	/* clear any pending data.
    266 	 */
    267 	for (i = 0; i < 10000; i++) {
    268 		if ((TS102_UCTRL_STS_RXNE_STA &
    269 		    tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
    270 			break;
    271 		}
    272 		v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
    273 		tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
    274 	}
    275 
    276 	if (sa->sa_nintr != 0) {
    277 		(void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE,
    278 					 tctrl_intr, sc);
    279 		evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
    280 				     device_xname(sc->sc_dev), "intr");
    281 	}
    282 
    283 	/* See what the external status is */
    284 	sc->sc_ext_status = 0;
    285 	tctrl_read_ext_status();
    286 	if (sc->sc_ext_status != 0) {
    287 		const char *sep;
    288 
    289 		printf("%s: ", device_xname(sc->sc_dev));
    290 		v = sc->sc_ext_status;
    291 		for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
    292 			if (v & 1) {
    293 				printf("%s%s", sep, tctrl_ext_statuses[i]);
    294 				sep = ", ";
    295 			}
    296 		}
    297 		printf("\n");
    298 	}
    299 
    300 	/* Get a current of the control bitport */
    301 	tctrl_setup_bitport_nop();
    302 	tctrl_write(sc, TS102_REG_UCTRL_INT,
    303 		    TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
    304 	sc->sc_lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0;
    305 	sc->sc_power_state = PWR_RESUME;
    306 
    307 	sc->sc_extvga = (sc->sc_ext_status &
    308 	    TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0;
    309 	sc->sc_video_callback = NULL;
    310 
    311 
    312 	sc->sc_wantdata = 0;
    313 	sc->sc_event_count = 0;
    314 	sc->sc_ext_pending = 0;
    315 		sc->sc_ext_pending = 0;
    316 
    317 	selinit(&sc->sc_rsel);
    318 
    319 	/* setup sensors and register the power button */
    320 	tctrl_sensor_setup(sc);
    321 	tctrl_lid_state(sc);
    322 	tctrl_ac_state(sc);
    323 
    324 	/* initialize the LCD */
    325 	tctrl_init_lcd();
    326 
    327 	/* initialize sc_lcdstate */
    328 	sc->sc_lcdstate = 0;
    329 	sc->sc_lcdwanted = 0;
    330 	tadpole_set_lcd(2, 0);
    331 
    332 	/* fire up the LCD event thread */
    333 	sc->sc_events = 0;
    334 
    335 	if (kthread_create(PRI_NONE, 0, NULL, tctrl_event_thread, sc,
    336 	    &sc->sc_thread, "%s", device_xname(sc->sc_dev)) != 0) {
    337 		printf("%s: unable to create event kthread",
    338 		    device_xname(sc->sc_dev));
    339 	}
    340 }
    341 
    342 static int
    343 tctrl_intr(void *arg)
    344 {
    345 	struct tctrl_softc *sc = arg;
    346 	unsigned int v, d;
    347 	int progress = 0;
    348 
    349     again:
    350 	/* find out the cause(s) of the interrupt */
    351 	v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK;
    352 
    353 	/* clear the cause(s) of the interrupt */
    354 	tctrl_write(sc, TS102_REG_UCTRL_STS, v);
    355 
    356 	v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
    357 	if (sc->sc_cmdoff >= sc->sc_cmdlen) {
    358 		v &= ~TS102_UCTRL_STS_TXNF_STA;
    359 		if (tctrl_read(sc, TS102_REG_UCTRL_INT) &
    360 		    TS102_UCTRL_INT_TXNF_REQ) {
    361 			tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
    362 			progress = 1;
    363 		}
    364 	}
    365 	if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
    366 	    sc->sc_state != TCTRL_IDLE)) {
    367 		wakeup(sc);
    368 		return progress;
    369 	}
    370 
    371 	progress = 1;
    372 	if (v & TS102_UCTRL_STS_RXNE_STA) {
    373 		d = tctrl_read_data(sc);
    374 		switch (sc->sc_state) {
    375 		case TCTRL_IDLE:
    376 			if (d == 0xfa) {
    377 				/*
    378 				 * external event,
    379 				 * set a flag and wakeup the event thread
    380 				 */
    381 				sc->sc_ext_pending = 1;
    382 			} else {
    383 				printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
    384 					device_xname(sc->sc_dev), sc->sc_op, d);
    385 			}
    386 			goto again;
    387 		case TCTRL_ACK:
    388 			if (d != 0xfe) {
    389 				printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
    390 					device_xname(sc->sc_dev), sc->sc_op, d);
    391 			}
    392 #ifdef TCTRLDEBUG
    393 			printf(" ack=0x%02x", d);
    394 #endif
    395 			sc->sc_rsplen--;
    396 			sc->sc_rspoff = 0;
    397 			sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
    398 			sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
    399 #ifdef TCTRLDEBUG
    400 			if (sc->sc_rsplen > 0) {
    401 				printf(" [data(%u)]", sc->sc_rsplen);
    402 			} else {
    403 				printf(" [idle]\n");
    404 			}
    405 #endif
    406 			goto again;
    407 		case TCTRL_DATA:
    408 			sc->sc_rspbuf[sc->sc_rspoff++] = d;
    409 #ifdef TCTRLDEBUG
    410 			printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
    411 #endif
    412 			if (sc->sc_rspoff == sc->sc_rsplen) {
    413 #ifdef TCTRLDEBUG
    414 				printf(" [idle]\n");
    415 #endif
    416 				sc->sc_state = TCTRL_IDLE;
    417 				sc->sc_wantdata = 0;
    418 			}
    419 			goto again;
    420 		default:
    421 			printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
    422 			       device_xname(sc->sc_dev), sc->sc_op, d, sc->sc_state);
    423 			goto again;
    424 		}
    425 	}
    426 	if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
    427 	    sc->sc_flags & TCTRL_SEND_REQUEST) {
    428 		if (sc->sc_flags & TCTRL_SEND_REQUEST) {
    429 			sc->sc_flags &= ~TCTRL_SEND_REQUEST;
    430 			sc->sc_wantdata = 1;
    431 		}
    432 		if (sc->sc_cmdlen > 0) {
    433 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    434 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    435 				|TS102_UCTRL_INT_TXNF_MSK
    436 				|TS102_UCTRL_INT_TXNF_REQ);
    437 			v = tctrl_read(sc, TS102_REG_UCTRL_STS);
    438 		}
    439 	}
    440 	if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
    441 		tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
    442 #ifdef TCTRLDEBUG
    443 		if (sc->sc_cmdoff == 1) {
    444 			printf("%s: op=0x%02x(l=%u)", device_xname(sc->sc_dev),
    445 				sc->sc_cmdbuf[0], sc->sc_rsplen);
    446 		} else {
    447 			printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
    448 				sc->sc_cmdbuf[sc->sc_cmdoff-1]);
    449 		}
    450 #endif
    451 		if (sc->sc_cmdoff == sc->sc_cmdlen) {
    452 			sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
    453 #ifdef TCTRLDEBUG
    454 			printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
    455 #endif
    456 			if (sc->sc_cmdoff == 1) {
    457 				sc->sc_op = sc->sc_cmdbuf[0];
    458 			}
    459 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    460 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    461 				& (~TS102_UCTRL_INT_TXNF_MSK
    462 				   |TS102_UCTRL_INT_TXNF_REQ));
    463 		} else if (sc->sc_state == TCTRL_IDLE) {
    464 			sc->sc_op = sc->sc_cmdbuf[0];
    465 			sc->sc_state = TCTRL_ARGS;
    466 #ifdef TCTRLDEBUG
    467 			printf(" [args]");
    468 #endif
    469 		}
    470 	}
    471 	goto again;
    472 }
    473 
    474 static void
    475 tctrl_setup_bitport_nop(void)
    476 {
    477 	struct tctrl_softc *sc;
    478 	struct tctrl_req req;
    479 	int s;
    480 
    481 	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
    482 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    483 	req.cmdbuf[1] = 0xff;
    484 	req.cmdbuf[2] = 0x00;
    485 	req.cmdlen = 3;
    486 	req.rsplen = 2;
    487 	tadpole_request(&req, 1, 0);
    488 	s = splts102();
    489 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    490 	splx(s);
    491 }
    492 
    493 static void
    494 tctrl_setup_bitport(void)
    495 {
    496 	struct tctrl_softc *sc;
    497 	struct tctrl_req req;
    498 	int s;
    499 
    500 	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
    501 	s = splts102();
    502 	req.cmdbuf[2] = 0;
    503 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    504 	    || (!sc->sc_tft_on)) {
    505 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
    506 	}
    507 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    508 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    509 	req.cmdlen = 3;
    510 	req.rsplen = 2;
    511 	tadpole_request(&req, 1, 0);
    512 	s = splts102();
    513 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    514 	splx(s);
    515 }
    516 
    517 /*
    518  * The tadpole microcontroller is not preprogrammed with icon
    519  * representations.  The machine boots with the DC-IN light as
    520  * a blank (all 0x00) and the other lights, as 4 rows of horizontal
    521  * bars.  The below code initializes the icons in the system to
    522  * sane values.  Some of these icons could be used for any purpose
    523  * desired, namely the pcmcia, LAN and WAN lights.  For the disk spinner,
    524  * only the backslash is unprogrammed.  (sigh)
    525  *
    526  * programming the icons is simple.  It is a 5x8 matrix, which each row a
    527  * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
    528  */
    529 
    530 static void
    531 tctrl_init_lcd(void)
    532 {
    533 	struct tctrl_req req;
    534 
    535 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    536 	req.cmdlen = 11;
    537 	req.rsplen = 1;
    538 	req.cmdbuf[1] = 0x08;	/*len*/
    539 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD;
    540 	req.cmdbuf[3] =  0x00;	/* ..... */
    541 	req.cmdbuf[4] =  0x00;	/* ..... */
    542 	req.cmdbuf[5] =  0x1f;	/* XXXXX */
    543 	req.cmdbuf[6] =  0x00;	/* ..... */
    544 	req.cmdbuf[7] =  0x15;	/* X.X.X */
    545 	req.cmdbuf[8] =  0x00;	/* ..... */
    546 	req.cmdbuf[9] =  0x00;	/* ..... */
    547 	req.cmdbuf[10] = 0x00;	/* ..... */
    548 	tadpole_request(&req, 1, 0);
    549 
    550 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    551 	req.cmdlen = 11;
    552 	req.rsplen = 1;
    553 	req.cmdbuf[1] = 0x08;	/*len*/
    554 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH;
    555 	req.cmdbuf[3] =  0x00;	/* ..... */
    556 	req.cmdbuf[4] =  0x10;	/* X.... */
    557 	req.cmdbuf[5] =  0x08;	/* .X... */
    558 	req.cmdbuf[6] =  0x04;	/* ..X.. */
    559 	req.cmdbuf[7] =  0x02;	/* ...X. */
    560 	req.cmdbuf[8] =  0x01;	/* ....X */
    561 	req.cmdbuf[9] =  0x00;	/* ..... */
    562 	req.cmdbuf[10] = 0x00;	/* ..... */
    563 	tadpole_request(&req, 1, 0);
    564 
    565 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    566 	req.cmdlen = 11;
    567 	req.rsplen = 1;
    568 	req.cmdbuf[1] = 0x08;	/*len*/
    569 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1;
    570 	req.cmdbuf[3] =  0x0c;	/* .XXX. */
    571 	req.cmdbuf[4] =  0x16;	/* X.XX. */
    572 	req.cmdbuf[5] =  0x10;	/* X.... */
    573 	req.cmdbuf[6] =  0x15;	/* X.X.X */
    574 	req.cmdbuf[7] =  0x10;	/* X.... */
    575 	req.cmdbuf[8] =  0x16;	/* X.XX. */
    576 	req.cmdbuf[9] =  0x0c;	/* .XXX. */
    577 	req.cmdbuf[10] = 0x00;	/* ..... */
    578 	tadpole_request(&req, 1, 0);
    579 
    580 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    581 	req.cmdlen = 11;
    582 	req.rsplen = 1;
    583 	req.cmdbuf[1] = 0x08;	/*len*/
    584 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2;
    585 	req.cmdbuf[3] =  0x0c;	/* .XXX. */
    586 	req.cmdbuf[4] =  0x0d;	/* .XX.X */
    587 	req.cmdbuf[5] =  0x01;	/* ....X */
    588 	req.cmdbuf[6] =  0x15;	/* X.X.X */
    589 	req.cmdbuf[7] =  0x01;	/* ....X */
    590 	req.cmdbuf[8] =  0x0d;	/* .XX.X */
    591 	req.cmdbuf[9] =  0x0c;	/* .XXX. */
    592 	req.cmdbuf[10] = 0x00;	/* ..... */
    593 	tadpole_request(&req, 1, 0);
    594 
    595 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    596 	req.cmdlen = 11;
    597 	req.rsplen = 1;
    598 	req.cmdbuf[1] = 0x08;	/*len*/
    599 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1;
    600 	req.cmdbuf[3] =  0x00;	/* ..... */
    601 	req.cmdbuf[4] =  0x04;	/* ..X.. */
    602 	req.cmdbuf[5] =  0x08;	/* .X... */
    603 	req.cmdbuf[6] =  0x13;	/* X..XX */
    604 	req.cmdbuf[7] =  0x08;	/* .X... */
    605 	req.cmdbuf[8] =  0x04;	/* ..X.. */
    606 	req.cmdbuf[9] =  0x00;	/* ..... */
    607 	req.cmdbuf[10] = 0x00;	/* ..... */
    608 	tadpole_request(&req, 1, 0);
    609 
    610 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    611 	req.cmdlen = 11;
    612 	req.rsplen = 1;
    613 	req.cmdbuf[1] = 0x08;	/*len*/
    614 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2;
    615 	req.cmdbuf[3] =  0x00;	/* ..... */
    616 	req.cmdbuf[4] =  0x04;	/* ..X.. */
    617 	req.cmdbuf[5] =  0x02;	/* ...X. */
    618 	req.cmdbuf[6] =  0x19;	/* XX..X */
    619 	req.cmdbuf[7] =  0x02;	/* ...X. */
    620 	req.cmdbuf[8] =  0x04;	/* ..X.. */
    621 	req.cmdbuf[9] =  0x00;	/* ..... */
    622 	req.cmdbuf[10] = 0x00;	/* ..... */
    623 	tadpole_request(&req, 1, 0);
    624 
    625 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    626 	req.cmdlen = 11;
    627 	req.rsplen = 1;
    628 	req.cmdbuf[1] = 0x08;	/*len*/
    629 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA;
    630 	req.cmdbuf[3] =  0x00;	/* ..... */
    631 	req.cmdbuf[4] =  0x0c;	/* .XXX. */
    632 	req.cmdbuf[5] =  0x1f;	/* XXXXX */
    633 	req.cmdbuf[6] =  0x1f;	/* XXXXX */
    634 	req.cmdbuf[7] =  0x1f;	/* XXXXX */
    635 	req.cmdbuf[8] =  0x1f;	/* XXXXX */
    636 	req.cmdbuf[9] =  0x00;	/* ..... */
    637 	req.cmdbuf[10] = 0x00;	/* ..... */
    638 	tadpole_request(&req, 1, 0);
    639 }
    640 
    641 /* sc_lcdwanted -> lcd_state */
    642 void
    643 tctrl_update_lcd(struct tctrl_softc *sc)
    644 {
    645 	struct tctrl_req req;
    646 	int s;
    647 
    648 	s = splhigh();
    649 	if (sc->sc_lcdwanted == sc->sc_lcdstate) {
    650 		splx(s);
    651 		return;
    652 	}
    653 	sc->sc_lcdstate = sc->sc_lcdwanted;
    654 	splx(s);
    655 
    656 	/*
    657 	 * the mask setup on this particular command is *very* bizzare
    658 	 * and totally undocumented.
    659 	 */
    660 	req.cmdbuf[0] = TS102_OP_CTL_LCD;
    661 
    662 	/* leave caps-lock alone */
    663 	req.cmdbuf[2] = (u_int8_t)(sc->sc_lcdstate & 0xfe);
    664 	req.cmdbuf[3] = (u_int8_t)((sc->sc_lcdstate & 0x100)>>8);
    665 
    666 	req.cmdbuf[1] = 1;
    667 	req.cmdbuf[4] = 0;
    668 
    669 
    670 	/* XXX this thing is weird.... */
    671 	req.cmdlen = 3;
    672 	req.rsplen = 2;
    673 
    674 	/* below are the values one would expect but which won't work */
    675 #if 0
    676 	req.cmdlen = 5;
    677 	req.rsplen = 4;
    678 #endif
    679 	tadpole_request(&req, 1, 0);
    680 }
    681 
    682 
    683 /*
    684  * set the blinken-lights on the lcd.  what:
    685  * what = 0 off,  what = 1 on,  what = 2 toggle
    686  */
    687 
    688 void
    689 tadpole_set_lcd(int what, unsigned short which)
    690 {
    691 	struct tctrl_softc *sc;
    692 	int s;
    693 
    694 	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
    695 
    696 	s = splhigh();
    697 	switch (what) {
    698 		case 0:
    699 			sc->sc_lcdwanted &= ~which;
    700 			break;
    701 		case 1:
    702 			sc->sc_lcdwanted |= which;
    703 			break;
    704 		case 2:
    705 			sc->sc_lcdwanted ^= which;
    706 			break;
    707 	}
    708 	splx(s);
    709 }
    710 
    711 static void
    712 tctrl_read_ext_status(void)
    713 {
    714 	struct tctrl_softc *sc;
    715 	struct tctrl_req req;
    716 	int s;
    717 
    718 	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
    719 	req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
    720 	req.cmdlen = 1;
    721 	req.rsplen = 3;
    722 #ifdef TCTRLDEBUG
    723 	printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
    724 #endif
    725 	tadpole_request(&req, 1, 0);
    726 	s = splts102();
    727 	sc->sc_ext_status = (req.rspbuf[0] << 8) + req.rspbuf[1];
    728 	splx(s);
    729 #ifdef TCTRLDEBUG
    730 	printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
    731 #endif
    732 }
    733 
    734 /*
    735  * return 0 if the user will notice and handle the event,
    736  * return 1 if the kernel driver should do so.
    737  */
    738 static int
    739 tctrl_apm_record_event(struct tctrl_softc *sc, u_int event_type)
    740 {
    741 	struct apm_event_info *evp;
    742 
    743 	if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
    744 	    (sc->sc_event_count < APM_NEVENTS)) {
    745 		evp = &sc->sc_event_list[sc->sc_event_ptr];
    746 		sc->sc_event_count++;
    747 		sc->sc_event_ptr++;
    748 		sc->sc_event_ptr %= APM_NEVENTS;
    749 		evp->type = event_type;
    750 		evp->index = ++tctrl_apm_evindex;
    751 		selnotify(&sc->sc_rsel, 0, 0);
    752 		return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
    753 	}
    754 	return(1);
    755 }
    756 
    757 static void
    758 tctrl_read_event_status(struct tctrl_softc *sc)
    759 {
    760 	struct tctrl_req req;
    761 	int s;
    762 	uint32_t v;
    763 
    764 	req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
    765 	req.cmdlen = 1;
    766 	req.rsplen = 3;
    767 	tadpole_request(&req, 1, 0);
    768 	s = splts102();
    769 	v = req.rspbuf[0] * 256 + req.rspbuf[1];
    770 #ifdef TCTRLDEBUG
    771 	printf("event: %x\n",v);
    772 #endif
    773 	if (v & TS102_EVENT_STATUS_POWERON_BTN_PRESSED) {
    774 		printf("%s: Power button pressed\n",device_xname(sc->sc_dev));
    775 		tctrl_powerfail(sc);
    776 	}
    777 	if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
    778 		printf("%s: SHUTDOWN REQUEST!\n", device_xname(sc->sc_dev));
    779 		tctrl_powerfail(sc);
    780 	}
    781 	if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
    782 /*printf("%s: VERY LOW POWER WARNING!\n", device_xname(sc->sc_dev));*/
    783 /* according to a tadpole header, and observation */
    784 #ifdef TCTRLDEBUG
    785 		printf("%s: Battery charge level change\n",
    786 		    device_xname(sc->sc_dev));
    787 #endif
    788 	}
    789 	if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
    790 		if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
    791 			printf("%s: LOW POWER WARNING!\n", device_xname(sc->sc_dev));
    792 	}
    793 	if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
    794 		splx(s);
    795 		tctrl_read_ext_status();
    796 		tctrl_ac_state(sc);
    797 		s = splts102();
    798 		if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
    799 			printf("%s: main power %s\n", device_xname(sc->sc_dev),
    800 			    (sc->sc_ext_status &
    801 			    TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
    802 			    "restored" : "removed");
    803 	}
    804 	if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
    805 		splx(s);
    806 		tctrl_read_ext_status();
    807 		tctrl_lid_state(sc);
    808 		tctrl_setup_bitport();
    809 #ifdef TCTRLDEBUG
    810 		printf("%s: lid %s\n", device_xname(sc->sc_dev),
    811 		    (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    812 		    ? "closed" : "opened");
    813 #endif
    814 	}
    815 	if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) {
    816 		int vga;
    817 		splx(s);
    818 		tctrl_read_ext_status();
    819 		vga = (sc->sc_ext_status &
    820 		    TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0;
    821 		if (vga != sc->sc_extvga) {
    822 			sc->sc_extvga = vga;
    823 			if (sc->sc_video_callback != NULL) {
    824 				sc->sc_video_callback(
    825 				    sc->sc_video_callback_cookie,
    826 				    sc->sc_extvga);
    827 			}
    828 		}
    829 	}
    830 #ifdef DIAGNOSTIC
    831 	if (v & TS102_EVENT_STATUS_EXT_MOUSE_STATUS_CHANGE) {
    832 		splx(s);
    833 		tctrl_read_ext_status();
    834 		if (sc->sc_ext_status &
    835 		    TS102_EXT_STATUS_EXTERNAL_MOUSE_ATTACHED) {
    836 			printf("tctrl: external mouse detected\n");
    837 		}
    838 	}
    839 #endif
    840 	sc->sc_ext_pending = 0;
    841 	splx(s);
    842 }
    843 
    844 static void
    845 tctrl_lock(struct tctrl_softc *sc)
    846 {
    847 
    848 	mutex_enter(&sc->sc_requestlock);
    849 }
    850 
    851 static void
    852 tctrl_unlock(struct tctrl_softc *sc)
    853 {
    854 
    855 	mutex_exit(&sc->sc_requestlock);
    856 }
    857 
    858 int
    859 tadpole_request(struct tctrl_req *req, int spin, int sleep)
    860 {
    861 	struct tctrl_softc *sc;
    862 	int i, s;
    863 
    864 	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
    865 	if (!sc)
    866 		return ENODEV;
    867 
    868 	tctrl_lock(sc);
    869 
    870 	if (spin)
    871 		s = splhigh();
    872 	else
    873 		s = splts102();
    874 	sc->sc_flags |= TCTRL_SEND_REQUEST;
    875 	memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
    876 #ifdef DIAGNOSTIC
    877 	if (sc->sc_wantdata != 0) {
    878 		splx(s);
    879 		printf("tctrl: we lost the race\n");
    880 		tctrl_unlock(sc);
    881 		return EAGAIN;
    882 	}
    883 #endif
    884 	sc->sc_wantdata = 1;
    885 	sc->sc_rsplen = req->rsplen;
    886 	sc->sc_cmdlen = req->cmdlen;
    887 	sc->sc_cmdoff = sc->sc_rspoff = 0;
    888 
    889 	/* we spin for certain commands, like poweroffs */
    890 	if (spin) {
    891 /*		for (i = 0; i < 30000; i++) {*/
    892 		i = 0;
    893 		while ((sc->sc_wantdata == 1) && (i < 30000)) {
    894 			tctrl_intr(sc);
    895 			DELAY(1);
    896 			i++;
    897 		}
    898 #ifdef DIAGNOSTIC
    899 		if (i >= 30000) {
    900 			printf("tctrl: timeout busy waiting for micro controller request!\n");
    901 			sc->sc_wantdata = 0;
    902 			splx(s);
    903 			tctrl_unlock(sc);
    904 			return EAGAIN;
    905 		}
    906 #endif
    907 	} else {
    908 		int timeout = 5 * (sc->sc_rsplen + sc->sc_cmdlen);
    909 		tctrl_intr(sc);
    910 		i = 0;
    911 		while (((sc->sc_rspoff != sc->sc_rsplen) ||
    912 		    (sc->sc_cmdoff != sc->sc_cmdlen)) &&
    913 		    (i < timeout))
    914 			if (sleep) {
    915 				tsleep(sc, PWAIT, "tctrl_data", 15);
    916 				i++;
    917 			} else
    918 				DELAY(1);
    919 #ifdef DIAGNOSTIC
    920 		if (i >= timeout) {
    921 			printf("tctrl: timeout waiting for microcontroller request\n");
    922 			sc->sc_wantdata = 0;
    923 			splx(s);
    924 			tctrl_unlock(sc);
    925 			return EAGAIN;
    926 		}
    927 #endif
    928 	}
    929 	/*
    930 	 * we give the user a reasonable amount of time for a command
    931 	 * to complete.  If it doesn't complete in time, we hand them
    932 	 * garbage.  This is here to stop things like setting the
    933 	 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
    934 	 */
    935 	sc->sc_wantdata = 0;
    936 	memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
    937 	splx(s);
    938 
    939 	tctrl_unlock(sc);
    940 	return 0;
    941 }
    942 
    943 void
    944 tadpole_powerdown(void)
    945 {
    946 	struct tctrl_req req;
    947 
    948 	req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
    949 	req.cmdlen = 1;
    950 	req.rsplen = 1;
    951 	tadpole_request(&req, 1, 0);
    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 = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
    962 	while (sc->sc_wantdata != 0)
    963 		DELAY(1);
    964 	s = splts102();
    965 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
    966 	    || (sc->sc_tft_on)) {
    967 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
    968 	} else {
    969 		req.cmdbuf[2] = 0;
    970 	}
    971 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    972 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    973 	req.cmdlen = 3;
    974 	req.rsplen = 2;
    975 
    976 	if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
    977 		sc->sc_tft_on = enabled;
    978 		if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
    979 			splx(s);
    980 			return;
    981 		}
    982 		tadpole_request(&req, 1, 0);
    983 		sc->sc_bitport =
    984 		    (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    985 	}
    986 	splx(s);
    987 }
    988 
    989 static void
    990 tctrl_write_data(struct tctrl_softc *sc, uint8_t v)
    991 {
    992 	unsigned int i;
    993 
    994 	for (i = 0; i < 100; i++)  {
    995 		if (TS102_UCTRL_STS_TXNF_STA &
    996 		    tctrl_read(sc, TS102_REG_UCTRL_STS))
    997 			break;
    998 	}
    999 	tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
   1000 }
   1001 
   1002 static uint8_t
   1003 tctrl_read_data(struct tctrl_softc *sc)
   1004 {
   1005 	unsigned int i, v;
   1006 
   1007 	for (i = 0; i < 100000; i++) {
   1008 		if (TS102_UCTRL_STS_RXNE_STA &
   1009 		    tctrl_read(sc, TS102_REG_UCTRL_STS))
   1010 			break;
   1011 		DELAY(1);
   1012 	}
   1013 
   1014 	v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
   1015 	tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
   1016 	return v;
   1017 }
   1018 
   1019 static uint8_t
   1020 tctrl_read(struct tctrl_softc *sc, bus_size_t off)
   1021 {
   1022 
   1023 	sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
   1024 	return sc->sc_junk;
   1025 }
   1026 
   1027 static void
   1028 tctrl_write(struct tctrl_softc *sc, bus_size_t off, uint8_t v)
   1029 {
   1030 
   1031 	sc->sc_junk = v;
   1032 	bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
   1033 }
   1034 
   1035 int
   1036 tctrlopen(dev_t dev, int flags, int mode, struct lwp *l)
   1037 {
   1038 	int unit = (minor(dev)&0xf0);
   1039 	int ctl = (minor(dev)&0x0f);
   1040 	struct tctrl_softc *sc;
   1041 
   1042 	if (unit >= tctrl_cd.cd_ndevs)
   1043 		return(ENXIO);
   1044 	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
   1045 	if (!sc)
   1046 		return(ENXIO);
   1047 
   1048 	switch (ctl) {
   1049 	case TCTRL_STD_DEV:
   1050 		break;
   1051 	case TCTRL_APMCTL_DEV:
   1052 		if (!(flags & FWRITE))
   1053 			return(EINVAL);
   1054 		if (sc->sc_flags & TCTRL_APM_CTLOPEN)
   1055 			return(EBUSY);
   1056 		sc->sc_flags |= TCTRL_APM_CTLOPEN;
   1057 		break;
   1058 	default:
   1059 		return(ENXIO);
   1060 		break;
   1061 	}
   1062 
   1063 	return(0);
   1064 }
   1065 
   1066 int
   1067 tctrlclose(dev_t dev, int flags, int mode, struct lwp *l)
   1068 {
   1069 	int ctl = (minor(dev)&0x0f);
   1070 	struct tctrl_softc *sc;
   1071 
   1072 	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
   1073 	if (!sc)
   1074 		return(ENXIO);
   1075 
   1076 	switch (ctl) {
   1077 	case TCTRL_STD_DEV:
   1078 		break;
   1079 	case TCTRL_APMCTL_DEV:
   1080 		sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
   1081 		break;
   1082 	}
   1083 	return(0);
   1084 }
   1085 
   1086 int
   1087 tctrlioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
   1088 {
   1089 	struct tctrl_req req, *reqn;
   1090 	struct tctrl_pwr *pwrreq;
   1091 	struct apm_power_info *powerp;
   1092 	struct apm_event_info *evp;
   1093 	struct tctrl_softc *sc;
   1094 	int i;
   1095 	uint8_t c;
   1096 
   1097 	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
   1098 	if (!sc)
   1099 		return ENXIO;
   1100 
   1101         switch (cmd) {
   1102 
   1103 	case APM_IOC_STANDBY:
   1104 		/* turn off backlight and so on ? */
   1105 
   1106 		return 0; /* for now */
   1107 
   1108 	case APM_IOC_SUSPEND:
   1109 		/* not sure what to do here - we can't really suspend */
   1110 
   1111 		return 0; /* for now */
   1112 
   1113 	case OAPM_IOC_GETPOWER:
   1114 	case APM_IOC_GETPOWER:
   1115 		powerp = (struct apm_power_info *)data;
   1116 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
   1117 		req.cmdlen = 1;
   1118 		req.rsplen = 2;
   1119 		tadpole_request(&req, 0, l->l_proc ? 1 : 0);
   1120 		if (req.rspbuf[0] > 0x00)
   1121 			powerp->battery_state = APM_BATT_CHARGING;
   1122 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
   1123 		req.cmdlen = 1;
   1124 		req.rsplen = 3;
   1125 		tadpole_request(&req, 0, l->l_proc ? 1 : 0);
   1126 		c = req.rspbuf[0];
   1127 		powerp->battery_life = c;
   1128 		if (c > 0x70)	/* the tadpole sometimes dips below zero, and */
   1129 			c = 0;	/* into the 255 range. */
   1130 		powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
   1131 		if (powerp->battery_state != APM_BATT_CHARGING) {
   1132 			if (c < 0x20)
   1133 				powerp->battery_state = APM_BATT_CRITICAL;
   1134 			else if (c < 0x40)
   1135 				powerp->battery_state = APM_BATT_LOW;
   1136 			else if (c < 0x66)
   1137 				powerp->battery_state = APM_BATT_HIGH;
   1138 			else
   1139 				powerp->battery_state = APM_BATT_UNKNOWN;
   1140 		}
   1141 
   1142 		if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
   1143 			powerp->ac_state = APM_AC_ON;
   1144 		else
   1145 			powerp->ac_state = APM_AC_OFF;
   1146 		break;
   1147 
   1148 	case APM_IOC_NEXTEVENT:
   1149 		if (!sc->sc_event_count)
   1150 			return EAGAIN;
   1151 
   1152 		evp = (struct apm_event_info *)data;
   1153 		i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
   1154 		i %= APM_NEVENTS;
   1155 		*evp = sc->sc_event_list[i];
   1156 		sc->sc_event_count--;
   1157 		return(0);
   1158 
   1159 	/* this ioctl assumes the caller knows exactly what he is doing */
   1160 	case TCTRL_CMD_REQ:
   1161 		reqn = (struct tctrl_req *)data;
   1162 		if ((i = kauth_authorize_device_passthru(l->l_cred,
   1163 		    dev, KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data)) != 0 &&
   1164 		    (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
   1165 		    (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
   1166 		    reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
   1167 		    reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
   1168 		    reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
   1169 		    reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
   1170 		    (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
   1171 		    reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
   1172 		    reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
   1173 			return(i);
   1174 		tadpole_request(reqn, 0, l->l_proc ? 1 : 0);
   1175 		break;
   1176 	/* serial power mode (via auxiotwo) */
   1177 	case TCTRL_SERIAL_PWR:
   1178 		pwrreq = (struct tctrl_pwr *)data;
   1179 		if (pwrreq->rw)
   1180 			pwrreq->state = auxiotwoserialgetapm();
   1181 		else
   1182 			auxiotwoserialsetapm(pwrreq->state);
   1183 		break;
   1184 
   1185 	/* modem power mode (via auxio) */
   1186 	case TCTRL_MODEM_PWR:
   1187 		return(EOPNOTSUPP); /* for now */
   1188 		break;
   1189 
   1190 
   1191         default:
   1192                 return (ENOTTY);
   1193         }
   1194         return (0);
   1195 }
   1196 
   1197 int
   1198 tctrlpoll(dev_t dev, int events, struct lwp *l)
   1199 {
   1200 	struct tctrl_softc *sc = device_lookup_private(&tctrl_cd,
   1201 						       TCTRL_STD_DEV);
   1202 	int revents = 0;
   1203 
   1204 	if (events & (POLLIN | POLLRDNORM)) {
   1205 		if (sc->sc_event_count)
   1206 			revents |= events & (POLLIN | POLLRDNORM);
   1207 		else
   1208 			selrecord(l, &sc->sc_rsel);
   1209 	}
   1210 
   1211 	return (revents);
   1212 }
   1213 
   1214 static void
   1215 filt_tctrlrdetach(struct knote *kn)
   1216 {
   1217 	struct tctrl_softc *sc = kn->kn_hook;
   1218 	int s;
   1219 
   1220 	s = splts102();
   1221 	SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
   1222 	splx(s);
   1223 }
   1224 
   1225 static int
   1226 filt_tctrlread(struct knote *kn, long hint)
   1227 {
   1228 	struct tctrl_softc *sc = kn->kn_hook;
   1229 
   1230 	kn->kn_data = sc->sc_event_count;
   1231 	return (kn->kn_data > 0);
   1232 }
   1233 
   1234 static const struct filterops tctrlread_filtops = {
   1235 	.f_isfd = 1,
   1236 	.f_attach = NULL,
   1237 	.f_detach = filt_tctrlrdetach,
   1238 	.f_event = filt_tctrlread,
   1239 };
   1240 
   1241 int
   1242 tctrlkqfilter(dev_t dev, struct knote *kn)
   1243 {
   1244 	struct tctrl_softc *sc = device_lookup_private(&tctrl_cd,
   1245 						       TCTRL_STD_DEV);
   1246 	struct klist *klist;
   1247 	int s;
   1248 
   1249 	switch (kn->kn_filter) {
   1250 	case EVFILT_READ:
   1251 		klist = &sc->sc_rsel.sel_klist;
   1252 		kn->kn_fop = &tctrlread_filtops;
   1253 		break;
   1254 
   1255 	default:
   1256 		return (1);
   1257 	}
   1258 
   1259 	kn->kn_hook = sc;
   1260 
   1261 	s = splts102();
   1262 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
   1263 	splx(s);
   1264 
   1265 	return (0);
   1266 }
   1267 
   1268 static void
   1269 tctrl_sensor_setup(struct tctrl_softc *sc)
   1270 {
   1271 	int i, error;
   1272 
   1273 	sc->sc_sme = sysmon_envsys_create();
   1274 
   1275 	/* case temperature */
   1276 	(void)strlcpy(sc->sc_sensor[0].desc, "Case temperature",
   1277 	    sizeof(sc->sc_sensor[0].desc));
   1278 	sc->sc_sensor[0].units = ENVSYS_STEMP;
   1279 	sc->sc_sensor[0].state = ENVSYS_SINVALID;
   1280 
   1281 	/* battery voltage */
   1282 	(void)strlcpy(sc->sc_sensor[1].desc, "Internal battery voltage",
   1283 	    sizeof(sc->sc_sensor[1].desc));
   1284 	sc->sc_sensor[1].units = ENVSYS_SVOLTS_DC;
   1285 	sc->sc_sensor[1].state = ENVSYS_SINVALID;
   1286 
   1287 	/* DC voltage */
   1288 	(void)strlcpy(sc->sc_sensor[2].desc, "DC-In voltage",
   1289 	    sizeof(sc->sc_sensor[2].desc));
   1290 	sc->sc_sensor[2].units = ENVSYS_SVOLTS_DC;
   1291 	sc->sc_sensor[2].state = ENVSYS_SINVALID;
   1292 
   1293 	for (i = 0; i < ENVSYS_NUMSENSORS; i++) {
   1294 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
   1295 						&sc->sc_sensor[i])) {
   1296 			sysmon_envsys_destroy(sc->sc_sme);
   1297 			return;
   1298 		}
   1299 	}
   1300 
   1301 	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
   1302 	sc->sc_sme->sme_cookie = sc;
   1303 	sc->sc_sme->sme_refresh = tctrl_refresh;
   1304 
   1305 	if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) {
   1306 		printf("%s: couldn't register sensors (%d)\n",
   1307 		    device_xname(sc->sc_dev), error);
   1308 		sysmon_envsys_destroy(sc->sc_sme);
   1309 		return;
   1310 	}
   1311 
   1312 	/* now register the power button */
   1313 
   1314 	sysmon_task_queue_init();
   1315 
   1316 	sc->sc_powerpressed = 0;
   1317 	memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
   1318 	sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev);
   1319 	sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
   1320 	if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
   1321 		printf("%s: unable to register power button with sysmon\n",
   1322 		    device_xname(sc->sc_dev));
   1323 
   1324 	memset(&sc->sc_sm_lid, 0, sizeof(struct sysmon_pswitch));
   1325 	sc->sc_sm_lid.smpsw_name = device_xname(sc->sc_dev);
   1326 	sc->sc_sm_lid.smpsw_type = PSWITCH_TYPE_LID;
   1327 	if (sysmon_pswitch_register(&sc->sc_sm_lid) != 0)
   1328 		printf("%s: unable to register lid switch with sysmon\n",
   1329 		    device_xname(sc->sc_dev));
   1330 
   1331 	memset(&sc->sc_sm_ac, 0, sizeof(struct sysmon_pswitch));
   1332 	sc->sc_sm_ac.smpsw_name = device_xname(sc->sc_dev);
   1333 	sc->sc_sm_ac.smpsw_type = PSWITCH_TYPE_ACADAPTER;
   1334 	if (sysmon_pswitch_register(&sc->sc_sm_ac) != 0)
   1335 		printf("%s: unable to register AC adaptor with sysmon\n",
   1336 		    device_xname(sc->sc_dev));
   1337 }
   1338 
   1339 static void
   1340 tctrl_power_button_pressed(void *arg)
   1341 {
   1342 	struct tctrl_softc *sc = arg;
   1343 
   1344 	sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
   1345 	sc->sc_powerpressed = 0;
   1346 }
   1347 
   1348 static void
   1349 tctrl_lid_state(struct tctrl_softc *sc)
   1350 {
   1351 	int state;
   1352 
   1353 	state = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ?
   1354 	    PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED;
   1355 	sysmon_pswitch_event(&sc->sc_sm_lid, state);
   1356 }
   1357 
   1358 static void
   1359 tctrl_ac_state(struct tctrl_softc *sc)
   1360 {
   1361 	int state;
   1362 
   1363 	state = (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
   1364 	    PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED;
   1365 	sysmon_pswitch_event(&sc->sc_sm_ac, state);
   1366 }
   1367 
   1368 static int
   1369 tctrl_powerfail(void *arg)
   1370 {
   1371 	struct tctrl_softc *sc = (struct tctrl_softc *)arg;
   1372 
   1373 	/*
   1374 	 * We lost power. Queue a callback with thread context to
   1375 	 * handle all the real work.
   1376 	 */
   1377 	if (sc->sc_powerpressed == 0) {
   1378 		sc->sc_powerpressed = 1;
   1379 		sysmon_task_queue_sched(0, tctrl_power_button_pressed, sc);
   1380 	}
   1381 	return (1);
   1382 }
   1383 
   1384 static void
   1385 tctrl_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
   1386 {
   1387 	/*struct tctrl_softc *sc = sme->sme_cookie;*/
   1388 	struct tctrl_req req;
   1389 	int sleepable;
   1390 	int i;
   1391 
   1392 	i = edata->sensor;
   1393 	sleepable = curlwp ? 1 : 0;
   1394 
   1395 	switch (i)
   1396 	{
   1397 		case 0:	/* case temperature */
   1398 			req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
   1399 			req.cmdlen = 1;
   1400 			req.rsplen = 2;
   1401 			tadpole_request(&req, 0, sleepable);
   1402 			edata->value_cur =             /* 273160? */
   1403 			    (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
   1404 			    / 9 + 273150000);
   1405 			req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
   1406 			req.cmdlen = 1;
   1407 			req.rsplen = 2;
   1408 			tadpole_request(&req, 0, sleepable);
   1409 			edata->value_max =
   1410 			    (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
   1411 			    / 9 + 273150000);
   1412 			edata->flags |= ENVSYS_FVALID_MAX;
   1413 			req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
   1414 			req.cmdlen = 1;
   1415 			req.rsplen = 2;
   1416 			tadpole_request(&req, 0, sleepable);
   1417 			edata->value_min =
   1418 			    (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
   1419 			    / 9 + 273150000);
   1420 			edata->flags |= ENVSYS_FVALID_MIN;
   1421 			edata->units = ENVSYS_STEMP;
   1422 			break;
   1423 
   1424 		case 1: /* battery voltage */
   1425 			{
   1426 				edata->units = ENVSYS_SVOLTS_DC;
   1427 				req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
   1428 				req.cmdlen = 1;
   1429 				req.rsplen = 2;
   1430 				tadpole_request(&req, 0, sleepable);
   1431 				edata->value_cur = (int32_t)req.rspbuf[0] *
   1432 				    1000000 / 11;
   1433 			}
   1434 			break;
   1435 		case 2: /* DC voltage */
   1436 			{
   1437 				edata->units = ENVSYS_SVOLTS_DC;
   1438 				req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
   1439 				req.cmdlen = 1;
   1440 				req.rsplen = 2;
   1441 				tadpole_request(&req, 0, sleepable);
   1442 				edata->value_cur = (int32_t)req.rspbuf[0] *
   1443 				    1000000 / 11;
   1444 			}
   1445 			break;
   1446 	}
   1447 	edata->state = ENVSYS_SVALID;
   1448 }
   1449 
   1450 static void
   1451 tctrl_event_thread(void *v)
   1452 {
   1453 	struct tctrl_softc *sc = v;
   1454 	device_t dv;
   1455 	struct sd_softc *sd;
   1456 
   1457 	for (sd = NULL; sd == NULL;) {
   1458 		dv = device_find_by_xname("sd0");
   1459 		if (dv != NULL)
   1460 			sd = device_private(dv);
   1461 		else
   1462 			tsleep(&sc->sc_events, PWAIT, "probe_disk", hz);
   1463 	}
   1464 
   1465 	dv = device_find_by_xname("le0");
   1466 
   1467 	struct lance_softc *le = dv != NULL ? device_private(dv) : NULL;
   1468 	struct dk_softc *dk = &sd->sc_dksc;
   1469 	printf("found %s\n", device_xname(dk->sc_dev));
   1470 
   1471 	struct io_stats *io = dk->sc_dkdev.dk_stats;
   1472 	int rcount = io->io_rxfer;
   1473 	int wcount = io->io_wxfer;
   1474 
   1475 	tctrl_read_event_status(sc);
   1476 
   1477 	int ticks = hz / 2;
   1478 	for (;;) {
   1479 		tsleep(&sc->sc_events, PWAIT, "tctrl_event", ticks);
   1480 		int s = splhigh();
   1481 		if ((rcount != io->io_rxfer) || (wcount != io->io_wxfer)) {
   1482 			rcount = io->io_rxfer;
   1483 			wcount = io->io_wxfer;
   1484 			sc->sc_lcdwanted |= TS102_LCD_DISK_ACTIVE;
   1485 		} else
   1486 			sc->sc_lcdwanted &= ~TS102_LCD_DISK_ACTIVE;
   1487 
   1488 		if (le != NULL) {
   1489 			if (le->sc_havecarrier != 0)
   1490 				sc->sc_lcdwanted |= TS102_LCD_LAN_ACTIVE;
   1491 			else
   1492 				sc->sc_lcdwanted &= ~TS102_LCD_LAN_ACTIVE;
   1493 		}
   1494 		splx(s);
   1495 		tctrl_update_lcd(sc);
   1496 		if (sc->sc_ext_pending)
   1497 			tctrl_read_event_status(sc);
   1498 	}
   1499 }
   1500 
   1501 void
   1502 tadpole_register_callback(void (*callback)(void *, int), void *cookie)
   1503 {
   1504 	struct tctrl_softc *sc;
   1505 
   1506 	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
   1507 	sc->sc_video_callback = callback;
   1508 	sc->sc_video_callback_cookie = cookie;
   1509 	if (sc->sc_video_callback != NULL) {
   1510 		sc->sc_video_callback(sc->sc_video_callback_cookie,
   1511 		    sc->sc_extvga);
   1512 	}
   1513 }
   1514