Home | History | Annotate | Line # | Download | only in dev
tctrl.c revision 1.13.6.4
      1  1.13.6.4  nathanw /*	$NetBSD: tctrl.c,v 1.13.6.4 2002/10/18 02:39:55 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.4  nathanw CFATTACH_DECL(tctrl, sizeof(struct tctrl_softc),
    152  1.13.6.4  nathanw     tctrl_match, tctrl_attach, NULL, NULL);
    153  1.13.6.2  nathanw 
    154  1.13.6.2  nathanw extern struct cfdriver tctrl_cd;
    155  1.13.6.2  nathanw /* XXX wtf is this? see i386/apm.c */
    156  1.13.6.2  nathanw int tctrl_apm_evindex;
    157  1.13.6.2  nathanw 
    158  1.13.6.2  nathanw static int
    159  1.13.6.2  nathanw tctrl_match(parent, cf, aux)
    160  1.13.6.2  nathanw 	struct device *parent;
    161  1.13.6.2  nathanw 	struct cfdata *cf;
    162  1.13.6.2  nathanw 	void *aux;
    163  1.13.6.2  nathanw {
    164  1.13.6.2  nathanw 	union obio_attach_args *uoba = aux;
    165  1.13.6.2  nathanw 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
    166  1.13.6.2  nathanw 
    167  1.13.6.2  nathanw 	if (uoba->uoba_isobio4 != 0) {
    168  1.13.6.2  nathanw 		return (0);
    169  1.13.6.2  nathanw 	}
    170  1.13.6.2  nathanw 
    171  1.13.6.2  nathanw 	/* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
    172  1.13.6.2  nathanw 	 * (who's interface is off the TS102 PCMCIA controller but there
    173  1.13.6.2  nathanw 	 * exists a OpenProm for microcontroller interface).
    174  1.13.6.2  nathanw 	 */
    175  1.13.6.2  nathanw 	return strcmp("uctrl", sa->sa_name) == 0;
    176  1.13.6.2  nathanw }
    177  1.13.6.2  nathanw 
    178  1.13.6.2  nathanw static void
    179  1.13.6.2  nathanw tctrl_attach(parent, self, aux)
    180  1.13.6.2  nathanw 	struct device *parent;
    181  1.13.6.2  nathanw 	struct device *self;
    182  1.13.6.2  nathanw 	void *aux;
    183  1.13.6.2  nathanw {
    184  1.13.6.2  nathanw 	struct tctrl_softc *sc = (void *)self;
    185  1.13.6.2  nathanw 	union obio_attach_args *uoba = aux;
    186  1.13.6.2  nathanw 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
    187  1.13.6.2  nathanw 	unsigned int i, v;
    188  1.13.6.2  nathanw #if 0
    189  1.13.6.2  nathanw 	unsigned int ack, msb, lsb;
    190  1.13.6.2  nathanw #endif
    191  1.13.6.2  nathanw 
    192  1.13.6.2  nathanw 	/* We're living on a sbus slot that looks like an obio that
    193  1.13.6.2  nathanw 	 * looks like an sbus slot.
    194  1.13.6.2  nathanw 	 */
    195  1.13.6.2  nathanw 	sc->sc_memt = sa->sa_bustag;
    196  1.13.6.2  nathanw 	if (sbus_bus_map(sc->sc_memt,
    197  1.13.6.2  nathanw 			 sa->sa_slot,
    198  1.13.6.2  nathanw 			 sa->sa_offset - TS102_REG_UCTRL_INT,
    199  1.13.6.2  nathanw 			 sa->sa_size,
    200  1.13.6.2  nathanw 			 BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) {
    201  1.13.6.2  nathanw 		printf(": can't map registers\n");
    202  1.13.6.2  nathanw 		return;
    203  1.13.6.2  nathanw 	}
    204  1.13.6.2  nathanw 
    205  1.13.6.2  nathanw 	printf("\n");
    206  1.13.6.2  nathanw 
    207  1.13.6.2  nathanw 	sc->sc_tft_on = 1;
    208  1.13.6.2  nathanw 
    209  1.13.6.2  nathanw 	/* clear any pending data.
    210  1.13.6.2  nathanw 	 */
    211  1.13.6.2  nathanw 	for (i = 0; i < 10000; i++) {
    212  1.13.6.2  nathanw 		if ((TS102_UCTRL_STS_RXNE_STA &
    213  1.13.6.2  nathanw 		    tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
    214  1.13.6.2  nathanw 			break;
    215  1.13.6.2  nathanw 		}
    216  1.13.6.2  nathanw 		v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
    217  1.13.6.2  nathanw 		tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
    218  1.13.6.2  nathanw 	}
    219  1.13.6.2  nathanw 
    220  1.13.6.2  nathanw 	if (sa->sa_nintr != 0) {
    221  1.13.6.2  nathanw 		(void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE,
    222  1.13.6.2  nathanw 		    0, tctrl_intr, sc);
    223  1.13.6.2  nathanw 		evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
    224  1.13.6.2  nathanw 		    sc->sc_dev.dv_xname, "intr");
    225  1.13.6.2  nathanw 	}
    226  1.13.6.2  nathanw 
    227  1.13.6.2  nathanw 	/* See what the external status is
    228  1.13.6.2  nathanw 	 */
    229  1.13.6.2  nathanw 
    230  1.13.6.2  nathanw 	tctrl_read_ext_status();
    231  1.13.6.2  nathanw 	if (sc->sc_ext_status != 0) {
    232  1.13.6.2  nathanw 		const char *sep;
    233  1.13.6.2  nathanw 
    234  1.13.6.2  nathanw 		printf("%s: ", sc->sc_dev.dv_xname);
    235  1.13.6.2  nathanw 		v = sc->sc_ext_status;
    236  1.13.6.2  nathanw 		for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
    237  1.13.6.2  nathanw 			if (v & 1) {
    238  1.13.6.2  nathanw 				printf("%s%s", sep, tctrl_ext_statuses[i]);
    239  1.13.6.2  nathanw 				sep = ", ";
    240  1.13.6.2  nathanw 			}
    241  1.13.6.2  nathanw 		}
    242  1.13.6.2  nathanw 		printf("\n");
    243  1.13.6.2  nathanw 	}
    244  1.13.6.2  nathanw 
    245  1.13.6.2  nathanw 	/* Get a current of the control bitport;
    246  1.13.6.2  nathanw 	 */
    247  1.13.6.2  nathanw 	tctrl_setup_bitport_nop();
    248  1.13.6.2  nathanw 	tctrl_write(sc, TS102_REG_UCTRL_INT,
    249  1.13.6.2  nathanw 		    TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
    250  1.13.6.2  nathanw 
    251  1.13.6.2  nathanw 	sc->sc_wantdata = 0;
    252  1.13.6.2  nathanw 	sc->sc_event_count = 0;
    253  1.13.6.2  nathanw 
    254  1.13.6.2  nathanw 	/* prime the sensor data */
    255  1.13.6.2  nathanw 	sprintf(sc->sc_esensors[0].desc, "%s", "Internal Unit Temperature");
    256  1.13.6.2  nathanw 	sc->sc_esensors[0].units = ENVSYS_STEMP;
    257  1.13.6.2  nathanw 	sprintf(sc->sc_esensors[1].desc, "%s", "Internal Battery Voltage");
    258  1.13.6.2  nathanw 	sc->sc_esensors[1].units = ENVSYS_SVOLTS_DC;
    259  1.13.6.2  nathanw 	sprintf(sc->sc_esensors[2].desc, "%s", "DC-In Voltage");
    260  1.13.6.2  nathanw 	sc->sc_esensors[2].units = ENVSYS_SVOLTS_DC;
    261  1.13.6.2  nathanw 
    262  1.13.6.2  nathanw 	/* initialize the LCD */
    263  1.13.6.2  nathanw 	tctrl_init_lcd();
    264  1.13.6.2  nathanw 
    265  1.13.6.2  nathanw 	/* initialize sc_lcdstate */
    266  1.13.6.2  nathanw 	sc->sc_lcdstate = 0;
    267  1.13.6.2  nathanw 	tctrl_set_lcd(2, 0);
    268  1.13.6.2  nathanw }
    269  1.13.6.2  nathanw 
    270  1.13.6.2  nathanw static int
    271  1.13.6.2  nathanw tctrl_intr(arg)
    272  1.13.6.2  nathanw 	void *arg;
    273  1.13.6.2  nathanw {
    274  1.13.6.2  nathanw 	struct tctrl_softc *sc = arg;
    275  1.13.6.2  nathanw 	unsigned int v, d;
    276  1.13.6.2  nathanw 	int progress = 0;
    277  1.13.6.2  nathanw 
    278  1.13.6.2  nathanw     again:
    279  1.13.6.2  nathanw 	/* find out the cause(s) of the interrupt */
    280  1.13.6.2  nathanw 	v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK;
    281  1.13.6.2  nathanw 
    282  1.13.6.2  nathanw 	/* clear the cause(s) of the interrupt */
    283  1.13.6.2  nathanw 	tctrl_write(sc, TS102_REG_UCTRL_STS, v);
    284  1.13.6.2  nathanw 
    285  1.13.6.2  nathanw 	v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
    286  1.13.6.2  nathanw 	if (sc->sc_cmdoff >= sc->sc_cmdlen) {
    287  1.13.6.2  nathanw 		v &= ~TS102_UCTRL_STS_TXNF_STA;
    288  1.13.6.2  nathanw 		if (tctrl_read(sc, TS102_REG_UCTRL_INT) & TS102_UCTRL_INT_TXNF_REQ) {
    289  1.13.6.2  nathanw 			tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
    290  1.13.6.2  nathanw 			progress = 1;
    291  1.13.6.2  nathanw 		}
    292  1.13.6.2  nathanw 	}
    293  1.13.6.2  nathanw 	if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
    294  1.13.6.2  nathanw 	    sc->sc_state != TCTRL_IDLE)) {
    295  1.13.6.2  nathanw 		wakeup(sc);
    296  1.13.6.2  nathanw 		return progress;
    297  1.13.6.2  nathanw 	}
    298  1.13.6.2  nathanw 
    299  1.13.6.2  nathanw 	progress = 1;
    300  1.13.6.2  nathanw 	if (v & TS102_UCTRL_STS_RXNE_STA) {
    301  1.13.6.2  nathanw 		d = tctrl_read_data(sc);
    302  1.13.6.2  nathanw 		switch (sc->sc_state) {
    303  1.13.6.2  nathanw 		case TCTRL_IDLE:
    304  1.13.6.2  nathanw 			if (d == 0xfa) {
    305  1.13.6.2  nathanw 				/* external event */
    306  1.13.6.2  nathanw 				callout_reset(&tctrl_event_ch, 1,
    307  1.13.6.2  nathanw 				    tctrl_read_event_status, NULL);
    308  1.13.6.2  nathanw 			} else {
    309  1.13.6.2  nathanw 				printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
    310  1.13.6.2  nathanw 					sc->sc_dev.dv_xname, sc->sc_op, d);
    311  1.13.6.2  nathanw 			}
    312  1.13.6.2  nathanw 			goto again;
    313  1.13.6.2  nathanw 		case TCTRL_ACK:
    314  1.13.6.2  nathanw 			if (d != 0xfe) {
    315  1.13.6.2  nathanw 				printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
    316  1.13.6.2  nathanw 					sc->sc_dev.dv_xname, sc->sc_op, d);
    317  1.13.6.2  nathanw 			}
    318  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    319  1.13.6.2  nathanw 			printf(" ack=0x%02x", d);
    320  1.13.6.2  nathanw #endif
    321  1.13.6.2  nathanw 			sc->sc_rsplen--;
    322  1.13.6.2  nathanw 			sc->sc_rspoff = 0;
    323  1.13.6.2  nathanw 			sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
    324  1.13.6.2  nathanw 			sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
    325  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    326  1.13.6.2  nathanw 			if (sc->sc_rsplen > 0) {
    327  1.13.6.2  nathanw 				printf(" [data(%u)]", sc->sc_rsplen);
    328  1.13.6.2  nathanw 			} else {
    329  1.13.6.2  nathanw 				printf(" [idle]\n");
    330  1.13.6.2  nathanw 			}
    331  1.13.6.2  nathanw #endif
    332  1.13.6.2  nathanw 			goto again;
    333  1.13.6.2  nathanw 		case TCTRL_DATA:
    334  1.13.6.2  nathanw 			sc->sc_rspbuf[sc->sc_rspoff++] = d;
    335  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    336  1.13.6.2  nathanw 			printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
    337  1.13.6.2  nathanw #endif
    338  1.13.6.2  nathanw 			if (sc->sc_rspoff == sc->sc_rsplen) {
    339  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    340  1.13.6.2  nathanw 				printf(" [idle]\n");
    341  1.13.6.2  nathanw #endif
    342  1.13.6.2  nathanw 				sc->sc_state = TCTRL_IDLE;
    343  1.13.6.2  nathanw 				sc->sc_wantdata = 0;
    344  1.13.6.2  nathanw 			}
    345  1.13.6.2  nathanw 			goto again;
    346  1.13.6.2  nathanw 		default:
    347  1.13.6.2  nathanw 			printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
    348  1.13.6.2  nathanw 			       sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
    349  1.13.6.2  nathanw 			goto again;
    350  1.13.6.2  nathanw 		}
    351  1.13.6.2  nathanw 	}
    352  1.13.6.2  nathanw 	if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
    353  1.13.6.2  nathanw 	    sc->sc_flags & TCTRL_SEND_REQUEST) {
    354  1.13.6.2  nathanw 		if (sc->sc_flags & TCTRL_SEND_REQUEST) {
    355  1.13.6.2  nathanw 			sc->sc_flags &= ~TCTRL_SEND_REQUEST;
    356  1.13.6.2  nathanw 			sc->sc_wantdata = 1;
    357  1.13.6.2  nathanw 		}
    358  1.13.6.2  nathanw 		if (sc->sc_cmdlen > 0) {
    359  1.13.6.2  nathanw 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    360  1.13.6.2  nathanw 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    361  1.13.6.2  nathanw 				|TS102_UCTRL_INT_TXNF_MSK
    362  1.13.6.2  nathanw 				|TS102_UCTRL_INT_TXNF_REQ);
    363  1.13.6.2  nathanw 			v = tctrl_read(sc, TS102_REG_UCTRL_STS);
    364  1.13.6.2  nathanw 		}
    365  1.13.6.2  nathanw 	}
    366  1.13.6.2  nathanw 	if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
    367  1.13.6.2  nathanw 		tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
    368  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    369  1.13.6.2  nathanw 		if (sc->sc_cmdoff == 1) {
    370  1.13.6.2  nathanw 			printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
    371  1.13.6.2  nathanw 				sc->sc_cmdbuf[0], sc->sc_rsplen);
    372  1.13.6.2  nathanw 		} else {
    373  1.13.6.2  nathanw 			printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
    374  1.13.6.2  nathanw 				sc->sc_cmdbuf[sc->sc_cmdoff-1]);
    375  1.13.6.2  nathanw 		}
    376  1.13.6.2  nathanw #endif
    377  1.13.6.2  nathanw 		if (sc->sc_cmdoff == sc->sc_cmdlen) {
    378  1.13.6.2  nathanw 			sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
    379  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    380  1.13.6.2  nathanw 			printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
    381  1.13.6.2  nathanw #endif
    382  1.13.6.2  nathanw 			if (sc->sc_cmdoff == 1) {
    383  1.13.6.2  nathanw 				sc->sc_op = sc->sc_cmdbuf[0];
    384  1.13.6.2  nathanw 			}
    385  1.13.6.2  nathanw 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    386  1.13.6.2  nathanw 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    387  1.13.6.2  nathanw 				& (~TS102_UCTRL_INT_TXNF_MSK
    388  1.13.6.2  nathanw 				   |TS102_UCTRL_INT_TXNF_REQ));
    389  1.13.6.2  nathanw 		} else if (sc->sc_state == TCTRL_IDLE) {
    390  1.13.6.2  nathanw 			sc->sc_op = sc->sc_cmdbuf[0];
    391  1.13.6.2  nathanw 			sc->sc_state = TCTRL_ARGS;
    392  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    393  1.13.6.2  nathanw 			printf(" [args]");
    394  1.13.6.2  nathanw #endif
    395  1.13.6.2  nathanw 		}
    396  1.13.6.2  nathanw 	}
    397  1.13.6.2  nathanw 	goto again;
    398  1.13.6.2  nathanw }
    399  1.13.6.2  nathanw 
    400  1.13.6.2  nathanw static void
    401  1.13.6.2  nathanw tctrl_setup_bitport_nop(void)
    402  1.13.6.2  nathanw {
    403  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    404  1.13.6.2  nathanw 	struct tctrl_req req;
    405  1.13.6.2  nathanw 	int s;
    406  1.13.6.2  nathanw 
    407  1.13.6.2  nathanw 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    408  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    409  1.13.6.2  nathanw 	req.cmdbuf[1] = 0xff;
    410  1.13.6.2  nathanw 	req.cmdbuf[2] = 0;
    411  1.13.6.2  nathanw 	req.cmdlen = 3;
    412  1.13.6.2  nathanw 	req.rsplen = 2;
    413  1.13.6.2  nathanw 	req.p = NULL;
    414  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    415  1.13.6.2  nathanw 	s = splts102();
    416  1.13.6.2  nathanw 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    417  1.13.6.2  nathanw 	splx(s);
    418  1.13.6.2  nathanw }
    419  1.13.6.2  nathanw 
    420  1.13.6.2  nathanw static void
    421  1.13.6.2  nathanw tctrl_setup_bitport(void)
    422  1.13.6.2  nathanw {
    423  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    424  1.13.6.2  nathanw 	struct tctrl_req req;
    425  1.13.6.2  nathanw 	int s;
    426  1.13.6.2  nathanw 
    427  1.13.6.2  nathanw 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    428  1.13.6.2  nathanw 	s = splts102();
    429  1.13.6.2  nathanw 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    430  1.13.6.2  nathanw 	    || (!sc->sc_tft_on)) {
    431  1.13.6.2  nathanw 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
    432  1.13.6.2  nathanw 	} else {
    433  1.13.6.2  nathanw 		req.cmdbuf[2] = 0;
    434  1.13.6.2  nathanw 	}
    435  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    436  1.13.6.2  nathanw 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    437  1.13.6.2  nathanw 	req.cmdlen = 3;
    438  1.13.6.2  nathanw 	req.rsplen = 2;
    439  1.13.6.2  nathanw 	req.p = NULL;
    440  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    441  1.13.6.2  nathanw 	s = splts102();
    442  1.13.6.2  nathanw 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    443  1.13.6.2  nathanw 	splx(s);
    444  1.13.6.2  nathanw }
    445  1.13.6.2  nathanw 
    446  1.13.6.2  nathanw /*
    447  1.13.6.2  nathanw  * The tadpole microcontroller is not preprogrammed with icon
    448  1.13.6.2  nathanw  * representations.  The machine boots with the DC-IN light as
    449  1.13.6.2  nathanw  * a blank (all 0x00) and the other lights, as 4 rows of horizontal
    450  1.13.6.2  nathanw  * bars.  The below code initializes the icons in the system to
    451  1.13.6.2  nathanw  * sane values.  Some of these icons could be used for any purpose
    452  1.13.6.2  nathanw  * desired, namely the pcmcia, LAN and WAN lights.  For the disk spinner,
    453  1.13.6.2  nathanw  * only the backslash is unprogrammed.  (sigh)
    454  1.13.6.2  nathanw  *
    455  1.13.6.2  nathanw  * programming the icons is simple.  It is a 5x8 matrix, which each row a
    456  1.13.6.2  nathanw  * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
    457  1.13.6.2  nathanw  */
    458  1.13.6.2  nathanw 
    459  1.13.6.2  nathanw static void
    460  1.13.6.2  nathanw tctrl_init_lcd(void)
    461  1.13.6.2  nathanw {
    462  1.13.6.2  nathanw 	struct tctrl_req req;
    463  1.13.6.2  nathanw 
    464  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    465  1.13.6.2  nathanw 	req.cmdlen = 11;
    466  1.13.6.2  nathanw 	req.rsplen = 1;
    467  1.13.6.2  nathanw 	req.cmdbuf[1] = 0x08;	/*len*/
    468  1.13.6.2  nathanw 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD;
    469  1.13.6.2  nathanw 	req.cmdbuf[3] =  0x00;	/* ..... */
    470  1.13.6.2  nathanw 	req.cmdbuf[4] =  0x00;	/* ..... */
    471  1.13.6.2  nathanw 	req.cmdbuf[5] =  0x1f;	/* XXXXX */
    472  1.13.6.2  nathanw 	req.cmdbuf[6] =  0x00;	/* ..... */
    473  1.13.6.2  nathanw 	req.cmdbuf[7] =  0x15;	/* X.X.X */
    474  1.13.6.2  nathanw 	req.cmdbuf[8] =  0x00;	/* ..... */
    475  1.13.6.2  nathanw 	req.cmdbuf[9] =  0x00;	/* ..... */
    476  1.13.6.2  nathanw 	req.cmdbuf[10] = 0x00;	/* ..... */
    477  1.13.6.2  nathanw 	req.p = NULL;
    478  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    479  1.13.6.2  nathanw 
    480  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    481  1.13.6.2  nathanw 	req.cmdlen = 11;
    482  1.13.6.2  nathanw 	req.rsplen = 1;
    483  1.13.6.2  nathanw 	req.cmdbuf[1] = 0x08;	/*len*/
    484  1.13.6.2  nathanw 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH;
    485  1.13.6.2  nathanw 	req.cmdbuf[3] =  0x00;	/* ..... */
    486  1.13.6.2  nathanw 	req.cmdbuf[4] =  0x10;	/* X.... */
    487  1.13.6.2  nathanw 	req.cmdbuf[5] =  0x08;	/* .X... */
    488  1.13.6.2  nathanw 	req.cmdbuf[6] =  0x04;	/* ..X.. */
    489  1.13.6.2  nathanw 	req.cmdbuf[7] =  0x02;	/* ...X. */
    490  1.13.6.2  nathanw 	req.cmdbuf[8] =  0x01;	/* ....X */
    491  1.13.6.2  nathanw 	req.cmdbuf[9] =  0x00;	/* ..... */
    492  1.13.6.2  nathanw 	req.cmdbuf[10] = 0x00;	/* ..... */
    493  1.13.6.2  nathanw 	req.p = NULL;
    494  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    495  1.13.6.2  nathanw 
    496  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    497  1.13.6.2  nathanw 	req.cmdlen = 11;
    498  1.13.6.2  nathanw 	req.rsplen = 1;
    499  1.13.6.2  nathanw 	req.cmdbuf[1] = 0x08;	/*len*/
    500  1.13.6.2  nathanw 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1;
    501  1.13.6.2  nathanw 	req.cmdbuf[3] =  0x0c;	/* .XXX. */
    502  1.13.6.2  nathanw 	req.cmdbuf[4] =  0x16;	/* X.XX. */
    503  1.13.6.2  nathanw 	req.cmdbuf[5] =  0x10;	/* X.... */
    504  1.13.6.2  nathanw 	req.cmdbuf[6] =  0x15;	/* X.X.X */
    505  1.13.6.2  nathanw 	req.cmdbuf[7] =  0x10;	/* X.... */
    506  1.13.6.2  nathanw 	req.cmdbuf[8] =  0x16;	/* X.XX. */
    507  1.13.6.2  nathanw 	req.cmdbuf[9] =  0x0c;	/* .XXX. */
    508  1.13.6.2  nathanw 	req.cmdbuf[10] = 0x00;	/* ..... */
    509  1.13.6.2  nathanw 	req.p = NULL;
    510  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    511  1.13.6.2  nathanw 
    512  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    513  1.13.6.2  nathanw 	req.cmdlen = 11;
    514  1.13.6.2  nathanw 	req.rsplen = 1;
    515  1.13.6.2  nathanw 	req.cmdbuf[1] = 0x08;	/*len*/
    516  1.13.6.2  nathanw 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2;
    517  1.13.6.2  nathanw 	req.cmdbuf[3] =  0x0c;	/* .XXX. */
    518  1.13.6.2  nathanw 	req.cmdbuf[4] =  0x0d;	/* .XX.X */
    519  1.13.6.2  nathanw 	req.cmdbuf[5] =  0x01;	/* ....X */
    520  1.13.6.2  nathanw 	req.cmdbuf[6] =  0x15;	/* X.X.X */
    521  1.13.6.2  nathanw 	req.cmdbuf[7] =  0x01;	/* ....X */
    522  1.13.6.2  nathanw 	req.cmdbuf[8] =  0x0d;	/* .XX.X */
    523  1.13.6.2  nathanw 	req.cmdbuf[9] =  0x0c;	/* .XXX. */
    524  1.13.6.2  nathanw 	req.cmdbuf[10] = 0x00;	/* ..... */
    525  1.13.6.2  nathanw 	req.p = NULL;
    526  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    527  1.13.6.2  nathanw 
    528  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    529  1.13.6.2  nathanw 	req.cmdlen = 11;
    530  1.13.6.2  nathanw 	req.rsplen = 1;
    531  1.13.6.2  nathanw 	req.cmdbuf[1] = 0x08;	/*len*/
    532  1.13.6.2  nathanw 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1;
    533  1.13.6.2  nathanw 	req.cmdbuf[3] =  0x00;	/* ..... */
    534  1.13.6.2  nathanw 	req.cmdbuf[4] =  0x04;	/* ..X.. */
    535  1.13.6.2  nathanw 	req.cmdbuf[5] =  0x08;	/* .X... */
    536  1.13.6.2  nathanw 	req.cmdbuf[6] =  0x13;	/* X..XX */
    537  1.13.6.2  nathanw 	req.cmdbuf[7] =  0x08;	/* .X... */
    538  1.13.6.2  nathanw 	req.cmdbuf[8] =  0x04;	/* ..X.. */
    539  1.13.6.2  nathanw 	req.cmdbuf[9] =  0x00;	/* ..... */
    540  1.13.6.2  nathanw 	req.cmdbuf[10] = 0x00;	/* ..... */
    541  1.13.6.2  nathanw 	req.p = NULL;
    542  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    543  1.13.6.2  nathanw 
    544  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    545  1.13.6.2  nathanw 	req.cmdlen = 11;
    546  1.13.6.2  nathanw 	req.rsplen = 1;
    547  1.13.6.2  nathanw 	req.cmdbuf[1] = 0x08;	/*len*/
    548  1.13.6.2  nathanw 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2;
    549  1.13.6.2  nathanw 	req.cmdbuf[3] =  0x00;	/* ..... */
    550  1.13.6.2  nathanw 	req.cmdbuf[4] =  0x04;	/* ..X.. */
    551  1.13.6.2  nathanw 	req.cmdbuf[5] =  0x02;	/* ...X. */
    552  1.13.6.2  nathanw 	req.cmdbuf[6] =  0x19;	/* XX..X */
    553  1.13.6.2  nathanw 	req.cmdbuf[7] =  0x02;	/* ...X. */
    554  1.13.6.2  nathanw 	req.cmdbuf[8] =  0x04;	/* ..X.. */
    555  1.13.6.2  nathanw 	req.cmdbuf[9] =  0x00;	/* ..... */
    556  1.13.6.2  nathanw 	req.cmdbuf[10] = 0x00;	/* ..... */
    557  1.13.6.2  nathanw 	req.p = NULL;
    558  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    559  1.13.6.2  nathanw 
    560  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
    561  1.13.6.2  nathanw 	req.cmdlen = 11;
    562  1.13.6.2  nathanw 	req.rsplen = 1;
    563  1.13.6.2  nathanw 	req.cmdbuf[1] = 0x08;	/*len*/
    564  1.13.6.2  nathanw 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA;
    565  1.13.6.2  nathanw 	req.cmdbuf[3] =  0x00;	/* ..... */
    566  1.13.6.2  nathanw 	req.cmdbuf[4] =  0x0c;	/* .XXX. */
    567  1.13.6.2  nathanw 	req.cmdbuf[5] =  0x1f;	/* XXXXX */
    568  1.13.6.2  nathanw 	req.cmdbuf[6] =  0x1f;	/* XXXXX */
    569  1.13.6.2  nathanw 	req.cmdbuf[7] =  0x1f;	/* XXXXX */
    570  1.13.6.2  nathanw 	req.cmdbuf[8] =  0x1f;	/* XXXXX */
    571  1.13.6.2  nathanw 	req.cmdbuf[9] =  0x00;	/* ..... */
    572  1.13.6.2  nathanw 	req.cmdbuf[10] = 0x00;	/* ..... */
    573  1.13.6.2  nathanw 	req.p = NULL;
    574  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    575  1.13.6.2  nathanw }
    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  * set the blinken-lights on the lcd.  what:
    581  1.13.6.2  nathanw  * what = 0 off,  what = 1 on,  what = 2 toggle
    582  1.13.6.2  nathanw  */
    583  1.13.6.2  nathanw 
    584  1.13.6.2  nathanw void
    585  1.13.6.2  nathanw tctrl_set_lcd(what, which)
    586  1.13.6.2  nathanw 	int what;
    587  1.13.6.2  nathanw 	unsigned short which;
    588  1.13.6.2  nathanw {
    589  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    590  1.13.6.2  nathanw 	struct tctrl_req req;
    591  1.13.6.2  nathanw 	int s;
    592  1.13.6.2  nathanw 
    593  1.13.6.2  nathanw 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    594  1.13.6.2  nathanw 	s = splts102();
    595  1.13.6.2  nathanw 
    596  1.13.6.2  nathanw 	/* provide a quick exit to save cpu time */
    597  1.13.6.2  nathanw 	if ((what == 1 && sc->sc_lcdstate & which) ||
    598  1.13.6.2  nathanw 	    (what == 0 && !(sc->sc_lcdstate & which))) {
    599  1.13.6.2  nathanw 		splx(s);
    600  1.13.6.2  nathanw 		return;
    601  1.13.6.2  nathanw 	}
    602  1.13.6.2  nathanw 	/*
    603  1.13.6.2  nathanw 	 * the mask setup on this particular command is *very* bizzare
    604  1.13.6.2  nathanw 	 * and totally undocumented.
    605  1.13.6.2  nathanw 	 */
    606  1.13.6.2  nathanw 	if ((what == 1) || (what == 2 && !(sc->sc_lcdstate & which))) {
    607  1.13.6.2  nathanw 		req.cmdbuf[2] = (u_int8_t)(which&0xff);
    608  1.13.6.2  nathanw 		req.cmdbuf[3] = (u_int8_t)(which>>8);
    609  1.13.6.2  nathanw 	} else {
    610  1.13.6.2  nathanw 		req.cmdbuf[2] = 0;
    611  1.13.6.2  nathanw 		req.cmdbuf[3] = 0;
    612  1.13.6.2  nathanw 	}
    613  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_CTL_LCD;
    614  1.13.6.2  nathanw 	req.cmdbuf[4] = (u_int8_t)(~which>>8);
    615  1.13.6.2  nathanw 	req.cmdbuf[1] = (u_int8_t)(~which&0xff);
    616  1.13.6.2  nathanw 
    617  1.13.6.2  nathanw 	/* XXX this thing is weird.... */
    618  1.13.6.2  nathanw 	req.cmdlen = 3;
    619  1.13.6.2  nathanw 	req.rsplen = 2;
    620  1.13.6.2  nathanw #if 0
    621  1.13.6.2  nathanw 	req.cmdlen = 5;
    622  1.13.6.2  nathanw 	req.rsplen = 4;
    623  1.13.6.2  nathanw #endif
    624  1.13.6.2  nathanw 	req.p = NULL;
    625  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    626  1.13.6.2  nathanw 	s = splts102();
    627  1.13.6.2  nathanw 	sc->sc_lcdstate = (unsigned short)req.rspbuf[0];
    628  1.13.6.2  nathanw 	splx(s);
    629  1.13.6.2  nathanw }
    630  1.13.6.2  nathanw 
    631  1.13.6.2  nathanw static void
    632  1.13.6.2  nathanw tctrl_read_ext_status(void)
    633  1.13.6.2  nathanw {
    634  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    635  1.13.6.2  nathanw 	struct tctrl_req req;
    636  1.13.6.2  nathanw 	int s;
    637  1.13.6.2  nathanw 
    638  1.13.6.2  nathanw 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    639  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
    640  1.13.6.2  nathanw 	req.cmdlen = 1;
    641  1.13.6.2  nathanw 	req.rsplen = 3;
    642  1.13.6.2  nathanw 	req.p = NULL;
    643  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    644  1.13.6.2  nathanw 	printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
    645  1.13.6.2  nathanw #endif
    646  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    647  1.13.6.2  nathanw 	s = splts102();
    648  1.13.6.2  nathanw 	sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1];
    649  1.13.6.2  nathanw 	splx(s);
    650  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    651  1.13.6.2  nathanw 	printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
    652  1.13.6.2  nathanw #endif
    653  1.13.6.2  nathanw }
    654  1.13.6.2  nathanw 
    655  1.13.6.2  nathanw /*
    656  1.13.6.2  nathanw  * return 0 if the user will notice and handle the event,
    657  1.13.6.2  nathanw  * return 1 if the kernel driver should do so.
    658  1.13.6.2  nathanw  */
    659  1.13.6.2  nathanw static int
    660  1.13.6.2  nathanw tctrl_apm_record_event(sc, event_type)
    661  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    662  1.13.6.2  nathanw 	u_int event_type;
    663  1.13.6.2  nathanw {
    664  1.13.6.2  nathanw 	struct apm_event_info *evp;
    665  1.13.6.2  nathanw 
    666  1.13.6.2  nathanw 	if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
    667  1.13.6.2  nathanw 	    (sc->sc_event_count < APM_NEVENTS)) {
    668  1.13.6.2  nathanw 		evp = &sc->sc_event_list[sc->sc_event_ptr];
    669  1.13.6.2  nathanw 		sc->sc_event_count++;
    670  1.13.6.2  nathanw 		sc->sc_event_ptr++;
    671  1.13.6.2  nathanw 		sc->sc_event_ptr %= APM_NEVENTS;
    672  1.13.6.2  nathanw 		evp->type = event_type;
    673  1.13.6.2  nathanw 		evp->index = ++tctrl_apm_evindex;
    674  1.13.6.2  nathanw 		selwakeup(&sc->sc_rsel);
    675  1.13.6.2  nathanw 		return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
    676  1.13.6.2  nathanw 	}
    677  1.13.6.2  nathanw 	return(1);
    678  1.13.6.2  nathanw }
    679  1.13.6.2  nathanw 
    680  1.13.6.2  nathanw static void
    681  1.13.6.2  nathanw tctrl_read_event_status(arg)
    682  1.13.6.2  nathanw 	void *arg;
    683  1.13.6.2  nathanw {
    684  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    685  1.13.6.2  nathanw 	struct tctrl_req req;
    686  1.13.6.2  nathanw 	int s;
    687  1.13.6.2  nathanw 	unsigned int v;
    688  1.13.6.2  nathanw 
    689  1.13.6.2  nathanw 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    690  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
    691  1.13.6.2  nathanw 	req.cmdlen = 1;
    692  1.13.6.2  nathanw 	req.rsplen = 3;
    693  1.13.6.2  nathanw 	req.p = NULL;
    694  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    695  1.13.6.2  nathanw 	s = splts102();
    696  1.13.6.2  nathanw 	v = req.rspbuf[0] * 256 + req.rspbuf[1];
    697  1.13.6.2  nathanw 	if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
    698  1.13.6.2  nathanw 		printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
    699  1.13.6.2  nathanw 	}
    700  1.13.6.2  nathanw 	if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
    701  1.13.6.2  nathanw /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
    702  1.13.6.2  nathanw /* according to a tadpole header, and observation */
    703  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    704  1.13.6.2  nathanw 		printf("%s: Battery charge level change\n", sc->sc_dev.dv_xname);
    705  1.13.6.2  nathanw #endif
    706  1.13.6.2  nathanw 	}
    707  1.13.6.2  nathanw 	if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
    708  1.13.6.2  nathanw 		if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
    709  1.13.6.2  nathanw 			printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
    710  1.13.6.2  nathanw 	}
    711  1.13.6.2  nathanw 	if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
    712  1.13.6.2  nathanw 		splx(s);
    713  1.13.6.2  nathanw 		tctrl_read_ext_status();
    714  1.13.6.2  nathanw 		s = splts102();
    715  1.13.6.2  nathanw 		if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
    716  1.13.6.2  nathanw 			printf("%s: main power %s\n", sc->sc_dev.dv_xname,
    717  1.13.6.2  nathanw 			    (sc->sc_ext_status &
    718  1.13.6.2  nathanw 			    TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
    719  1.13.6.2  nathanw 			    "restored" : "removed");
    720  1.13.6.2  nathanw 	}
    721  1.13.6.2  nathanw 	if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
    722  1.13.6.2  nathanw 		splx(s);
    723  1.13.6.2  nathanw 		tctrl_read_ext_status();
    724  1.13.6.2  nathanw 		tctrl_setup_bitport();
    725  1.13.6.2  nathanw #ifdef TCTRLDEBUG
    726  1.13.6.2  nathanw 		printf("%s: lid %s\n", sc->sc_dev.dv_xname,
    727  1.13.6.2  nathanw 		    (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    728  1.13.6.2  nathanw 		    ? "closed" : "opened");
    729  1.13.6.2  nathanw #endif
    730  1.13.6.2  nathanw 	}
    731  1.13.6.2  nathanw 	splx(s);
    732  1.13.6.2  nathanw }
    733  1.13.6.2  nathanw 
    734  1.13.6.2  nathanw void
    735  1.13.6.2  nathanw tadpole_request(req, spin)
    736  1.13.6.2  nathanw 	struct tctrl_req *req;
    737  1.13.6.2  nathanw 	int spin;
    738  1.13.6.2  nathanw {
    739  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    740  1.13.6.2  nathanw 	int i, s;
    741  1.13.6.2  nathanw 
    742  1.13.6.2  nathanw 	if (tctrl_cd.cd_devs == NULL
    743  1.13.6.2  nathanw 	    || tctrl_cd.cd_ndevs == 0
    744  1.13.6.2  nathanw 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
    745  1.13.6.2  nathanw 		return;
    746  1.13.6.2  nathanw 	}
    747  1.13.6.2  nathanw 
    748  1.13.6.2  nathanw 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    749  1.13.6.2  nathanw 	while (sc->sc_wantdata != 0) {
    750  1.13.6.2  nathanw 		if (req->p != NULL)
    751  1.13.6.2  nathanw 			tsleep(&sc->sc_wantdata, PLOCK, "tctrl_lock", 10);
    752  1.13.6.2  nathanw 		else
    753  1.13.6.2  nathanw 			DELAY(1);
    754  1.13.6.2  nathanw 	}
    755  1.13.6.2  nathanw 	if (spin)
    756  1.13.6.2  nathanw 		s = splhigh();
    757  1.13.6.2  nathanw 	else
    758  1.13.6.2  nathanw 		s = splts102();
    759  1.13.6.2  nathanw 	sc->sc_flags |= TCTRL_SEND_REQUEST;
    760  1.13.6.2  nathanw 	memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
    761  1.13.6.2  nathanw 	sc->sc_wantdata = 1;
    762  1.13.6.2  nathanw 	sc->sc_rsplen = req->rsplen;
    763  1.13.6.2  nathanw 	sc->sc_cmdlen = req->cmdlen;
    764  1.13.6.2  nathanw 	sc->sc_cmdoff = sc->sc_rspoff = 0;
    765  1.13.6.2  nathanw 
    766  1.13.6.2  nathanw 	/* we spin for certain commands, like poweroffs */
    767  1.13.6.2  nathanw 	if (spin) {
    768  1.13.6.2  nathanw /*		for (i = 0; i < 30000; i++) {*/
    769  1.13.6.2  nathanw 		while (sc->sc_wantdata == 1) {
    770  1.13.6.2  nathanw 			tctrl_intr(sc);
    771  1.13.6.2  nathanw 			DELAY(1);
    772  1.13.6.2  nathanw 		}
    773  1.13.6.2  nathanw 	} else {
    774  1.13.6.2  nathanw 		tctrl_intr(sc);
    775  1.13.6.2  nathanw 		i = 0;
    776  1.13.6.2  nathanw 		while (((sc->sc_rspoff != sc->sc_rsplen) ||
    777  1.13.6.2  nathanw 		    (sc->sc_cmdoff != sc->sc_cmdlen)) &&
    778  1.13.6.2  nathanw 		    (i < (5 * sc->sc_rsplen + sc->sc_cmdlen)))
    779  1.13.6.2  nathanw 			if (req->p != NULL) {
    780  1.13.6.2  nathanw 				tsleep(sc, PWAIT, "tctrl_data", 15);
    781  1.13.6.2  nathanw 				i++;
    782  1.13.6.2  nathanw 			}
    783  1.13.6.2  nathanw 			else
    784  1.13.6.2  nathanw 				DELAY(1);
    785  1.13.6.2  nathanw 	}
    786  1.13.6.2  nathanw 	/*
    787  1.13.6.2  nathanw 	 * we give the user a reasonable amount of time for a command
    788  1.13.6.2  nathanw 	 * to complete.  If it doesn't complete in time, we hand them
    789  1.13.6.2  nathanw 	 * garbage.  This is here to stop things like setting the
    790  1.13.6.2  nathanw 	 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
    791  1.13.6.2  nathanw 	 */
    792  1.13.6.2  nathanw 	sc->sc_wantdata = 0;
    793  1.13.6.2  nathanw 	memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
    794  1.13.6.2  nathanw 	splx(s);
    795  1.13.6.2  nathanw }
    796  1.13.6.2  nathanw 
    797  1.13.6.2  nathanw void
    798  1.13.6.2  nathanw tadpole_powerdown(void)
    799  1.13.6.2  nathanw {
    800  1.13.6.2  nathanw 	struct tctrl_req req;
    801  1.13.6.2  nathanw 
    802  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
    803  1.13.6.2  nathanw 	req.cmdlen = 1;
    804  1.13.6.2  nathanw 	req.rsplen = 1;
    805  1.13.6.2  nathanw 	req.p = NULL;
    806  1.13.6.2  nathanw 	tadpole_request(&req, 1);
    807  1.13.6.2  nathanw }
    808  1.13.6.2  nathanw 
    809  1.13.6.2  nathanw void
    810  1.13.6.2  nathanw tadpole_set_video(enabled)
    811  1.13.6.2  nathanw 	int enabled;
    812  1.13.6.2  nathanw {
    813  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    814  1.13.6.2  nathanw 	struct tctrl_req req;
    815  1.13.6.2  nathanw 	int s;
    816  1.13.6.2  nathanw 
    817  1.13.6.2  nathanw 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    818  1.13.6.2  nathanw 	while (sc->sc_wantdata != 0)
    819  1.13.6.2  nathanw 		DELAY(1);
    820  1.13.6.2  nathanw 	s = splts102();
    821  1.13.6.2  nathanw 	req.p = NULL;
    822  1.13.6.2  nathanw 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
    823  1.13.6.2  nathanw 	    || (sc->sc_tft_on)) {
    824  1.13.6.2  nathanw 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
    825  1.13.6.2  nathanw 	} else {
    826  1.13.6.2  nathanw 		req.cmdbuf[2] = 0;
    827  1.13.6.2  nathanw 	}
    828  1.13.6.2  nathanw 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    829  1.13.6.2  nathanw 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    830  1.13.6.2  nathanw 	req.cmdlen = 3;
    831  1.13.6.2  nathanw 	req.rsplen = 2;
    832  1.13.6.2  nathanw 
    833  1.13.6.2  nathanw 	if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
    834  1.13.6.2  nathanw 		sc->sc_tft_on = enabled;
    835  1.13.6.2  nathanw 		if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
    836  1.13.6.2  nathanw 			splx(s);
    837  1.13.6.2  nathanw 			return;
    838  1.13.6.2  nathanw 		}
    839  1.13.6.2  nathanw 		tadpole_request(&req, 1);
    840  1.13.6.2  nathanw 		sc->sc_bitport =
    841  1.13.6.2  nathanw 		    (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    842  1.13.6.2  nathanw 	}
    843  1.13.6.2  nathanw 	splx(s);
    844  1.13.6.2  nathanw }
    845  1.13.6.2  nathanw 
    846  1.13.6.2  nathanw static void
    847  1.13.6.2  nathanw tctrl_write_data(sc, v)
    848  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    849  1.13.6.2  nathanw 	u_int8_t v;
    850  1.13.6.2  nathanw {
    851  1.13.6.2  nathanw 	unsigned int i;
    852  1.13.6.2  nathanw 
    853  1.13.6.2  nathanw 	for (i = 0; i < 100; i++)  {
    854  1.13.6.2  nathanw 		if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
    855  1.13.6.2  nathanw 			break;
    856  1.13.6.2  nathanw 	}
    857  1.13.6.2  nathanw 	tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
    858  1.13.6.2  nathanw }
    859  1.13.6.2  nathanw 
    860  1.13.6.2  nathanw static u_int8_t
    861  1.13.6.2  nathanw tctrl_read_data(sc)
    862  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    863  1.13.6.2  nathanw {
    864  1.13.6.2  nathanw 	unsigned int i, v;
    865  1.13.6.2  nathanw 
    866  1.13.6.2  nathanw 	for (i = 0; i < 100000; i++) {
    867  1.13.6.2  nathanw 		if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
    868  1.13.6.2  nathanw 			break;
    869  1.13.6.2  nathanw 		DELAY(1);
    870  1.13.6.2  nathanw 	}
    871  1.13.6.2  nathanw 
    872  1.13.6.2  nathanw 	v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
    873  1.13.6.2  nathanw 	tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
    874  1.13.6.2  nathanw 	return v;
    875  1.13.6.2  nathanw }
    876  1.13.6.2  nathanw 
    877  1.13.6.2  nathanw static u_int8_t
    878  1.13.6.2  nathanw tctrl_read(sc, off)
    879  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    880  1.13.6.2  nathanw 	bus_size_t off;
    881  1.13.6.2  nathanw {
    882  1.13.6.2  nathanw 
    883  1.13.6.2  nathanw 	sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
    884  1.13.6.2  nathanw 	return sc->sc_junk;
    885  1.13.6.2  nathanw }
    886  1.13.6.2  nathanw 
    887  1.13.6.2  nathanw static void
    888  1.13.6.2  nathanw tctrl_write(sc, off, v)
    889  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    890  1.13.6.2  nathanw 	bus_size_t off;
    891  1.13.6.2  nathanw 	u_int8_t v;
    892  1.13.6.2  nathanw {
    893  1.13.6.2  nathanw 
    894  1.13.6.2  nathanw 	sc->sc_junk = v;
    895  1.13.6.2  nathanw 	bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
    896  1.13.6.2  nathanw }
    897  1.13.6.2  nathanw 
    898  1.13.6.2  nathanw int
    899  1.13.6.2  nathanw tctrlopen(dev, flags, mode, p)
    900  1.13.6.2  nathanw 	dev_t dev;
    901  1.13.6.2  nathanw 	int flags, mode;
    902  1.13.6.2  nathanw 	struct proc *p;
    903  1.13.6.2  nathanw {
    904  1.13.6.2  nathanw 	int unit = (minor(dev)&0xf0);
    905  1.13.6.2  nathanw 	int ctl = (minor(dev)&0x0f);
    906  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    907  1.13.6.2  nathanw 
    908  1.13.6.2  nathanw 	if (unit >= tctrl_cd.cd_ndevs)
    909  1.13.6.2  nathanw 		return(ENXIO);
    910  1.13.6.2  nathanw 	sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
    911  1.13.6.2  nathanw 	if (!sc)
    912  1.13.6.2  nathanw 		return(ENXIO);
    913  1.13.6.2  nathanw 
    914  1.13.6.2  nathanw 	switch (ctl) {
    915  1.13.6.2  nathanw 	case TCTRL_STD_DEV:
    916  1.13.6.2  nathanw 		break;
    917  1.13.6.2  nathanw 	case TCTRL_APMCTL_DEV:
    918  1.13.6.2  nathanw 		if (!(flags & FWRITE))
    919  1.13.6.2  nathanw 			return(EINVAL);
    920  1.13.6.2  nathanw 		if (sc->sc_flags & TCTRL_APM_CTLOPEN)
    921  1.13.6.2  nathanw 			return(EBUSY);
    922  1.13.6.2  nathanw 		sc->sc_flags |= TCTRL_APM_CTLOPEN;
    923  1.13.6.2  nathanw 		break;
    924  1.13.6.2  nathanw 	default:
    925  1.13.6.2  nathanw 		return(ENXIO);
    926  1.13.6.2  nathanw 		break;
    927  1.13.6.2  nathanw 	}
    928  1.13.6.2  nathanw 
    929  1.13.6.2  nathanw 	return(0);
    930  1.13.6.2  nathanw }
    931  1.13.6.2  nathanw 
    932  1.13.6.2  nathanw int
    933  1.13.6.2  nathanw tctrlclose(dev, flags, mode, p)
    934  1.13.6.2  nathanw 	dev_t dev;
    935  1.13.6.2  nathanw 	int flags, mode;
    936  1.13.6.2  nathanw 	struct proc *p;
    937  1.13.6.2  nathanw {
    938  1.13.6.2  nathanw 	int ctl = (minor(dev)&0x0f);
    939  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    940  1.13.6.2  nathanw 
    941  1.13.6.2  nathanw 	sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
    942  1.13.6.2  nathanw 	if (!sc)
    943  1.13.6.2  nathanw 		return(ENXIO);
    944  1.13.6.2  nathanw 
    945  1.13.6.2  nathanw 	switch (ctl) {
    946  1.13.6.2  nathanw 	case TCTRL_STD_DEV:
    947  1.13.6.2  nathanw 		break;
    948  1.13.6.2  nathanw 	case TCTRL_APMCTL_DEV:
    949  1.13.6.2  nathanw 		sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
    950  1.13.6.2  nathanw 		break;
    951  1.13.6.2  nathanw 	}
    952  1.13.6.2  nathanw 	return(0);
    953  1.13.6.2  nathanw }
    954  1.13.6.2  nathanw 
    955  1.13.6.2  nathanw int
    956  1.13.6.2  nathanw tctrlioctl(dev, cmd, data, flags, p)
    957  1.13.6.2  nathanw         dev_t dev;
    958  1.13.6.2  nathanw         u_long cmd;
    959  1.13.6.2  nathanw         caddr_t data;
    960  1.13.6.2  nathanw         int flags;
    961  1.13.6.2  nathanw         struct proc *p;
    962  1.13.6.2  nathanw {
    963  1.13.6.2  nathanw 	struct tctrl_req req, *reqn;
    964  1.13.6.2  nathanw 	struct tctrl_pwr *pwrreq;
    965  1.13.6.2  nathanw 	envsys_range_t *envrange;
    966  1.13.6.2  nathanw 	envsys_temp_data_t *envdata;
    967  1.13.6.2  nathanw 	envsys_temp_info_t *envinfo;
    968  1.13.6.2  nathanw 	struct apm_power_info *powerp;
    969  1.13.6.2  nathanw 	struct apm_event_info *evp;
    970  1.13.6.2  nathanw 	struct tctrl_softc *sc;
    971  1.13.6.2  nathanw 	int i;
    972  1.13.6.2  nathanw 	u_int j;
    973  1.13.6.2  nathanw 	u_int16_t a;
    974  1.13.6.2  nathanw 	u_int8_t c;
    975  1.13.6.2  nathanw 
    976  1.13.6.2  nathanw 	if (tctrl_cd.cd_devs == NULL
    977  1.13.6.2  nathanw 	    || tctrl_cd.cd_ndevs == 0
    978  1.13.6.2  nathanw 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
    979  1.13.6.2  nathanw 		return ENXIO;
    980  1.13.6.2  nathanw 	}
    981  1.13.6.2  nathanw 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    982  1.13.6.2  nathanw         switch (cmd) {
    983  1.13.6.2  nathanw 
    984  1.13.6.2  nathanw 	case APM_IOC_STANDBY:
    985  1.13.6.2  nathanw 		return(EOPNOTSUPP); /* for now */
    986  1.13.6.2  nathanw 
    987  1.13.6.2  nathanw 	case APM_IOC_SUSPEND:
    988  1.13.6.2  nathanw 		return(EOPNOTSUPP); /* for now */
    989  1.13.6.2  nathanw 
    990  1.13.6.4  nathanw 	case OAPM_IOC_GETPOWER:
    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