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