[BACK]Return to apm.c CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / i386

Annotation of sys/arch/i386/i386/apm.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: apm.c,v 1.76 2007/07/02 17:11:29 thib Exp $   */
                      2:
                      3: /*-
                      4:  * Copyright (c) 1998-2001 Michael Shalayeff. All rights reserved.
                      5:  * Copyright (c) 1995 John T. Kohl.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by the University of
                     18:  *     California, Berkeley and its contributors.
                     19:  * 4. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  *
                     35:  */
                     36:
                     37: #include "apm.h"
                     38:
                     39: #if NAPM > 1
                     40: #error only one APM device may be configured
                     41: #endif
                     42:
                     43: #include <sys/param.h>
                     44: #include <sys/systm.h>
                     45: #include <sys/signalvar.h>
                     46: #include <sys/kernel.h>
                     47: #include <sys/kthread.h>
                     48: #include <sys/rwlock.h>
                     49: #include <sys/proc.h>
                     50: #include <sys/user.h>
                     51: #include <sys/malloc.h>
                     52: #include <sys/device.h>
                     53: #include <sys/fcntl.h>
                     54: #include <sys/ioctl.h>
                     55: #include <sys/event.h>
                     56: #include <sys/mount.h> /* for vfs_syncwait() proto */
                     57:
                     58: #include <machine/conf.h>
                     59: #include <machine/cpu.h>
                     60: #include <machine/cpufunc.h>
                     61: #include <machine/gdt.h>
                     62: #include <machine/psl.h>
                     63:
                     64: #include <dev/isa/isareg.h>
                     65: #include <i386/isa/isa_machdep.h>
                     66: #include <i386/isa/nvram.h>
                     67: #include <dev/isa/isavar.h>
                     68:
                     69: #include <machine/biosvar.h>
                     70: #include <machine/apmvar.h>
                     71:
                     72: #if defined(APMDEBUG)
                     73: #define DPRINTF(x)     printf x
                     74: #else
                     75: #define        DPRINTF(x)      /**/
                     76: #endif
                     77:
                     78: struct cfdriver apm_cd = {
                     79:        NULL, "apm", DV_DULL
                     80: };
                     81:
                     82: struct apm_softc {
                     83:        struct device sc_dev;
                     84:        struct klist sc_note;
                     85:        int     sc_flags;
                     86:        int     batt_life;
                     87:        struct proc *sc_thread;
                     88:        struct rwlock sc_lock;
                     89: };
                     90: #define        SCFLAG_OREAD    0x0000001
                     91: #define        SCFLAG_OWRITE   0x0000002
                     92: #define        SCFLAG_OPEN     (SCFLAG_OREAD|SCFLAG_OWRITE)
                     93:
                     94: int    apmprobe(struct device *, void *, void *);
                     95: void   apmattach(struct device *, struct device *, void *);
                     96:
                     97: struct cfattach apm_ca = {
                     98:        sizeof(struct apm_softc), apmprobe, apmattach
                     99: };
                    100:
                    101: void   filt_apmrdetach(struct knote *kn);
                    102: int    filt_apmread(struct knote *kn, long hint);
                    103:
                    104: struct filterops apmread_filtops = {
                    105:        1, NULL, filt_apmrdetach, filt_apmread
                    106: };
                    107:
                    108: /* battery percentage at where we get verbose in our warnings.  This
                    109:  * value can be changed using sysctl(8), value machdep.apmwarn.
                    110:  * Setting it to zero kills all warnings
                    111:  */
                    112: int    cpu_apmwarn = 10;
                    113:
                    114: #define        APM_RESUME_HOLDOFF      3
                    115:
                    116: /*
                    117:  * Flags to control kernel display
                    118:  *     SCFLAG_NOPRINT:         do not output APM power messages due to
                    119:  *                             a power change event.
                    120:  *
                    121:  *     SCFLAG_PCTPRINT:        do not output APM power messages due to
                    122:  *                             to a power change event unless the battery
                    123:  *                             percentage changes.
                    124:  */
                    125: #define SCFLAG_NOPRINT 0x0008000
                    126: #define SCFLAG_PCTPRINT        0x0004000
                    127: #define SCFLAG_PRINT   (SCFLAG_NOPRINT|SCFLAG_PCTPRINT)
                    128:
                    129: #define        APMUNIT(dev)    (minor(dev)&0xf0)
                    130: #define        APMDEV(dev)     (minor(dev)&0x0f)
                    131: #define APMDEV_NORMAL  0
                    132: #define APMDEV_CTL     8
                    133:
                    134: int    apm_standbys;
                    135: int    apm_userstandbys;
                    136: int    apm_suspends;
                    137: int    apm_resumes;
                    138: int    apm_battlow;
                    139: int    apm_evindex;
                    140: int    apm_error;
                    141: int    apm_op_inprog;
                    142:
                    143: u_int  apm_flags;
                    144: u_char apm_majver;
                    145: u_char apm_minver;
                    146: int    apm_dobusy = 0;
                    147: int    apm_doidle = 0;
                    148: int    apm_bebatt = 0;
                    149: int    apm_idle_called = 0;
                    150: int    apm_attached = 0;
                    151:
                    152: struct {
                    153:        u_int32_t entry;
                    154:        u_int16_t seg;
                    155:        u_int16_t pad;
                    156: } apm_ep;
                    157:
                    158: struct apmregs {
                    159:        u_int32_t       ax;
                    160:        u_int32_t       bx;
                    161:        u_int32_t       cx;
                    162:        u_int32_t       dx;
                    163: };
                    164:
                    165: int  apmcall(u_int, u_int, struct apmregs *);
                    166: void apm_power_print(struct apm_softc *, struct apmregs *);
                    167: int  apm_handle_event(struct apm_softc *, struct apmregs *);
                    168: void apm_set_ver(struct apm_softc *);
                    169: int  apm_periodic_check(struct apm_softc *);
                    170: void apm_thread_create(void *v);
                    171: void apm_thread(void *);
                    172: void apm_disconnect(struct apm_softc *);
                    173: void apm_perror(const char *, struct apmregs *);
                    174: void apm_powmgt_enable(int onoff);
                    175: void apm_powmgt_engage(int onoff, u_int devid);
                    176: /* void apm_devpowmgt_enable(int onoff, u_int devid); */
                    177: int  apm_record_event(struct apm_softc *sc, u_int type);
                    178: const char *apm_err_translate(int code);
                    179:
                    180: #define        apm_get_powstat(r) apmcall(APM_POWER_STATUS, APM_DEV_ALLDEVS, r)
                    181: void   apm_standby(void);
                    182: void   apm_suspend(void);
                    183: void   apm_resume(struct apm_softc *, struct apmregs *);
                    184:
                    185: static int __inline
                    186: apm_get_event(struct apmregs *r)
                    187: {
                    188:        int rv;
                    189:
                    190:        bzero(r, sizeof(*r));
                    191:        rv = apmcall(APM_GET_PM_EVENT, 0, r);
                    192:        return rv;
                    193: }
                    194:
                    195: const char *
                    196: apm_err_translate(int code)
                    197: {
                    198:        switch (code) {
                    199:        case APM_ERR_PM_DISABLED:
                    200:                return "power management disabled";
                    201:        case APM_ERR_REALALREADY:
                    202:                return "real mode interface already connected";
                    203:        case APM_ERR_NOTCONN:
                    204:                return "interface not connected";
                    205:        case APM_ERR_16ALREADY:
                    206:                return "16-bit interface already connected";
                    207:        case APM_ERR_16NOTSUPP:
                    208:                return "16-bit interface not supported";
                    209:        case APM_ERR_32ALREADY:
                    210:                return "32-bit interface already connected";
                    211:        case APM_ERR_32NOTSUPP:
                    212:                return "32-bit interface not supported";
                    213:        case APM_ERR_UNRECOG_DEV:
                    214:                return "unrecognized device ID";
                    215:        case APM_ERR_ERANGE:
                    216:                return "parameter out of range";
                    217:        case APM_ERR_NOTENGAGED:
                    218:                return "interface not engaged";
                    219:        case APM_ERR_UNABLE:
                    220:                return "unable to enter requested state";
                    221:        case APM_ERR_NOEVENTS:
                    222:                return "No pending events";
                    223:        case APM_ERR_NOT_PRESENT:
                    224:                return "No APM present";
                    225:        default:
                    226:                return "unknown error code?";
                    227:        }
                    228: }
                    229:
                    230: int apmerrors = 0;
                    231:
                    232: void
                    233: apm_perror(const char *str, struct apmregs *regs)
                    234: {
                    235:        printf("apm0: APM %s: %s (%d)\n", str,
                    236:            apm_err_translate(APM_ERR_CODE(regs)),
                    237:            APM_ERR_CODE(regs));
                    238:        delay(1000000);
                    239:
                    240:        apmerrors++;
                    241: }
                    242:
                    243: void
                    244: apm_power_print (struct apm_softc *sc, struct apmregs *regs)
                    245: {
                    246: #if !defined(APM_NOPRINT)
                    247:        sc->batt_life = BATT_LIFE(regs);
                    248:        if (BATT_LIFE(regs) != APM_BATT_LIFE_UNKNOWN) {
                    249:                printf("%s: battery life expectancy %d%%\n",
                    250:                    sc->sc_dev.dv_xname,
                    251:                    BATT_LIFE(regs));
                    252:        }
                    253:        printf("%s: AC ", sc->sc_dev.dv_xname);
                    254:        switch (AC_STATE(regs)) {
                    255:        case APM_AC_OFF:
                    256:                printf("off,");
                    257:                break;
                    258:        case APM_AC_ON:
                    259:                printf("on,");
                    260:                break;
                    261:        case APM_AC_BACKUP:
                    262:                printf("backup power,");
                    263:                break;
                    264:        default:
                    265:        case APM_AC_UNKNOWN:
                    266:                printf("unknown,");
                    267:                break;
                    268:        }
                    269:        if (apm_minver == 0) {
                    270:                printf(" battery is ");
                    271:                switch (BATT_STATE(regs)) {
                    272:                case APM_BATT_HIGH:
                    273:                        printf("high");
                    274:                        break;
                    275:                case APM_BATT_LOW:
                    276:                        printf("low");
                    277:                        break;
                    278:                case APM_BATT_CRITICAL:
                    279:                        printf("CRITICAL");
                    280:                        break;
                    281:                case APM_BATT_CHARGING:
                    282:                        printf("charging");
                    283:                        break;
                    284:                case APM_BATT_UNKNOWN:
                    285:                        printf("unknown");
                    286:                        break;
                    287:                default:
                    288:                        printf("undecoded (%x)", BATT_STATE(regs));
                    289:                        break;
                    290:                }
                    291:        } else if (apm_minver >= 1) {
                    292:                if (BATT_FLAGS(regs) & APM_BATT_FLAG_NOBATTERY)
                    293:                        printf(" no battery");
                    294:                else {
                    295:                        printf(" battery charge ");
                    296:                        if (BATT_FLAGS(regs) & APM_BATT_FLAG_HIGH)
                    297:                                printf("high");
                    298:                        else if (BATT_FLAGS(regs) & APM_BATT_FLAG_LOW)
                    299:                                printf("low");
                    300:                        else if (BATT_FLAGS(regs) & APM_BATT_FLAG_CRITICAL)
                    301:                                printf("critical");
                    302:                        else
                    303:                                printf("unknown");
                    304:                        if (BATT_FLAGS(regs) & APM_BATT_FLAG_CHARGING)
                    305:                                printf(", charging");
                    306:                        if (BATT_REM_VALID(regs)) {
                    307:                                int life = BATT_REMAINING(regs);
                    308:                                if (apm_bebatt)
                    309:                                        life = swap16(life);
                    310:                                printf(", estimated %d:%02d hours",
                    311:                                    life / 60, life % 60);
                    312:                        }
                    313:                }
                    314:        }
                    315:
                    316:        printf("\n");
                    317: #endif
                    318: }
                    319:
                    320: void
                    321: apm_suspend()
                    322: {
                    323:        dopowerhooks(PWR_SUSPEND);
                    324:
                    325:        if (cold)
                    326:                vfs_syncwait(0);
                    327:
                    328:        (void)apm_set_powstate(APM_DEV_ALLDEVS, APM_SYS_SUSPEND);
                    329: }
                    330:
                    331: void
                    332: apm_standby()
                    333: {
                    334:        dopowerhooks(PWR_STANDBY);
                    335:
                    336:        if (cold)
                    337:                vfs_syncwait(0);
                    338:
                    339:        (void)apm_set_powstate(APM_DEV_ALLDEVS, APM_SYS_STANDBY);
                    340: }
                    341:
                    342: void
                    343: apm_resume(struct apm_softc *sc, struct apmregs *regs)
                    344: {
                    345:        extern int perflevel;
                    346:
                    347:        apm_resumes = APM_RESUME_HOLDOFF;
                    348:
                    349:        /* they say that some machines may require reinitializing the clock */
                    350:        initrtclock();
                    351:
                    352:        inittodr(time_second);
                    353:        /* lower bit in cx means pccard was powered down */
                    354:        dopowerhooks(PWR_RESUME);
                    355:        apm_record_event(sc, regs->bx);
                    356:
                    357:        /* acknowledge any rtc interrupt we may have missed */
                    358:        rtcdrain(NULL);
                    359:
                    360:        /* restore hw.setperf */
                    361:        if (cpu_setperf != NULL)
                    362:                cpu_setperf(perflevel);
                    363: }
                    364:
                    365: int
                    366: apm_record_event(struct apm_softc *sc, u_int type)
                    367: {
                    368:        if (!apm_error && (sc->sc_flags & SCFLAG_OPEN) == 0) {
                    369:                DPRINTF(("apm_record_event: no user waiting\n"));
                    370:                apm_error++;
                    371:                return 1;
                    372:        }
                    373:
                    374:        apm_evindex++;
                    375:        KNOTE(&sc->sc_note, APM_EVENT_COMPOSE(type, apm_evindex));
                    376:        return (0);
                    377: }
                    378:
                    379: int
                    380: apm_handle_event(struct apm_softc *sc, struct apmregs *regs)
                    381: {
                    382:        struct apmregs nregs;
                    383:        int ret = 0;
                    384:
                    385:        switch (regs->bx) {
                    386:        case APM_NOEVENT:
                    387:                ret++;
                    388:                break;
                    389:
                    390:        case APM_USER_STANDBY_REQ:
                    391:                if (apm_resumes || apm_op_inprog)
                    392:                        break;
                    393:                DPRINTF(("user wants STANDBY--fat chance\n"));
                    394:                apm_op_inprog++;
                    395:                if (apm_record_event(sc, regs->bx)) {
                    396:                        DPRINTF(("standby ourselves\n"));
                    397:                        apm_userstandbys++;
                    398:                }
                    399:                break;
                    400:        case APM_STANDBY_REQ:
                    401:                if (apm_resumes || apm_op_inprog)
                    402:                        break;
                    403:                DPRINTF(("standby requested\n"));
                    404:                if (apm_standbys || apm_suspends) {
                    405:                        DPRINTF(("premature standby\n"));
                    406:                        apm_error++;
                    407:                        ret++;
                    408:                }
                    409:                apm_op_inprog++;
                    410:                if (apm_record_event(sc, regs->bx)) {
                    411:                        DPRINTF(("standby ourselves\n"));
                    412:                        apm_standbys++;
                    413:                }
                    414:                break;
                    415:        case APM_USER_SUSPEND_REQ:
                    416:                if (apm_resumes || apm_op_inprog)
                    417:                        break;
                    418:                DPRINTF(("user wants suspend--fat chance!\n"));
                    419:                apm_op_inprog++;
                    420:                if (apm_record_event(sc, regs->bx)) {
                    421:                        DPRINTF(("suspend ourselves\n"));
                    422:                        apm_suspends++;
                    423:                }
                    424:                break;
                    425:        case APM_SUSPEND_REQ:
                    426:                if (apm_resumes || apm_op_inprog)
                    427:                        break;
                    428:                DPRINTF(("suspend requested\n"));
                    429:                if (apm_standbys || apm_suspends) {
                    430:                        DPRINTF(("premature suspend\n"));
                    431:                        apm_error++;
                    432:                        ret++;
                    433:                }
                    434:                apm_op_inprog++;
                    435:                if (apm_record_event(sc, regs->bx)) {
                    436:                        DPRINTF(("suspend ourselves\n"));
                    437:                        apm_suspends++;
                    438:                }
                    439:                break;
                    440:        case APM_POWER_CHANGE:
                    441:                DPRINTF(("power status change\n"));
                    442:                if (apm_get_powstat(&nregs) == 0 &&
                    443:                    BATT_LIFE(&nregs) != APM_BATT_LIFE_UNKNOWN &&
                    444:                    BATT_LIFE(&nregs) < cpu_apmwarn &&
                    445:                    (sc->sc_flags & SCFLAG_PRINT) != SCFLAG_NOPRINT &&
                    446:                    ((sc->sc_flags & SCFLAG_PRINT) != SCFLAG_PCTPRINT ||
                    447:                     sc->batt_life != BATT_LIFE(&nregs)))
                    448:                        apm_power_print(sc, &nregs);
                    449:                apm_record_event(sc, regs->bx);
                    450:                break;
                    451:        case APM_NORMAL_RESUME:
                    452:                DPRINTF(("system resumed\n"));
                    453:                apm_resume(sc, regs);
                    454:                break;
                    455:        case APM_CRIT_RESUME:
                    456:                DPRINTF(("system resumed without us!\n"));
                    457:                apm_resume(sc, regs);
                    458:                break;
                    459:        case APM_SYS_STANDBY_RESUME:
                    460:                DPRINTF(("system standby resume\n"));
                    461:                apm_resume(sc, regs);
                    462:                break;
                    463:        case APM_UPDATE_TIME:
                    464:                DPRINTF(("update time, please\n"));
                    465:                inittodr(time_second);
                    466:                apm_record_event(sc, regs->bx);
                    467:                break;
                    468:        case APM_CRIT_SUSPEND_REQ:
                    469:                DPRINTF(("suspend required immediately\n"));
                    470:                apm_record_event(sc, regs->bx);
                    471:                apm_suspend();
                    472:                break;
                    473:        case APM_BATTERY_LOW:
                    474:                DPRINTF(("Battery low!\n"));
                    475:                apm_battlow++;
                    476:                apm_record_event(sc, regs->bx);
                    477:                break;
                    478:        case APM_CAPABILITY_CHANGE:
                    479:                DPRINTF(("capability change\n"));
                    480:                if (apm_minver < 2) {
                    481:                        DPRINTF(("adult event\n"));
                    482:                } else {
                    483:                        if (apmcall(APM_GET_CAPABILITIES, APM_DEV_APM_BIOS,
                    484:                            &nregs) != 0) {
                    485:                                apm_perror("get capabilities", &nregs);
                    486:                        } else {
                    487:                                apm_get_powstat(&nregs);
                    488:                        }
                    489:                }
                    490:                break;
                    491:        default: {
                    492: #ifdef APMDEBUG
                    493:                char *p;
                    494:                switch (regs->bx >> 8) {
                    495:                case 0: p = "reserved system";  break;
                    496:                case 1: p = "reserved device";  break;
                    497:                case 2: p = "OEM defined";      break;
                    498:                default:p = "reserved";         break;
                    499:                }
                    500: #endif
                    501:                DPRINTF(("apm_handle_event: %s event, code %d\n", p, regs->bx));
                    502:            }
                    503:        }
                    504:        return ret;
                    505: }
                    506:
                    507: int
                    508: apm_periodic_check(struct apm_softc *sc)
                    509: {
                    510:        struct apmregs regs;
                    511:        int ret = 0;
                    512:
                    513:        if (apm_op_inprog)
                    514:                apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_INPROG);
                    515:
                    516:        while (1) {
                    517:                if (apm_get_event(&regs) != 0) {
                    518:                        /* i think some bioses combine the error codes */
                    519:                        if (!(APM_ERR_CODE(&regs) & APM_ERR_NOEVENTS))
                    520:                                apm_perror("get event", &regs);
                    521:                        break;
                    522:                }
                    523:
                    524:                if (apm_handle_event(sc, &regs))
                    525:                        break;
                    526:        }
                    527:
                    528:        if (apm_error || APM_ERR_CODE(&regs) == APM_ERR_NOTCONN)
                    529:                ret = -1;
                    530:
                    531:        if (apm_suspends /*|| (apm_battlow && apm_userstandbys)*/) {
                    532:                apm_op_inprog = 0;
                    533:                apm_suspend();
                    534:        } else if (apm_standbys || apm_userstandbys) {
                    535:                apm_op_inprog = 0;
                    536:                apm_standby();
                    537:        }
                    538:        apm_suspends = apm_standbys = apm_battlow = apm_userstandbys = 0;
                    539:        apm_error = 0;
                    540:
                    541:        if (apm_resumes)
                    542:                apm_resumes--;
                    543:        return (ret);
                    544: }
                    545:
                    546: void
                    547: apm_powmgt_enable(int onoff)
                    548: {
                    549:        struct apmregs regs;
                    550:
                    551:        bzero(&regs, sizeof(regs));
                    552:        regs.cx = onoff ? APM_MGT_ENABLE : APM_MGT_DISABLE;
                    553:        if (apmcall(APM_PWR_MGT_ENABLE,
                    554:            (apm_minver? APM_DEV_APM_BIOS : APM_MGT_ALL), &regs) != 0)
                    555:                apm_perror("power management enable", &regs);
                    556: }
                    557:
                    558: void
                    559: apm_powmgt_engage(int onoff, u_int dev)
                    560: {
                    561:        struct apmregs regs;
                    562:
                    563:        if (apm_minver == 0)
                    564:                return;
                    565:        bzero(&regs, sizeof(regs));
                    566:        regs.cx = onoff ? APM_MGT_ENGAGE : APM_MGT_DISENGAGE;
                    567:        if (apmcall(APM_PWR_MGT_ENGAGE, dev, &regs) != 0)
                    568:                printf("apm0: APM engage (device %x): %s (%d)\n",
                    569:                    dev, apm_err_translate(APM_ERR_CODE(&regs)),
                    570:                    APM_ERR_CODE(&regs));
                    571: }
                    572:
                    573: #ifdef notused
                    574: void
                    575: apm_devpowmgt_enable(int onoff, u_int dev)
                    576: {
                    577:        struct apmregs regs;
                    578:
                    579:        if (apm_minver == 0)
                    580:                return;
                    581:        /* enable is auto BIOS management.
                    582:         * disable is program control.
                    583:         */
                    584:        bzero(&regs, sizeof(regs));
                    585:        regs.cx = onoff ? APM_MGT_ENABLE : APM_MGT_DISABLE;
                    586:        if (apmcall(APM_DEVICE_MGMT_ENABLE, dev, &regs) != 0)
                    587:                printf("APM device engage (device %x): %s (%d)\n",
                    588:                    dev, apm_err_translate(APM_ERR_CODE(&regs)),
                    589:                    APM_ERR_CODE(&regs));
                    590: }
                    591: #endif
                    592:
                    593: int
                    594: apm_set_powstate(u_int dev, u_int state)
                    595: {
                    596:        struct apmregs regs;
                    597:
                    598:        if (!apm_cd.cd_ndevs || (apm_minver == 0 && state > APM_SYS_OFF))
                    599:                return EINVAL;
                    600:        bzero(&regs, sizeof(regs));
                    601:        regs.cx = state;
                    602:        if (apmcall(APM_SET_PWR_STATE, dev, &regs) != 0) {
                    603:                apm_perror("set power state", &regs);
                    604:                if (APM_ERR_CODE(&regs) == APM_ERR_UNRECOG_DEV)
                    605:                        return ENXIO;
                    606:                else
                    607:                        return EIO;
                    608:        }
                    609:        return 0;
                    610: }
                    611:
                    612: void
                    613: apm_cpu_busy(void)
                    614: {
                    615:        struct apmregs regs;
                    616:
                    617:        if (!apm_cd.cd_ndevs)   /* No APM device, punt */
                    618:                return;
                    619:        if (!apm_dobusy)
                    620:                return;
                    621:        if (!apm_idle_called)
                    622:                return;
                    623:
                    624:        if (apm_flags & APM_IDLE_SLOWS) {
                    625:                bzero(&regs, sizeof(regs));
                    626:                if (apmcall(APM_CPU_BUSY, 0, &regs) != 0) {
                    627: #ifdef DIAGNOSTIC
                    628:                        apm_perror("set CPU busy", &regs);
                    629: #endif
                    630:                }
                    631:                apm_idle_called = 0;
                    632:        }
                    633: }
                    634:
                    635: void
                    636: apm_cpu_idle(void)
                    637: {
                    638:        struct apmregs regs;
                    639:        static u_int64_t call_apm = 0;
                    640:
                    641:        if (!apm_cd.cd_ndevs) { /* No APM device, wait for next interrupt */
                    642:                __asm __volatile("sti;hlt");
                    643:                return;
                    644:        }
                    645:
                    646:        if (!apm_doidle) {
                    647:                __asm __volatile("sti;hlt");
                    648:                return;
                    649:        }
                    650:
                    651:        /*
                    652:         * We call the bios APM_IDLE routine here only when we
                    653:         * have been idle for some time - otherwise we just hlt.
                    654:         */
                    655:
                    656:        if  (call_apm != curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]) {
                    657:                /* Always call BIOS halt/idle stuff */
                    658:                bzero(&regs, sizeof(regs));
                    659:                if (apmcall(APM_CPU_IDLE, 0, &regs) != 0) {
                    660: #ifdef APMDEBUG
                    661:                        apm_perror("set CPU idle", &regs);
                    662: #endif
                    663:                }
                    664:                apm_idle_called = 1;
                    665:                /* If BIOS did halt, don't do it again! */
                    666:                if (apm_flags & APM_IDLE_SLOWS) {
                    667:                        __asm __volatile("sti;hlt");
                    668:                }
                    669:                call_apm = curcpu()->ci_schedstate.spc_cp_time[CP_IDLE];
                    670:        } else {
                    671:                __asm __volatile("sti;hlt");
                    672:        }
                    673: }
                    674:
                    675: void
                    676: apm_set_ver(struct apm_softc *self)
                    677: {
                    678:        struct apmregs regs;
                    679:        int rv = 0;
                    680:
                    681:        bzero(&regs, sizeof(regs));
                    682:        regs.cx = APM_VERSION;
                    683:
                    684:        if (APM_MAJOR(apm_flags) == 1 && APM_MINOR(apm_flags) == 2 &&
                    685:            (rv = apmcall(APM_DRIVER_VERSION, APM_DEV_APM_BIOS, &regs)) == 0) {
                    686:                apm_majver = APM_CONN_MAJOR(&regs);
                    687:                apm_minver = APM_CONN_MINOR(&regs);
                    688:        } else {
                    689: #ifdef APMDEBUG
                    690:                if (rv)
                    691:                        apm_perror("set version 1.2", &regs);
                    692: #endif
                    693:                /* try downgrading to 1.1 */
                    694:                bzero(&regs, sizeof(regs));
                    695:                regs.cx = 0x0101;
                    696:
                    697:                if (apmcall(APM_DRIVER_VERSION, APM_DEV_APM_BIOS, &regs) == 0) {
                    698:                        apm_majver = 1;
                    699:                        apm_minver = 1;
                    700:                } else {
                    701: #ifdef APMDEBUG
                    702:                        apm_perror("set version 1.1", &regs);
                    703: #endif
                    704:                        /* stay w/ flags then */
                    705:                        apm_majver = APM_MAJOR(apm_flags);
                    706:                        apm_minver = APM_MINOR(apm_flags);
                    707:
                    708:                        /* fix version for some endianess-challenged compaqs */
                    709:                        if (!apm_majver) {
                    710:                                apm_majver = 1;
                    711:                                apm_minver = 0;
                    712:                        }
                    713:                }
                    714:        }
                    715:        printf(": Power Management spec V%d.%d", apm_majver, apm_minver);
                    716:        if (apm_flags & APM_IDLE_SLOWS) {
                    717:                DPRINTF((" (slowidle)"));
                    718:                apm_dobusy = 1;
                    719:                apm_doidle = 1;
                    720:        } else {
                    721:                apm_dobusy = 0;
                    722:                apm_doidle = 1;
                    723:        }
                    724: #ifdef DIAGNOSTIC
                    725:        if (apm_flags & APM_BIOS_PM_DISABLED)
                    726:                printf(" (BIOS mgmt disabled)");
                    727:        if (apm_flags & APM_BIOS_PM_DISENGAGED)
                    728:                printf(" (BIOS managing devices)");
                    729: #endif
                    730:        printf("\n");
                    731: }
                    732:
                    733: void
                    734: apm_disconnect(struct apm_softc *sc)
                    735: {
                    736:        struct apmregs regs;
                    737:
                    738:        bzero(&regs, sizeof(regs));
                    739:        if (apmcall(APM_SYSTEM_DEFAULTS,
                    740:            (apm_minver == 1 ? APM_DEV_ALLDEVS : APM_DEFAULTS_ALL), &regs))
                    741:                apm_perror("system defaults failed", &regs);
                    742:
                    743:        if (apmcall(APM_DISCONNECT, APM_DEV_APM_BIOS, &regs))
                    744:                apm_perror("disconnect failed", &regs);
                    745:        else
                    746:                printf("%s: disconnected\n", sc->sc_dev.dv_xname);
                    747:        apm_flags |= APM_BIOS_PM_DISABLED;
                    748: }
                    749:
                    750: int
                    751: apmprobe(struct device *parent, void *match, void *aux)
                    752: {
                    753:        struct bios_attach_args *ba = aux;
                    754:        bios_apminfo_t *ap = ba->bios_apmp;
                    755:        bus_space_handle_t ch, dh;
                    756:
                    757:        if (apm_cd.cd_ndevs || strcmp(ba->bios_dev, "apm") ||
                    758:            !(ba->bios_apmp->apm_detail & APM_32BIT_SUPPORTED)) {
                    759:                DPRINTF(("%s: %x\n", ba->bios_dev, ba->bios_apmp->apm_detail));
                    760:                return 0;
                    761:        }
                    762:
                    763:        /* addresses check
                    764:           since pc* console and vga* probes much later
                    765:           we cannot check for video memory being mapped
                    766:           for apm stuff w/ bus_space_map() */
                    767:        if (ap->apm_code_len == 0 ||
                    768:            (ap->apm_code32_base < IOM_BEGIN &&
                    769:             ap->apm_code32_base + ap->apm_code_len > IOM_BEGIN) ||
                    770:            (ap->apm_code16_base < IOM_BEGIN &&
                    771:             ap->apm_code16_base + ap->apm_code16_len > IOM_BEGIN) ||
                    772:            (ap->apm_data_base < IOM_BEGIN &&
                    773:             ap->apm_data_base + ap->apm_data_len > IOM_BEGIN))
                    774:                return 0;
                    775:
                    776:        if (bus_space_map(ba->bios_memt, ap->apm_code32_base,
                    777:            ap->apm_code_len, 1, &ch) != 0) {
                    778:                DPRINTF(("apm0: can't map code\n"));
                    779:                return 0;
                    780:        }
                    781:        bus_space_unmap(ba->bios_memt, ch, ap->apm_code_len);
                    782:
                    783:        if (bus_space_map(ba->bios_memt, ap->apm_data_base,
                    784:            ap->apm_data_len, 1, &dh) != 0) {
                    785:                DPRINTF(("apm0: can't map data\n"));
                    786:                return 0;
                    787:        }
                    788:        bus_space_unmap(ba->bios_memt, dh, ap->apm_data_len);
                    789:        return 1;
                    790: }
                    791:
                    792: void
                    793: apmattach(struct device *parent, struct device *self, void *aux)
                    794: {
                    795:        struct bios_attach_args *ba = aux;
                    796:        bios_apminfo_t *ap = ba->bios_apmp;
                    797:        struct apm_softc *sc = (void *)self;
                    798:        struct apmregs regs;
                    799:        u_int cbase, clen, l;
                    800:        bus_space_handle_t ch16, ch32, dh;
                    801:
                    802:        apm_flags = ap->apm_detail;
                    803:        /*
                    804:         * set up GDT descriptors for APM
                    805:         */
                    806:        if (apm_flags & APM_32BIT_SUPPORTED) {
                    807:
                    808:                /* truncate segments' limits to a page */
                    809:                ap->apm_code_len -= (ap->apm_code32_base +
                    810:                    ap->apm_code_len + 1) & 0xfff;
                    811:                ap->apm_code16_len -= (ap->apm_code16_base +
                    812:                    ap->apm_code16_len + 1) & 0xfff;
                    813:                ap->apm_data_len -= (ap->apm_data_base +
                    814:                    ap->apm_data_len + 1) & 0xfff;
                    815:
                    816:                /* adjust version */
                    817:                if ((sc->sc_dev.dv_cfdata->cf_flags & APM_VERMASK) &&
                    818:                    (apm_flags & APM_VERMASK) !=
                    819:                    (sc->sc_dev.dv_cfdata->cf_flags & APM_VERMASK))
                    820:                        apm_flags = (apm_flags & ~APM_VERMASK) |
                    821:                            (sc->sc_dev.dv_cfdata->cf_flags & APM_VERMASK);
                    822:                if (sc->sc_dev.dv_cfdata->cf_flags & APM_NOCLI) {
                    823:                        extern int apm_cli; /* from apmcall.S */
                    824:                        apm_cli = 0;
                    825:                }
                    826:                if (sc->sc_dev.dv_cfdata->cf_flags & APM_BEBATT)
                    827:                        apm_bebatt = 1;
                    828:                apm_ep.seg = GSEL(GAPM32CODE_SEL,SEL_KPL);
                    829:                apm_ep.entry = ap->apm_entry;
                    830:                cbase = min(ap->apm_code32_base, ap->apm_code16_base);
                    831:                clen = max(ap->apm_code32_base + ap->apm_code_len,
                    832:                           ap->apm_code16_base + ap->apm_code16_len) - cbase;
                    833:                if ((cbase <= ap->apm_data_base &&
                    834:                     cbase + clen >= ap->apm_data_base) ||
                    835:                    (ap->apm_data_base <= cbase &&
                    836:                     ap->apm_data_base + ap->apm_data_len >= cbase)) {
                    837:                        l = max(ap->apm_data_base + ap->apm_data_len + 1,
                    838:                                cbase + clen + 1) -
                    839:                            min(ap->apm_data_base, cbase);
                    840:                        bus_space_map(ba->bios_memt,
                    841:                                min(ap->apm_data_base, cbase),
                    842:                                l, 1, &dh);
                    843:                        ch16 = dh;
                    844:                        if (ap->apm_data_base < cbase)
                    845:                                ch16 += cbase - ap->apm_data_base;
                    846:                        else
                    847:                                dh += ap->apm_data_base - cbase;
                    848:                } else {
                    849:
                    850:                        bus_space_map(ba->bios_memt, cbase, clen + 1, 1, &ch16);
                    851:                        bus_space_map(ba->bios_memt, ap->apm_data_base,
                    852:                            ap->apm_data_len + 1, 1, &dh);
                    853:                }
                    854:                ch32 = ch16;
                    855:                if (ap->apm_code16_base == cbase)
                    856:                        ch32 += ap->apm_code32_base - cbase;
                    857:                else
                    858:                        ch16 += ap->apm_code16_base - cbase;
                    859:
                    860:                setgdt(GAPM32CODE_SEL, (void *)ch32, ap->apm_code_len,
                    861:                    SDT_MEMERA, SEL_KPL, 1, 0);
                    862:                setgdt(GAPM16CODE_SEL, (void *)ch16, ap->apm_code16_len,
                    863:                    SDT_MEMERA, SEL_KPL, 0, 0);
                    864:                setgdt(GAPMDATA_SEL, (void *)dh, ap->apm_data_len, SDT_MEMRWA,
                    865:                    SEL_KPL, 1, 0);
                    866:                DPRINTF((": flags %x code 32:%x/%x[%x] 16:%x/%x[%x] "
                    867:                    "data %x/%x/%x ep %x (%x:%x)\n%s", apm_flags,
                    868:                    ap->apm_code32_base, ch32, ap->apm_code_len,
                    869:                    ap->apm_code16_base, ch16, ap->apm_code16_len,
                    870:                    ap->apm_data_base, dh, ap->apm_data_len,
                    871:                    ap->apm_entry, apm_ep.seg, ap->apm_entry+ch32,
                    872:                    sc->sc_dev.dv_xname));
                    873:
                    874:                apm_set_ver(sc);
                    875:
                    876:                if (apm_flags & APM_BIOS_PM_DISABLED)
                    877:                        apm_powmgt_enable(1);
                    878:                /*
                    879:                 * Engage cooperative power mgt (we get to do it)
                    880:                 * on all devices (v1.1).
                    881:                 */
                    882:                apm_powmgt_engage(1, APM_DEV_ALLDEVS);
                    883:
                    884:                bzero(&regs, sizeof(regs));
                    885:                if (apm_get_powstat(&regs) == 0)
                    886:                        apm_power_print(sc, &regs);
                    887:                else
                    888:                        apm_perror("get power status", &regs);
                    889:                apm_cpu_busy();
                    890:
                    891:                rw_init(&sc->sc_lock, "apmlk");
                    892:
                    893:                /*
                    894:                 * Do a check once, ignoring any errors. This avoids
                    895:                 * gratuitous APM disconnects on laptops where the first
                    896:                 * event in the queue (after a boot) is non-recognizable.
                    897:                 * The IBM ThinkPad 770Z is one of those.
                    898:                 */
                    899:                apm_periodic_check(sc);
                    900:
                    901:                if (apm_periodic_check(sc) == -1) {
                    902:                        apm_disconnect(sc);
                    903:                        apm_dobusy = apm_doidle = 0;
                    904:                } else {
                    905:                        kthread_create_deferred(apm_thread_create, sc);
                    906:                        apm_attached = 1;
                    907:                }
                    908:        } else {
                    909:                setgdt(GAPM32CODE_SEL, NULL, 0, 0, 0, 0, 0);
                    910:                setgdt(GAPM16CODE_SEL, NULL, 0, 0, 0, 0, 0);
                    911:                setgdt(GAPMDATA_SEL, NULL, 0, 0, 0, 0, 0);
                    912:        }
                    913:        /* XXX - To go away */
                    914:        printf("apm0: flags %x dobusy %d doidle %d\n",
                    915:            apm_flags, apm_dobusy, apm_doidle);
                    916: }
                    917:
                    918: void
                    919: apm_thread_create(void *v)
                    920: {
                    921:        struct apm_softc *sc = v;
                    922:
                    923: #ifdef MULTIPROCESSOR
                    924:        if (ncpus > 1) {
                    925:                apm_disconnect(sc);
                    926:                apm_dobusy = apm_doidle = 0;
                    927:                return;
                    928:        }
                    929: #endif
                    930:
                    931:        if (kthread_create(apm_thread, sc, &sc->sc_thread, "%s",
                    932:            sc->sc_dev.dv_xname)) {
                    933:                apm_disconnect(sc);
                    934:                printf("%s: failed to create kernel thread, disabled",
                    935:                    sc->sc_dev.dv_xname);
                    936:                apm_dobusy = apm_doidle = 0;
                    937:        }
                    938: }
                    939:
                    940: void
                    941: apm_thread(void *v)
                    942: {
                    943:        struct apm_softc *sc = v;
                    944:
                    945:        for (;;) {
                    946:                rw_enter_write(&sc->sc_lock);
                    947:                (void) apm_periodic_check(sc);
                    948:                rw_exit_write(&sc->sc_lock);
                    949:                tsleep(&lbolt, PWAIT, "apmev", 0);
                    950:        }
                    951: }
                    952:
                    953: int
                    954: apmopen(dev_t dev, int flag, int mode, struct proc *p)
                    955: {
                    956:        struct apm_softc *sc;
                    957:        int error = 0;
                    958:
                    959:        /* apm0 only */
                    960:        if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
                    961:            !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
                    962:                return ENXIO;
                    963:
                    964:        if (apm_flags & APM_BIOS_PM_DISABLED)
                    965:                return ENXIO;
                    966:
                    967:        DPRINTF(("apmopen: dev %d pid %d flag %x mode %x\n",
                    968:            APMDEV(dev), p->p_pid, flag, mode));
                    969:
                    970:        rw_enter_write(&sc->sc_lock);
                    971:        switch (APMDEV(dev)) {
                    972:        case APMDEV_CTL:
                    973:                if (!(flag & FWRITE)) {
                    974:                        error = EINVAL;
                    975:                        break;
                    976:                }
                    977:                if (sc->sc_flags & SCFLAG_OWRITE) {
                    978:                        error = EBUSY;
                    979:                        break;
                    980:                }
                    981:                sc->sc_flags |= SCFLAG_OWRITE;
                    982:                break;
                    983:        case APMDEV_NORMAL:
                    984:                if (!(flag & FREAD) || (flag & FWRITE)) {
                    985:                        error = EINVAL;
                    986:                        break;
                    987:                }
                    988:                sc->sc_flags |= SCFLAG_OREAD;
                    989:                break;
                    990:        default:
                    991:                error = ENXIO;
                    992:                break;
                    993:        }
                    994:        rw_exit_write(&sc->sc_lock);
                    995:        return error;
                    996: }
                    997:
                    998: int
                    999: apmclose(dev_t dev, int flag, int mode, struct proc *p)
                   1000: {
                   1001:        struct apm_softc *sc;
                   1002:
                   1003:        /* apm0 only */
                   1004:        if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
                   1005:            !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
                   1006:                return ENXIO;
                   1007:
                   1008:        DPRINTF(("apmclose: pid %d flag %x mode %x\n", p->p_pid, flag, mode));
                   1009:
                   1010:        rw_enter_write(&sc->sc_lock);
                   1011:        switch (APMDEV(dev)) {
                   1012:        case APMDEV_CTL:
                   1013:                sc->sc_flags &= ~SCFLAG_OWRITE;
                   1014:                break;
                   1015:        case APMDEV_NORMAL:
                   1016:                sc->sc_flags &= ~SCFLAG_OREAD;
                   1017:                break;
                   1018:        }
                   1019:        rw_exit_write(&sc->sc_lock);
                   1020:        return 0;
                   1021: }
                   1022:
                   1023: int
                   1024: apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
                   1025: {
                   1026:        struct apm_softc *sc;
                   1027:        struct apmregs regs;
                   1028:        int error = 0;
                   1029:
                   1030:        /* apm0 only */
                   1031:        if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
                   1032:            !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
                   1033:                return ENXIO;
                   1034:
                   1035:        rw_enter_write(&sc->sc_lock);
                   1036:        switch (cmd) {
                   1037:                /* some ioctl names from linux */
                   1038:        case APM_IOC_STANDBY:
                   1039:                if ((flag & FWRITE) == 0)
                   1040:                        error = EBADF;
                   1041:                else
                   1042:                        apm_userstandbys++;
                   1043:                break;
                   1044:        case APM_IOC_SUSPEND:
                   1045:                if ((flag & FWRITE) == 0)
                   1046:                        error = EBADF;
                   1047:                else
                   1048:                        apm_suspends++;
                   1049:                break;
                   1050:        case APM_IOC_PRN_CTL:
                   1051:                if ((flag & FWRITE) == 0)
                   1052:                        error = EBADF;
                   1053:                else {
                   1054:                        int flag = *(int *)data;
                   1055:                        DPRINTF(( "APM_IOC_PRN_CTL: %d\n", flag ));
                   1056:                        switch (flag) {
                   1057:                        case APM_PRINT_ON:      /* enable printing */
                   1058:                                sc->sc_flags &= ~SCFLAG_PRINT;
                   1059:                                break;
                   1060:                        case APM_PRINT_OFF: /* disable printing */
                   1061:                                sc->sc_flags &= ~SCFLAG_PRINT;
                   1062:                                sc->sc_flags |= SCFLAG_NOPRINT;
                   1063:                                break;
                   1064:                        case APM_PRINT_PCT: /* disable some printing */
                   1065:                                sc->sc_flags &= ~SCFLAG_PRINT;
                   1066:                                sc->sc_flags |= SCFLAG_PCTPRINT;
                   1067:                                break;
                   1068:                        default:
                   1069:                                error = EINVAL;
                   1070:                                break;
                   1071:                        }
                   1072:                }
                   1073:                break;
                   1074:        case APM_IOC_DEV_CTL:
                   1075:                if ((flag & FWRITE) == 0)
                   1076:                        error = EBADF;
                   1077:                else {
                   1078:                        struct apm_ctl *actl = (struct apm_ctl *)data;
                   1079:
                   1080:                        bzero(&regs, sizeof(regs));
                   1081:                        if (!apmcall(APM_GET_POWER_STATE, actl->dev, &regs))
                   1082:                                printf("%s: dev %04x state %04x\n",
                   1083:                                    sc->sc_dev.dv_xname, dev, regs.cx);
                   1084:
                   1085:                        error = apm_set_powstate(actl->dev, actl->mode);
                   1086:                }
                   1087:                break;
                   1088:        case APM_IOC_GETPOWER:
                   1089:                if (apm_get_powstat(&regs) == 0) {
                   1090:                        struct apm_power_info *powerp =
                   1091:                            (struct apm_power_info *)data;
                   1092:
                   1093:                        bzero(powerp, sizeof(*powerp));
                   1094:                        if (BATT_LIFE(&regs) != APM_BATT_LIFE_UNKNOWN)
                   1095:                                powerp->battery_life = BATT_LIFE(&regs);
                   1096:                        powerp->ac_state = AC_STATE(&regs);
                   1097:                        switch (apm_minver) {
                   1098:                        case 0:
                   1099:                                if (!(BATT_FLAGS(&regs) & APM_BATT_FLAG_NOBATTERY))
                   1100:                                        powerp->battery_state = BATT_STATE(&regs);
                   1101:                                break;
                   1102:                        case 1:
                   1103:                        default:
                   1104:                                if (BATT_FLAGS(&regs) & APM_BATT_FLAG_HIGH)
                   1105:                                        powerp->battery_state = APM_BATT_HIGH;
                   1106:                                else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_LOW)
                   1107:                                        powerp->battery_state = APM_BATT_LOW;
                   1108:                                else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_CRITICAL)
                   1109:                                        powerp->battery_state = APM_BATT_CRITICAL;
                   1110:                                else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_CHARGING)
                   1111:                                        powerp->battery_state = APM_BATT_CHARGING;
                   1112:                                else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_NOBATTERY)
                   1113:                                        powerp->battery_state = APM_BATTERY_ABSENT;
                   1114:                                else
                   1115:                                        powerp->battery_state = APM_BATT_UNKNOWN;
                   1116:                                if (BATT_REM_VALID(&regs)) {
                   1117:                                        powerp->minutes_left = BATT_REMAINING(&regs);
                   1118:                                        if (apm_bebatt)
                   1119:                                                powerp->minutes_left =
                   1120:                                                    swap16(powerp->minutes_left);
                   1121:                                }
                   1122:                        }
                   1123:                } else {
                   1124:                        apm_perror("ioctl get power status", &regs);
                   1125:                        error = EIO;
                   1126:                }
                   1127:                break;
                   1128:
                   1129:        default:
                   1130:                error = ENOTTY;
                   1131:        }
                   1132:
                   1133:        rw_exit_write(&sc->sc_lock);
                   1134:        return error;
                   1135: }
                   1136:
                   1137: void
                   1138: filt_apmrdetach(struct knote *kn)
                   1139: {
                   1140:        struct apm_softc *sc = (struct apm_softc *)kn->kn_hook;
                   1141:
                   1142:        rw_enter_write(&sc->sc_lock);
                   1143:        SLIST_REMOVE(&sc->sc_note, kn, knote, kn_selnext);
                   1144:        rw_exit_write(&sc->sc_lock);
                   1145: }
                   1146:
                   1147: int
                   1148: filt_apmread(struct knote *kn, long hint)
                   1149: {
                   1150:        /* XXX weird kqueue_scan() semantics */
                   1151:        if (hint && !kn->kn_data)
                   1152:                kn->kn_data = (int)hint;
                   1153:        return (1);
                   1154: }
                   1155:
                   1156: int
                   1157: apmkqfilter(dev_t dev, struct knote *kn)
                   1158: {
                   1159:        struct apm_softc *sc;
                   1160:
                   1161:        /* apm0 only */
                   1162:        if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
                   1163:            !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
                   1164:                return ENXIO;
                   1165:
                   1166:        switch (kn->kn_filter) {
                   1167:        case EVFILT_READ:
                   1168:                kn->kn_fop = &apmread_filtops;
                   1169:                break;
                   1170:        default:
                   1171:                return (1);
                   1172:        }
                   1173:
                   1174:        kn->kn_hook = (caddr_t)sc;
                   1175:
                   1176:        rw_enter_write(&sc->sc_lock);
                   1177:        SLIST_INSERT_HEAD(&sc->sc_note, kn, kn_selnext);
                   1178:        rw_exit_write(&sc->sc_lock);
                   1179:        return (0);
                   1180: }

CVSweb