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