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