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