aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/acpica
diff options
context:
space:
mode:
authorNate Lawson <njl@FreeBSD.org>2005-07-23 19:36:00 +0000
committerNate Lawson <njl@FreeBSD.org>2005-07-23 19:36:00 +0000
commit76f6fe4f31fa9c97f4a6f7713149ed9950323286 (patch)
tree098bd44131b4884e3f9bfa4b18f7728aa68f1ff4 /sys/dev/acpica
parentd3a46d12534fcaf88c90cc8eb2a2e75f10e2c457 (diff)
Notes
Diffstat (limited to 'sys/dev/acpica')
-rw-r--r--sys/dev/acpica/acpi_battery.c378
-rw-r--r--sys/dev/acpica/acpi_cmbat.c509
-rw-r--r--sys/dev/acpica/acpi_if.m25
-rw-r--r--sys/dev/acpica/acpiio.h44
-rw-r--r--sys/dev/acpica/acpivar.h16
5 files changed, 448 insertions, 524 deletions
diff --git a/sys/dev/acpica/acpi_battery.c b/sys/dev/acpica/acpi_battery.c
index 6857e9195aa0a..06fd60d634058 100644
--- a/sys/dev/acpica/acpi_battery.c
+++ b/sys/dev/acpica/acpi_battery.c
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2005 Nate Lawson
* Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
* All rights reserved.
*
@@ -39,96 +40,248 @@ __FBSDID("$FreeBSD$");
#include <dev/acpica/acpivar.h>
#include <dev/acpica/acpiio.h>
-MALLOC_DEFINE(M_ACPIBATT, "acpibatt", "ACPI generic battery data");
+/* Default seconds before re-sampling the battery state. */
+#define ACPI_BATTERY_INFO_EXPIRE 5
-struct acpi_batteries {
- TAILQ_ENTRY(acpi_batteries) link;
- struct acpi_battdesc battdesc;
-};
+static int acpi_batteries_initted;
+static int acpi_battery_info_expire = ACPI_BATTERY_INFO_EXPIRE;
+static struct acpi_battinfo acpi_battery_battinfo;
+static struct sysctl_ctx_list acpi_battery_sysctl_ctx;
+static struct sysctl_oid *acpi_battery_sysctl_tree;
-static TAILQ_HEAD(,acpi_batteries) acpi_batteries;
-static int acpi_batteries_initted;
-static int acpi_batteries_units;
-static int acpi_battery_info_expire = 5;
-static struct acpi_battinfo acpi_battery_battinfo;
ACPI_SERIAL_DECL(battery, "ACPI generic battery");
+static void acpi_reset_battinfo(struct acpi_battinfo *info);
+static int acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg);
+static int acpi_battery_sysctl(SYSCTL_HANDLER_ARGS);
+static int acpi_battery_units_sysctl(SYSCTL_HANDLER_ARGS);
+static int acpi_battery_init(void);
+
int
-acpi_battery_get_info_expire(void)
+acpi_battery_register(device_t dev)
{
- return (acpi_battery_info_expire);
+ int error;
+
+ error = 0;
+ ACPI_SERIAL_BEGIN(battery);
+ if (!acpi_batteries_initted)
+ error = acpi_battery_init();
+ ACPI_SERIAL_END(battery);
+ return (error);
+}
+
+int
+acpi_battery_remove(device_t dev)
+{
+
+ return (0);
}
int
acpi_battery_get_units(void)
{
- return (acpi_batteries_units);
+ devclass_t batt_dc;
+
+ batt_dc = devclass_find("battery");
+ if (batt_dc == NULL)
+ return (0);
+ return (devclass_get_count(batt_dc));
}
int
-acpi_battery_get_battdesc(int unit, struct acpi_battdesc *battdesc)
+acpi_battery_get_info_expire(void)
{
- struct acpi_batteries *bp;
- int error, i;
- error = ENXIO;
- ACPI_SERIAL_BEGIN(battery);
- if (unit < 0 || unit >= acpi_batteries_units)
- goto out;
+ return (acpi_battery_info_expire);
+}
- i = 0;
- TAILQ_FOREACH(bp, &acpi_batteries, link) {
- if (unit == i) {
- battdesc->type = bp->battdesc.type;
- battdesc->phys_unit = bp->battdesc.phys_unit;
- error = 0;
- break;
- }
- i++;
- }
+/* Check _BST results for validity. */
+int
+acpi_battery_bst_valid(struct acpi_bst *bst)
+{
+ if (bst->state >= ACPI_BATT_STAT_MAX || bst->cap == 0xffffffff ||
+ bst->volt == 0xffffffff)
+ return (FALSE);
+ else
+ return (TRUE);
+}
-out:
- ACPI_SERIAL_END(battery);
- return (error);
+/* Check _BIF results for validity. */
+int
+acpi_battery_bif_valid(struct acpi_bif *bif)
+{
+ if (bif->lfcap == 0)
+ return (FALSE);
+ else
+ return (TRUE);
}
+/* Get info about one or all batteries. */
int
-acpi_battery_get_battinfo(int unit, struct acpi_battinfo *battinfo)
+acpi_battery_get_battinfo(device_t dev, struct acpi_battinfo *battinfo)
{
- struct acpi_battdesc battdesc;
- int error;
+ int batt_stat, devcount, dev_idx, error, i;
+ int total_cap, total_min, valid_rate, valid_units;
+ devclass_t batt_dc;
+ device_t batt_dev;
+ struct acpi_bst *bst;
+ struct acpi_bif *bif;
+ struct acpi_battinfo *bi;
- error = 0;
- if (unit == -1) {
- error = acpi_cmbat_get_battinfo(-1, battinfo);
- goto out;
- } else {
- error = acpi_battery_get_battdesc(unit, &battdesc);
- if (error != 0)
- goto out;
+ /*
+ * Get the battery devclass and number of devices. If there are none
+ * or error, return immediately.
+ */
+ batt_dc = devclass_find("battery");
+ if (batt_dc == NULL)
+ return (ENXIO);
+ devcount = devclass_get_count(batt_dc);
+ if (devcount == 0)
+ return (ENXIO);
+
+ /*
+ * Allocate storage for all _BST data, their derived battinfo data,
+ * and the current battery's _BIF data.
+ */
+ bst = malloc(devcount * sizeof(*bst), M_TEMP, M_WAITOK);
+ bi = malloc(devcount * sizeof(*bi), M_TEMP, M_WAITOK);
+ bif = malloc(sizeof(*bif), M_TEMP, M_WAITOK);
- switch (battdesc.type) {
- case ACPI_BATT_TYPE_CMBAT:
- error = acpi_cmbat_get_battinfo(battdesc.phys_unit, battinfo);
- break;
- default:
- error = ENXIO;
- break;
+ /*
+ * Pass 1: for each battery that is present and valid, get its status,
+ * calculate percent capacity remaining, and sum all the current
+ * discharge rates.
+ */
+ dev_idx = -1;
+ batt_stat = valid_rate = valid_units = 0;
+ for (i = 0; i < devcount; i++) {
+ /* Find the device. If it disappeared, the user can try again. */
+ batt_dev = devclass_get_device(batt_dc, i);
+ if (batt_dev == NULL) {
+ error = ENOMEM;
+ goto out;
}
+
+ /* Default info for every battery is "not present". */
+ acpi_reset_battinfo(&bi[i]);
+
+ /* If examining a specific battery and this is it, record its index. */
+ if (dev != NULL && dev == batt_dev)
+ dev_idx = i;
+
+ /* Be sure we can get various info from the battery. */
+ if (!acpi_BatteryIsPresent(batt_dev) ||
+ ACPI_BATT_GET_STATUS(batt_dev, &bst[i]) != 0 ||
+ ACPI_BATT_GET_INFO(batt_dev, bif) != 0)
+ continue;
+
+ /* If a battery is not installed, we sometimes get strange values. */
+ if (!acpi_battery_bst_valid(&bst[i]) ||
+ !acpi_battery_bif_valid(bif))
+ continue;
+
+ /* Record state and calculate percent capacity remaining. */
+ valid_units++;
+ batt_stat |= bst[i].state;
+ bi[i].state = bst[i].state;
+ bi[i].cap = 100 * bst[i].cap / bif->lfcap;
+
+ /*
+ * Some laptops report the "design-capacity" instead of the
+ * "real-capacity" when the battery is fully charged. That breaks
+ * the above arithmetic as it needs to be 100% maximum.
+ */
+ if (bi[i].cap > 100)
+ bi[i].cap = 100;
+
+ /*
+ * On systems with more than one battery, they may get used
+ * sequentially, thus bst.rate may only signify the one currently
+ * in use. For the remaining batteries, bst.rate will be zero,
+ * which makes it impossible to calculate the total remaining time.
+ * Therefore, we sum the bst.rate for batteries in the discharging
+ * state and use the sum to calculate the total remaining time.
+ */
+ if (bst[i].rate > 0 && (bst[i].state & ACPI_BATT_STAT_DISCHARG))
+ valid_rate += bst[i].rate;
+ }
+
+ /* If the caller asked for a device but we didn't find it, error. */
+ if (dev != NULL && dev_idx < 0) {
+ error = ENXIO;
+ goto out;
}
+ /* Pass 2: calculate capacity and remaining time for all batteries. */
+ total_cap = total_min = 0;
+ for (i = 0; i < devcount; i++) {
+ /*
+ * If any batteries are discharging, use the sum of the bst.rate
+ * values. Otherwise, we are on AC power, and there is infinite
+ * time remaining for this battery until we go offline.
+ */
+ if (valid_rate > 0)
+ bi[i].min = 60 * bst[i].cap / valid_rate;
+ else
+ bi[i].min = 0;
+ total_min += bi[i].min;
+ total_cap += bi[i].cap;
+ }
+
+ /*
+ * Return total battery percent and time remaining. If there are
+ * no valid batteries, report values as unknown.
+ */
+ if (valid_units > 0) {
+ if (dev == NULL) {
+ battinfo->cap = total_cap / valid_units;
+ battinfo->min = total_min;
+ battinfo->state = batt_stat;
+ battinfo->rate = valid_rate;
+ } else {
+ battinfo->cap = bi[dev_idx].cap;
+ battinfo->min = bi[dev_idx].min;
+ battinfo->state = bi[dev_idx].state;
+ battinfo->rate = bst[dev_idx].rate;
+ }
+ } else
+ acpi_reset_battinfo(battinfo);
+
+ error = 0;
+
out:
+ if (bi)
+ free(bi, M_TEMP);
+ if (bif)
+ free(bif, M_TEMP);
+ if (bst)
+ free(bst, M_TEMP);
return (error);
}
+static void
+acpi_reset_battinfo(struct acpi_battinfo *info)
+{
+ info->cap = -1;
+ info->min = -1;
+ info->state = ACPI_BATT_STAT_NOT_PRESENT;
+ info->rate = -1;
+}
+
static int
acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg)
{
union acpi_battery_ioctl_arg *ioctl_arg;
int error, unit;
+ device_t dev;
+ error = ENXIO;
ioctl_arg = (union acpi_battery_ioctl_arg *)addr;
- error = 0;
+ unit = ioctl_arg->unit;
+ if (unit != ACPI_BATTERY_ALL_UNITS)
+ dev = devclass_get_device(devclass_find("battery"), unit);
+ else
+ dev = NULL;
/*
* No security check required: information retrieval only. If
@@ -138,17 +291,20 @@ acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg)
case ACPIIO_BATT_GET_UNITS:
*(int *)addr = acpi_battery_get_units();
break;
- case ACPIIO_BATT_GET_BATTDESC:
- unit = ioctl_arg->unit;
- error = acpi_battery_get_battdesc(unit, &ioctl_arg->battdesc);
- break;
case ACPIIO_BATT_GET_BATTINFO:
- unit = ioctl_arg->unit;
- error = acpi_battery_get_battinfo(unit, &ioctl_arg->battinfo);
+ if (dev != NULL || unit == ACPI_BATTERY_ALL_UNITS)
+ error = acpi_battery_get_battinfo(dev, &ioctl_arg->battinfo);
+ break;
+ case ACPIIO_BATT_GET_BIF:
+ if (dev != NULL)
+ error = ACPI_BATT_GET_INFO(dev, &ioctl_arg->bif);
+ break;
+ case ACPIIO_BATT_GET_BST:
+ if (dev != NULL)
+ error = ACPI_BATT_GET_STATUS(dev, &ioctl_arg->bst);
break;
default:
error = EINVAL;
- break;
}
return (error);
@@ -159,13 +315,23 @@ acpi_battery_sysctl(SYSCTL_HANDLER_ARGS)
{
int val, error;
- acpi_battery_get_battinfo(-1, &acpi_battery_battinfo);
+ acpi_battery_get_battinfo(NULL, &acpi_battery_battinfo);
val = *(u_int *)oidp->oid_arg1;
error = sysctl_handle_int(oidp, &val, 0, req);
return (error);
}
static int
+acpi_battery_units_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ int count, error;
+
+ count = acpi_battery_get_units();
+ error = sysctl_handle_int(oidp, &count, 0, req);
+ return (error);
+}
+
+static int
acpi_battery_init(void)
{
struct acpi_softc *sc;
@@ -180,98 +346,54 @@ acpi_battery_init(void)
goto out;
sc = device_get_softc(dev);
- TAILQ_INIT(&acpi_batteries);
-
- /* XXX We should back out registered ioctls on error. */
error = acpi_register_ioctl(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl,
NULL);
if (error != 0)
goto out;
- error = acpi_register_ioctl(ACPIIO_BATT_GET_BATTDESC, acpi_battery_ioctl,
+ error = acpi_register_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl,
NULL);
if (error != 0)
goto out;
- error = acpi_register_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl,
- NULL);
+ error = acpi_register_ioctl(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl, NULL);
+ if (error != 0)
+ goto out;
+ error = acpi_register_ioctl(ACPIIO_BATT_GET_BST, acpi_battery_ioctl, NULL);
if (error != 0)
goto out;
- sysctl_ctx_init(&sc->acpi_battery_sysctl_ctx);
- sc->acpi_battery_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_battery_sysctl_ctx,
+ sysctl_ctx_init(&acpi_battery_sysctl_ctx);
+ acpi_battery_sysctl_tree = SYSCTL_ADD_NODE(&acpi_battery_sysctl_ctx,
SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "battery", CTLFLAG_RD,
0, "");
- SYSCTL_ADD_PROC(&sc->acpi_battery_sysctl_ctx,
- SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree),
+ SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
+ SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
OID_AUTO, "life", CTLTYPE_INT | CTLFLAG_RD,
&acpi_battery_battinfo.cap, 0, acpi_battery_sysctl, "I", "");
- SYSCTL_ADD_PROC(&sc->acpi_battery_sysctl_ctx,
- SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree),
+ SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
+ SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
OID_AUTO, "time", CTLTYPE_INT | CTLFLAG_RD,
&acpi_battery_battinfo.min, 0, acpi_battery_sysctl, "I", "");
- SYSCTL_ADD_PROC(&sc->acpi_battery_sysctl_ctx,
- SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree),
+ SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
+ SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RD,
&acpi_battery_battinfo.state, 0, acpi_battery_sysctl, "I", "");
- SYSCTL_ADD_INT(&sc->acpi_battery_sysctl_ctx,
- SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree),
- OID_AUTO, "units", CTLFLAG_RD, &acpi_batteries_units, 0, "");
- SYSCTL_ADD_INT(&sc->acpi_battery_sysctl_ctx,
- SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree),
+ SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
+ SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
+ OID_AUTO, "units", CTLTYPE_INT | CTLFLAG_RD,
+ NULL, 0, acpi_battery_units_sysctl, "I", "");
+ SYSCTL_ADD_INT(&acpi_battery_sysctl_ctx,
+ SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
OID_AUTO, "info_expire", CTLFLAG_RD | CTLFLAG_RW,
&acpi_battery_info_expire, 0, "");
acpi_batteries_initted = TRUE;
out:
- return (error);
-}
-
-int
-acpi_battery_register(int type, int phys_unit)
-{
- struct acpi_batteries *bp;
- int error;
-
- error = 0;
- bp = malloc(sizeof(*bp), M_ACPIBATT, M_NOWAIT);
- if (bp == NULL)
- return (ENOMEM);
-
- ACPI_SERIAL_BEGIN(battery);
- if (!acpi_batteries_initted && (error = acpi_battery_init()) != 0) {
- printf("acpi_battery_register failed for unit %d\n", phys_unit);
- goto out;
+ if (error != 0) {
+ acpi_deregister_ioctl(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl);
+ acpi_deregister_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl);
+ acpi_deregister_ioctl(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl);
+ acpi_deregister_ioctl(ACPIIO_BATT_GET_BST, acpi_battery_ioctl);
}
- bp->battdesc.type = type;
- bp->battdesc.phys_unit = phys_unit;
- TAILQ_INSERT_TAIL(&acpi_batteries, bp, link);
- acpi_batteries_units++;
-
-out:
- ACPI_SERIAL_END(battery);
- if (error)
- free(bp, M_ACPIBATT);
return (error);
}
-
-int
-acpi_battery_remove(int type, int phys_unit)
-{
- struct acpi_batteries *bp, *tmp;
- int ret;
-
- ret = ENOENT;
- ACPI_SERIAL_BEGIN(battery);
- TAILQ_FOREACH_SAFE(bp, &acpi_batteries, link, tmp) {
- if (bp->battdesc.type == type && bp->battdesc.phys_unit == phys_unit) {
- TAILQ_REMOVE(&acpi_batteries, bp, link);
- acpi_batteries_units--;
- ret = 0;
- break;
- }
- }
- ACPI_SERIAL_END(battery);
- if (ret == 0)
- free(bp, M_ACPIBATT);
- return (ret);
-}
diff --git a/sys/dev/acpica/acpi_cmbat.c b/sys/dev/acpica/acpi_cmbat.c
index 54e4982250607..e60ea17a39094 100644
--- a/sys/dev/acpica/acpi_cmbat.c
+++ b/sys/dev/acpica/acpi_cmbat.c
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2005 Nate Lawson
* Copyright (c) 2000 Munehiro Matsuda
* Copyright (c) 2000 Takanori Watanabe
* Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
@@ -24,10 +25,11 @@
* 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.
- *
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include "opt_acpi.h"
#include <sys/param.h>
#include <sys/kernel.h>
@@ -60,41 +62,29 @@ ACPI_MODULE_NAME("BATTERY")
struct acpi_cmbat_softc {
device_t dev;
+ int flags;
struct acpi_bif bif;
struct acpi_bst bst;
struct timespec bif_lastupdated;
struct timespec bst_lastupdated;
-
- int flags;
- int present;
- int cap;
- int min;
- int full_charge_time;
- int initializing;
- int phys_unit;
};
-static struct timespec acpi_cmbat_info_lastupdated;
ACPI_SERIAL_DECL(cmbat, "ACPI cmbat");
-/* XXX: devclass_get_maxunit() don't give us the current allocated units. */
-static int acpi_cmbat_units = 0;
-
-static int acpi_cmbat_info_expired(struct timespec *);
-static void acpi_cmbat_info_updated(struct timespec *);
-static void acpi_cmbat_get_bst(void *);
-static void acpi_cmbat_get_bif(void *);
-static void acpi_cmbat_notify_handler(ACPI_HANDLE, UINT32, void *);
-static int acpi_cmbat_probe(device_t);
-static int acpi_cmbat_attach(device_t);
-static int acpi_cmbat_detach(device_t);
-static int acpi_cmbat_resume(device_t);
-static int acpi_cmbat_ioctl(u_long, caddr_t, void *);
-static int acpi_cmbat_is_bst_valid(struct acpi_bst*);
-static int acpi_cmbat_is_bif_valid(struct acpi_bif*);
-static int acpi_cmbat_get_total_battinfo(struct acpi_battinfo *);
-static void acpi_cmbat_init_battery(void *);
+static int acpi_cmbat_probe(device_t dev);
+static int acpi_cmbat_attach(device_t dev);
+static int acpi_cmbat_detach(device_t dev);
+static int acpi_cmbat_resume(device_t dev);
+static void acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify,
+ void *context);
+static int acpi_cmbat_info_expired(struct timespec *lastupdated);
+static void acpi_cmbat_info_updated(struct timespec *lastupdated);
+static void acpi_cmbat_get_bst(device_t dev);
+static void acpi_cmbat_get_bif(device_t dev);
+static int acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp);
+static int acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp);
+static void acpi_cmbat_init_battery(void *arg);
static device_method_t acpi_cmbat_methods[] = {
/* Device interface */
@@ -103,11 +93,15 @@ static device_method_t acpi_cmbat_methods[] = {
DEVMETHOD(device_detach, acpi_cmbat_detach),
DEVMETHOD(device_resume, acpi_cmbat_resume),
+ /* ACPI battery interface */
+ DEVMETHOD(acpi_batt_get_info, acpi_cmbat_bif),
+ DEVMETHOD(acpi_batt_get_status, acpi_cmbat_bst),
+
{0, 0}
};
static driver_t acpi_cmbat_driver = {
- "acpi_cmbat",
+ "battery",
acpi_cmbat_methods,
sizeof(struct acpi_cmbat_softc),
};
@@ -117,6 +111,96 @@ DRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, 0, 0);
MODULE_DEPEND(acpi_cmbat, acpi, 1, 1, 1);
static int
+acpi_cmbat_probe(device_t dev)
+{
+ static char *cmbat_ids[] = { "PNP0C0A", NULL };
+
+ if (acpi_disabled("cmbat") ||
+ ACPI_ID_PROBE(device_get_parent(dev), dev, cmbat_ids) == NULL)
+ return (ENXIO);
+
+ device_set_desc(dev, "ACPI Control Method Battery");
+ return (0);
+}
+
+static int
+acpi_cmbat_attach(device_t dev)
+{
+ int error;
+ ACPI_HANDLE handle;
+ struct acpi_cmbat_softc *sc;
+
+ sc = device_get_softc(dev);
+ handle = acpi_get_handle(dev);
+ sc->dev = dev;
+
+ timespecclear(&sc->bif_lastupdated);
+ timespecclear(&sc->bst_lastupdated);
+
+ error = acpi_battery_register(dev);
+ if (error != 0) {
+ device_printf(dev, "registering battery failed\n");
+ return (error);
+ }
+
+ /*
+ * Install a system notify handler in addition to the device notify.
+ * Toshiba notebook uses this alternate notify for its battery.
+ */
+ AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY,
+ acpi_cmbat_notify_handler, dev);
+
+ AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev);
+
+ return (0);
+}
+
+static int
+acpi_cmbat_detach(device_t dev)
+{
+
+ acpi_battery_remove(dev);
+ return (0);
+}
+
+static int
+acpi_cmbat_resume(device_t dev)
+{
+
+ AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev);
+ return (0);
+}
+
+static void
+acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+ struct acpi_cmbat_softc *sc;
+ device_t dev;
+
+ dev = (device_t)context;
+ sc = device_get_softc(dev);
+
+ /*
+ * Clear the appropriate last updated time. The next call to retrieve
+ * the battery status will get the new value for us. We don't need to
+ * acquire a lock since we are only clearing the time stamp and since
+ * calling _BST/_BIF can trigger a notify, we could deadlock also.
+ */
+ switch (notify) {
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ case ACPI_BATTERY_BST_CHANGE:
+ timespecclear(&sc->bst_lastupdated);
+ break;
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_BATTERY_BIF_CHANGE:
+ timespecclear(&sc->bif_lastupdated);
+ break;
+ }
+
+ acpi_UserNotify("CMBAT", h, notify);
+}
+
+static int
acpi_cmbat_info_expired(struct timespec *lastupdated)
{
struct timespec curtime;
@@ -145,9 +229,8 @@ acpi_cmbat_info_updated(struct timespec *lastupdated)
}
static void
-acpi_cmbat_get_bst(void *context)
+acpi_cmbat_get_bst(device_t dev)
{
- device_t dev;
struct acpi_cmbat_softc *sc;
ACPI_STATUS as;
ACPI_OBJECT *res;
@@ -156,7 +239,6 @@ acpi_cmbat_get_bst(void *context)
ACPI_SERIAL_ASSERT(cmbat);
- dev = context;
sc = device_get_softc(dev);
h = acpi_get_handle(dev);
bst_buffer.Pointer = NULL;
@@ -205,9 +287,8 @@ end:
}
static void
-acpi_cmbat_get_bif(void *context)
+acpi_cmbat_get_bif(device_t dev)
{
- device_t dev;
struct acpi_cmbat_softc *sc;
ACPI_STATUS as;
ACPI_OBJECT *res;
@@ -216,7 +297,6 @@ acpi_cmbat_get_bif(void *context)
ACPI_SERIAL_ASSERT(cmbat);
- dev = context;
sc = device_get_softc(dev);
h = acpi_get_handle(dev);
bif_buffer.Pointer = NULL;
@@ -273,319 +353,59 @@ end:
AcpiOsFree(bif_buffer.Pointer);
}
-static void
-acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
-{
- device_t dev;
- struct acpi_cmbat_softc *sc;
-
- dev = (device_t)context;
- sc = device_get_softc(dev);
-
- acpi_UserNotify("CMBAT", h, notify);
-
- /*
- * Clear the appropriate last updated time. The next call to retrieve
- * the battery status will get the new value for us. We don't need to
- * acquire a lock since we are only clearing the time stamp and since
- * calling _BST/_BIF can trigger a notify, we could deadlock also.
- */
- switch (notify) {
- case ACPI_NOTIFY_DEVICE_CHECK:
- case ACPI_BATTERY_BST_CHANGE:
- timespecclear(&sc->bst_lastupdated);
- break;
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_BATTERY_BIF_CHANGE:
- timespecclear(&sc->bif_lastupdated);
- break;
- default:
- break;
- }
-}
-
static int
-acpi_cmbat_probe(device_t dev)
-{
- static char *cmbat_ids[] = { "PNP0C0A", NULL };
-
- if (acpi_disabled("cmbat") ||
- ACPI_ID_PROBE(device_get_parent(dev), dev, cmbat_ids) == NULL)
- return (ENXIO);
-
- device_set_desc(dev, "Control Method Battery");
- return (0);
-}
-
-static int
-acpi_cmbat_attach(device_t dev)
+acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp)
{
- int error;
- ACPI_HANDLE handle;
struct acpi_cmbat_softc *sc;
sc = device_get_softc(dev);
- handle = acpi_get_handle(dev);
- sc->dev = dev;
-
- /*
- * Install a system notify handler in addition to the device notify.
- * Toshiba notebook uses this alternate notify for its battery.
- */
- AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY,
- acpi_cmbat_notify_handler, dev);
ACPI_SERIAL_BEGIN(cmbat);
- timespecclear(&sc->bif_lastupdated);
- timespecclear(&sc->bst_lastupdated);
-
- if (acpi_cmbat_units == 0) {
- error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BIF,
- acpi_cmbat_ioctl, NULL);
- if (error != 0) {
- device_printf(dev, "register bif ioctl failed\n");
- return (error);
- }
- error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BST,
- acpi_cmbat_ioctl, NULL);
- if (error != 0) {
- device_printf(dev, "register bst ioctl failed\n");
- return (error);
- }
- }
-
- sc->phys_unit = acpi_cmbat_units;
- error = acpi_battery_register(ACPI_BATT_TYPE_CMBAT, sc->phys_unit);
- if (error != 0) {
- device_printf(dev, "registering battery %d failed\n", sc->phys_unit);
- return (error);
- }
- acpi_cmbat_units++;
- timespecclear(&acpi_cmbat_info_lastupdated);
- ACPI_SERIAL_END(cmbat);
-
- AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev);
-
- return (0);
-}
-
-static int
-acpi_cmbat_detach(device_t dev)
-{
- struct acpi_cmbat_softc *sc;
-
- sc = device_get_softc(dev);
- ACPI_SERIAL_BEGIN(cmbat);
- acpi_battery_remove(ACPI_BATT_TYPE_CMBAT, sc->phys_unit);
- acpi_cmbat_units--;
+ acpi_cmbat_get_bif(dev);
+ bifp->units = sc->bif.units;
+ bifp->dcap = sc->bif.dcap;
+ bifp->lfcap = sc->bif.lfcap;
+ bifp->btech = sc->bif.btech;
+ bifp->dvol = sc->bif.dvol;
+ bifp->wcap = sc->bif.wcap;
+ bifp->lcap = sc->bif.lcap;
+ bifp->gra1 = sc->bif.gra1;
+ bifp->gra2 = sc->bif.gra2;
+ strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model));
+ strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial));
+ strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type));
+ strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo));
ACPI_SERIAL_END(cmbat);
- return (0);
-}
-static int
-acpi_cmbat_resume(device_t dev)
-{
- AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev);
return (0);
}
static int
-acpi_cmbat_ioctl(u_long cmd, caddr_t addr, void *arg)
+acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp)
{
- device_t dev;
- union acpi_battery_ioctl_arg *ioctl_arg;
struct acpi_cmbat_softc *sc;
- struct acpi_bif *bifp;
- struct acpi_bst *bstp;
- ioctl_arg = (union acpi_battery_ioctl_arg *)addr;
- dev = devclass_get_device(acpi_cmbat_devclass, ioctl_arg->unit);
- if (dev == NULL)
- return (ENXIO);
sc = device_get_softc(dev);
- /*
- * No security check required: information retrieval only. If
- * new functions are added here, a check might be required.
- */
ACPI_SERIAL_BEGIN(cmbat);
- switch (cmd) {
- case ACPIIO_CMBAT_GET_BIF:
- acpi_cmbat_get_bif(dev);
- bifp = &ioctl_arg->bif;
- bifp->units = sc->bif.units;
- bifp->dcap = sc->bif.dcap;
- bifp->lfcap = sc->bif.lfcap;
- bifp->btech = sc->bif.btech;
- bifp->dvol = sc->bif.dvol;
- bifp->wcap = sc->bif.wcap;
- bifp->lcap = sc->bif.lcap;
- bifp->gra1 = sc->bif.gra1;
- bifp->gra2 = sc->bif.gra2;
- strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model));
- strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial));
- strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type));
- strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo));
- break;
- case ACPIIO_CMBAT_GET_BST:
- bstp = &ioctl_arg->bst;
- if (acpi_BatteryIsPresent(dev)) {
- acpi_cmbat_get_bst(dev);
- bstp->state = sc->bst.state;
- bstp->rate = sc->bst.rate;
- bstp->cap = sc->bst.cap;
- bstp->volt = sc->bst.volt;
- } else {
- bstp->state = ACPI_BATT_STAT_NOT_PRESENT;
- }
- break;
- default:
- break;
- }
+ if (acpi_BatteryIsPresent(dev)) {
+ acpi_cmbat_get_bst(dev);
+ bstp->state = sc->bst.state;
+ bstp->rate = sc->bst.rate;
+ bstp->cap = sc->bst.cap;
+ bstp->volt = sc->bst.volt;
+ } else
+ bstp->state = ACPI_BATT_STAT_NOT_PRESENT;
ACPI_SERIAL_END(cmbat);
return (0);
}
-static int
-acpi_cmbat_is_bst_valid(struct acpi_bst *bst)
-{
- if (bst->state >= ACPI_BATT_STAT_MAX || bst->cap == 0xffffffff ||
- bst->volt == 0xffffffff)
- return (FALSE);
- else
- return (TRUE);
-}
-
-static int
-acpi_cmbat_is_bif_valid(struct acpi_bif *bif)
-{
- if (bif->lfcap == 0)
- return (FALSE);
- else
- return (TRUE);
-}
-
-static int
-acpi_cmbat_get_total_battinfo(struct acpi_battinfo *battinfo)
-{
- int i;
- int error;
- int batt_stat;
- int valid_rate, valid_units;
- int cap, min;
- int total_cap, total_min, total_full;
- struct acpi_cmbat_softc *sc;
-
- ACPI_SERIAL_ASSERT(cmbat);
-
- cap = min = -1;
- batt_stat = ACPI_BATT_STAT_NOT_PRESENT;
- error = 0;
-
- /* Get battery status, valid rate and valid units */
- batt_stat = valid_rate = valid_units = 0;
- for (i = 0; i < acpi_cmbat_units; i++) {
- sc = devclass_get_softc(acpi_cmbat_devclass, i);
- if (sc == NULL)
- continue;
- sc->present = acpi_BatteryIsPresent(sc->dev);
- if (!sc->present)
- continue;
- acpi_cmbat_get_bst(sc->dev);
-
- /* If battery not installed, we get strange values */
- if (!acpi_cmbat_is_bst_valid(&sc->bst) ||
- !acpi_cmbat_is_bif_valid(&sc->bif)) {
- sc->present = FALSE;
- continue;
- }
-
- valid_units++;
- sc->cap = 100 * sc->bst.cap / sc->bif.lfcap;
-
- /*
- * Some laptops report the "design-capacity" instead of the
- * "real-capacity" when the battery is fully charged.
- * That breaks the above arithmetic as it needs to be 100% maximum.
- */
- if (sc->cap > 100)
- sc->cap = 100;
-
- batt_stat |= sc->bst.state;
-
- /*
- * XXX Hack to calculate total battery time.
- *
- * On systems with more than one battery, they may get used
- * sequentially, thus bst.rate may only signify the one in use.
- * For the remaining batteries, bst.rate will be zero, which
- * makes it impossible to calculate the remaining time. Some
- * other systems may need the sum of all the bst.rate values
- * when discharging. Therefore, we sum the bst.rate for valid
- * batteries (ones in the discharging state) and use the sum
- * to calculate the total remaining time.
- */
- if (sc->bst.rate > 0) {
- if (sc->bst.state & ACPI_BATT_STAT_DISCHARG)
- valid_rate += sc->bst.rate;
- }
- }
-
- /* Calculate total battery capacity and time */
- total_cap = total_min = total_full = 0;
- for (i = 0; i < acpi_cmbat_units; i++) {
- sc = devclass_get_softc(acpi_cmbat_devclass, i);
- if (!sc->present)
- continue;
-
- /*
- * If any batteries are discharging, use the sum of the bst.rate
- * values. Otherwise, use the full charge time to estimate
- * remaining time. If neither are available, assume no charge.
- */
- if (valid_rate > 0)
- sc->min = 60 * sc->bst.cap / valid_rate;
- else if (sc->full_charge_time > 0)
- sc->min = (sc->full_charge_time * sc->cap) / 100;
- else
- sc->min = 0;
- total_min += sc->min;
- total_cap += sc->cap;
- total_full += sc->full_charge_time;
- }
-
- /* Battery life */
- if (valid_units == 0) {
- cap = -1;
- batt_stat = ACPI_BATT_STAT_NOT_PRESENT;
- } else
- cap = total_cap / valid_units;
-
- /* Battery time */
- if (valid_units == 0)
- min = -1;
- else if (valid_rate == 0 || (batt_stat & ACPI_BATT_STAT_CHARGING)) {
- if (total_full == 0)
- min = -1;
- else
- min = (total_full * cap) / 100;
- } else
- min = total_min;
- acpi_cmbat_info_updated(&acpi_cmbat_info_lastupdated);
-
- battinfo->cap = cap;
- battinfo->min = min;
- battinfo->state = batt_stat;
-
- return (error);
-}
-
static void
acpi_cmbat_init_battery(void *arg)
{
struct acpi_cmbat_softc *sc;
- int retry;
+ int retry, valid;
device_t dev;
dev = (device_t)arg;
@@ -593,9 +413,13 @@ acpi_cmbat_init_battery(void *arg)
ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
"battery initialization start\n");
+ /*
+ * Try repeatedly to get valid data from the battery. Since the
+ * embedded controller isn't always ready just after boot, we may have
+ * to wait a while.
+ */
for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) {
- sc->present = acpi_BatteryIsPresent(dev);
- if (!sc->present)
+ if (!acpi_BatteryIsPresent(dev))
continue;
ACPI_SERIAL_BEGIN(cmbat);
@@ -603,10 +427,11 @@ acpi_cmbat_init_battery(void *arg)
timespecclear(&sc->bif_lastupdated);
acpi_cmbat_get_bst(dev);
acpi_cmbat_get_bif(dev);
+ valid = acpi_battery_bst_valid(&sc->bst) &&
+ acpi_battery_bif_valid(&sc->bif);
ACPI_SERIAL_END(cmbat);
- if (acpi_cmbat_is_bst_valid(&sc->bst) &&
- acpi_cmbat_is_bif_valid(&sc->bif))
+ if (valid)
break;
}
@@ -618,39 +443,3 @@ acpi_cmbat_init_battery(void *arg)
"battery initialization done, tried %d times\n", retry + 1);
}
}
-
-/*
- * Public interfaces.
- */
-int
-acpi_cmbat_get_battinfo(int unit, struct acpi_battinfo *battinfo)
-{
- int error;
- struct acpi_cmbat_softc *sc;
-
- ACPI_SERIAL_BEGIN(cmbat);
- error = acpi_cmbat_get_total_battinfo(battinfo);
- if (unit == -1 || error)
- goto out;
-
- error = ENXIO;
- if (unit >= acpi_cmbat_units)
- goto out;
- if ((sc = devclass_get_softc(acpi_cmbat_devclass, unit)) == NULL)
- goto out;
-
- if (!sc->present) {
- battinfo->cap = -1;
- battinfo->min = -1;
- battinfo->state = ACPI_BATT_STAT_NOT_PRESENT;
- } else {
- battinfo->cap = sc->cap;
- battinfo->min = sc->min;
- battinfo->state = sc->bst.state;
- }
- error = 0;
-
-out:
- ACPI_SERIAL_END(cmbat);
- return (error);
-}
diff --git a/sys/dev/acpica/acpi_if.m b/sys/dev/acpica/acpi_if.m
index 8c7706c3ceb4f..51c479cc24a5b 100644
--- a/sys/dev/acpica/acpi_if.m
+++ b/sys/dev/acpica/acpi_if.m
@@ -51,6 +51,9 @@ INTERFACE acpi;
HEADER {
typedef ACPI_STATUS (*acpi_scan_cb_t)(ACPI_HANDLE h, device_t *dev,
int level, void *arg);
+
+ struct acpi_bif;
+ struct acpi_bst;
};
#
@@ -197,3 +200,25 @@ METHOD int ec_write {
ACPI_INTEGER val;
int width;
};
+
+#
+# Get battery information (_BIF format)
+#
+# device_t dev: Battery device
+# struct acpi_bif *bif: Pointer to storage for _BIF results
+#
+METHOD int batt_get_info {
+ device_t dev;
+ struct acpi_bif *bif;
+};
+
+#
+# Get battery status (_BST format)
+#
+# device_t dev: Battery device
+# struct acpi_bst *bst: Pointer to storage for _BST results
+#
+METHOD int batt_get_status {
+ device_t dev;
+ struct acpi_bst *bst;
+};
diff --git a/sys/dev/acpica/acpiio.h b/sys/dev/acpica/acpiio.h
index 42894f29d4773..aa18c385bdf41 100644
--- a/sys/dev/acpica/acpiio.h
+++ b/sys/dev/acpica/acpiio.h
@@ -35,31 +35,24 @@
*/
#define ACPIIO_SETSLPSTATE _IOW('P', 3, int)
-struct acpi_battdesc {
- int type; /* battery type */
- int phys_unit; /* physical unit of devclass */
-};
-
-#define ACPI_BATT_TYPE_CMBAT 0x0000
-#define ACPI_BATT_TYPE_SMBAT 0x0001
-
struct acpi_battinfo {
int cap; /* percent */
int min; /* remaining time (in minutes) */
int state; /* battery state */
+ int rate; /* emptying rate */
};
#define ACPI_CMBAT_MAXSTRLEN 32
struct acpi_bif {
- u_int32_t units; /* 0 for mWh, 1 for mAh */
- u_int32_t dcap; /* Design Capacity */
- u_int32_t lfcap; /* Last Full capacity */
- u_int32_t btech; /* Battery Technology */
- u_int32_t dvol; /* Design voltage (mV) */
- u_int32_t wcap; /* WARN capacity */
- u_int32_t lcap; /* Low capacity */
- u_int32_t gra1; /* Granularity 1 (Warn to Low) */
- u_int32_t gra2; /* Granularity 2 (Full to Warn) */
+ uint32_t units; /* 0 for mWh, 1 for mAh */
+ uint32_t dcap; /* Design Capacity */
+ uint32_t lfcap; /* Last Full capacity */
+ uint32_t btech; /* Battery Technology */
+ uint32_t dvol; /* Design voltage (mV) */
+ uint32_t wcap; /* WARN capacity */
+ uint32_t lcap; /* Low capacity */
+ uint32_t gra1; /* Granularity 1 (Warn to Low) */
+ uint32_t gra2; /* Granularity 2 (Full to Warn) */
char model[ACPI_CMBAT_MAXSTRLEN]; /* model identifier */
char serial[ACPI_CMBAT_MAXSTRLEN]; /* Serial number */
char type[ACPI_CMBAT_MAXSTRLEN]; /* Type */
@@ -67,10 +60,10 @@ struct acpi_bif {
};
struct acpi_bst {
- u_int32_t state; /* Battery State */
- u_int32_t rate; /* Present Rate */
- u_int32_t cap; /* Remaining Capacity */
- u_int32_t volt; /* Present Voltage */
+ uint32_t state; /* Battery State */
+ uint32_t rate; /* Present Rate */
+ uint32_t cap; /* Remaining Capacity */
+ uint32_t volt; /* Present Voltage */
};
#define ACPI_BATT_STAT_DISCHARG 0x0001
@@ -80,20 +73,19 @@ struct acpi_bst {
#define ACPI_BATT_STAT_MAX 0x0007
union acpi_battery_ioctl_arg {
- int unit; /* argument: logical unit (-1 = overall) */
+ int unit; /* Device unit or ACPI_BATTERY_ALL_UNITS. */
- struct acpi_battdesc battdesc;
- struct acpi_battinfo battinfo;
+ struct acpi_battinfo battinfo;
struct acpi_bif bif;
struct acpi_bst bst;
};
+#define ACPI_BATTERY_ALL_UNITS (-1)
+
/* Common battery ioctls */
#define ACPIIO_BATT_GET_UNITS _IOR('B', 0x01, int)
-#define ACPIIO_BATT_GET_TYPE _IOR('B', 0x02, union acpi_battery_ioctl_arg)
#define ACPIIO_BATT_GET_BATTINFO _IOWR('B', 0x03, union acpi_battery_ioctl_arg)
-#define ACPIIO_BATT_GET_BATTDESC _IOWR('B', 0x04, union acpi_battery_ioctl_arg)
#define ACPIIO_BATT_GET_BIF _IOWR('B', 0x10, union acpi_battery_ioctl_arg)
#define ACPIIO_BATT_GET_BST _IOWR('B', 0x11, union acpi_battery_ioctl_arg)
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index e8431e9730e2f..9c0547d24daf7 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -74,9 +74,6 @@ struct acpi_softc {
bus_dmamap_t acpi_wakemap;
vm_offset_t acpi_wakeaddr;
vm_paddr_t acpi_wakephys;
-
- struct sysctl_ctx_list acpi_battery_sysctl_ctx;
- struct sysctl_oid *acpi_battery_sysctl_tree;
};
struct acpi_device {
@@ -393,16 +390,15 @@ int acpi_machdep_quirks(int *quirks);
/* Battery Abstraction. */
struct acpi_battinfo;
-struct acpi_battdesc;
-int acpi_battery_register(int, int);
-int acpi_battery_remove(int, int);
-int acpi_battery_get_battinfo(int, struct acpi_battinfo *);
+int acpi_battery_register(device_t dev);
+int acpi_battery_remove(device_t dev);
int acpi_battery_get_units(void);
int acpi_battery_get_info_expire(void);
-int acpi_battery_get_battdesc(int, struct acpi_battdesc *);
-
-int acpi_cmbat_get_battinfo(int, struct acpi_battinfo *);
+int acpi_battery_bst_valid(struct acpi_bst *bst);
+int acpi_battery_bif_valid(struct acpi_bif *bif);
+int acpi_battery_get_battinfo(device_t dev,
+ struct acpi_battinfo *info);
/* Embedded controller. */
void acpi_ec_ecdt_probe(device_t);