[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

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