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