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