diff options
Diffstat (limited to 'sys/arch/loongson/dev/apm.c')
-rw-r--r-- | sys/arch/loongson/dev/apm.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/sys/arch/loongson/dev/apm.c b/sys/arch/loongson/dev/apm.c new file mode 100644 index 00000000000..13afdf8a094 --- /dev/null +++ b/sys/arch/loongson/dev/apm.c @@ -0,0 +1,346 @@ +/* $OpenBSD: apm.c,v 1.1 2010/02/28 08:30:27 otto Exp $ */ + +/*- + * Copyright (c) 2001 Alexander Guy. All rights reserved. + * Copyright (c) 1998-2001 Michael Shalayeff. All rights reserved. + * Copyright (c) 1995 John T. Kohl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the authors nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "apm.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> +#include <sys/event.h> + +#include <machine/autoconf.h> +#include <machine/conf.h> +#include <machine/cpu.h> +#include <machine/apmvar.h> + + + +#if defined(APMDEBUG) +#define DPRINTF(x) printf x +#else +#define DPRINTF(x) /**/ +#endif + +struct apm_softc { + struct device sc_dev; + struct klist sc_note; + int sc_flags; +}; + +int apmmatch(struct device *, void *, void *); +void apmattach(struct device *, struct device *, void *); + +struct cfattach apm_ca = { + sizeof(struct apm_softc), apmmatch, apmattach +}; + +struct cfdriver apm_cd = { + NULL, "apm", DV_DULL +}; + +#define APMUNIT(dev) (minor(dev)&0xf0) +#define APMDEV(dev) (minor(dev)&0x0f) +#define APMDEV_NORMAL 0 +#define APMDEV_CTL 8 + +void filt_apmrdetach(struct knote *kn); +int filt_apmread(struct knote *kn, long hint); +int apmkqfilter(dev_t dev, struct knote *kn); +int apm_getdefaultinfo(struct apm_power_info *); + +struct filterops apmread_filtops = + { 1, NULL, filt_apmrdetach, filt_apmread}; + +int (*get_apminfo)(struct apm_power_info *) = apm_getdefaultinfo; + +/* + * Flags to control kernel display + * SCFLAG_NOPRINT: do not output APM power messages due to + * a power change event. + * + * SCFLAG_PCTPRINT: do not output APM power messages due to + * to a power change event unless the battery + * percentage changes. + */ + +#define SCFLAG_NOPRINT 0x0008000 +#define SCFLAG_PCTPRINT 0x0004000 +#define SCFLAG_PRINT (SCFLAG_NOPRINT|SCFLAG_PCTPRINT) + +#define SCFLAG_OREAD (1 << 0) +#define SCFLAG_OWRITE (1 << 1) +#define SCFLAG_OPEN (SCFLAG_OREAD|SCFLAG_OWRITE) + + +int +apmmatch(struct device *parent, void *match, void *aux) +{ + struct mainbus_attach_args *maa = aux; + + if (strcmp(maa->maa_name, apm_cd.cd_name) == 0) + return (1); + return (0); +} + +void +apmattach(struct device *parent, struct device *self, void *aux) +{ + printf("\n"); +} + +int +apmopen(dev_t dev, int flag, int mode, struct proc *p) +{ + struct apm_softc *sc; + int error = 0; + + /* apm0 only */ + if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 || + !(sc = apm_cd.cd_devs[APMUNIT(dev)])) + return ENXIO; + + DPRINTF(("apmopen: dev %d pid %d flag %x mode %x\n", + APMDEV(dev), p->p_pid, flag, mode)); + + switch (APMDEV(dev)) { + case APMDEV_CTL: + if (!(flag & FWRITE)) { + error = EINVAL; + break; + } + if (sc->sc_flags & SCFLAG_OWRITE) { + error = EBUSY; + break; + } + sc->sc_flags |= SCFLAG_OWRITE; + break; + case APMDEV_NORMAL: + if (!(flag & FREAD) || (flag & FWRITE)) { + error = EINVAL; + break; + } + sc->sc_flags |= SCFLAG_OREAD; + break; + default: + error = ENXIO; + break; + } + return error; +} + +int +apmclose(dev_t dev, int flag, int mode, struct proc *p) +{ + struct apm_softc *sc; + + /* apm0 only */ + if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 || + !(sc = apm_cd.cd_devs[APMUNIT(dev)])) + return ENXIO; + + DPRINTF(("apmclose: pid %d flag %x mode %x\n", p->p_pid, flag, mode)); + + switch (APMDEV(dev)) { + case APMDEV_CTL: + sc->sc_flags &= ~SCFLAG_OWRITE; + break; + case APMDEV_NORMAL: + sc->sc_flags &= ~SCFLAG_OREAD; + break; + } + return 0; +} + +int +apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct apm_softc *sc; + struct apm_power_info *power; + int error = 0; + + /* apm0 only */ + if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 || + !(sc = apm_cd.cd_devs[APMUNIT(dev)])) + return ENXIO; + + switch (cmd) { + /* some ioctl names from linux */ + case APM_IOC_STANDBY: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = EOPNOTSUPP; /* XXX */ + break; + case APM_IOC_SUSPEND: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = EOPNOTSUPP; /* XXX */ + break; + case APM_IOC_PRN_CTL: + if ((flag & FWRITE) == 0) + error = EBADF; + else { + int flag = *(int *)data; + DPRINTF(( "APM_IOC_PRN_CTL: %d\n", flag )); + switch (flag) { + case APM_PRINT_ON: /* enable printing */ + sc->sc_flags &= ~SCFLAG_PRINT; + break; + case APM_PRINT_OFF: /* disable printing */ + sc->sc_flags &= ~SCFLAG_PRINT; + sc->sc_flags |= SCFLAG_NOPRINT; + break; + case APM_PRINT_PCT: /* disable some printing */ + sc->sc_flags &= ~SCFLAG_PRINT; + sc->sc_flags |= SCFLAG_PCTPRINT; + break; + default: + error = EINVAL; + break; + } + } + break; + case APM_IOC_DEV_CTL: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = EOPNOTSUPP; /* XXX */ + break; + case APM_IOC_GETPOWER: + power = (struct apm_power_info *)data; + error = (*get_apminfo)(power); + break; + case APM_IOC_STANDBY_REQ: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = EOPNOTSUPP; /* XXX */ + break; + case APM_IOC_SUSPEND_REQ: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = EOPNOTSUPP; /* XXX */ + break; + default: + error = ENOTTY; + } + + return error; +} + +void +filt_apmrdetach(struct knote *kn) +{ + struct apm_softc *sc = (struct apm_softc *)kn->kn_hook; + + SLIST_REMOVE(&sc->sc_note, kn, knote, kn_selnext); +} + +int +filt_apmread(struct knote *kn, long hint) +{ + /* XXX weird kqueue_scan() semantics */ + if (hint && !kn->kn_data) + kn->kn_data = (int)hint; + + return (1); +} + +int +apmkqfilter(dev_t dev, struct knote *kn) +{ + struct apm_softc *sc; + + /* apm0 only */ + if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 || + !(sc = apm_cd.cd_devs[APMUNIT(dev)])) + return ENXIO; + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &apmread_filtops; + break; + default: + return (1); + } + + kn->kn_hook = (caddr_t)sc; + SLIST_INSERT_HEAD(&sc->sc_note, kn, kn_selnext); + + return (0); +} + +int +apm_getdefaultinfo(struct apm_power_info *info) +{ + info->battery_state = APM_BATTERY_ABSENT; + info->ac_state = APM_AC_ON; + info->battery_life = 0; + info->minutes_left = 0; + return (0); +} + +void +apm_setinfohook(int (*hook)(struct apm_power_info *)) +{ + get_apminfo = hook; +} + +int +apm_record_event(u_int event, const char *src, const char *msg) +{ + static int apm_evindex; + struct apm_softc *sc; + + /* apm0 only */ + if (apm_cd.cd_ndevs == 0 || (sc = apm_cd.cd_devs[0]) == NULL) + return ENXIO; + + if ((sc->sc_flags & SCFLAG_NOPRINT) == 0) + printf("%s: %s %s\n", sc->sc_dev.dv_xname, src, msg); + + /* skip if no user waiting */ + if ((sc->sc_flags & SCFLAG_OPEN) == 0) + return (1); + + apm_evindex++; + KNOTE(&sc->sc_note, APM_EVENT_COMPOSE(event, apm_evindex)); + + return (0); +} |