Annotation of sys/arch/macppc/dev/apm.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: apm.c,v 1.12 2006/01/18 23:21:17 miod Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 2001 Alexander Guy. All rights reserved.
! 5: * Copyright (c) 1998-2001 Michael Shalayeff. All rights reserved.
! 6: * Copyright (c) 1995 John T. Kohl. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed by the University of
! 19: * California, Berkeley and its contributors.
! 20: * 4. Neither the name of the University nor the names of its contributors
! 21: * may be used to endorse or promote products derived from this software
! 22: * without specific prior written permission.
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 30: * OR SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 34: * SUCH DAMAGE.
! 35: *
! 36: */
! 37:
! 38: #include "apm.h"
! 39:
! 40: #if NAPM > 1
! 41: #error only one APM emulation device may be configured
! 42: #endif
! 43:
! 44: #include <sys/param.h>
! 45: #include <sys/systm.h>
! 46: #include <sys/kernel.h>
! 47: #include <sys/proc.h>
! 48: #include <sys/device.h>
! 49: #include <sys/fcntl.h>
! 50: #include <sys/ioctl.h>
! 51: #include <sys/event.h>
! 52:
! 53: #include <machine/conf.h>
! 54: #include <machine/cpu.h>
! 55: #include <machine/apmvar.h>
! 56:
! 57: #include <dev/adb/adb.h>
! 58: #include <macppc/dev/adbvar.h>
! 59: #include <macppc/dev/pm_direct.h>
! 60:
! 61: #if defined(APMDEBUG)
! 62: #define DPRINTF(x) printf x
! 63: #else
! 64: #define DPRINTF(x) /**/
! 65: #endif
! 66:
! 67: struct apm_softc {
! 68: struct device sc_dev;
! 69: struct klist sc_note;
! 70: int sc_flags;
! 71: };
! 72:
! 73: int apmmatch(struct device *, void *, void *);
! 74: void apmattach(struct device *, struct device *, void *);
! 75:
! 76: struct cfattach apm_ca = {
! 77: sizeof(struct apm_softc), apmmatch, apmattach
! 78: };
! 79:
! 80: struct cfdriver apm_cd = {
! 81: NULL, "apm", DV_DULL
! 82: };
! 83:
! 84: #define APMUNIT(dev) (minor(dev)&0xf0)
! 85: #define APMDEV(dev) (minor(dev)&0x0f)
! 86: #define APMDEV_NORMAL 0
! 87: #define APMDEV_CTL 8
! 88:
! 89: void filt_apmrdetach(struct knote *kn);
! 90: int filt_apmread(struct knote *kn, long hint);
! 91: int apmkqfilter(dev_t dev, struct knote *kn);
! 92:
! 93: struct filterops apmread_filtops =
! 94: { 1, NULL, filt_apmrdetach, filt_apmread};
! 95:
! 96: /*
! 97: * Flags to control kernel display
! 98: * SCFLAG_NOPRINT: do not output APM power messages due to
! 99: * a power change event.
! 100: *
! 101: * SCFLAG_PCTPRINT: do not output APM power messages due to
! 102: * to a power change event unless the battery
! 103: * percentage changes.
! 104: */
! 105:
! 106: #define SCFLAG_NOPRINT 0x0008000
! 107: #define SCFLAG_PCTPRINT 0x0004000
! 108: #define SCFLAG_PRINT (SCFLAG_NOPRINT|SCFLAG_PCTPRINT)
! 109:
! 110: #define SCFLAG_OREAD (1 << 0)
! 111: #define SCFLAG_OWRITE (1 << 1)
! 112: #define SCFLAG_OPEN (SCFLAG_OREAD|SCFLAG_OWRITE)
! 113:
! 114:
! 115: int
! 116: apmmatch(struct device *parent, void *match, void *aux)
! 117: {
! 118: struct adb_attach_args *aa = (void *)aux;
! 119: if (aa->origaddr != ADBADDR_APM ||
! 120: aa->handler_id != ADBADDR_APM ||
! 121: aa->adbaddr != ADBADDR_APM)
! 122: return 0;
! 123:
! 124: if (adbHardware != ADB_HW_PMU)
! 125: return 0;
! 126:
! 127: return 1;
! 128: }
! 129:
! 130: void
! 131: apmattach(struct device *parent, struct device *self, void *aux)
! 132: {
! 133: struct pmu_battery_info info;
! 134:
! 135: pm_battery_info(0, &info);
! 136:
! 137: printf(": battery flags 0x%X, ", info.flags);
! 138: printf("%d%% charged\n", ((info.cur_charge * 100) / info.max_charge));
! 139: }
! 140:
! 141: int
! 142: apmopen(dev_t dev, int flag, int mode, struct proc *p)
! 143: {
! 144: struct apm_softc *sc;
! 145: int error = 0;
! 146:
! 147: /* apm0 only */
! 148: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
! 149: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
! 150: return ENXIO;
! 151:
! 152: DPRINTF(("apmopen: dev %d pid %d flag %x mode %x\n",
! 153: APMDEV(dev), p->p_pid, flag, mode));
! 154:
! 155: switch (APMDEV(dev)) {
! 156: case APMDEV_CTL:
! 157: if (!(flag & FWRITE)) {
! 158: error = EINVAL;
! 159: break;
! 160: }
! 161: if (sc->sc_flags & SCFLAG_OWRITE) {
! 162: error = EBUSY;
! 163: break;
! 164: }
! 165: sc->sc_flags |= SCFLAG_OWRITE;
! 166: break;
! 167: case APMDEV_NORMAL:
! 168: if (!(flag & FREAD) || (flag & FWRITE)) {
! 169: error = EINVAL;
! 170: break;
! 171: }
! 172: sc->sc_flags |= SCFLAG_OREAD;
! 173: break;
! 174: default:
! 175: error = ENXIO;
! 176: break;
! 177: }
! 178: return error;
! 179: }
! 180:
! 181: int
! 182: apmclose(dev_t dev, int flag, int mode, struct proc *p)
! 183: {
! 184: struct apm_softc *sc;
! 185:
! 186: /* apm0 only */
! 187: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
! 188: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
! 189: return ENXIO;
! 190:
! 191: DPRINTF(("apmclose: pid %d flag %x mode %x\n", p->p_pid, flag, mode));
! 192:
! 193: switch (APMDEV(dev)) {
! 194: case APMDEV_CTL:
! 195: sc->sc_flags &= ~SCFLAG_OWRITE;
! 196: break;
! 197: case APMDEV_NORMAL:
! 198: sc->sc_flags &= ~SCFLAG_OREAD;
! 199: break;
! 200: }
! 201: return 0;
! 202: }
! 203:
! 204: int
! 205: apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 206: {
! 207: struct apm_softc *sc;
! 208: struct pmu_battery_info batt;
! 209: struct apm_power_info *power;
! 210: int error = 0;
! 211:
! 212: /* apm0 only */
! 213: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
! 214: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
! 215: return ENXIO;
! 216:
! 217: switch (cmd) {
! 218: /* some ioctl names from linux */
! 219: case APM_IOC_STANDBY:
! 220: if ((flag & FWRITE) == 0)
! 221: error = EBADF;
! 222: break;
! 223: case APM_IOC_SUSPEND:
! 224: if ((flag & FWRITE) == 0)
! 225: error = EBADF;
! 226: break;
! 227: case APM_IOC_PRN_CTL:
! 228: if ((flag & FWRITE) == 0)
! 229: error = EBADF;
! 230: else {
! 231: int flag = *(int *)data;
! 232: DPRINTF(( "APM_IOC_PRN_CTL: %d\n", flag ));
! 233: switch (flag) {
! 234: case APM_PRINT_ON: /* enable printing */
! 235: sc->sc_flags &= ~SCFLAG_PRINT;
! 236: break;
! 237: case APM_PRINT_OFF: /* disable printing */
! 238: sc->sc_flags &= ~SCFLAG_PRINT;
! 239: sc->sc_flags |= SCFLAG_NOPRINT;
! 240: break;
! 241: case APM_PRINT_PCT: /* disable some printing */
! 242: sc->sc_flags &= ~SCFLAG_PRINT;
! 243: sc->sc_flags |= SCFLAG_PCTPRINT;
! 244: break;
! 245: default:
! 246: error = EINVAL;
! 247: break;
! 248: }
! 249: }
! 250: break;
! 251: case APM_IOC_DEV_CTL:
! 252: if ((flag & FWRITE) == 0)
! 253: error = EBADF;
! 254: break;
! 255: case APM_IOC_GETPOWER:
! 256: power = (struct apm_power_info *)data;
! 257:
! 258: pm_battery_info(0, &batt);
! 259:
! 260: power->ac_state = ((batt.flags & PMU_PWR_AC_PRESENT) ?
! 261: APM_AC_ON : APM_AC_OFF);
! 262: power->battery_life =
! 263: ((batt.cur_charge * 100) / batt.max_charge);
! 264:
! 265: /*
! 266: * If the battery is charging, return the minutes left until
! 267: * charging is complete. apmd knows this.
! 268: */
! 269:
! 270: if (!(batt.flags & PMU_PWR_BATT_PRESENT)) {
! 271: power->battery_state = APM_BATT_UNKNOWN;
! 272: power->minutes_left = 0;
! 273: power->battery_life = 0;
! 274: } else if ((power->ac_state == APM_AC_ON) &&
! 275: (batt.draw > 0)) {
! 276: power->minutes_left =
! 277: (((batt.max_charge - batt.cur_charge) * 3600) /
! 278: batt.draw) / 60;
! 279: power->battery_state = APM_BATT_CHARGING;
! 280: } else {
! 281: power->minutes_left =
! 282: ((batt.cur_charge * 3600) / (-batt.draw)) / 60;
! 283:
! 284: /* XXX - Arbitrary */
! 285: if (power->battery_life > 60)
! 286: power->battery_state = APM_BATT_HIGH;
! 287: else if (power->battery_life < 10)
! 288: power->battery_state = APM_BATT_CRITICAL;
! 289: else
! 290: power->battery_state = APM_BATT_LOW;
! 291: }
! 292: break;
! 293:
! 294: default:
! 295: error = ENOTTY;
! 296: }
! 297:
! 298: return error;
! 299: }
! 300:
! 301: void
! 302: filt_apmrdetach(struct knote *kn)
! 303: {
! 304: struct apm_softc *sc = (struct apm_softc *)kn->kn_hook;
! 305:
! 306: SLIST_REMOVE(&sc->sc_note, kn, knote, kn_selnext);
! 307: }
! 308:
! 309: int
! 310: filt_apmread(struct knote *kn, long hint)
! 311: {
! 312: /* XXX weird kqueue_scan() semantics */
! 313: if (hint && !kn->kn_data)
! 314: kn->kn_data = (int)hint;
! 315:
! 316: return (1);
! 317: }
! 318:
! 319: int
! 320: apmkqfilter(dev_t dev, struct knote *kn)
! 321: {
! 322: struct apm_softc *sc;
! 323:
! 324: /* apm0 only */
! 325: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
! 326: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
! 327: return ENXIO;
! 328:
! 329: switch (kn->kn_filter) {
! 330: case EVFILT_READ:
! 331: kn->kn_fop = &apmread_filtops;
! 332: break;
! 333: default:
! 334: return (1);
! 335: }
! 336:
! 337: kn->kn_hook = (caddr_t)sc;
! 338: SLIST_INSERT_HEAD(&sc->sc_note, kn, kn_selnext);
! 339:
! 340: return (0);
! 341: }
CVSweb