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