mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
power_supply: Add API for safe access of power supply function attrs
Add simple wrappers for accessing power supply's function attributes: - get_property -> power_supply_get_property - set_property -> power_supply_set_property - property_is_writeable -> power_supply_property_is_writeable - external_power_changed -> power_supply_external_power_changed This API along with atomic usage counter adds a safe way of accessing a power supply from another driver. If power supply is unregistered after obtaining reference to it by some driver, then the API wrappers won't be executed in invalid (freed) context. Next patch changing the ownership of power supply class is still needed to fully fix race conditions in accessing freed power supply. Signed-off-by: Krzysztof Kozlowski <[email protected]> Reviewed-by: Bartlomiej Zolnierkiewicz <[email protected]> Reviewed-by: Sebastian Reichel <[email protected]> Acked-by: Pavel Machek <[email protected]> Signed-off-by: Sebastian Reichel <[email protected]>
This commit is contained in:
parent
2dc9215d7c
commit
bc1540561c
2 changed files with 62 additions and 1 deletions
|
|
@ -314,7 +314,9 @@ EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
|
|||
|
||||
int power_supply_set_battery_charged(struct power_supply *psy)
|
||||
{
|
||||
if (psy->type == POWER_SUPPLY_TYPE_BATTERY && psy->set_charged) {
|
||||
if (atomic_read(&psy->use_cnt) >= 0 &&
|
||||
psy->type == POWER_SUPPLY_TYPE_BATTERY &&
|
||||
psy->set_charged) {
|
||||
psy->set_charged(psy);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -366,6 +368,47 @@ struct power_supply *power_supply_get_by_phandle(struct device_node *np,
|
|||
EXPORT_SYMBOL_GPL(power_supply_get_by_phandle);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
int power_supply_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
if (atomic_read(&psy->use_cnt) <= 0)
|
||||
return -ENODEV;
|
||||
|
||||
return psy->get_property(psy, psp, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_get_property);
|
||||
|
||||
int power_supply_set_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
if (atomic_read(&psy->use_cnt) <= 0 || !psy->set_property)
|
||||
return -ENODEV;
|
||||
|
||||
return psy->set_property(psy, psp, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_set_property);
|
||||
|
||||
int power_supply_property_is_writeable(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
if (atomic_read(&psy->use_cnt) <= 0 || !psy->property_is_writeable)
|
||||
return -ENODEV;
|
||||
|
||||
return psy->property_is_writeable(psy, psp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_property_is_writeable);
|
||||
|
||||
void power_supply_external_power_changed(struct power_supply *psy)
|
||||
{
|
||||
if (atomic_read(&psy->use_cnt) <= 0 || !psy->external_power_changed)
|
||||
return;
|
||||
|
||||
psy->external_power_changed(psy);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_external_power_changed);
|
||||
|
||||
int power_supply_powers(struct power_supply *psy, struct device *dev)
|
||||
{
|
||||
return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers");
|
||||
|
|
@ -555,6 +598,7 @@ static int __power_supply_register(struct device *parent,
|
|||
dev->release = power_supply_dev_release;
|
||||
dev_set_drvdata(dev, psy);
|
||||
psy->dev = dev;
|
||||
atomic_inc(&psy->use_cnt);
|
||||
if (cfg) {
|
||||
psy->drv_data = cfg->drv_data;
|
||||
psy->of_node = cfg->of_node;
|
||||
|
|
@ -676,6 +720,7 @@ EXPORT_SYMBOL_GPL(devm_power_supply_register_no_ws);
|
|||
|
||||
void power_supply_unregister(struct power_supply *psy)
|
||||
{
|
||||
WARN_ON(atomic_dec_return(&psy->use_cnt));
|
||||
cancel_work_sync(&psy->changed_work);
|
||||
sysfs_remove_link(&psy->dev->kobj, "powers");
|
||||
power_supply_remove_triggers(psy);
|
||||
|
|
|
|||
Loading…
Reference in a new issue