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