Annotation of src/sys/arch/sparc/dev/tctrl.c, revision 1.35

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

CVSweb <webmaster@jp.NetBSD.org>