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