static int
acpi_smbat_get_bst(device_t dev, struct acpi_bst *bst)
{
	struct acpi_smbat_softc *sc;
	int error;
	uint32_t factor;
	int16_t val;
	uint8_t	addr;

	ACPI_SERIAL_BEGIN(smbat);

	addr = SMBATT_ADDRESS;
	error = ENXIO;
	sc = device_get_softc(dev);

	if (!acpi_smbat_info_expired(&sc->bst_lastupdated)) {
		error = 0;
		goto out;
	}

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_MODE, &val))
		goto out;
	if (val & SMBATT_BM_CAPACITY_MODE)
		factor = 10;
	else
		factor = 1;

	/* get battery status */
	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_STATUS, &val))
		goto out;

	sc->bst.state = 0;
	if (val & SMBATT_BS_DISCHARGING)
		sc->bst.state |= ACPI_BATT_STAT_DISCHARG;

	if (val & SMBATT_BS_REMAINING_CAPACITY_ALARM)
		sc->bst.state |= ACPI_BATT_STAT_CRITICAL;

	/*
	 * If the rate is negative, it is discharging.  Otherwise,
	 * it is charging.
	 */
	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_CURRENT, &val))
		goto out;

	if (val > 0) {
		sc->bst.rate = val * factor;
		sc->bst.state &= ~SMBATT_BS_DISCHARGING;
		sc->bst.state |= ACPI_BATT_STAT_CHARGING;
	} else if (val < 0)
		sc->bst.rate = (-val) * factor;
	else
		sc->bst.rate = 0;

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_REMAINING_CAPACITY, &val))
		goto out;
	sc->bst.cap = val * factor;

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_VOLTAGE, &val))
		goto out;
	sc->bst.volt = val;

	acpi_smbat_info_updated(&sc->bst_lastupdated);
	error = 0;

out:
	if (error == 0)
		memcpy(bst, &sc->bst, sizeof(sc->bst));
	ACPI_SERIAL_END(smbat);
	return (error);
}
static int
acpi_smbat_get_bif(device_t dev, struct acpi_bif *bif)
{
	struct acpi_smbat_softc *sc;
	int error;
	uint32_t factor;
	uint16_t val;
	uint8_t addr;

	ACPI_SERIAL_BEGIN(smbat);

	addr = SMBATT_ADDRESS;
	error = ENXIO;
	sc = device_get_softc(dev);

	if (!acpi_smbat_info_expired(&sc->bif_lastupdated)) {
		error = 0;
		goto out;
	}

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_MODE, &val))
		goto out;
	if (val & SMBATT_BM_CAPACITY_MODE) {
		factor = 10;
		sc->bif.units = ACPI_BIF_UNITS_MW;
	} else {
		factor = 1;
		sc->bif.units = ACPI_BIF_UNITS_MA;
	}

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_DESIGN_CAPACITY, &val))
		goto out;
	sc->bif.dcap = val * factor;

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_FULL_CHARGE_CAPACITY, &val))
		goto out;
	sc->bif.lfcap = val * factor;
	sc->bif.btech = 1;		/* secondary (rechargeable) */

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_DESIGN_VOLTAGE, &val))
		goto out;
	sc->bif.dvol = val;

	sc->bif.wcap = sc->bif.dcap / 10;
	sc->bif.lcap = sc->bif.dcap / 10;

	sc->bif.gra1 = factor;	/* not supported */
	sc->bif.gra2 = factor;	/* not supported */

	if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_DEVICE_NAME,
	    sc->bif.model, sizeof(sc->bif.model)))
		goto out;

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_SERIAL_NUMBER, &val))
		goto out;
	snprintf(sc->bif.serial, sizeof(sc->bif.serial), "0x%04x", val);

	if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_DEVICE_CHEMISTRY,
	    sc->bif.type, sizeof(sc->bif.type)))
		goto out;

	if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_MANUFACTURER_DATA,
	    sc->bif.oeminfo, sizeof(sc->bif.oeminfo)))
		goto out;

	/* XXX check if device was replugged during read? */

	acpi_smbat_info_updated(&sc->bif_lastupdated);
	error = 0;

out:
	if (error == 0)
		memcpy(bif, &sc->bif, sizeof(sc->bif));
	ACPI_SERIAL_END(smbat);
	return (error);
}