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