staticunsignedint cache_time = 1000;
module_param(cache_time, uint, 0644);
MODULE_PARM_DESC(cache_time, "battery state caching time in milliseconds [default: 1000]");
/* -- State management. ----------------------------------------------------- */
/* * Delay for battery update quirk. See spwr_external_power_changed() below * for more details.
*/ #define SPWR_AC_BAT_UPDATE_DELAY msecs_to_jiffies(5000)
mutex_lock(&bat->lock);
unit = get_unaligned_le32(&bat->bix.power_unit);
present = spwr_battery_present(bat);
status = spwr_battery_update_bix_unlocked(bat); if (status) goto out;
/* If battery has been attached, (re-)initialize alarm. */ if (!present && spwr_battery_present(bat)) {
u32 cap_warn = get_unaligned_le32(&bat->bix.design_cap_warn);
status = spwr_battery_set_alarm_unlocked(bat, cap_warn); if (status) goto out;
}
/* * Warn if the unit has changed. This is something we genuinely don't * expect to happen, so make this a big warning. If it does, we'll * need to add support for it.
*/
WARN_ON(unit != get_unaligned_le32(&bat->bix.power_unit));
out:
mutex_unlock(&bat->lock);
if (!status)
power_supply_changed(bat->psy);
return status;
}
staticint spwr_battery_recheck_status(struct spwr_battery_device *bat)
{ int status;
status = spwr_battery_update_bst(bat, false); if (!status)
power_supply_changed(bat->psy);
/* * We cannot use strict matching when registering the notifier as the * EC expects us to register it against instance ID 0. Strict matching * would thus drop events, as those may have non-zero instance IDs in * this subsystem. So we need to check the instance ID of the event * here manually.
*/ if (event->instance_id != bat->sdev->uid.instance) return0;
/* * Handle battery update quirk: When the battery is fully charged (or * charged up to the limit imposed by the UEFI battery limit) and the * adapter is plugged in or removed, the EC does not send a separate * event for the state (charging/discharging) change. Furthermore it * may take some time until the state is updated on the battery. * Schedule an update to solve this.
*/
if (state & SAM_BATTERY_STATE_CRITICAL) return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
if (spwr_battery_is_full(bat)) return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
if (remaining_cap <= bat->alarm) return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
}
staticint spwr_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
{ struct spwr_battery_device *bat = power_supply_get_drvdata(psy);
u32 value; int status;
mutex_lock(&bat->lock);
status = spwr_battery_update_bst_unlocked(bat, true); if (status) goto out;
/* Abort if battery is not present. */ if (!spwr_battery_present(bat) && psp != POWER_SUPPLY_PROP_PRESENT) {
status = -ENODEV; goto out;
}
switch (psp) { case POWER_SUPPLY_PROP_STATUS:
val->intval = spwr_battery_prop_status(bat); break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = spwr_battery_present(bat); break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = spwr_battery_prop_technology(bat); break;
case POWER_SUPPLY_PROP_CYCLE_COUNT:
value = get_unaligned_le32(&bat->bix.cycle_count); if (value != SPWR_BATTERY_VALUE_UNKNOWN)
val->intval = value; else
status = -ENODATA; break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
value = get_unaligned_le32(&bat->bix.design_voltage); if (value != SPWR_BATTERY_VALUE_UNKNOWN)
val->intval = value * 1000; else
status = -ENODATA; break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
value = get_unaligned_le32(&bat->bst.present_voltage); if (value != SPWR_BATTERY_VALUE_UNKNOWN)
val->intval = value * 1000; else
status = -ENODATA; break;
case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_POWER_NOW:
value = get_unaligned_le32(&bat->bst.present_rate); if (value != SPWR_BATTERY_VALUE_UNKNOWN)
val->intval = value * 1000; else
status = -ENODATA; break;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
value = get_unaligned_le32(&bat->bix.design_cap); if (value != SPWR_BATTERY_VALUE_UNKNOWN)
val->intval = value * 1000; else
status = -ENODATA; break;
case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_ENERGY_FULL:
value = get_unaligned_le32(&bat->bix.last_full_charge_cap); if (value != SPWR_BATTERY_VALUE_UNKNOWN)
val->intval = value * 1000; else
status = -ENODATA; break;
case POWER_SUPPLY_PROP_CHARGE_NOW: case POWER_SUPPLY_PROP_ENERGY_NOW:
value = get_unaligned_le32(&bat->bst.remaining_cap); if (value != SPWR_BATTERY_VALUE_UNKNOWN)
val->intval = value * 1000; else
status = -ENODATA; break;
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = spwr_battery_prop_capacity(bat); break;
case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
val->intval = spwr_battery_prop_capacity_level(bat); break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = bat->bix.model; break;
case POWER_SUPPLY_PROP_MANUFACTURER:
val->strval = bat->bix.oem_info; break;
case POWER_SUPPLY_PROP_SERIAL_NUMBER:
val->strval = bat->bix.serial; break;
MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
MODULE_DESCRIPTION("Battery driver for Surface System Aggregator Module");
MODULE_LICENSE("GPL");
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.20Bemerkung:
(vorverarbeitet am 2026-06-07)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.