Home | History | Annotate | Line # | Download | only in dev
tctrl.c revision 1.2.8.1
      1  1.2.8.1  wrstuden /*	$NetBSD: tctrl.c,v 1.2.8.1 1999/12/27 18:33:47 wrstuden Exp $	*/
      2      1.1      matt 
      3      1.1      matt /*-
      4      1.1      matt  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5      1.1      matt  * All rights reserved.
      6      1.1      matt  *
      7      1.1      matt  * This code is derived from software contributed to The NetBSD Foundation
      8      1.1      matt  * by Matt Thomas.
      9      1.1      matt  *
     10      1.1      matt  * Redistribution and use in source and binary forms, with or without
     11      1.1      matt  * modification, are permitted provided that the following conditions
     12      1.1      matt  * are met:
     13      1.1      matt  * 1. Redistributions of source code must retain the above copyright
     14      1.1      matt  *    notice, this list of conditions and the following disclaimer.
     15      1.1      matt  * 2. Redistributions in binary form must reproduce the above copyright
     16      1.1      matt  *    notice, this list of conditions and the following disclaimer in the
     17      1.1      matt  *    documentation and/or other materials provided with the distribution.
     18      1.1      matt  * 3. All advertising materials mentioning features or use of this software
     19      1.1      matt  *    must display the following acknowledgement:
     20      1.1      matt  *        This product includes software developed by the NetBSD
     21      1.1      matt  *        Foundation, Inc. and its contributors.
     22      1.1      matt  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23      1.1      matt  *    contributors may be used to endorse or promote products derived
     24      1.1      matt  *    from this software without specific prior written permission.
     25      1.1      matt  *
     26      1.1      matt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27      1.1      matt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28      1.1      matt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29      1.1      matt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30      1.1      matt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31      1.1      matt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32      1.1      matt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33      1.1      matt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34      1.1      matt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35      1.1      matt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36      1.1      matt  * POSSIBILITY OF SUCH DAMAGE.
     37      1.1      matt  */
     38      1.1      matt 
     39      1.1      matt #include <sys/param.h>
     40      1.1      matt #include <sys/systm.h>
     41      1.1      matt #include <sys/ioctl.h>
     42      1.1      matt #include <sys/select.h>
     43      1.1      matt #include <sys/tty.h>
     44      1.1      matt #include <sys/proc.h>
     45      1.1      matt #include <sys/user.h>
     46      1.1      matt #include <sys/conf.h>
     47      1.1      matt #include <sys/file.h>
     48      1.1      matt #include <sys/uio.h>
     49      1.1      matt #include <sys/kernel.h>
     50      1.1      matt #include <sys/syslog.h>
     51      1.1      matt #include <sys/types.h>
     52      1.1      matt #include <sys/device.h>
     53  1.2.8.1  wrstuden #include <sys/envsys.h>
     54  1.2.8.1  wrstuden #include <sys/poll.h>
     55      1.1      matt 
     56  1.2.8.1  wrstuden #include <machine/apmvar.h>
     57      1.1      matt #include <machine/autoconf.h>
     58      1.1      matt #include <machine/cpu.h>
     59      1.1      matt #include <machine/bus.h>
     60  1.2.8.1  wrstuden #include <machine/tctrl.h>
     61      1.1      matt 
     62      1.1      matt #include <sparc/dev/ts102reg.h>
     63      1.1      matt #include <sparc/dev/tctrlvar.h>
     64      1.1      matt 
     65  1.2.8.1  wrstuden cdev_decl(tctrl);
     66  1.2.8.1  wrstuden 
     67  1.2.8.1  wrstuden extern struct cfdriver tctrl_cd;
     68  1.2.8.1  wrstuden 
     69      1.1      matt static const char *tctrl_ext_statuses[16] = {
     70      1.1      matt 	"main power available",
     71      1.1      matt 	"internal battery attached",
     72      1.1      matt 	"external battery attached",
     73      1.1      matt 	"external VGA attached",
     74      1.1      matt 	"external keyboard attached",
     75      1.1      matt 	"external mouse attached",
     76      1.1      matt 	"lid down",
     77      1.1      matt 	"internal battery charging",
     78      1.1      matt 	"external battery charging",
     79      1.1      matt 	"internal battery discharging",
     80      1.1      matt 	"external battery discharging",
     81      1.1      matt };
     82      1.1      matt 
     83      1.1      matt struct tctrl_softc {
     84  1.2.8.1  wrstuden 	struct	device sc_dev;
     85  1.2.8.1  wrstuden 	bus_space_tag_t	sc_memt;
     86  1.2.8.1  wrstuden 	bus_space_handle_t	sc_memh;
     87  1.2.8.1  wrstuden 	unsigned int	sc_junk;
     88  1.2.8.1  wrstuden 	unsigned int	sc_ext_status;
     89  1.2.8.1  wrstuden 	unsigned int	sc_flags;
     90  1.2.8.1  wrstuden #define TCTRL_SEND_REQUEST		0x0001
     91  1.2.8.1  wrstuden #define TCTRL_APM_CTLOPEN		0x0002
     92  1.2.8.1  wrstuden 	unsigned int	sc_wantdata;
     93      1.1      matt 	enum { TCTRL_IDLE, TCTRL_ARGS,
     94      1.1      matt 		TCTRL_ACK, TCTRL_DATA } sc_state;
     95  1.2.8.1  wrstuden 	u_int8_t	sc_cmdbuf[16];
     96  1.2.8.1  wrstuden 	u_int8_t	sc_rspbuf[16];
     97  1.2.8.1  wrstuden 	u_int8_t	sc_bitport;
     98  1.2.8.1  wrstuden 	u_int8_t	sc_tft_on;
     99  1.2.8.1  wrstuden 	u_int8_t	sc_op;
    100  1.2.8.1  wrstuden 	u_int8_t	sc_cmdoff;
    101  1.2.8.1  wrstuden 	u_int8_t	sc_cmdlen;
    102  1.2.8.1  wrstuden 	u_int8_t	sc_rspoff;
    103  1.2.8.1  wrstuden 	u_int8_t	sc_rsplen;
    104  1.2.8.1  wrstuden 	/* APM stuff */
    105  1.2.8.1  wrstuden #define APM_NEVENTS 16
    106  1.2.8.1  wrstuden 	struct	apm_event_info sc_event_list[APM_NEVENTS];
    107  1.2.8.1  wrstuden 	int	sc_event_count;
    108  1.2.8.1  wrstuden 	int	sc_event_ptr;
    109  1.2.8.1  wrstuden 	struct	selinfo sc_rsel;
    110  1.2.8.1  wrstuden 	/* ENVSYS stuff */
    111  1.2.8.1  wrstuden #define ENVSYS_NUMSENSORS 3
    112  1.2.8.1  wrstuden 	struct	envsys_sensor sc_esensors[ENVSYS_NUMSENSORS];
    113      1.1      matt 
    114  1.2.8.1  wrstuden 	struct	evcnt sc_intrcnt;	/* interrupt counting */
    115      1.1      matt };
    116      1.1      matt 
    117  1.2.8.1  wrstuden #define TCTRL_STD_DEV		0
    118  1.2.8.1  wrstuden #define TCTRL_APMCTL_DEV	8
    119      1.1      matt 
    120  1.2.8.1  wrstuden static int tctrl_match __P((struct device *parent, struct cfdata *cf,
    121  1.2.8.1  wrstuden 	void *aux));
    122  1.2.8.1  wrstuden static void tctrl_attach __P((struct device *parent, struct device *self,
    123  1.2.8.1  wrstuden 	void *aux));
    124  1.2.8.1  wrstuden static void tctrl_write __P((struct tctrl_softc *sc, bus_size_t off,
    125  1.2.8.1  wrstuden 	u_int8_t v));
    126  1.2.8.1  wrstuden static u_int8_t tctrl_read __P((struct tctrl_softc *sc, bus_size_t off));
    127  1.2.8.1  wrstuden static void tctrl_write_data __P((struct tctrl_softc *sc, u_int8_t v));
    128  1.2.8.1  wrstuden static u_int8_t tctrl_read_data __P((struct tctrl_softc *sc));
    129  1.2.8.1  wrstuden static int tctrl_intr __P((void *arg));
    130  1.2.8.1  wrstuden static void tctrl_setup_bitport __P((void));
    131  1.2.8.1  wrstuden static void tctrl_setup_bitport_nop __P((void));
    132  1.2.8.1  wrstuden static void tctrl_read_ext_status __P((void));
    133  1.2.8.1  wrstuden static void tctrl_read_event_status __P((void *arg));
    134  1.2.8.1  wrstuden static int tctrl_apm_record_event __P((struct tctrl_softc *sc,
    135  1.2.8.1  wrstuden 	u_int event_type));
    136      1.1      matt 
    137      1.1      matt struct cfattach tctrl_ca = {
    138      1.1      matt 	sizeof(struct tctrl_softc), tctrl_match, tctrl_attach
    139      1.1      matt };
    140      1.1      matt 
    141      1.1      matt extern struct cfdriver tctrl_cd;
    142  1.2.8.1  wrstuden /* XXX wtf is this? see i386/apm.c */
    143  1.2.8.1  wrstuden int tctrl_apm_evindex;
    144      1.1      matt 
    145      1.1      matt static int
    146  1.2.8.1  wrstuden tctrl_match(parent, cf, aux)
    147  1.2.8.1  wrstuden 	struct device *parent;
    148  1.2.8.1  wrstuden 	struct cfdata *cf;
    149  1.2.8.1  wrstuden 	void *aux;
    150      1.1      matt {
    151      1.1      matt 	union obio_attach_args *uoba = aux;
    152      1.1      matt 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
    153      1.1      matt 
    154      1.1      matt 	if (uoba->uoba_isobio4 != 0) {
    155      1.1      matt 		return (0);
    156      1.1      matt 	}
    157      1.1      matt 
    158      1.1      matt 	/* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
    159      1.1      matt 	 * (who's interface is off the TS102 PCMCIA controller but there
    160      1.1      matt 	 * exists a OpenProm for microcontroller interface).
    161      1.1      matt 	 */
    162      1.1      matt 	return strcmp("uctrl", sa->sa_name) == 0;
    163      1.1      matt }
    164      1.1      matt 
    165      1.1      matt static void
    166  1.2.8.1  wrstuden tctrl_attach(parent, self, aux)
    167  1.2.8.1  wrstuden 	struct device *parent;
    168  1.2.8.1  wrstuden 	struct device *self;
    169  1.2.8.1  wrstuden 	void *aux;
    170      1.1      matt {
    171      1.1      matt 	struct tctrl_softc *sc = (void *)self;
    172      1.1      matt 	union obio_attach_args *uoba = aux;
    173      1.1      matt 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
    174      1.2      matt 	unsigned int i, v;
    175      1.2      matt #if 0
    176      1.1      matt 	unsigned int ack, msb, lsb;
    177      1.2      matt #endif
    178      1.1      matt 
    179      1.1      matt 	/* We're living on a sbus slot that looks like an obio that
    180      1.1      matt 	 * looks like an sbus slot.
    181      1.1      matt 	 */
    182      1.1      matt 	sc->sc_memt = sa->sa_bustag;
    183      1.1      matt 	if (sbus_bus_map(sc->sc_memt, sa->sa_slot,
    184      1.1      matt 			 sa->sa_offset - TS102_REG_UCTRL_INT, sa->sa_size,
    185      1.1      matt 			 BUS_SPACE_MAP_LINEAR, 0,
    186      1.1      matt 			 &sc->sc_memh) != 0) {
    187      1.1      matt 		printf(": can't map registers\n");
    188      1.1      matt 		return;
    189      1.1      matt 	}
    190      1.1      matt 
    191      1.2      matt 	printf("\n");
    192      1.2      matt 
    193      1.1      matt 	sc->sc_tft_on = 1;
    194      1.2      matt 
    195      1.1      matt 	/* clear any pending data.
    196      1.1      matt 	 */
    197      1.1      matt 	for (i = 0; i < 10000; i++) {
    198  1.2.8.1  wrstuden 		if ((TS102_UCTRL_STS_RXNE_STA &
    199  1.2.8.1  wrstuden 		    tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
    200      1.1      matt 			break;
    201      1.1      matt 		}
    202      1.1      matt 		v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
    203      1.2      matt 		tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
    204      1.1      matt 	}
    205      1.1      matt 
    206  1.2.8.1  wrstuden 	if (sa->sa_nintr != 0) {
    207  1.2.8.1  wrstuden 		(void)bus_intr_establish(sc->sc_memt, sa->sa_pri,
    208  1.2.8.1  wrstuden 		    0, tctrl_intr, sc);
    209  1.2.8.1  wrstuden 		evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
    210  1.2.8.1  wrstuden 	}
    211      1.2      matt 
    212      1.2      matt 	/* See what the external status is
    213      1.2      matt 	 */
    214      1.1      matt 
    215  1.2.8.1  wrstuden 	tctrl_read_ext_status();
    216      1.2      matt 	if (sc->sc_ext_status != 0) {
    217      1.2      matt 		const char *sep;
    218      1.1      matt 
    219      1.1      matt 		printf("%s: ", sc->sc_dev.dv_xname);
    220      1.2      matt 		v = sc->sc_ext_status;
    221      1.1      matt 		for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
    222      1.1      matt 			if (v & 1) {
    223      1.1      matt 				printf("%s%s", sep, tctrl_ext_statuses[i]);
    224      1.1      matt 				sep = ", ";
    225      1.1      matt 			}
    226      1.1      matt 		}
    227      1.1      matt 		printf("\n");
    228      1.1      matt 	}
    229      1.1      matt 
    230      1.2      matt 	/* Get a current of the control bitport;
    231      1.2      matt 	 */
    232  1.2.8.1  wrstuden 	tctrl_setup_bitport_nop();
    233      1.2      matt 	tctrl_write(sc, TS102_REG_UCTRL_INT,
    234      1.2      matt 		    TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
    235      1.1      matt 
    236  1.2.8.1  wrstuden 	sc->sc_wantdata = 0;
    237  1.2.8.1  wrstuden 	sc->sc_event_count = 0;
    238  1.2.8.1  wrstuden 
    239  1.2.8.1  wrstuden 	/* prime the sensor data */
    240  1.2.8.1  wrstuden 	sprintf(sc->sc_esensors[0].desc, "%s", "Internal Unit Temperature");
    241  1.2.8.1  wrstuden 	sc->sc_esensors[0].units = ENVSYS_STEMP;
    242  1.2.8.1  wrstuden 	sprintf(sc->sc_esensors[1].desc, "%s", "Internal Battery Voltage");
    243  1.2.8.1  wrstuden 	sc->sc_esensors[1].units = ENVSYS_SVOLTS_DC;
    244  1.2.8.1  wrstuden 	sprintf(sc->sc_esensors[2].desc, "%s", "DC-In Voltage");
    245  1.2.8.1  wrstuden 	sc->sc_esensors[2].units = ENVSYS_SVOLTS_DC;
    246      1.1      matt }
    247      1.1      matt 
    248      1.1      matt static int
    249  1.2.8.1  wrstuden tctrl_intr(arg)
    250  1.2.8.1  wrstuden 	void *arg;
    251      1.1      matt {
    252      1.1      matt 	struct tctrl_softc *sc = arg;
    253      1.1      matt 	unsigned int v, d;
    254      1.1      matt 	int progress = 0;
    255      1.1      matt 
    256      1.1      matt     again:
    257      1.1      matt 	/* find out the cause(s) of the interrupt */
    258      1.1      matt 	v = tctrl_read(sc, TS102_REG_UCTRL_STS);
    259      1.1      matt 
    260      1.1      matt 	/* clear the cause(s) of the interrupt */
    261      1.1      matt 	tctrl_write(sc, TS102_REG_UCTRL_STS, v);
    262      1.1      matt 
    263      1.2      matt 	v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
    264      1.1      matt 	if (sc->sc_cmdoff >= sc->sc_cmdlen) {
    265      1.2      matt 		v &= ~TS102_UCTRL_STS_TXNF_STA;
    266  1.2.8.1  wrstuden 		if (tctrl_read(sc, TS102_REG_UCTRL_INT) & TS102_UCTRL_INT_TXNF_REQ) {
    267  1.2.8.1  wrstuden 			tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
    268  1.2.8.1  wrstuden 			progress = 1;
    269  1.2.8.1  wrstuden 		}
    270      1.1      matt 	}
    271  1.2.8.1  wrstuden 	if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
    272  1.2.8.1  wrstuden 	    sc->sc_state != TCTRL_IDLE)) {
    273  1.2.8.1  wrstuden 		wakeup(sc);
    274      1.1      matt 		return progress;
    275      1.1      matt 	}
    276      1.1      matt 
    277      1.1      matt 	progress = 1;
    278      1.2      matt 	if (v & TS102_UCTRL_STS_RXNE_STA) {
    279      1.1      matt 		d = tctrl_read_data(sc);
    280      1.1      matt 		switch (sc->sc_state) {
    281      1.1      matt 		case TCTRL_IDLE:
    282      1.2      matt 			if (d == 0xfa) {
    283  1.2.8.1  wrstuden 				/* external event */
    284  1.2.8.1  wrstuden 				timeout(tctrl_read_event_status, (void *)0, 1);
    285      1.2      matt 			} else {
    286      1.2      matt 				printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
    287      1.2      matt 					sc->sc_dev.dv_xname, sc->sc_op, d);
    288      1.1      matt 			}
    289      1.2      matt 			goto again;
    290      1.1      matt 		case TCTRL_ACK:
    291      1.1      matt 			if (d != 0xfe) {
    292      1.2      matt 				printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
    293      1.1      matt 					sc->sc_dev.dv_xname, sc->sc_op, d);
    294      1.1      matt 			}
    295  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    296      1.2      matt 			printf(" ack=0x%02x", d);
    297      1.2      matt #endif
    298      1.2      matt 			sc->sc_rsplen--;
    299      1.2      matt 			sc->sc_rspoff = 0;
    300      1.1      matt 			sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
    301  1.2.8.1  wrstuden 			sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
    302  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    303      1.2      matt 			if (sc->sc_rsplen > 0) {
    304      1.2      matt 				printf(" [data(%u)]", sc->sc_rsplen);
    305      1.2      matt 			} else {
    306      1.2      matt 				printf(" [idle]\n");
    307      1.2      matt 			}
    308      1.2      matt #endif
    309      1.2      matt 			goto again;
    310      1.1      matt 		case TCTRL_DATA:
    311      1.1      matt 			sc->sc_rspbuf[sc->sc_rspoff++] = d;
    312  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    313      1.2      matt 			printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
    314      1.2      matt #endif
    315      1.1      matt 			if (sc->sc_rspoff == sc->sc_rsplen) {
    316  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    317      1.2      matt 				printf(" [idle]\n");
    318      1.2      matt #endif
    319      1.1      matt 				sc->sc_state = TCTRL_IDLE;
    320  1.2.8.1  wrstuden 				sc->sc_wantdata = 0;
    321      1.1      matt 			}
    322      1.2      matt 			goto again;
    323      1.1      matt 		default:
    324      1.1      matt 			printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
    325      1.1      matt 			       sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
    326      1.2      matt 			goto again;
    327      1.1      matt 		}
    328      1.1      matt 	}
    329  1.2.8.1  wrstuden 	if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
    330  1.2.8.1  wrstuden 	    sc->sc_flags & TCTRL_SEND_REQUEST) {
    331  1.2.8.1  wrstuden 		if (sc->sc_flags & TCTRL_SEND_REQUEST) {
    332  1.2.8.1  wrstuden 			sc->sc_flags &= ~TCTRL_SEND_REQUEST;
    333  1.2.8.1  wrstuden 			sc->sc_wantdata = 1;
    334  1.2.8.1  wrstuden 		}
    335      1.1      matt 		if (sc->sc_cmdlen > 0) {
    336      1.1      matt 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    337      1.1      matt 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    338      1.1      matt 				|TS102_UCTRL_INT_TXNF_MSK
    339      1.1      matt 				|TS102_UCTRL_INT_TXNF_REQ);
    340      1.1      matt 			v = tctrl_read(sc, TS102_REG_UCTRL_STS);
    341      1.1      matt 		}
    342      1.1      matt 	}
    343      1.2      matt 	if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
    344      1.1      matt 		tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
    345  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    346      1.2      matt 		if (sc->sc_cmdoff == 1) {
    347      1.2      matt 			printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
    348      1.2      matt 				sc->sc_cmdbuf[0], sc->sc_rsplen);
    349      1.2      matt 		} else {
    350      1.2      matt 			printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
    351      1.2      matt 				sc->sc_cmdbuf[sc->sc_cmdoff-1]);
    352      1.2      matt 		}
    353      1.2      matt #endif
    354      1.1      matt 		if (sc->sc_cmdoff == sc->sc_cmdlen) {
    355      1.1      matt 			sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
    356  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    357      1.2      matt 			printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
    358      1.2      matt #endif
    359      1.2      matt 			if (sc->sc_cmdoff == 1) {
    360      1.2      matt 				sc->sc_op = sc->sc_cmdbuf[0];
    361      1.2      matt 			}
    362      1.1      matt 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    363      1.1      matt 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    364      1.1      matt 				& (~TS102_UCTRL_INT_TXNF_MSK
    365      1.1      matt 				   |TS102_UCTRL_INT_TXNF_REQ));
    366      1.1      matt 		} else if (sc->sc_state == TCTRL_IDLE) {
    367      1.1      matt 			sc->sc_op = sc->sc_cmdbuf[0];
    368      1.1      matt 			sc->sc_state = TCTRL_ARGS;
    369  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    370      1.2      matt 			printf(" [args]");
    371      1.2      matt #endif
    372      1.1      matt 		}
    373      1.1      matt 	}
    374      1.1      matt 	goto again;
    375      1.1      matt }
    376      1.1      matt 
    377      1.1      matt static void
    378  1.2.8.1  wrstuden tctrl_setup_bitport_nop(void)
    379      1.1      matt {
    380  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    381  1.2.8.1  wrstuden 	struct tctrl_req req;
    382  1.2.8.1  wrstuden 	int s;
    383  1.2.8.1  wrstuden 
    384  1.2.8.1  wrstuden 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    385  1.2.8.1  wrstuden 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    386  1.2.8.1  wrstuden 	req.cmdbuf[1] = 0xff;
    387  1.2.8.1  wrstuden 	req.cmdbuf[2] = 0;
    388  1.2.8.1  wrstuden 	req.cmdlen = 3;
    389  1.2.8.1  wrstuden 	req.rsplen = 2;
    390  1.2.8.1  wrstuden 	req.p = NULL;
    391  1.2.8.1  wrstuden 	tadpole_request(&req, 1);
    392  1.2.8.1  wrstuden 	s = splts102();
    393  1.2.8.1  wrstuden 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    394  1.2.8.1  wrstuden 	splx(s);
    395  1.2.8.1  wrstuden }
    396  1.2.8.1  wrstuden 
    397  1.2.8.1  wrstuden static void
    398  1.2.8.1  wrstuden tctrl_setup_bitport(void)
    399  1.2.8.1  wrstuden {
    400  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    401  1.2.8.1  wrstuden 	struct tctrl_req req;
    402  1.2.8.1  wrstuden 	int s;
    403  1.2.8.1  wrstuden 
    404  1.2.8.1  wrstuden 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    405  1.2.8.1  wrstuden 	s = splts102();
    406  1.2.8.1  wrstuden 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    407  1.2.8.1  wrstuden 	    || (!sc->sc_tft_on)) {
    408  1.2.8.1  wrstuden 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
    409      1.1      matt 	} else {
    410  1.2.8.1  wrstuden 		req.cmdbuf[2] = 0;
    411      1.1      matt 	}
    412  1.2.8.1  wrstuden 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    413  1.2.8.1  wrstuden 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    414  1.2.8.1  wrstuden 	req.cmdlen = 3;
    415  1.2.8.1  wrstuden 	req.rsplen = 2;
    416  1.2.8.1  wrstuden 	req.p = NULL;
    417  1.2.8.1  wrstuden 	tadpole_request(&req, 1);
    418  1.2.8.1  wrstuden 	s = splts102();
    419  1.2.8.1  wrstuden 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    420  1.2.8.1  wrstuden 	splx(s);
    421      1.1      matt }
    422      1.1      matt 
    423      1.1      matt static void
    424  1.2.8.1  wrstuden tctrl_read_ext_status(void)
    425      1.1      matt {
    426  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    427  1.2.8.1  wrstuden 	struct tctrl_req req;
    428  1.2.8.1  wrstuden 	int s;
    429  1.2.8.1  wrstuden 
    430  1.2.8.1  wrstuden 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    431  1.2.8.1  wrstuden 	req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
    432  1.2.8.1  wrstuden 	req.cmdlen = 1;
    433  1.2.8.1  wrstuden 	req.rsplen = 3;
    434  1.2.8.1  wrstuden 	req.p = NULL;
    435  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    436  1.2.8.1  wrstuden 	printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
    437  1.2.8.1  wrstuden #endif
    438  1.2.8.1  wrstuden 	tadpole_request(&req, 1);
    439  1.2.8.1  wrstuden 	s = splts102();
    440  1.2.8.1  wrstuden 	sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1];
    441  1.2.8.1  wrstuden 	splx(s);
    442  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    443  1.2.8.1  wrstuden 	printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
    444  1.2.8.1  wrstuden #endif
    445  1.2.8.1  wrstuden }
    446  1.2.8.1  wrstuden 
    447  1.2.8.1  wrstuden /*
    448  1.2.8.1  wrstuden  * return 0 if the user will notice and handle the event,
    449  1.2.8.1  wrstuden  * return 1 if the kernel driver should do so.
    450  1.2.8.1  wrstuden  */
    451  1.2.8.1  wrstuden static int
    452  1.2.8.1  wrstuden tctrl_apm_record_event(sc, event_type)
    453  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    454  1.2.8.1  wrstuden 	u_int event_type;
    455  1.2.8.1  wrstuden {
    456  1.2.8.1  wrstuden 	struct apm_event_info *evp;
    457  1.2.8.1  wrstuden 
    458  1.2.8.1  wrstuden 	if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
    459  1.2.8.1  wrstuden 	    (sc->sc_event_count < APM_NEVENTS)) {
    460  1.2.8.1  wrstuden 		evp = &sc->sc_event_list[sc->sc_event_ptr];
    461  1.2.8.1  wrstuden 		sc->sc_event_count++;
    462  1.2.8.1  wrstuden 		sc->sc_event_ptr++;
    463  1.2.8.1  wrstuden 		sc->sc_event_ptr %= APM_NEVENTS;
    464  1.2.8.1  wrstuden 		evp->type = event_type;
    465  1.2.8.1  wrstuden 		evp->index = ++tctrl_apm_evindex;
    466  1.2.8.1  wrstuden 		selwakeup(&sc->sc_rsel);
    467  1.2.8.1  wrstuden 		return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
    468      1.1      matt 	}
    469  1.2.8.1  wrstuden 	return(1);
    470  1.2.8.1  wrstuden }
    471  1.2.8.1  wrstuden 
    472  1.2.8.1  wrstuden static void
    473  1.2.8.1  wrstuden tctrl_read_event_status(arg)
    474  1.2.8.1  wrstuden 	void *arg;
    475  1.2.8.1  wrstuden {
    476  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    477  1.2.8.1  wrstuden 	struct tctrl_req req;
    478  1.2.8.1  wrstuden 	int s;
    479  1.2.8.1  wrstuden 	unsigned int v;
    480  1.2.8.1  wrstuden 
    481  1.2.8.1  wrstuden 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    482  1.2.8.1  wrstuden 	req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
    483  1.2.8.1  wrstuden 	req.cmdlen = 1;
    484  1.2.8.1  wrstuden 	req.rsplen = 3;
    485  1.2.8.1  wrstuden 	req.p = NULL;
    486  1.2.8.1  wrstuden 	tadpole_request(&req, 1);
    487  1.2.8.1  wrstuden 	s = splts102();
    488  1.2.8.1  wrstuden 	v = req.rspbuf[0] * 256 + req.rspbuf[1];
    489  1.2.8.1  wrstuden 	if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
    490  1.2.8.1  wrstuden 		printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
    491  1.2.8.1  wrstuden 	}
    492  1.2.8.1  wrstuden 	if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
    493  1.2.8.1  wrstuden /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
    494  1.2.8.1  wrstuden /* according to a tadpole header, and observation */
    495  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    496  1.2.8.1  wrstuden 		printf("%s: Battery charge level change\n", sc->sc_dev.dv_xname);
    497  1.2.8.1  wrstuden #endif
    498  1.2.8.1  wrstuden 	}
    499  1.2.8.1  wrstuden 	if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
    500  1.2.8.1  wrstuden 		if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
    501      1.1      matt 			printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
    502  1.2.8.1  wrstuden 	}
    503  1.2.8.1  wrstuden 	if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
    504  1.2.8.1  wrstuden 		splx(s);
    505  1.2.8.1  wrstuden 		tctrl_read_ext_status();
    506  1.2.8.1  wrstuden 		s = splts102();
    507  1.2.8.1  wrstuden 		if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
    508      1.1      matt 			printf("%s: main power %s\n", sc->sc_dev.dv_xname,
    509  1.2.8.1  wrstuden 			    (sc->sc_ext_status &
    510  1.2.8.1  wrstuden 			    TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
    511  1.2.8.1  wrstuden 			    "restored" : "removed");
    512  1.2.8.1  wrstuden 	}
    513  1.2.8.1  wrstuden 	if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
    514  1.2.8.1  wrstuden 		splx(s);
    515  1.2.8.1  wrstuden 		tctrl_read_ext_status();
    516  1.2.8.1  wrstuden 		tctrl_setup_bitport();
    517  1.2.8.1  wrstuden #ifdef TCTRLDEBUG
    518  1.2.8.1  wrstuden 		printf("%s: lid %s\n", sc->sc_dev.dv_xname,
    519  1.2.8.1  wrstuden 		    (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    520  1.2.8.1  wrstuden 		    ? "closed" : "opened");
    521      1.2      matt #endif
    522      1.1      matt 	}
    523  1.2.8.1  wrstuden 	splx(s);
    524      1.1      matt }
    525      1.1      matt 
    526      1.1      matt void
    527  1.2.8.1  wrstuden tadpole_request(req, spin)
    528  1.2.8.1  wrstuden 	struct tctrl_req *req;
    529  1.2.8.1  wrstuden 	int spin;
    530      1.1      matt {
    531      1.1      matt 	struct tctrl_softc *sc;
    532      1.1      matt 	int i, s;
    533      1.1      matt 
    534      1.1      matt 	if (tctrl_cd.cd_devs == NULL
    535      1.1      matt 	    || tctrl_cd.cd_ndevs == 0
    536  1.2.8.1  wrstuden 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
    537      1.1      matt 		return;
    538      1.1      matt 	}
    539      1.1      matt 
    540  1.2.8.1  wrstuden 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    541  1.2.8.1  wrstuden 	while (sc->sc_wantdata != 0) {
    542  1.2.8.1  wrstuden 		if (req->p != NULL)
    543  1.2.8.1  wrstuden 			tsleep(&sc->sc_wantdata, PLOCK, "tctrl_lock", 10);
    544  1.2.8.1  wrstuden 		else
    545  1.2.8.1  wrstuden 			DELAY(1);
    546  1.2.8.1  wrstuden 	}
    547  1.2.8.1  wrstuden 	if (spin)
    548  1.2.8.1  wrstuden 		s = splhigh();
    549  1.2.8.1  wrstuden 	else
    550  1.2.8.1  wrstuden 		s = splts102();
    551  1.2.8.1  wrstuden 	sc->sc_flags |= TCTRL_SEND_REQUEST;
    552  1.2.8.1  wrstuden 	memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
    553  1.2.8.1  wrstuden 	sc->sc_wantdata = 1;
    554  1.2.8.1  wrstuden 	sc->sc_rsplen = req->rsplen;
    555  1.2.8.1  wrstuden 	sc->sc_cmdlen = req->cmdlen;
    556  1.2.8.1  wrstuden 	sc->sc_cmdoff = sc->sc_rspoff = 0;
    557  1.2.8.1  wrstuden 
    558  1.2.8.1  wrstuden 	/* we spin for certain commands, like poweroffs */
    559  1.2.8.1  wrstuden 	if (spin) {
    560  1.2.8.1  wrstuden 		for (i = 0; i < 30000; i++) {
    561  1.2.8.1  wrstuden 			tctrl_intr(sc);
    562  1.2.8.1  wrstuden 			DELAY(1);
    563  1.2.8.1  wrstuden 		}
    564  1.2.8.1  wrstuden 	} else {
    565      1.1      matt 		tctrl_intr(sc);
    566  1.2.8.1  wrstuden 		i = 0;
    567  1.2.8.1  wrstuden 		while (((sc->sc_rspoff != sc->sc_rsplen) ||
    568  1.2.8.1  wrstuden 		    (sc->sc_cmdoff != sc->sc_cmdlen)) &&
    569  1.2.8.1  wrstuden 		    (i < (5 * sc->sc_rsplen + sc->sc_cmdlen)))
    570  1.2.8.1  wrstuden 			if (req->p != NULL) {
    571  1.2.8.1  wrstuden 				tsleep(sc, PWAIT, "tctrl_data", 15);
    572  1.2.8.1  wrstuden 				i++;
    573  1.2.8.1  wrstuden 			}
    574  1.2.8.1  wrstuden 			else
    575  1.2.8.1  wrstuden 				DELAY(1);
    576      1.1      matt 	}
    577  1.2.8.1  wrstuden 	/*
    578  1.2.8.1  wrstuden 	 * we give the user a reasonable amount of time for a command
    579  1.2.8.1  wrstuden 	 * to complete.  If it doesn't complete in time, we hand them
    580  1.2.8.1  wrstuden 	 * garbage.  This is here to stop things like setting the
    581  1.2.8.1  wrstuden 	 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
    582  1.2.8.1  wrstuden 	 */
    583  1.2.8.1  wrstuden 	sc->sc_wantdata = 0;
    584  1.2.8.1  wrstuden 	memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
    585      1.1      matt 	splx(s);
    586      1.1      matt }
    587      1.1      matt 
    588      1.1      matt void
    589  1.2.8.1  wrstuden tadpole_powerdown(void)
    590  1.2.8.1  wrstuden {
    591  1.2.8.1  wrstuden 	struct tctrl_req req;
    592  1.2.8.1  wrstuden 
    593  1.2.8.1  wrstuden 	req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
    594  1.2.8.1  wrstuden 	req.cmdlen = 1;
    595  1.2.8.1  wrstuden 	req.rsplen = 1;
    596  1.2.8.1  wrstuden 	req.p = NULL;
    597  1.2.8.1  wrstuden 	tadpole_request(&req, 1);
    598  1.2.8.1  wrstuden }
    599  1.2.8.1  wrstuden 
    600  1.2.8.1  wrstuden void
    601  1.2.8.1  wrstuden tadpole_set_video(enabled)
    602  1.2.8.1  wrstuden 	int enabled;
    603      1.1      matt {
    604      1.1      matt 	struct tctrl_softc *sc;
    605  1.2.8.1  wrstuden 	struct tctrl_req req;
    606      1.1      matt 	int s;
    607      1.1      matt 
    608  1.2.8.1  wrstuden 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    609  1.2.8.1  wrstuden 	while (sc->sc_wantdata != 0)
    610  1.2.8.1  wrstuden 		DELAY(1);
    611  1.2.8.1  wrstuden 	s = splts102();
    612  1.2.8.1  wrstuden 	req.p = NULL;
    613  1.2.8.1  wrstuden 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
    614  1.2.8.1  wrstuden 	    || (sc->sc_tft_on)) {
    615  1.2.8.1  wrstuden 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
    616  1.2.8.1  wrstuden 	} else {
    617  1.2.8.1  wrstuden 		req.cmdbuf[2] = 0;
    618      1.1      matt 	}
    619  1.2.8.1  wrstuden 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
    620  1.2.8.1  wrstuden 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    621  1.2.8.1  wrstuden 	req.cmdlen = 3;
    622  1.2.8.1  wrstuden 	req.rsplen = 2;
    623      1.1      matt 
    624      1.1      matt 	if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
    625      1.1      matt 		sc->sc_tft_on = enabled;
    626      1.1      matt 		if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
    627      1.1      matt 			splx(s);
    628      1.1      matt 			return;
    629      1.1      matt 		}
    630  1.2.8.1  wrstuden 		tadpole_request(&req, 1);
    631  1.2.8.1  wrstuden 		sc->sc_bitport =
    632  1.2.8.1  wrstuden 		    (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
    633      1.1      matt 	}
    634      1.1      matt 	splx(s);
    635      1.1      matt }
    636      1.1      matt 
    637      1.1      matt static void
    638  1.2.8.1  wrstuden tctrl_write_data(sc, v)
    639  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    640  1.2.8.1  wrstuden 	u_int8_t v;
    641      1.1      matt {
    642      1.1      matt 	unsigned int i;
    643  1.2.8.1  wrstuden 
    644      1.1      matt 	for (i = 0; i < 100; i++)  {
    645      1.2      matt 		if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
    646      1.1      matt 			break;
    647      1.1      matt 	}
    648      1.1      matt 	tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
    649      1.1      matt }
    650      1.1      matt 
    651      1.1      matt static u_int8_t
    652  1.2.8.1  wrstuden tctrl_read_data(sc)
    653  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    654  1.2.8.1  wrstuden {
    655      1.1      matt 	unsigned int i, v;
    656      1.1      matt 
    657      1.1      matt 	for (i = 0; i < 100000; i++) {
    658      1.2      matt 		if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
    659      1.1      matt 			break;
    660      1.1      matt 		DELAY(1);
    661      1.1      matt 	}
    662      1.1      matt 
    663      1.1      matt 	v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
    664      1.2      matt 	tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
    665      1.1      matt 	return v;
    666      1.1      matt }
    667      1.1      matt 
    668      1.1      matt static u_int8_t
    669  1.2.8.1  wrstuden tctrl_read(sc, off)
    670  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    671  1.2.8.1  wrstuden 	bus_size_t off;
    672      1.1      matt {
    673  1.2.8.1  wrstuden 
    674      1.2      matt 	sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
    675      1.1      matt 	return sc->sc_junk;
    676      1.1      matt }
    677      1.1      matt 
    678      1.1      matt static void
    679  1.2.8.1  wrstuden tctrl_write(sc, off, v)
    680  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    681  1.2.8.1  wrstuden 	bus_size_t off;
    682  1.2.8.1  wrstuden 	u_int8_t v;
    683      1.1      matt {
    684  1.2.8.1  wrstuden 
    685      1.1      matt 	sc->sc_junk = v;
    686      1.2      matt 	bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
    687  1.2.8.1  wrstuden }
    688  1.2.8.1  wrstuden 
    689  1.2.8.1  wrstuden int
    690  1.2.8.1  wrstuden tctrlopen(dev, flags, mode, p)
    691  1.2.8.1  wrstuden 	dev_t dev;
    692  1.2.8.1  wrstuden 	int flags, mode;
    693  1.2.8.1  wrstuden 	struct proc *p;
    694  1.2.8.1  wrstuden {
    695  1.2.8.1  wrstuden 	int unit = (minor(dev)&0xf0);
    696  1.2.8.1  wrstuden 	int ctl = (minor(dev)&0x0f);
    697  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    698  1.2.8.1  wrstuden 
    699  1.2.8.1  wrstuden 	if (unit >= tctrl_cd.cd_ndevs)
    700  1.2.8.1  wrstuden 		return(ENXIO);
    701  1.2.8.1  wrstuden 	sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
    702  1.2.8.1  wrstuden 	if (!sc)
    703  1.2.8.1  wrstuden 		return(ENXIO);
    704  1.2.8.1  wrstuden 
    705  1.2.8.1  wrstuden 	switch (ctl) {
    706  1.2.8.1  wrstuden 	case TCTRL_STD_DEV:
    707  1.2.8.1  wrstuden 		break;
    708  1.2.8.1  wrstuden 	case TCTRL_APMCTL_DEV:
    709  1.2.8.1  wrstuden 		if (!(flags & FWRITE))
    710  1.2.8.1  wrstuden 			return(EINVAL);
    711  1.2.8.1  wrstuden 		if (sc->sc_flags & TCTRL_APM_CTLOPEN)
    712  1.2.8.1  wrstuden 			return(EBUSY);
    713  1.2.8.1  wrstuden 		sc->sc_flags |= TCTRL_APM_CTLOPEN;
    714  1.2.8.1  wrstuden 		break;
    715  1.2.8.1  wrstuden 	default:
    716  1.2.8.1  wrstuden 		return(ENXIO);
    717  1.2.8.1  wrstuden 		break;
    718  1.2.8.1  wrstuden 	}
    719  1.2.8.1  wrstuden 
    720  1.2.8.1  wrstuden 	return(0);
    721  1.2.8.1  wrstuden }
    722  1.2.8.1  wrstuden 
    723  1.2.8.1  wrstuden int
    724  1.2.8.1  wrstuden tctrlclose(dev, flags, mode, p)
    725  1.2.8.1  wrstuden 	dev_t dev;
    726  1.2.8.1  wrstuden 	int flags, mode;
    727  1.2.8.1  wrstuden 	struct proc *p;
    728  1.2.8.1  wrstuden {
    729  1.2.8.1  wrstuden 	int ctl = (minor(dev)&0x0f);
    730  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    731  1.2.8.1  wrstuden 
    732  1.2.8.1  wrstuden 	sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
    733  1.2.8.1  wrstuden 	if (!sc)
    734  1.2.8.1  wrstuden 		return(ENXIO);
    735  1.2.8.1  wrstuden 
    736  1.2.8.1  wrstuden 	switch (ctl) {
    737  1.2.8.1  wrstuden 	case TCTRL_STD_DEV:
    738  1.2.8.1  wrstuden 		break;
    739  1.2.8.1  wrstuden 	case TCTRL_APMCTL_DEV:
    740  1.2.8.1  wrstuden 		sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
    741  1.2.8.1  wrstuden 		break;
    742  1.2.8.1  wrstuden 	}
    743  1.2.8.1  wrstuden 	return(0);
    744  1.2.8.1  wrstuden }
    745  1.2.8.1  wrstuden 
    746  1.2.8.1  wrstuden int
    747  1.2.8.1  wrstuden tctrlioctl(dev, cmd, data, flags, p)
    748  1.2.8.1  wrstuden         dev_t dev;
    749  1.2.8.1  wrstuden         u_long cmd;
    750  1.2.8.1  wrstuden         caddr_t data;
    751  1.2.8.1  wrstuden         int flags;
    752  1.2.8.1  wrstuden         struct proc *p;
    753  1.2.8.1  wrstuden {
    754  1.2.8.1  wrstuden 	struct tctrl_req req, *reqn;
    755  1.2.8.1  wrstuden 	envsys_range_t *envrange;
    756  1.2.8.1  wrstuden 	envsys_temp_data_t *envdata;
    757  1.2.8.1  wrstuden 	envsys_temp_info_t *envinfo;
    758  1.2.8.1  wrstuden 	struct apm_power_info *powerp;
    759  1.2.8.1  wrstuden 	struct apm_event_info *evp;
    760  1.2.8.1  wrstuden 	struct tctrl_softc *sc;
    761  1.2.8.1  wrstuden 	int i;
    762  1.2.8.1  wrstuden 	u_int j;
    763  1.2.8.1  wrstuden 	u_int16_t a;
    764  1.2.8.1  wrstuden 	u_int8_t c;
    765  1.2.8.1  wrstuden 
    766  1.2.8.1  wrstuden 	if (tctrl_cd.cd_devs == NULL
    767  1.2.8.1  wrstuden 	    || tctrl_cd.cd_ndevs == 0
    768  1.2.8.1  wrstuden 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
    769  1.2.8.1  wrstuden 		return ENXIO;
    770  1.2.8.1  wrstuden 	}
    771  1.2.8.1  wrstuden 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
    772  1.2.8.1  wrstuden         switch (cmd) {
    773  1.2.8.1  wrstuden 
    774  1.2.8.1  wrstuden 	case APM_IOC_STANDBY:
    775  1.2.8.1  wrstuden 		return(EOPNOTSUPP); /* for now */
    776  1.2.8.1  wrstuden 
    777  1.2.8.1  wrstuden 	case APM_IOC_SUSPEND:
    778  1.2.8.1  wrstuden 		return(EOPNOTSUPP); /* for now */
    779  1.2.8.1  wrstuden 
    780  1.2.8.1  wrstuden 	case APM_IOC_GETPOWER:
    781  1.2.8.1  wrstuden 		powerp = (struct apm_power_info *)data;
    782  1.2.8.1  wrstuden 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
    783  1.2.8.1  wrstuden 		req.cmdlen = 1;
    784  1.2.8.1  wrstuden 		req.rsplen = 2;
    785  1.2.8.1  wrstuden 		req.p = p;
    786  1.2.8.1  wrstuden 		tadpole_request(&req, 0);
    787  1.2.8.1  wrstuden 		if (req.rspbuf[0] > 0x00)
    788  1.2.8.1  wrstuden 			powerp->battery_state = APM_BATT_CHARGING;
    789  1.2.8.1  wrstuden 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
    790  1.2.8.1  wrstuden 		req.cmdlen = 1;
    791  1.2.8.1  wrstuden 		req.rsplen = 3;
    792  1.2.8.1  wrstuden 		req.p = p;
    793  1.2.8.1  wrstuden 		tadpole_request(&req, 0);
    794  1.2.8.1  wrstuden 		c = req.rspbuf[0];
    795  1.2.8.1  wrstuden 		powerp->battery_life = c;
    796  1.2.8.1  wrstuden 		powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
    797  1.2.8.1  wrstuden 		if (powerp->battery_state != APM_BATT_CHARGING) {
    798  1.2.8.1  wrstuden 			if (c < 0x20)
    799  1.2.8.1  wrstuden 				powerp->battery_state = APM_BATT_CRITICAL;
    800  1.2.8.1  wrstuden 			else if (c < 0x40)
    801  1.2.8.1  wrstuden 				powerp->battery_state = APM_BATT_LOW;
    802  1.2.8.1  wrstuden 			else if (c < 0x66)
    803  1.2.8.1  wrstuden 				powerp->battery_state = APM_BATT_HIGH;
    804  1.2.8.1  wrstuden 			else
    805  1.2.8.1  wrstuden 				powerp->battery_state = APM_BATT_UNKNOWN;
    806  1.2.8.1  wrstuden 		}
    807  1.2.8.1  wrstuden 		req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
    808  1.2.8.1  wrstuden 		req.cmdlen = 1;
    809  1.2.8.1  wrstuden 		req.rsplen = 3;
    810  1.2.8.1  wrstuden 		req.p = p;
    811  1.2.8.1  wrstuden 		tadpole_request(&req, 0);
    812  1.2.8.1  wrstuden 		a = req.rspbuf[0] * 256 + req.rspbuf[1];
    813  1.2.8.1  wrstuden 		if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
    814  1.2.8.1  wrstuden 			powerp->ac_state = APM_AC_ON;
    815  1.2.8.1  wrstuden 		else
    816  1.2.8.1  wrstuden 			powerp->ac_state = APM_AC_OFF;
    817  1.2.8.1  wrstuden 		break;
    818  1.2.8.1  wrstuden 
    819  1.2.8.1  wrstuden 	case APM_IOC_NEXTEVENT:
    820  1.2.8.1  wrstuden 		if (!sc->sc_event_count)
    821  1.2.8.1  wrstuden 			return EAGAIN;
    822  1.2.8.1  wrstuden 
    823  1.2.8.1  wrstuden 		evp = (struct apm_event_info *)data;
    824  1.2.8.1  wrstuden 		i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
    825  1.2.8.1  wrstuden 		i %= APM_NEVENTS;
    826  1.2.8.1  wrstuden 		*evp = sc->sc_event_list[i];
    827  1.2.8.1  wrstuden 		sc->sc_event_count--;
    828  1.2.8.1  wrstuden 		return(0);
    829  1.2.8.1  wrstuden 
    830  1.2.8.1  wrstuden 	/* this ioctl assumes the caller knows exactly what he is doing */
    831  1.2.8.1  wrstuden 	case TCTRL_CMD_REQ:
    832  1.2.8.1  wrstuden 		reqn = (struct tctrl_req *)data;
    833  1.2.8.1  wrstuden 		if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 &&
    834  1.2.8.1  wrstuden 		    (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
    835  1.2.8.1  wrstuden 		    (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
    836  1.2.8.1  wrstuden 		    reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
    837  1.2.8.1  wrstuden 		    reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
    838  1.2.8.1  wrstuden 		    reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
    839  1.2.8.1  wrstuden 		    reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
    840  1.2.8.1  wrstuden 		    (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
    841  1.2.8.1  wrstuden 		    reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
    842  1.2.8.1  wrstuden 		    reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
    843  1.2.8.1  wrstuden 			return(i);
    844  1.2.8.1  wrstuden 		reqn->p = p;
    845  1.2.8.1  wrstuden 		tadpole_request(reqn, 0);
    846  1.2.8.1  wrstuden 		break;
    847  1.2.8.1  wrstuden 
    848  1.2.8.1  wrstuden 	case ENVSYS_VERSION:
    849  1.2.8.1  wrstuden 		*(int32_t *)data = 1000;
    850  1.2.8.1  wrstuden 		break;
    851  1.2.8.1  wrstuden 
    852  1.2.8.1  wrstuden 	case ENVSYS_GRANGE:
    853  1.2.8.1  wrstuden 		envrange = (envsys_range_t *)data;
    854  1.2.8.1  wrstuden 		i = 0;
    855  1.2.8.1  wrstuden 		envrange->high = envrange->low = 0;
    856  1.2.8.1  wrstuden 		for (j=0; j < ENVSYS_NUMSENSORS; j++) {
    857  1.2.8.1  wrstuden 			if (!i && envrange->units == sc->sc_esensors[j].units) {
    858  1.2.8.1  wrstuden 				envrange->low = j;
    859  1.2.8.1  wrstuden 				i++;
    860  1.2.8.1  wrstuden 			}
    861  1.2.8.1  wrstuden 			if (i && envrange->units == sc->sc_esensors[j].units)
    862  1.2.8.1  wrstuden 				envrange->high = j;
    863  1.2.8.1  wrstuden 		}
    864  1.2.8.1  wrstuden 		if (!i) {
    865  1.2.8.1  wrstuden 			envrange->high = 0;
    866  1.2.8.1  wrstuden 			envrange->low = 1;
    867  1.2.8.1  wrstuden 		}
    868  1.2.8.1  wrstuden 		break;
    869  1.2.8.1  wrstuden 
    870  1.2.8.1  wrstuden 	case ENVSYS_GTREDATA:
    871  1.2.8.1  wrstuden 		envdata = (envsys_temp_data_t *)data;
    872  1.2.8.1  wrstuden 		if (envdata->sensor >= ENVSYS_NUMSENSORS) {
    873  1.2.8.1  wrstuden 			envdata->validflags = 0;
    874  1.2.8.1  wrstuden 			break;
    875  1.2.8.1  wrstuden 		}
    876  1.2.8.1  wrstuden 		envdata->warnflags = ENVSYS_WARN_OK;
    877  1.2.8.1  wrstuden 		if (envdata->sensor == 0) {
    878  1.2.8.1  wrstuden 			envdata->validflags |= ENVSYS_FVALID;
    879  1.2.8.1  wrstuden 			req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
    880  1.2.8.1  wrstuden 			req.cmdlen = 1;
    881  1.2.8.1  wrstuden 			req.rsplen = 2;
    882  1.2.8.1  wrstuden 			req.p = p;
    883  1.2.8.1  wrstuden 			tadpole_request(&req, 0);
    884  1.2.8.1  wrstuden 			envdata->cur.data_us =             /* 273160? */
    885  1.2.8.1  wrstuden 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
    886  1.2.8.1  wrstuden 			envdata->validflags |= ENVSYS_FCURVALID;
    887  1.2.8.1  wrstuden 			req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
    888  1.2.8.1  wrstuden 			req.cmdlen = 1;
    889  1.2.8.1  wrstuden 			req.rsplen = 2;
    890  1.2.8.1  wrstuden 			req.p = p;
    891  1.2.8.1  wrstuden 			tadpole_request(&req, 0);
    892  1.2.8.1  wrstuden 			envdata->max.data_us =
    893  1.2.8.1  wrstuden 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
    894  1.2.8.1  wrstuden 			envdata->validflags |= ENVSYS_FMAXVALID;
    895  1.2.8.1  wrstuden 			req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
    896  1.2.8.1  wrstuden 			req.cmdlen = 1;
    897  1.2.8.1  wrstuden 			req.rsplen = 2;
    898  1.2.8.1  wrstuden 			req.p = p;
    899  1.2.8.1  wrstuden 			tadpole_request(&req, 0);
    900  1.2.8.1  wrstuden 			envdata->min.data_us =
    901  1.2.8.1  wrstuden 			    (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
    902  1.2.8.1  wrstuden 			envdata->validflags |= ENVSYS_FMINVALID;
    903  1.2.8.1  wrstuden 			envdata->units = sc->sc_esensors[envdata->sensor].units;
    904  1.2.8.1  wrstuden 			break;
    905  1.2.8.1  wrstuden 		} else if (envdata->sensor == 1 || envdata->sensor == 2) {
    906  1.2.8.1  wrstuden 			envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
    907  1.2.8.1  wrstuden 			envdata->units = sc->sc_esensors[envdata->sensor].units;
    908  1.2.8.1  wrstuden 			if (envdata->sensor == 1)
    909  1.2.8.1  wrstuden 				req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
    910  1.2.8.1  wrstuden 			else
    911  1.2.8.1  wrstuden 				req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
    912  1.2.8.1  wrstuden 			req.cmdlen = 1;
    913  1.2.8.1  wrstuden 			req.rsplen = 2;
    914  1.2.8.1  wrstuden 			req.p = p;
    915  1.2.8.1  wrstuden 			tadpole_request(&req, 0);
    916  1.2.8.1  wrstuden 			envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000/11;
    917  1.2.8.1  wrstuden 			break;
    918  1.2.8.1  wrstuden 		}
    919  1.2.8.1  wrstuden 		break;
    920  1.2.8.1  wrstuden 
    921  1.2.8.1  wrstuden         case ENVSYS_GTREINFO:
    922  1.2.8.1  wrstuden 		envinfo = (envsys_temp_info_t *)data;
    923  1.2.8.1  wrstuden 		if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
    924  1.2.8.1  wrstuden 			envinfo->validflags = 0;
    925  1.2.8.1  wrstuden 			break;
    926  1.2.8.1  wrstuden 		}
    927  1.2.8.1  wrstuden 		envinfo->units = sc->sc_esensors[envinfo->sensor].units;
    928  1.2.8.1  wrstuden 		memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc,
    929  1.2.8.1  wrstuden 		    sizeof(sc->sc_esensors[envinfo->sensor].desc) >
    930  1.2.8.1  wrstuden 		    sizeof(envinfo->desc) ? sizeof(envinfo->desc) :
    931  1.2.8.1  wrstuden 		    sizeof(sc->sc_esensors[envinfo->sensor].desc));
    932  1.2.8.1  wrstuden 		if (envinfo->units == ENVSYS_STEMP) {
    933  1.2.8.1  wrstuden 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
    934  1.2.8.1  wrstuden 			    ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
    935  1.2.8.1  wrstuden 		} else if (envinfo->units == ENVSYS_SVOLTS_DC) {
    936  1.2.8.1  wrstuden 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
    937  1.2.8.1  wrstuden 		} else
    938  1.2.8.1  wrstuden 			envinfo->validflags = 0;
    939  1.2.8.1  wrstuden                 break;
    940  1.2.8.1  wrstuden 
    941  1.2.8.1  wrstuden         case ENVSYS_STREINFO:
    942  1.2.8.1  wrstuden 		envinfo = (envsys_temp_info_t *)data;
    943  1.2.8.1  wrstuden 		if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
    944  1.2.8.1  wrstuden 			envinfo->validflags = 0;
    945  1.2.8.1  wrstuden 			break;
    946  1.2.8.1  wrstuden 		}
    947  1.2.8.1  wrstuden 		if (envinfo->units == sc->sc_esensors[envinfo->sensor].units)
    948  1.2.8.1  wrstuden 			memcpy(sc->sc_esensors[envinfo->sensor].desc,
    949  1.2.8.1  wrstuden 			    envinfo->desc,
    950  1.2.8.1  wrstuden 			    sizeof(envinfo->desc) > sizeof(char)*32 ?
    951  1.2.8.1  wrstuden 			    sizeof(char)*32 : sizeof(envinfo->desc) );
    952  1.2.8.1  wrstuden 		if (envinfo->units == ENVSYS_STEMP) {
    953  1.2.8.1  wrstuden 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
    954  1.2.8.1  wrstuden 			    ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
    955  1.2.8.1  wrstuden 		} else if (envinfo->units == ENVSYS_SVOLTS_DC) {
    956  1.2.8.1  wrstuden 			envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
    957  1.2.8.1  wrstuden 		} else
    958  1.2.8.1  wrstuden 			envinfo->validflags = 0;
    959  1.2.8.1  wrstuden                 break;
    960  1.2.8.1  wrstuden 
    961  1.2.8.1  wrstuden 
    962  1.2.8.1  wrstuden         default:
    963  1.2.8.1  wrstuden                 return (ENOTTY);
    964  1.2.8.1  wrstuden         }
    965  1.2.8.1  wrstuden         return (0);
    966  1.2.8.1  wrstuden }
    967  1.2.8.1  wrstuden 
    968  1.2.8.1  wrstuden int
    969  1.2.8.1  wrstuden tctrlpoll(dev, events, p)
    970  1.2.8.1  wrstuden 	dev_t dev;
    971  1.2.8.1  wrstuden 	int events;
    972  1.2.8.1  wrstuden 	struct proc *p;
    973  1.2.8.1  wrstuden {
    974  1.2.8.1  wrstuden 	struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
    975  1.2.8.1  wrstuden 	int revents = 0;
    976  1.2.8.1  wrstuden 
    977  1.2.8.1  wrstuden 	if (events & (POLLIN | POLLRDNORM)) {
    978  1.2.8.1  wrstuden 		if (sc->sc_event_count)
    979  1.2.8.1  wrstuden 			revents |= events & (POLLIN | POLLRDNORM);
    980  1.2.8.1  wrstuden 		else
    981  1.2.8.1  wrstuden 			selrecord(p, &sc->sc_rsel);
    982  1.2.8.1  wrstuden 	}
    983  1.2.8.1  wrstuden 
    984  1.2.8.1  wrstuden 	return (revents);
    985      1.1      matt }
    986