[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     ! 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