Index: sys/dev/acpica/acpi_cmbat.c =================================================================== --- sys/dev/acpica/acpi_cmbat.c +++ sys/dev/acpica/acpi_cmbat.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,7 @@ #define ACPI_BATTERY_BST_CHANGE 0x80 #define ACPI_BATTERY_BIF_CHANGE 0x81 #define ACPI_BATTERY_BIX_CHANGE ACPI_BATTERY_BIF_CHANGE +#define ACPI_BATTERY_BTP_WARNING_LEVEL 20 struct acpi_cmbat_softc { device_t dev; @@ -69,7 +71,9 @@ struct acpi_bix bix; struct acpi_bst bst; - struct timespec bst_lastupdated; + struct timespec bst_lastupdated; + bool acpi_btp_exists; + int btp_warning_level; }; ACPI_SERIAL_DECL(cmbat, "ACPI cmbat"); @@ -87,6 +91,8 @@ static void acpi_cmbat_get_bix(void *arg); static int acpi_cmbat_bst(device_t, struct acpi_bst *); static int acpi_cmbat_bix(device_t, void *, size_t); +static void acpi_cmbat_btp(void *); +static int acpi_cmbat_btp_sysctl(SYSCTL_HANDLER_ARGS); static void acpi_cmbat_init_battery(void *arg); static device_method_t acpi_cmbat_methods[] = { @@ -526,6 +532,90 @@ } static void +acpi_cmbat_btp(void *arg) { + + struct acpi_cmbat_softc *sc; + device_t dev; + ACPI_HANDLE h; + ACPI_STATUS as; + uint64_t newtp; + + ACPI_SERIAL_ASSERT(cmbat); + + dev = arg; + sc = device_get_softc(dev); + h = acpi_get_handle(dev); + + /* + * Try to set a default warning level. + * If successful, we assume that _BTP exists, + * and create the sysctl. + */ + + sc->btp_warning_level= ACPI_BATTERY_BTP_WARNING_LEVEL; + newtp = sc->bix.lfcap * sc->btp_warning_level / 100; + as = acpi_SetInteger(h, "_BTP", (uint32_t) newtp); + + if(as == AE_NOT_FOUND) + sc->acpi_btp_exists = FALSE; + else if (ACPI_FAILURE(as)) { + ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), + "error setting _BTP --%s\n", AcpiFormatException(as)); + sc->acpi_btp_exists = FALSE; + } + else { + sc->acpi_btp_exists = TRUE; + struct sysctl_oid *cmbat_oid = device_get_sysctl_tree(dev); + SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(cmbat_oid), OID_AUTO, + "warning_level", CTLTYPE_INT | CTLFLAG_RW, 0, 0, + acpi_cmbat_btp_sysctl, "I" ,"battery warning level"); + } +} + +static int acpi_cmbat_btp_sysctl(SYSCTL_HANDLER_ARGS) { + + struct sysctl_oid *parent; + struct acpi_cmbat_softc *sc; + device_t dev; + ACPI_HANDLE h; + ACPI_STATUS as; + + long battery_index; + uint64_t newtp; + + ACPI_SERIAL_BEGIN(cmbat); + + parent = SYSCTL_PARENT(oidp); + battery_index = strtol(parent->oid_name, NULL, 0); + dev = devclass_get_device(acpi_cmbat_devclass, (int) battery_index); + + h = acpi_get_handle(dev); + sc = device_get_softc(dev); + + if(req->newptr) { + /* write request */ + SYSCTL_IN(req, &sc->btp_warning_level, sizeof(sc->btp_warning_level)); + + /* correct bogus writes */ + if(sc->btp_warning_level < 1 || sc->btp_warning_level > 99) + sc->btp_warning_level = ACPI_BATTERY_BTP_WARNING_LEVEL; + + newtp = sc->bix.lfcap * sc->btp_warning_level / 100; + as = acpi_SetInteger(h, "_BTP", (uint32_t) newtp); + + if(ACPI_FAILURE(as)) + ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), + "error setting _BTP -- %s\n", AcpiFormatException(as)); + } + else /* read request */ + SYSCTL_OUT(req, &sc->btp_warning_level, sizeof(sc->btp_warning_level)); + + ACPI_SERIAL_END(cmbat); + + return (0); +} + +static void acpi_cmbat_init_battery(void *arg) { struct acpi_cmbat_softc *sc; @@ -578,6 +668,10 @@ valid = acpi_battery_bst_valid(&sc->bst) && acpi_battery_bix_valid(&sc->bix); + + if(valid) + acpi_cmbat_btp(dev); + ACPI_SERIAL_END(cmbat); if (valid)