summaryrefslogtreecommitdiff
path: root/sys/arch/loongson
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2010-02-28 08:30:28 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2010-02-28 08:30:28 +0000
commitc518dd2600807e5276d21b9657745e6d5f4a9deb (patch)
tree959188edada0f5d7d75c046e952d1dd1c6507700 /sys/arch/loongson
parent79999529fca020d754c68793ff897c9230212875 (diff)
Basic apm(4), providing battery/power status and events. apm(4) is the
generic part, ykbec(4) provides the device specific parts. Other battery/power status drivers can easily hook to adb(4). With help from miod@; ok matthieu@ miod@ jasper@
Diffstat (limited to 'sys/arch/loongson')
-rw-r--r--sys/arch/loongson/conf/GENERIC3
-rw-r--r--sys/arch/loongson/conf/files.loongson6
-rw-r--r--sys/arch/loongson/dev/apm.c346
-rw-r--r--sys/arch/loongson/dev/kb3310.c223
-rw-r--r--sys/arch/loongson/dev/mainbus.c5
-rw-r--r--sys/arch/loongson/include/apmvar.h125
-rw-r--r--sys/arch/loongson/include/conf.h42
-rw-r--r--sys/arch/loongson/loongson/conf.c8
8 files changed, 676 insertions, 82 deletions
diff --git a/sys/arch/loongson/conf/GENERIC b/sys/arch/loongson/conf/GENERIC
index b9ed254b97f..a1eb201d101 100644
--- a/sys/arch/loongson/conf/GENERIC
+++ b/sys/arch/loongson/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.15 2010/02/26 14:53:11 miod Exp $
+# $OpenBSD: GENERIC,v 1.16 2010/02/28 08:30:27 otto Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -30,6 +30,7 @@ config bsd swap generic
mainbus0 at root
cpu0 at mainbus0
clock0 at mainbus0
+apm0 at mainbus0
# Main local buses
bonito* at mainbus0
diff --git a/sys/arch/loongson/conf/files.loongson b/sys/arch/loongson/conf/files.loongson
index a5099a90154..2536d626614 100644
--- a/sys/arch/loongson/conf/files.loongson
+++ b/sys/arch/loongson/conf/files.loongson
@@ -1,4 +1,4 @@
-# $OpenBSD: files.loongson,v 1.7 2010/02/26 14:53:11 miod Exp $
+# $OpenBSD: files.loongson,v 1.8 2010/02/28 08:30:27 otto Exp $
# Standard stanzas config(8) can't run without
maxpartitions 16
@@ -107,3 +107,7 @@ device smfb: wsemuldisplaydev, rasops16
attach smfb at pci with smfb_pci
attach smfb at voyager with smfb_voyager
file arch/loongson/dev/smfb.c smfb needs-flag
+
+device apm
+attach apm at mainbus
+file arch/loongson/dev/apm.c apm needs-flag
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);
+}
diff --git a/sys/arch/loongson/dev/kb3310.c b/sys/arch/loongson/dev/kb3310.c
index 600a5c24cac..38d1842dbbb 100644
--- a/sys/arch/loongson/dev/kb3310.c
+++ b/sys/arch/loongson/dev/kb3310.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kb3310.c,v 1.4 2010/02/24 18:29:39 otto Exp $ */
+/* $OpenBSD: kb3310.c,v 1.5 2010/02/28 08:30:27 otto Exp $ */
/*
* Copyright (c) 2010 Otto Moerbeek <otto@drijf.net>
*
@@ -21,9 +21,12 @@
#include <sys/device.h>
#include <sys/sensors.h>
+#include <machine/apmvar.h>
#include <machine/bus.h>
#include <dev/isa/isavar.h>
+#include "apm.h"
+
struct cfdriver ykbec_cd = {
NULL, "ykbec", DV_DULL,
};
@@ -31,13 +34,40 @@ struct cfdriver ykbec_cd = {
#define IO_YKBEC 0x381
#define IO_YKBECSIZE 0x3
-#define KB3310_NUM_SENSORS 12
+static const struct {
+ const char *desc;
+ int type;
+} ykbec_table[] = {
+#define YKBEC_FAN 0
+ { NULL, SENSOR_FANRPM },
+#define YKBEC_ITEMP 1
+ { "Internal temperature", SENSOR_TEMP },
+#define YKBEC_DCAP 2
+ { "Battery design capacity", SENSOR_AMPHOUR },
+#define YKBEC_FCAP 3
+ { "Battery full charge capacity", SENSOR_AMPHOUR },
+#define YKBEC_DVOLT 4
+ { "Battery design voltage", SENSOR_VOLTS_DC },
+#define YKBEC_BCURRENT 5
+ { "Battery current", SENSOR_AMPS },
+#define YKBEC_BVOLT 6
+ { "Battery voltage", SENSOR_VOLTS_DC },
+#define YKBEC_BTEMP 7
+ { "Battery temperature", SENSOR_TEMP },
+#define YKBEC_CAP 8
+ { "Battery capacity", SENSOR_PERCENT },
+#define YKBEC_CHARGING 9
+ { "Battery charging", SENSOR_INDICATOR },
+#define YKBEC_AC 10
+ { "AC-Power", SENSOR_INDICATOR }
+#define YKBEC_NSENSORS 11
+};
struct ykbec_softc {
struct device sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
- struct ksensor sc_sensor[KB3310_NUM_SENSORS];
+ struct ksensor sc_sensor[YKBEC_NSENSORS];
struct ksensordev sc_sensordev;
};
@@ -54,6 +84,21 @@ void ykbec_write(struct ykbec_softc *, u_int, u_int);
u_int ykbec_read(struct ykbec_softc *, u_int);
u_int ykbec_read16(struct ykbec_softc *, u_int);
+#if NAPM > 0
+int ykbec_apminfo(struct apm_power_info *);
+struct apm_power_info ykbec_apmdata;
+const char *ykbec_batstate[] = {
+ "high",
+ "low",
+ "critical",
+ "charging",
+ "unknown"
+};
+#define BATTERY_STRING(x) ((x) < nitems(ykbec_batstate) ? \
+ ykbec_batstate[x] : ykbec_batstate[4])
+#endif
+
+
int
ykbec_match(struct device *parent, void *match, void *aux)
{
@@ -83,6 +128,7 @@ ykbec_attach( struct device *parent, struct device *self, void *aux)
{
struct isa_attach_args *ia = aux;
struct ykbec_softc *sc = (struct ykbec_softc *)self;
+ int i;
sc->sc_iot = ia->ia_iot;
if (bus_space_map(sc->sc_iot, ia->ia_iobase, ia->ia_iosize, 0,
@@ -98,66 +144,20 @@ ykbec_attach( struct device *parent, struct device *self, void *aux)
printf(", unable to register update task\n");
return;
}
- sc->sc_sensor[0].type = SENSOR_FANRPM;
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[0]);
-
- sc->sc_sensor[1].type = SENSOR_TEMP;
- strlcpy(sc->sc_sensor[1].desc, "Internal temperature",
- sizeof(sc->sc_sensor[1].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[1]);
-
- sc->sc_sensor[2].type = SENSOR_AMPHOUR;
- strlcpy(sc->sc_sensor[2].desc, "Battery design capacity",
- sizeof(sc->sc_sensor[2].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[2]);
-
- sc->sc_sensor[3].type = SENSOR_AMPHOUR;
- strlcpy(sc->sc_sensor[3].desc, "Battery full charge capacity",
- sizeof(sc->sc_sensor[3].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[3]);
-
- sc->sc_sensor[4].type = SENSOR_VOLTS_DC;
- strlcpy(sc->sc_sensor[4].desc, "Battery design voltage",
- sizeof(sc->sc_sensor[4].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[4]);
-
- sc->sc_sensor[5].type = SENSOR_AMPS;
- strlcpy(sc->sc_sensor[5].desc, "Battery current",
- sizeof(sc->sc_sensor[5].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[5]);
-
- sc->sc_sensor[6].type = SENSOR_VOLTS_DC;
- strlcpy(sc->sc_sensor[6].desc, "Battery voltage",
- sizeof(sc->sc_sensor[6].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[6]);
-
- sc->sc_sensor[7].type = SENSOR_TEMP;
- strlcpy(sc->sc_sensor[7].desc, "Battery temperature",
- sizeof(sc->sc_sensor[7].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[7]);
-
- sc->sc_sensor[8].type = SENSOR_PERCENT;
- strlcpy(sc->sc_sensor[8].desc, "Battery capacity",
- sizeof(sc->sc_sensor[8].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[8]);
-
- sc->sc_sensor[9].type = SENSOR_INDICATOR;
- strlcpy(sc->sc_sensor[9].desc, "Battery charging",
- sizeof(sc->sc_sensor[9].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[9]);
-
- sc->sc_sensor[10].type = SENSOR_INDICATOR;
- strlcpy(sc->sc_sensor[10].desc, "AC-Power",
- sizeof(sc->sc_sensor[10].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[10]);
-
- sc->sc_sensor[11].type = SENSOR_INTEGER;
- strlcpy(sc->sc_sensor[11].desc, "Battery low-level status",
- sizeof(sc->sc_sensor[11].desc));
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[11]);
+
+ for (i = 0; i < YKBEC_NSENSORS; i++) {
+ sc->sc_sensor[i].type = ykbec_table[i].type;
+ if (ykbec_table[i].desc)
+ strlcpy(sc->sc_sensor[i].desc, ykbec_table[i].desc,
+ sizeof(sc->sc_sensor[i].desc));
+ sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
+ }
sensordev_install(&sc->sc_sensordev);
+#if NAPM > 0
+ apm_setinfohook(ykbec_apminfo);
+#endif
printf("\n");
}
@@ -247,33 +247,43 @@ ykbec_refresh(void *arg)
{
struct ykbec_softc *sc = (struct ykbec_softc *)arg;
u_int val, bat_charge, bat_status, charge_status, bat_state, power_flag;
+ u_int cap_pct, fullcap;
int current;
+#if NAPM > 0
+ struct apm_power_info old;
+#endif
val = ykbec_read16(sc, REG_FAN_SPEED_HIGH) & 0xfffff;
- if (val != 0)
+ if (val != 0) {
val = KB3310_FAN_SPEED_DIVIDER / val;
- else
- val = UINT_MAX;
- sc->sc_sensor[0].value = val;
+ sc->sc_sensor[YKBEC_FAN].value = val;
+ sc->sc_sensor[YKBEC_FAN].flags &= ~SENSOR_FINVALID;
+ } else
+ sc->sc_sensor[YKBEC_FAN].flags |= SENSOR_FINVALID;
val = ykbec_read(sc, ECTEMP_CURRENT_REG);
- sc->sc_sensor[1].value = val * 1000000 + 273150000;
+ sc->sc_sensor[YKBEC_ITEMP].value = val * 1000000 + 273150000;
- sc->sc_sensor[2].value = ykbec_read16(sc, REG_DESIGN_CAP_HIGH) * 1000;
- sc->sc_sensor[3].value = ykbec_read16(sc, REG_FULLCHG_CAP_HIGH) * 1000;
- sc->sc_sensor[4].value = ykbec_read16(sc, REG_DESIGN_VOL_HIGH) * 1000;
+ sc->sc_sensor[YKBEC_DCAP].value = ykbec_read16(sc, REG_DESIGN_CAP_HIGH)
+ * 1000;
+ fullcap = ykbec_read16(sc, REG_FULLCHG_CAP_HIGH);
+ sc->sc_sensor[YKBEC_FCAP].value = fullcap * 1000;
+ sc->sc_sensor[YKBEC_DVOLT].value = ykbec_read16(sc, REG_DESIGN_VOL_HIGH)
+ * 1000;
current = ykbec_read16(sc, REG_CURRENT_HIGH);
/* sign extend short -> int, int -> int64 will be done next statement */
current |= -(current & 0x8000);
- sc->sc_sensor[5].value = current * -1000;
+ sc->sc_sensor[YKBEC_BCURRENT].value = -1000 * current;
- sc->sc_sensor[6].value = ykbec_read16(sc, REG_VOLTAGE_HIGH) * 1000;
+ sc->sc_sensor[YKBEC_BVOLT].value = ykbec_read16(sc, REG_VOLTAGE_HIGH) *
+ 1000;
val = ykbec_read16(sc, REG_TEMPERATURE_HIGH);
- sc->sc_sensor[7].value = val * 1000000 + 273150000;
+ sc->sc_sensor[YKBEC_BTEMP].value = val * 1000000 + 273150000;
- sc->sc_sensor[8].value = ykbec_read16(sc, REG_RELATIVE_CAT_HIGH) * 1000;
+ cap_pct = ykbec_read16(sc, REG_RELATIVE_CAT_HIGH);
+ sc->sc_sensor[YKBEC_CAP].value = cap_pct * 1000;
bat_charge = ykbec_read(sc, REG_BAT_CHARGE);
bat_status = ykbec_read(sc, REG_BAT_STATUS);
@@ -281,8 +291,69 @@ ykbec_refresh(void *arg)
bat_state = ykbec_read(sc, REG_BAT_STATE);
power_flag = ykbec_read(sc, REG_POWER_FLAG);
- sc->sc_sensor[9].value = (bat_state & BAT_STATE_CHARGING) ? 1 : 0;
- sc->sc_sensor[10].value = (power_flag & POWER_FLAG_ADAPTER_IN) ? 1 : 0;
- sc->sc_sensor[11].value = (bat_state << 24) | (charge_status << 16) |
- (bat_status << 8) | bat_charge;
+ sc->sc_sensor[YKBEC_CHARGING].value = (bat_state & BAT_STATE_CHARGING) ?
+ 1 : 0;
+ sc->sc_sensor[YKBEC_AC].value = (power_flag & POWER_FLAG_ADAPTER_IN) ?
+ 1 : 0;
+
+#if NAPM > 0
+ bcopy(&ykbec_apmdata, &old, sizeof(old));
+ ykbec_apmdata.battery_life = cap_pct;
+ ykbec_apmdata.ac_state = (power_flag & POWER_FLAG_ADAPTER_IN) ?
+ APM_AC_ON : APM_AC_OFF;
+ if ((bat_status & BAT_STATUS_BAT_EXISTS) == 0) {
+ ykbec_apmdata.battery_state = APM_BATTERY_ABSENT;
+ ykbec_apmdata.minutes_left = 0;
+ ykbec_apmdata.battery_life = 0;
+ } else {
+ /* if charging, return the minutes until full */
+ if (bat_state & BAT_STATE_CHARGING) {
+ ykbec_apmdata.battery_state = APM_BATT_CHARGING;
+ if (current > 0) {
+ fullcap = (100 - cap_pct) * 60 * fullcap / 100;
+ ykbec_apmdata.minutes_left = fullcap / current;
+ } else
+ ykbec_apmdata.minutes_left = 0;
+ } else {
+ /* arbitrary */
+ if (cap_pct > 60)
+ ykbec_apmdata.battery_state = APM_BATT_HIGH;
+ else if (cap_pct < 10)
+ ykbec_apmdata.battery_state = APM_BATT_CRITICAL;
+ else
+ ykbec_apmdata.battery_state = APM_BATT_LOW;
+
+ current = -current;
+ /* Yeeloong draw is about 1A */
+ if (current <= 0)
+ current = 1000;
+ /* at 5?%, the Yeeloong shuts down */
+ if (cap_pct <= 5)
+ cap_pct = 0;
+ else
+ cap_pct -= 5;
+ fullcap = cap_pct * 60 * fullcap / 100;
+ ykbec_apmdata.minutes_left = fullcap / current;
+ }
+
+ }
+ if (old.ac_state != ykbec_apmdata.ac_state)
+ apm_record_event(APM_POWER_CHANGE, "AC power",
+ ykbec_apmdata.ac_state ? "restored" : "lost");
+ if (old.battery_state != ykbec_apmdata.battery_state)
+ apm_record_event(APM_POWER_CHANGE, "battery",
+ BATTERY_STRING(ykbec_apmdata.battery_state));
+#endif
+}
+
+
+#if NAPM > 0
+
+int
+ykbec_apminfo(struct apm_power_info *info)
+{
+ bcopy(&ykbec_apmdata, info, sizeof(struct apm_power_info));
+ return 0;
}
+
+#endif
diff --git a/sys/arch/loongson/dev/mainbus.c b/sys/arch/loongson/dev/mainbus.c
index 705bdd3b9e9..2dd88cf99e4 100644
--- a/sys/arch/loongson/dev/mainbus.c
+++ b/sys/arch/loongson/dev/mainbus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mainbus.c,v 1.3 2010/02/16 21:29:26 miod Exp $ */
+/* $OpenBSD: mainbus.c,v 1.4 2010/02/28 08:30:27 otto Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -72,6 +72,9 @@ mainbus_attach(struct device *parent, struct device *self, void *aux)
caa.caa_maa.maa_name = "bonito";
config_found(self, &caa.caa_maa, mainbus_print);
+
+ caa.caa_maa.maa_name = "apm";
+ config_found(self, &caa.caa_maa, mainbus_print);
}
int
diff --git a/sys/arch/loongson/include/apmvar.h b/sys/arch/loongson/include/apmvar.h
new file mode 100644
index 00000000000..7311616b411
--- /dev/null
+++ b/sys/arch/loongson/include/apmvar.h
@@ -0,0 +1,125 @@
+/* $OpenBSD: apmvar.h,v 1.1 2010/02/28 08:30:27 otto Exp $ */
+
+/*
+ * Copyright (c) 2001 Alexander Guy
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `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 AUTHOR 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 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.
+ *
+ */
+#ifndef _LOONGSON_APMVAR_H_
+#define _LOONGSON_APMVAR_H_
+
+#include <sys/ioccom.h>
+
+/* Advanced Power Management (v1.0 and v1.1 specification)
+ * functions/defines/etc.
+ */
+
+/* These definitions make up the heart of the user-land interface
+ * to the APM devices.
+ */
+
+#define APM_AC_OFF 0x00
+#define APM_AC_ON 0x01
+#define APM_AC_BACKUP 0x02
+#define APM_AC_UNKNOWN 0xff
+#define APM_BATT_HIGH 0x00
+#define APM_BATT_LOW 0x01
+#define APM_BATT_CRITICAL 0x02
+#define APM_BATT_CHARGING 0x03
+#define APM_BATT_UNKNOWN 0xff
+#define APM_BATT_LIFE_UNKNOWN 0xff
+
+#define APM_NOEVENT 0x0000
+#define APM_STANDBY_REQ 0x0001
+#define APM_SUSPEND_REQ 0x0002
+#define APM_NORMAL_RESUME 0x0003
+#define APM_CRIT_RESUME 0x0004 /* suspend/resume happened
+ without us */
+#define APM_BATTERY_LOW 0x0005
+#define APM_POWER_CHANGE 0x0006
+#define APM_UPDATE_TIME 0x0007
+#define APM_CRIT_SUSPEND_REQ 0x0008
+#define APM_USER_STANDBY_REQ 0x0009
+#define APM_USER_SUSPEND_REQ 0x000A
+#define APM_SYS_STANDBY_RESUME 0x000B
+#define APM_CAPABILITY_CHANGE 0x000C /* apm v1.2 */
+#define APM_EVENT_MASK 0xffff
+
+#define APM_EVENT_COMPOSE(t,i) ((((i) & 0x7fff) << 16)|((t) & APM_EVENT_MASK))
+#define APM_EVENT_TYPE(e) ((e) & APM_EVENT_MASK)
+#define APM_EVENT_INDEX(e) ((e) >> 16)
+
+/*
+ * LP (Laptop Package)
+ *
+ * Copyright (C) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+ *
+ * This software may be used, modified, copied, and distributed, in
+ * both source and binary form provided that the above copyright and
+ * these terms are retained. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with its
+ * use.
+ *
+ * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+ */
+
+#define APM_BATTERY_ABSENT 4
+
+struct apm_power_info {
+ u_char battery_state;
+ u_char ac_state;
+ u_char battery_life;
+ u_char spare1;
+ u_int minutes_left; /* estimate */
+ u_int spare2[6];
+};
+
+struct apm_ctl {
+ u_int dev;
+ u_int mode;
+};
+
+#define APM_IOC_REJECT _IOW('A', 0, struct apm_event_info) /* reject request # */
+#define APM_IOC_STANDBY _IO('A', 1) /* put system into standby */
+#define APM_IOC_SUSPEND _IO('A', 2) /* put system into suspend */
+#define APM_IOC_GETPOWER _IOR('A', 3, struct apm_power_info) /* fetch battery state */
+#define APM_IOC_DEV_CTL _IOW('A', 5, struct apm_ctl) /* put device into mode */
+#define APM_IOC_PRN_CTL _IOW('A', 6, int ) /* driver power status msg */
+#define APM_PRINT_ON 0 /* driver power status displayed */
+#define APM_PRINT_OFF 1 /* driver power status not displayed */
+#define APM_PRINT_PCT 2 /* driver power status only displayed
+ if the percentage changes */
+#define APM_IOC_STANDBY_REQ _IO('A', 7) /* request standby */
+#define APM_IOC_SUSPEND_REQ _IO('A', 8) /* request suspend */
+
+#ifdef _KERNEL
+void apm_setinfohook(int (*)(struct apm_power_info *));
+int apm_record_event(u_int, const char *, const char *);
+#endif
+
+#endif /* _LOONGSON_APMVAR_H_ */
diff --git a/sys/arch/loongson/include/conf.h b/sys/arch/loongson/include/conf.h
new file mode 100644
index 00000000000..e1cb29d0fc1
--- /dev/null
+++ b/sys/arch/loongson/include/conf.h
@@ -0,0 +1,42 @@
+/* $OpenBSD: conf.h,v 1.1 2010/02/28 08:30:27 otto Exp $ */
+/* $NetBSD: conf.h,v 1.2 1996/05/05 19:28:34 christos Exp $ */
+
+/*
+ * Copyright (c) 1996 Christos Zoulas. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 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 <sys/conf.h>
+
+/* open, close, write, ioctl, kqueue */
+#define cdev_apm_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \
+ (dev_type_mmap((*))) enodev, 0, D_KQFILTER, dev_init(c,n,kqfilter) }
+
+cdev_decl(apm);
diff --git a/sys/arch/loongson/loongson/conf.c b/sys/arch/loongson/loongson/conf.c
index 5ae3ba5ce56..4fac5af5bfc 100644
--- a/sys/arch/loongson/loongson/conf.c
+++ b/sys/arch/loongson/loongson/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.2 2010/02/11 20:14:49 otto Exp $ */
+/* $OpenBSD: conf.c,v 1.3 2010/02/28 08:30:27 otto Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -43,7 +43,8 @@
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/tty.h>
-#include <sys/conf.h>
+
+#include <machine/conf.h>
/*
* Block devices.
@@ -101,6 +102,7 @@ cdev_decl(fd);
#include "st.h"
#include "bpfilter.h"
#include "tun.h"
+#include "apm.h"
#include "com.h"
cdev_decl(com);
#include "lpt.h"
@@ -152,7 +154,7 @@ struct cdevsw cdevsw[] =
cdev_disk_init(NVND,vnd), /* 11: vnode disk */
cdev_bpf_init(NBPFILTER,bpf), /* 12: berkeley packet filter */
cdev_tun_init(NTUN,tun), /* 13: network tunnel */
- cdev_notdef(), /* 14: */
+ cdev_apm_init(NAPM,apm), /* 14: apm */
cdev_notdef(), /* 15: */
cdev_lpt_init(NLPT,lpt), /* 16: Parallel printer interface */
cdev_tty_init(NCOM,com), /* 17: 16C450 serial interface */