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