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