[BACK]Return to tctrl.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc / dev

Annotation of sys/arch/sparc/dev/tctrl.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: tctrl.c,v 1.18 2006/10/27 17:52:38 miod Exp $ */
        !             2: /*     $NetBSD: tctrl.c,v 1.2 1999/08/11 00:46:06 matt Exp $   */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Matt Thomas.
        !            10:  *
        !            11:  * Redistribution and use in source and binary forms, with or without
        !            12:  * modification, are permitted provided that the following conditions
        !            13:  * are met:
        !            14:  * 1. Redistributions of source code must retain the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer.
        !            16:  * 2. Redistributions in binary form must reproduce the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer in the
        !            18:  *    documentation and/or other materials provided with the distribution.
        !            19:  * 3. All advertising materials mentioning features or use of this software
        !            20:  *    must display the following acknowledgement:
        !            21:  *        This product includes software developed by the NetBSD
        !            22:  *        Foundation, Inc. and its contributors.
        !            23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            24:  *    contributors may be used to endorse or promote products derived
        !            25:  *    from this software without specific prior written permission.
        !            26:  *
        !            27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            37:  * POSSIBILITY OF SUCH DAMAGE.
        !            38:  */
        !            39: /*
        !            40:  * The /dev/apm{,ctl} interface code falls under the following license
        !            41:  * terms:
        !            42:  *
        !            43:  * Copyright (c) 1998-2001 Michael Shalayeff. All rights reserved.
        !            44:  * Copyright (c) 1995 John T. Kohl.  All rights reserved.
        !            45:  *
        !            46:  * Redistribution and use in source and binary forms, with or without
        !            47:  * modification, are permitted provided that the following conditions
        !            48:  * are met:
        !            49:  * 1. Redistributions of source code must retain the above copyright
        !            50:  *    notice, this list of conditions and the following disclaimer.
        !            51:  * 2. Redistributions in binary form must reproduce the above copyright
        !            52:  *    notice, this list of conditions and the following disclaimer in the
        !            53:  *    documentation and/or other materials provided with the distribution.
        !            54:  * 3. All advertising materials mentioning features or use of this software
        !            55:  *    must display the following acknowledgement:
        !            56:  *     This product includes software developed by the University of
        !            57:  *     California, Berkeley and its contributors.
        !            58:  * 4. Neither the name of the University nor the names of its contributors
        !            59:  *    may be used to endorse or promote products derived from this software
        !            60:  *    without specific prior written permission.
        !            61:  *
        !            62:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            63:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            64:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            65:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            66:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            67:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            68:  * OR SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            69:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            70:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            71:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            72:  * SUCH DAMAGE.
        !            73:  */
        !            74:
        !            75: #include <sys/param.h>
        !            76: #include <sys/systm.h>
        !            77: #include <sys/conf.h>
        !            78: #include <sys/kernel.h>
        !            79: #include <sys/device.h>
        !            80: #include <sys/event.h>
        !            81: #include <sys/fcntl.h>
        !            82: #include <sys/ioctl.h>
        !            83: #include <sys/proc.h>
        !            84: #include <sys/timeout.h>
        !            85:
        !            86: #include <machine/apmvar.h>
        !            87: #include <machine/autoconf.h>
        !            88: #include <machine/conf.h>
        !            89: #include <machine/cpu.h>
        !            90:
        !            91: #include <sparc/sparc/auxioreg.h>
        !            92:
        !            93: #include <sparc/dev/ts102reg.h>
        !            94: #include <sparc/dev/tctrlvar.h>
        !            95:
        !            96: /*
        !            97:  * Flags to control kernel display
        !            98:  *     SCFLAG_NOPRINT:         do not output APM power messages due to
        !            99:  *                             a power change event.
        !           100:  *
        !           101:  *     SCFLAG_PCTPRINT:        do not output APM power messages due to
        !           102:  *                             to a power change event unless the battery
        !           103:  *                             percentage changes.
        !           104:  */
        !           105:
        !           106: #define SCFLAG_NOPRINT 0x0008000
        !           107: #define SCFLAG_PCTPRINT        0x0004000
        !           108: #define SCFLAG_PRINT   (SCFLAG_NOPRINT|SCFLAG_PCTPRINT)
        !           109:
        !           110: const char *tctrl_ext_status[16] = {
        !           111:        "main power available",
        !           112:        "internal battery attached",
        !           113:        "external battery attached",
        !           114:        "external VGA attached",
        !           115:        "external keyboard attached",
        !           116:        "external mouse attached",
        !           117:        "lid down",
        !           118:        "internal battery charging",
        !           119:        "external battery charging",
        !           120:        "internal battery discharging",
        !           121:        "external battery discharging",
        !           122: };
        !           123:
        !           124: /* Request "packet" */
        !           125: struct tctrl_req {
        !           126:        u_int8_t        cmdbuf[16];
        !           127:        u_int           cmdlen;
        !           128:        u_int8_t        rspbuf[16];
        !           129:        u_int           rsplen;
        !           130: };
        !           131:
        !           132: struct tctrl_softc {
        !           133:        struct device sc_dev;
        !           134:        struct uctrl_regs *sc_regs;
        !           135:        struct intrhand sc_ih;
        !           136:        u_int   sc_ext_status;
        !           137:        u_int   sc_flags;
        !           138: #define        TCTRL_SEND_REQUEST              0x0001
        !           139: #define        TCTRL_ISXT                      0x0002
        !           140:        u_int   sc_wantdata;
        !           141:        enum { TCTRL_IDLE, TCTRL_ARGS,
        !           142:                TCTRL_ACK, TCTRL_DATA } sc_state;
        !           143:        u_int8_t sc_cmdbuf[16];
        !           144:        u_int8_t sc_rspbuf[16];
        !           145:        u_int8_t sc_tft_on;
        !           146:        u_int8_t sc_pcmcia_on;
        !           147:        u_int8_t sc_brightness;
        !           148:        u_int8_t sc_op;
        !           149:        u_int   sc_cmdoff;
        !           150:        u_int   sc_cmdlen;
        !           151:        u_int   sc_rspoff;
        !           152:        u_int   sc_rsplen;
        !           153:        u_int   sc_rspack;
        !           154:        u_int   sc_bellfreq;
        !           155:        u_int   sc_bellvol;
        !           156:
        !           157:        struct timeout sc_tmo;
        !           158:
        !           159:        /* /dev/apm{,ctl} fields */
        !           160:        struct klist sc_note;
        !           161:        u_int   sc_apmflags;
        !           162:
        !           163:        /* external video control callback */
        !           164:        void (*sc_evcb)(void *, int);
        !           165:        void *sc_evdata;
        !           166: };
        !           167:
        !           168: int    tctrl_match(struct device *, void *, void *);
        !           169: void   tctrl_attach(struct device *, struct device *, void *);
        !           170:
        !           171: void   tctrl_bell(struct tctrl_softc *, int, int);
        !           172: void   tctrl_brightness(struct tctrl_softc *, int, int);
        !           173: void   tctrl_init_lcd(struct tctrl_softc *);
        !           174: int    tctrl_intr(void *);
        !           175: void   tctrl_lcd(struct tctrl_softc *, int, int);
        !           176: u_int8_t tctrl_read_data(struct tctrl_softc *);
        !           177: void   tctrl_read_event_status(void *);
        !           178: void   tctrl_read_ext_status(struct tctrl_softc *);
        !           179: int    tctrl_request(struct tctrl_softc *, struct tctrl_req *);
        !           180: void   tctrl_tft(struct tctrl_softc *);
        !           181: void   tctrl_write_data(struct tctrl_softc *, u_int8_t);
        !           182:
        !           183: int    apm_record_event(struct tctrl_softc *, u_int);
        !           184:
        !           185: struct cfattach tctrl_ca = {
        !           186:        sizeof(struct tctrl_softc), tctrl_match, tctrl_attach
        !           187: };
        !           188:
        !           189: struct cfdriver tctrl_cd = {
        !           190:        NULL, "tctrl", DV_DULL
        !           191: };
        !           192:
        !           193: int
        !           194: tctrl_match(parent, vcf, aux)
        !           195:        struct device *parent;
        !           196:        void *vcf;
        !           197:        void *aux;
        !           198: {
        !           199:        struct confargs *ca = aux;
        !           200:        struct romaux *ra = &ca->ca_ra;
        !           201:
        !           202:        /*
        !           203:         * Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
        !           204:         * (which is really part of the TS102 PCMCIA controller, but there
        !           205:         * exists a distinct OpenProm node for the microcontroller interface).
        !           206:         */
        !           207:        if (strcmp("uctrl", ra->ra_name))
        !           208:                return (0);
        !           209:
        !           210:        return (1);
        !           211: }
        !           212:
        !           213: void
        !           214: tctrl_attach(parent, self, aux)
        !           215:        struct device *parent, *self;
        !           216:        void *aux;
        !           217: {
        !           218:        struct confargs *ca = aux;
        !           219:        struct tctrl_softc *sc = (void *)self;
        !           220:        u_int i, v;
        !           221:        int pri;
        !           222:
        !           223:        if (ca->ca_ra.ra_nintr != 1) {
        !           224:                printf(": expected 1 interrupt, got %d\n",
        !           225:                    ca->ca_ra.ra_nintr);
        !           226:                return;
        !           227:        }
        !           228:        pri = ca->ca_ra.ra_intr[0].int_pri;
        !           229:
        !           230:        if (ca->ca_ra.ra_nreg != 1) {
        !           231:                printf(": expected 1 register, got %d\n",
        !           232:                    ca->ca_ra.ra_nreg);
        !           233:                return;
        !           234:        }
        !           235:        sc->sc_regs = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
        !           236:            ca->ca_ra.ra_reg[0].rr_len);
        !           237:
        !           238:        printf(" pri %d\n", pri);
        !           239:
        !           240:        /*
        !           241:         * We need to check if we are running on the SPARCbook S3XT, which
        !           242:         * needs extra work to control the TFT power.
        !           243:         */
        !           244:        sc->sc_flags = 0;
        !           245:        if (strcmp(mainbus_model, "Tadpole_S3000XT") == 0)
        !           246:                sc->sc_flags |= TCTRL_ISXT;
        !           247:        sc->sc_tft_on = 1;
        !           248:
        !           249:        /* clear any pending data */
        !           250:        for (i = 0; i < 10000; i++) {
        !           251:                if ((TS102_UCTRL_STS_RXNE_STA & sc->sc_regs->stat) == 0)
        !           252:                        break;
        !           253:                v = sc->sc_regs->data;
        !           254:                sc->sc_regs->stat = TS102_UCTRL_STS_RXNE_STA;
        !           255:        }
        !           256:
        !           257:        sc->sc_ih.ih_fun = tctrl_intr;
        !           258:        sc->sc_ih.ih_arg = sc;
        !           259:        intr_establish(pri, &sc->sc_ih, -1, self->dv_xname);
        !           260:
        !           261:        timeout_set(&sc->sc_tmo, tctrl_read_event_status, sc);
        !           262:
        !           263:        /* See what the external status is */
        !           264:        tctrl_read_ext_status(sc);
        !           265:        if (sc->sc_ext_status != 0) {
        !           266:                const char *sep;
        !           267:                u_int len;
        !           268:
        !           269:                v = sc->sc_ext_status;
        !           270:                len = 0;
        !           271:                sep = "";
        !           272:                for (i = 0; v != 0; i++, v >>= 1) {
        !           273:                        if ((v & 1) == 0)
        !           274:                                continue;
        !           275:                        /* wrap to next line if necessary */
        !           276:                        if (len != 0 && len + strlen(sep) +
        !           277:                            strlen(tctrl_ext_status[i]) > 80) {
        !           278:                                printf("\n");
        !           279:                                len = 0;
        !           280:                        }
        !           281:                        if (len == 0) {
        !           282:                                printf("%s: ", sc->sc_dev.dv_xname);
        !           283:                                len = 2 + strlen(sc->sc_dev.dv_xname);
        !           284:                                sep = "";
        !           285:                        }
        !           286:                        printf("%s%s", sep, tctrl_ext_status[i]);
        !           287:                        len += strlen(sep) + strlen(tctrl_ext_status[i]);
        !           288:                        sep = ", ";
        !           289:                }
        !           290:                if (len != 0)
        !           291:                        printf("\n");
        !           292:        }
        !           293:
        !           294:        /* Get a few status values */
        !           295:        tctrl_bell(sc, 0xff, 0);
        !           296:        tctrl_brightness(sc, 0xff, 0);
        !           297:
        !           298:        /* Blank video if lid is closed during boot */
        !           299:        if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
        !           300:                tctrl_tft(sc);
        !           301:
        !           302:        sc->sc_regs->intr = TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK;
        !           303:
        !           304:        sc->sc_wantdata = 0;
        !           305:
        !           306:        /* Initialize the LCD icons */
        !           307:        tctrl_init_lcd(sc);
        !           308: }
        !           309:
        !           310: int
        !           311: tctrl_intr(void *arg)
        !           312: {
        !           313:        struct tctrl_softc *sc = arg;
        !           314:        unsigned int v, d;
        !           315:        int progress = 0;
        !           316:
        !           317: again:
        !           318:        /* find out the cause(s) of the interrupt */
        !           319:        v = sc->sc_regs->stat & TS102_UCTRL_STS_MASK;
        !           320:
        !           321:        /* clear the cause(s) of the interrupt */
        !           322:        sc->sc_regs->stat = v;
        !           323:
        !           324:        v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
        !           325:        if (sc->sc_cmdoff >= sc->sc_cmdlen) {
        !           326:                v &= ~TS102_UCTRL_STS_TXNF_STA;
        !           327:                if (sc->sc_regs->intr & TS102_UCTRL_INT_TXNF_REQ) {
        !           328:                        sc->sc_regs->intr = 0;
        !           329:                        progress = 1;
        !           330:                }
        !           331:        }
        !           332:        if (v == 0 && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
        !           333:            sc->sc_state != TCTRL_IDLE)) {
        !           334:                return (progress);
        !           335:        }
        !           336:
        !           337:        progress = 1;
        !           338:        if (v & TS102_UCTRL_STS_RXNE_STA) {
        !           339:                d = tctrl_read_data(sc);
        !           340:                switch (sc->sc_state) {
        !           341:                case TCTRL_IDLE:
        !           342:                        if (d == TS102_UCTRL_INTR) {
        !           343:                                /* external event */
        !           344:                                timeout_add(&sc->sc_tmo, 1);
        !           345:                        } else {
        !           346:                                printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
        !           347:                                        sc->sc_dev.dv_xname, sc->sc_op, d);
        !           348:                        }
        !           349:                        goto again;
        !           350:                case TCTRL_ACK:
        !           351: #ifdef TCTRLDEBUG
        !           352:                        printf(" ack=0x%02x", d);
        !           353: #endif
        !           354:                        switch (d) {
        !           355:                        case TS102_UCTRL_ACK:
        !           356:                                sc->sc_rspack = 1;
        !           357:                                sc->sc_rsplen--;
        !           358:                                sc->sc_rspoff = 0;
        !           359:                                sc->sc_state =
        !           360:                                    sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
        !           361:                                sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
        !           362: #ifdef TCTRLDEBUG
        !           363:                                if (sc->sc_rsplen > 0) {
        !           364:                                        printf(" [data(%u)]", sc->sc_rsplen);
        !           365:                                } else {
        !           366:                                        printf(" [idle]\n");
        !           367:                                }
        !           368: #endif
        !           369:                                goto again;
        !           370:                        default:
        !           371:                                printf("%s: (op=0x%02x): unexpected return value (0x%02x)\n",
        !           372:                                        sc->sc_dev.dv_xname, sc->sc_op, d);
        !           373:                                /* FALLTHROUGH */
        !           374:                        case TS102_UCTRL_NACK:
        !           375:                                printf("%s: command %x failed\n",
        !           376:                                    sc->sc_dev.dv_xname, sc->sc_op);
        !           377:                                sc->sc_rspack = 0;
        !           378:                                sc->sc_wantdata = 0;
        !           379:                                sc->sc_state = TCTRL_IDLE;
        !           380:                                break;
        !           381:                        }
        !           382:                        break;
        !           383:                case TCTRL_DATA:
        !           384:                        sc->sc_rspbuf[sc->sc_rspoff++] = d;
        !           385: #ifdef TCTRLDEBUG
        !           386:                        printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
        !           387: #endif
        !           388:                        if (sc->sc_rspoff == sc->sc_rsplen) {
        !           389: #ifdef TCTRLDEBUG
        !           390:                                printf(" [idle]\n");
        !           391: #endif
        !           392:                                sc->sc_state = TCTRL_IDLE;
        !           393:                                sc->sc_wantdata = 0;
        !           394:                        }
        !           395:                        goto again;
        !           396:                default:
        !           397:                        printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
        !           398:                               sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
        !           399:                        goto again;
        !           400:                }
        !           401:        }
        !           402:        if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
        !           403:            (sc->sc_flags & TCTRL_SEND_REQUEST)) {
        !           404:                if (sc->sc_flags & TCTRL_SEND_REQUEST) {
        !           405:                        sc->sc_flags &= ~TCTRL_SEND_REQUEST;
        !           406:                        sc->sc_wantdata = 1;
        !           407:                }
        !           408:                if (sc->sc_cmdlen > 0) {
        !           409:                        sc->sc_regs->intr =
        !           410:                            sc->sc_regs->intr | TS102_UCTRL_INT_TXNF_MSK
        !           411:                                |TS102_UCTRL_INT_TXNF_REQ;
        !           412:                        v = sc->sc_regs->stat;
        !           413:                }
        !           414:        }
        !           415:        if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
        !           416:                tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
        !           417: #ifdef TCTRLDEBUG
        !           418:                if (sc->sc_cmdoff == 1) {
        !           419:                        printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
        !           420:                                sc->sc_cmdbuf[0], sc->sc_rsplen);
        !           421:                } else {
        !           422:                        printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
        !           423:                                sc->sc_cmdbuf[sc->sc_cmdoff-1]);
        !           424:                }
        !           425: #endif
        !           426:                if (sc->sc_cmdoff == sc->sc_cmdlen) {
        !           427:                        sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
        !           428: #ifdef TCTRLDEBUG
        !           429:                        printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
        !           430: #endif
        !           431:                        if (sc->sc_cmdoff == 1) {
        !           432:                                sc->sc_op = sc->sc_cmdbuf[0];
        !           433:                        }
        !           434:                        sc->sc_regs->intr =
        !           435:                            sc->sc_regs->intr & (~TS102_UCTRL_INT_TXNF_MSK
        !           436:                                   |TS102_UCTRL_INT_TXNF_REQ);
        !           437:                } else if (sc->sc_state == TCTRL_IDLE) {
        !           438:                        sc->sc_op = sc->sc_cmdbuf[0];
        !           439:                        sc->sc_state = TCTRL_ARGS;
        !           440: #ifdef TCTRLDEBUG
        !           441:                        printf(" [args]");
        !           442: #endif
        !           443:                }
        !           444:        }
        !           445:        goto again;
        !           446: }
        !           447:
        !           448: /*
        !           449:  * The Tadpole microcontroller is not preprogrammed with icon
        !           450:  * representations.  The machine boots with the DC-IN light as
        !           451:  * a blank (all 0x00) and the other lights, as 4 rows of horizontal
        !           452:  * bars.  The below code initializes the few icons the system will use
        !           453:  * to sane values.
        !           454:  *
        !           455:  * Programming the icons is simple.  It is a 5x8 matrix, with each row a
        !           456:  * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
        !           457:  */
        !           458:
        !           459: static void tctrl_set_glyph(struct tctrl_softc *, u_int, const u_int8_t *);
        !           460:
        !           461: static const u_int8_t
        !           462:     tctrl_glyph_dc[] = { 0x00, 0x00, 0x1f, 0x00, 0x15, 0x00, 0x00, 0x00 },
        !           463: #if 0
        !           464:     tctrl_glyph_bs[] = { 0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00 },
        !           465:     tctrl_glyph_w1[] = { 0x0c, 0x16, 0x10, 0x15, 0x10, 0x16, 0x0c, 0x00 },
        !           466:     tctrl_glyph_w2[] = { 0x0c, 0x0d, 0x01, 0x15, 0x01, 0x0d, 0x0c, 0x00 },
        !           467:     tctrl_glyph_l1[] = { 0x00, 0x04, 0x08, 0x13, 0x08, 0x04, 0x00, 0x00 },
        !           468:     tctrl_glyph_l2[] = { 0x00, 0x04, 0x02, 0x19, 0x02, 0x04, 0x00, 0x00 },
        !           469: #endif
        !           470:     tctrl_glyph_pc[] = { 0x00, 0x0e, 0x0e, 0x1f, 0x1f, 0x1f, 0x1f, 0x00 };
        !           471:
        !           472: void
        !           473: tctrl_init_lcd(struct tctrl_softc *sc)
        !           474: {
        !           475:        tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_DC_GOOD, tctrl_glyph_dc);
        !           476: #if 0
        !           477:        tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_BACKSLASH, tctrl_glyph_bs);
        !           478:        tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_WAN1, tctrl_glyph_w1);
        !           479:        tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_WAN2, tctrl_glyph_w2);
        !           480:        tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_LAN1, tctrl_glyph_l1);
        !           481:        tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_LAN2, tctrl_glyph_l2);
        !           482: #endif
        !           483:        tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_PCMCIA, tctrl_glyph_pc);
        !           484: }
        !           485:
        !           486: static void
        !           487: tctrl_set_glyph(struct tctrl_softc *sc, u_int glyph, const u_int8_t *data)
        !           488: {
        !           489:        struct tctrl_req req;
        !           490:
        !           491:        req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
        !           492:        req.cmdbuf[1] = 8;
        !           493:        req.cmdbuf[2] = glyph;
        !           494:        bcopy(data, req.cmdbuf + 3, 8);
        !           495:        req.cmdlen = 3 + 8;
        !           496:        req.rsplen = 1;
        !           497:
        !           498:        tctrl_request(sc, &req);
        !           499: }
        !           500:
        !           501: void
        !           502: tctrl_read_event_status(void *arg)
        !           503: {
        !           504:        struct tctrl_softc *sc = (struct tctrl_softc *)arg;
        !           505:        struct tctrl_req req;
        !           506:        unsigned int v;
        !           507:
        !           508:        req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
        !           509:        req.cmdlen = 1;
        !           510:        req.rsplen = 3;
        !           511:
        !           512:        tctrl_request(sc, &req);
        !           513:
        !           514:        v = req.rspbuf[0] * 256 + req.rspbuf[1];
        !           515:
        !           516:        /*
        !           517:         * Read the new external status value if necessary
        !           518:         */
        !           519:        if (v & (TS102_EVENT_STATUS_DC_STATUS_CHANGE |
        !           520:            TS102_EVENT_STATUS_LID_STATUS_CHANGE |
        !           521:            TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE))
        !           522:                tctrl_read_ext_status(sc);
        !           523:
        !           524:        if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
        !           525:                printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
        !           526:        }
        !           527: #ifdef TCTRLDEBUG
        !           528:        /* Obviously status change */
        !           529:        if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
        !           530:                if (sc->sc_apmflags & SCFLAG_PCTPRINT)
        !           531:                        printf("%s: Battery level change\n",
        !           532:                            sc->sc_dev.dv_xname);
        !           533:        }
        !           534: #endif
        !           535:        if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
        !           536:                if ((sc->sc_apmflags & SCFLAG_NOPRINT) == 0)
        !           537:                        printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
        !           538:                apm_record_event(sc, APM_BATTERY_LOW);
        !           539:        }
        !           540:        if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
        !           541:                if ((sc->sc_apmflags & SCFLAG_NOPRINT) == 0)
        !           542:                        printf("%s: main power %s\n", sc->sc_dev.dv_xname,
        !           543:                            (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
        !           544:                              "restored" : "removed");
        !           545:                apm_record_event(sc, APM_POWER_CHANGE);
        !           546: #if 0 /* automatically done for us */
        !           547:                tctrl_lcd(sc, ~TS102_LCD_DC_OK,
        !           548:                    sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE ?
        !           549:                      TS102_LCD_DC_OK : 0);
        !           550: #endif
        !           551:        }
        !           552:        if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
        !           553:                /* blank or restore video if necessary */
        !           554:                if (sc->sc_tft_on)
        !           555:                        tctrl_tft(sc);
        !           556: #ifdef TCTRLDEBUG
        !           557:                printf("%s: lid %s\n", sc->sc_dev.dv_xname,
        !           558:                    (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ?
        !           559:                      "closed" : "opened");
        !           560: #endif
        !           561:        }
        !           562:        if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) {
        !           563:                printf("%s: external vga %s\n", sc->sc_dev.dv_xname,
        !           564:                    sc->sc_ext_status & TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED ?
        !           565:                      "attached" : "detached");
        !           566: #ifdef TCTRLDEBUG
        !           567:                req.cmdbuf[0] = TS102_OP_RD_EXT_VGA_PORT;
        !           568:                req.cmdlen = 1;
        !           569:                req.rsplen = 2;
        !           570:                tctrl_request(sc, &req);
        !           571:                printf("%s: vga status %x\n", sc->sc_dev.dv_xname,
        !           572:                    req.rspbuf[0]);
        !           573: #endif
        !           574:                if (sc->sc_evcb != NULL)
        !           575:                        (*sc->sc_evcb)(sc->sc_evdata, sc->sc_ext_status &
        !           576:                            TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED);
        !           577:        }
        !           578: }
        !           579:
        !           580: void
        !           581: tctrl_read_ext_status(struct tctrl_softc *sc)
        !           582: {
        !           583:        struct tctrl_req req;
        !           584:
        !           585:        req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
        !           586:        req.cmdlen = 1;
        !           587:        req.rsplen = 3;
        !           588: #ifdef TCTRLDEBUG
        !           589:        printf("tctrl_read_ext_status: before, ext_status = %x\n",
        !           590:            sc->sc_ext_status);
        !           591: #endif
        !           592:
        !           593:        tctrl_request(sc, &req);
        !           594:
        !           595:        sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1];
        !           596:
        !           597: #ifdef TCTRLDEBUG
        !           598:        printf("tctrl_read_ext_status: after, ext_status = %x\n",
        !           599:            sc->sc_ext_status);
        !           600: #endif
        !           601: }
        !           602:
        !           603: void
        !           604: tctrl_bell(struct tctrl_softc *sc, int mask, int value)
        !           605: {
        !           606:        struct tctrl_req req;
        !           607:
        !           608:        req.cmdbuf[0] = TS102_OP_CTL_SPEAKER_VOLUME;
        !           609:        req.cmdbuf[1] = mask;
        !           610:        req.cmdbuf[2] = value;
        !           611:        req.cmdlen = 3;
        !           612:        req.rsplen = 2;
        !           613:
        !           614:        tctrl_request(sc, &req);
        !           615:
        !           616:        /*
        !           617:         * Note that rspbuf[0] returns the previous value, before any
        !           618:         * adjustment happened.
        !           619:         */
        !           620:        if (mask == 0)
        !           621:                sc->sc_bellvol = value;
        !           622:        else
        !           623:                sc->sc_bellvol = req.rspbuf[0];
        !           624: }
        !           625:
        !           626: void
        !           627: tctrl_brightness(struct tctrl_softc *sc, int mask, int value)
        !           628: {
        !           629:        struct tctrl_req req;
        !           630:
        !           631:        req.cmdbuf[0] = TS102_OP_CTL_TFT_BRIGHTNESS;
        !           632:        req.cmdbuf[1] = mask;
        !           633:        req.cmdbuf[2] = value;
        !           634:        req.cmdlen = 3;
        !           635:        req.rsplen = 2;
        !           636:
        !           637:        tctrl_request(sc, &req);
        !           638:
        !           639:        /*
        !           640:         * Note that rspbuf[0] returns the previous value, before any
        !           641:         * adjustment happened.
        !           642:         */
        !           643:        if (mask == 0)
        !           644:                sc->sc_brightness = value;
        !           645:        else
        !           646:                sc->sc_brightness = req.rspbuf[0];
        !           647: }
        !           648:
        !           649: void
        !           650: tctrl_tft(struct tctrl_softc *sc)
        !           651: {
        !           652:        struct tctrl_req req;
        !           653:        int enable;
        !           654:
        !           655:        enable = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0 &&
        !           656:            sc->sc_tft_on;
        !           657:
        !           658:        req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
        !           659:        req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
        !           660:        req.cmdbuf[2] = enable ? 0 : TS102_BITPORT_TFTPWR;
        !           661:        req.cmdlen = 3;
        !           662:        req.rsplen = 2;
        !           663:
        !           664:        if ((sc->sc_flags & TCTRL_ISXT) != 0 && enable) {
        !           665:                sb_auxregbisc(0, AUXIO_TFT, 0);
        !           666:                delay(100000);  /* XXX is such a long delay really necessary? */
        !           667:        }
        !           668:
        !           669:        tctrl_request(sc, &req);
        !           670:
        !           671:        if ((sc->sc_flags & TCTRL_ISXT) != 0 && !enable) {
        !           672:                delay(100000);  /* XXX is such a long delay really necessary? */
        !           673:                sb_auxregbisc(0, 0, AUXIO_TFT);
        !           674:        }
        !           675: }
        !           676:
        !           677: void
        !           678: tctrl_lcd(struct tctrl_softc *sc, int mask, int value)
        !           679: {
        !           680:        struct tctrl_req req;
        !           681:
        !           682:        req.cmdbuf[0] = TS102_OP_CTL_LCD;
        !           683:
        !           684:        /*
        !           685:         * The mask setup for this particular command is *very* bizarre
        !           686:         * and totally undocumented.
        !           687:         * One would expect the cmdlen and rsplen to be 5 and 3,
        !           688:         * respectively, as well.  Though luck, they are not...
        !           689:         */
        !           690:
        !           691:        req.cmdbuf[1] = mask & 0xff;
        !           692:        req.cmdbuf[4] = (mask >> 8) & 0x01;
        !           693:
        !           694:        req.cmdbuf[2] = value & 0xff;
        !           695:        req.cmdbuf[3] = (value >> 8 & 0x01);
        !           696:
        !           697:        req.cmdlen = 3;
        !           698:        req.rsplen = 2;
        !           699:
        !           700:        tctrl_request(sc, &req);
        !           701: }
        !           702:
        !           703: int
        !           704: tctrl_request(struct tctrl_softc *sc, struct tctrl_req *req)
        !           705: {
        !           706:        int s, rv;
        !           707:
        !           708:        while (sc->sc_wantdata != 0) {
        !           709:                DELAY(1);
        !           710:        }
        !           711:
        !           712:        s = splhigh();
        !           713:        sc->sc_flags |= TCTRL_SEND_REQUEST;
        !           714:        bcopy(req->cmdbuf, sc->sc_cmdbuf, req->cmdlen);
        !           715:        sc->sc_wantdata = 1;
        !           716:        sc->sc_rsplen = req->rsplen;
        !           717:        sc->sc_cmdlen = req->cmdlen;
        !           718:        sc->sc_cmdoff = sc->sc_rspoff = 0;
        !           719:
        !           720:        do {
        !           721:                tctrl_intr(sc);
        !           722:        } while (sc->sc_state != TCTRL_IDLE);
        !           723:
        !           724:        sc->sc_wantdata = 0;    /* just in case... */
        !           725:
        !           726:        rv = sc->sc_rspack;
        !           727:        if (rv != 0)
        !           728:                bcopy(sc->sc_rspbuf, req->rspbuf, sc->sc_rsplen);
        !           729:        else
        !           730:                bzero(req->rspbuf, req->rsplen);        /* safety */
        !           731:        splx(s);
        !           732:
        !           733:        return (rv);
        !           734: }
        !           735:
        !           736: void
        !           737: tctrl_write_data(sc, v)
        !           738:        struct tctrl_softc *sc;
        !           739:        u_int8_t v;
        !           740: {
        !           741:        unsigned int i;
        !           742:
        !           743:        for (i = 0; i < 100; i++)  {
        !           744:                if (sc->sc_regs->stat & TS102_UCTRL_STS_TXNF_STA)
        !           745:                        break;
        !           746:        }
        !           747:        sc->sc_regs->data = v;
        !           748: }
        !           749:
        !           750: u_int8_t
        !           751: tctrl_read_data(sc)
        !           752:        struct tctrl_softc *sc;
        !           753: {
        !           754:        unsigned int i, v;
        !           755:
        !           756:        for (i = 0; i < 100000; i++) {
        !           757:                if (sc->sc_regs->stat & TS102_UCTRL_STS_RXNE_STA)
        !           758:                        break;
        !           759:                DELAY(1);
        !           760:        }
        !           761:
        !           762:        v = sc->sc_regs->data;
        !           763:        sc->sc_regs->stat = TS102_UCTRL_STS_RXNE_STA;
        !           764:        return v;
        !           765: }
        !           766:
        !           767: /*
        !           768:  * External interfaces, used by the display and pcmcia drivers, as well
        !           769:  * as the powerdown code.
        !           770:  */
        !           771:
        !           772: void
        !           773: tadpole_powerdown(void)
        !           774: {
        !           775:        struct tctrl_softc *sc;
        !           776:        struct tctrl_req req;
        !           777:
        !           778:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !           779:                return;
        !           780:        }
        !           781:
        !           782:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !           783:        req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
        !           784:        req.cmdlen = 1;
        !           785:        req.rsplen = 1;
        !           786:
        !           787:        tctrl_request(sc, &req);
        !           788: }
        !           789:
        !           790: void
        !           791: tadpole_set_brightness(int value)
        !           792: {
        !           793:        struct tctrl_softc *sc;
        !           794:
        !           795:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !           796:                return;
        !           797:        }
        !           798:
        !           799:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !           800:        if (value != sc->sc_brightness)
        !           801:                tctrl_brightness(sc, 0, value);
        !           802: }
        !           803:
        !           804: int
        !           805: tadpole_get_brightness()
        !           806: {
        !           807:        struct tctrl_softc *sc;
        !           808:
        !           809:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !           810:                return 0;
        !           811:        }
        !           812:
        !           813:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !           814:        return sc->sc_brightness;
        !           815: }
        !           816:
        !           817: void
        !           818: tadpole_set_video(int enabled)
        !           819: {
        !           820:        struct tctrl_softc *sc;
        !           821:
        !           822:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !           823:                return;
        !           824:        }
        !           825:
        !           826:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !           827:        if (sc->sc_tft_on ^ enabled) {
        !           828:                sc->sc_tft_on = enabled;
        !           829:                /* nothing to do if the lid is down */
        !           830:                if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0)
        !           831:                        tctrl_tft(sc);
        !           832:        }
        !           833: }
        !           834:
        !           835: u_int
        !           836: tadpole_get_video()
        !           837: {
        !           838:        struct tctrl_softc *sc;
        !           839:        unsigned int status;
        !           840:
        !           841:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !           842:                return 0;
        !           843:        }
        !           844:
        !           845:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !           846:        status = sc->sc_tft_on ? TV_ON : 0;
        !           847:
        !           848:        return status;
        !           849: }
        !           850:
        !           851: void
        !           852: tadpole_register_extvideo(void (*cb)(void *, int), void *data)
        !           853: {
        !           854:        struct tctrl_softc *sc;
        !           855:
        !           856:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !           857:                return;
        !           858:        }
        !           859:
        !           860:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !           861:        sc->sc_evcb = cb;
        !           862:        sc->sc_evdata = data;
        !           863:
        !           864:        (*cb)(data, sc->sc_ext_status & TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED);
        !           865: }
        !           866:
        !           867: void
        !           868: tadpole_set_pcmcia(int slot, int enabled)
        !           869: {
        !           870:        struct tctrl_softc *sc;
        !           871:        int mask;
        !           872:
        !           873:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !           874:                return;
        !           875:        }
        !           876:
        !           877:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !           878:        mask = 1 << slot;
        !           879:        enabled = enabled ? mask : 0;
        !           880:        if ((sc->sc_pcmcia_on ^ enabled) & mask) {
        !           881:                sc->sc_pcmcia_on ^= mask;
        !           882:                tctrl_lcd(sc, ~TS102_LCD_PCMCIA_ACTIVE,
        !           883:                    sc->sc_pcmcia_on ? TS102_LCD_PCMCIA_ACTIVE : 0);
        !           884:        }
        !           885: }
        !           886:
        !           887: int
        !           888: tadpole_bell(u_int duration, u_int freq, u_int volume)
        !           889: {
        !           890:        struct tctrl_softc *sc;
        !           891:        struct tctrl_req req;
        !           892:
        !           893:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !           894:                return (0);
        !           895:        }
        !           896:
        !           897:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !           898:
        !           899:        /* Adjust frequency if necessary (first time or frequence change) */
        !           900:        if (freq > 0 && freq <= 0xffff && freq != sc->sc_bellfreq) {
        !           901:                req.cmdbuf[0] = TS102_OP_CMD_SET_BELL_FREQ;
        !           902:                req.cmdbuf[1] = (freq >> 8) & 0xff;
        !           903:                req.cmdbuf[2] = freq & 0xff;
        !           904:                req.cmdlen = 3;
        !           905:                req.rsplen = 1;
        !           906:
        !           907:                tctrl_request(sc, &req);
        !           908:
        !           909:                sc->sc_bellfreq = freq;
        !           910:        }
        !           911:
        !           912:        /* Adjust volume if necessary */
        !           913:        if (volume >= 0 && volume <= 100) {
        !           914:                volume = (volume * 255) / 100;
        !           915:                if (volume != sc->sc_bellvol)
        !           916:                        tctrl_bell(sc, 0, volume);
        !           917:
        !           918:        }
        !           919:
        !           920:        req.cmdbuf[0] = TS102_OP_CMD_RING_BELL;
        !           921:        req.cmdbuf[1] = (duration >> 8) & 0xff;
        !           922:        req.cmdbuf[2] = duration & 0xff;
        !           923:        req.cmdlen = 3;
        !           924:        req.rsplen = 1;
        !           925:
        !           926:        tctrl_request(sc, &req);
        !           927:
        !           928:        return (1);
        !           929: }
        !           930:
        !           931: /*
        !           932:  * /dev/apm{,ctl} interface code
        !           933:  */
        !           934:
        !           935: #define        APMUNIT(dev)    (minor(dev)&0xf0)
        !           936: #define        APMDEV(dev)     (minor(dev)&0x0f)
        !           937: #define APMDEV_NORMAL  0
        !           938: #define APMDEV_CTL     8
        !           939:
        !           940: int    apmkqfilter(dev_t dev, struct knote *kn);
        !           941: void   filt_apmrdetach(struct knote *kn);
        !           942: int    filt_apmread(struct knote *kn, long hint);
        !           943:
        !           944: struct filterops apmread_filtops =
        !           945:        { 1, NULL, filt_apmrdetach, filt_apmread};
        !           946:
        !           947: #define        SCFLAG_OREAD    (1 << 0)
        !           948: #define        SCFLAG_OWRITE   (1 << 1)
        !           949: #define        SCFLAG_OPEN     (SCFLAG_OREAD|SCFLAG_OWRITE)
        !           950:
        !           951: int
        !           952: apmopen(dev_t dev, int flag, int mode, struct proc *p)
        !           953: {
        !           954:        struct tctrl_softc *sc;
        !           955:        int error = 0;
        !           956:
        !           957:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !           958:                return (ENXIO);
        !           959:        }
        !           960:
        !           961:        /* apm0 only */
        !           962:        if (APMUNIT(dev) != 0)
        !           963:                return (ENODEV);
        !           964:
        !           965:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !           966:
        !           967:        switch (APMDEV(dev)) {
        !           968:        case APMDEV_CTL:
        !           969:                if (!(flag & FWRITE)) {
        !           970:                        error = EINVAL;
        !           971:                        break;
        !           972:                }
        !           973:                if (sc->sc_apmflags & SCFLAG_OWRITE) {
        !           974:                        error = EBUSY;
        !           975:                        break;
        !           976:                }
        !           977:                sc->sc_apmflags |= SCFLAG_OWRITE;
        !           978:                break;
        !           979:        case APMDEV_NORMAL:
        !           980:                if (!(flag & FREAD) || (flag & FWRITE)) {
        !           981:                        error = EINVAL;
        !           982:                        break;
        !           983:                }
        !           984:                sc->sc_apmflags |= SCFLAG_OREAD;
        !           985:                break;
        !           986:        default:
        !           987:                error = ENXIO;
        !           988:                break;
        !           989:        }
        !           990:        return (error);
        !           991: }
        !           992:
        !           993: int
        !           994: apmclose(dev_t dev, int flag, int mode, struct proc *p)
        !           995: {
        !           996:        struct tctrl_softc *sc;
        !           997:
        !           998:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !           999:                return (ENXIO);
        !          1000:        }
        !          1001:
        !          1002:        /* apm0 only */
        !          1003:        if (APMUNIT(dev) != 0)
        !          1004:                return (ENODEV);
        !          1005:
        !          1006:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !          1007:
        !          1008:        switch (APMDEV(dev)) {
        !          1009:        case APMDEV_CTL:
        !          1010:                sc->sc_apmflags &= ~SCFLAG_OWRITE;
        !          1011:                break;
        !          1012:        case APMDEV_NORMAL:
        !          1013:                sc->sc_apmflags &= ~SCFLAG_OREAD;
        !          1014:                break;
        !          1015:        }
        !          1016:        return (0);
        !          1017: }
        !          1018:
        !          1019: int
        !          1020: apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
        !          1021: {
        !          1022:        struct tctrl_softc *sc;
        !          1023:        struct tctrl_req req;
        !          1024:        struct apm_power_info *power;
        !          1025:        u_int8_t c;
        !          1026:        int error = 0;
        !          1027:
        !          1028:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !          1029:                return (ENXIO);
        !          1030:        }
        !          1031:
        !          1032:        /* apm0 only */
        !          1033:        if (APMUNIT(dev) != 0)
        !          1034:                return (ENODEV);
        !          1035:
        !          1036:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !          1037:
        !          1038:        switch (cmd) {
        !          1039:                /* some ioctl names from linux */
        !          1040:        case APM_IOC_STANDBY:
        !          1041:                if ((flag & FWRITE) == 0)
        !          1042:                        error = EBADF;
        !          1043:                else
        !          1044:                        error = EOPNOTSUPP;     /* XXX */
        !          1045:                break;
        !          1046:        case APM_IOC_SUSPEND:
        !          1047:                if ((flag & FWRITE) == 0)
        !          1048:                        error = EBADF;
        !          1049:                else
        !          1050:                        error = EOPNOTSUPP;     /* XXX */
        !          1051:                break;
        !          1052:        case APM_IOC_PRN_CTL:
        !          1053:                if ((flag & FWRITE) == 0)
        !          1054:                        error = EBADF;
        !          1055:                else {
        !          1056:                        int flag = *(int *)data;
        !          1057:                        switch (flag) {
        !          1058:                        case APM_PRINT_ON:      /* enable printing */
        !          1059:                                sc->sc_apmflags &= ~SCFLAG_PRINT;
        !          1060:                                break;
        !          1061:                        case APM_PRINT_OFF: /* disable printing */
        !          1062:                                sc->sc_apmflags &= ~SCFLAG_PRINT;
        !          1063:                                sc->sc_apmflags |= SCFLAG_NOPRINT;
        !          1064:                                break;
        !          1065:                        case APM_PRINT_PCT: /* disable some printing */
        !          1066:                                sc->sc_apmflags &= ~SCFLAG_PRINT;
        !          1067:                                sc->sc_apmflags |= SCFLAG_PCTPRINT;
        !          1068:                                break;
        !          1069:                        default:
        !          1070:                                error = EINVAL;
        !          1071:                                break;
        !          1072:                        }
        !          1073:                }
        !          1074:                break;
        !          1075:        case APM_IOC_GETPOWER:
        !          1076:                power = (struct apm_power_info *)data;
        !          1077:
        !          1078:                if (sc->sc_ext_status &
        !          1079:                    TS102_EXT_STATUS_INTERNAL_BATTERY_ATTACHED) {
        !          1080:                        req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
        !          1081:                        req.cmdlen = 1;
        !          1082:                        req.rsplen = 2;
        !          1083:                        tctrl_request(sc, &req);
        !          1084:                        if (req.rspbuf[0] != 0)
        !          1085:                                power->battery_state = APM_BATT_CHARGING;
        !          1086:                        else
        !          1087:                                power->battery_state = APM_BATT_UNKNOWN;
        !          1088:
        !          1089:                        req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
        !          1090:                        req.cmdlen = 1;
        !          1091:                        req.rsplen = 3;
        !          1092:                        tctrl_request(sc, &req);
        !          1093:
        !          1094:                        c = req.rspbuf[0];
        !          1095:                        if (c >= TS102_CHARGE_UNKNOWN)
        !          1096:                                power->battery_life = 0;
        !          1097:                        else {
        !          1098:                                power->battery_life = c;
        !          1099:                                if (power->battery_state != APM_BATT_CHARGING) {
        !          1100:                                        if (c < 0x20)
        !          1101:                                                power->battery_state =
        !          1102:                                                    APM_BATT_CRITICAL;
        !          1103:                                        else if (c < 0x40)
        !          1104:                                                power->battery_state =
        !          1105:                                                    APM_BATT_HIGH;
        !          1106:                                        else if (c < 0x66)
        !          1107:                                                power->battery_state =
        !          1108:                                                    APM_BATT_HIGH;
        !          1109:                                }
        !          1110:                        }
        !          1111:                } else {
        !          1112:                        power->battery_state = APM_BATTERY_ABSENT;
        !          1113:                        power->battery_life = 0;
        !          1114:                }
        !          1115:                power->minutes_left = (u_int)-1;        /* unknown */
        !          1116:
        !          1117:                if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
        !          1118:                        power->ac_state = APM_AC_ON;
        !          1119:                else
        !          1120:                        power->ac_state = APM_AC_OFF;
        !          1121:                break;
        !          1122:
        !          1123:        default:
        !          1124:                error = ENOTTY;
        !          1125:        }
        !          1126:
        !          1127:        return (error);
        !          1128: }
        !          1129:
        !          1130: int
        !          1131: apm_record_event(struct tctrl_softc *sc, u_int type)
        !          1132: {
        !          1133:        static int apm_evindex;
        !          1134:
        !          1135:        /* skip if no user waiting */
        !          1136:        if ((sc->sc_apmflags & SCFLAG_OPEN) == 0)
        !          1137:                return (1);
        !          1138:
        !          1139:        apm_evindex++;
        !          1140:        KNOTE(&sc->sc_note, APM_EVENT_COMPOSE(type, apm_evindex));
        !          1141:
        !          1142:        return (0);
        !          1143: }
        !          1144:
        !          1145: void
        !          1146: filt_apmrdetach(struct knote *kn)
        !          1147: {
        !          1148:        struct tctrl_softc *sc = (struct tctrl_softc *)kn->kn_hook;
        !          1149:
        !          1150:        SLIST_REMOVE(&sc->sc_note, kn, knote, kn_selnext);
        !          1151: }
        !          1152:
        !          1153: int
        !          1154: filt_apmread(struct knote *kn, long hint)
        !          1155: {
        !          1156:        /* XXX weird kqueue_scan() semantics */
        !          1157:        if (hint && !kn->kn_data)
        !          1158:                kn->kn_data = (int)hint;
        !          1159:
        !          1160:        return (1);
        !          1161: }
        !          1162:
        !          1163: int
        !          1164: apmkqfilter(dev_t dev, struct knote *kn)
        !          1165: {
        !          1166:        struct tctrl_softc *sc;
        !          1167:
        !          1168:        if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
        !          1169:                return (ENXIO);
        !          1170:        }
        !          1171:
        !          1172:        /* apm0 only */
        !          1173:        if (APMUNIT(dev) != 0)
        !          1174:                return (ENODEV);
        !          1175:
        !          1176:        sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
        !          1177:
        !          1178:        switch (kn->kn_filter) {
        !          1179:        case EVFILT_READ:
        !          1180:                kn->kn_fop = &apmread_filtops;
        !          1181:                break;
        !          1182:        default:
        !          1183:                return (1);
        !          1184:        }
        !          1185:
        !          1186:        kn->kn_hook = (caddr_t)sc;
        !          1187:        SLIST_INSERT_HEAD(&sc->sc_note, kn, kn_selnext);
        !          1188:
        !          1189:        return (0);
        !          1190: }

CVSweb