linux/drivers/power/power_supply_core.c
<<
>>
Prefs
   1/*
   2 *  Universal power supply monitor class
   3 *
   4 *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
   5 *  Copyright © 2004  Szabolcs Gyurko
   6 *  Copyright © 2003  Ian Molton <spyro@f2s.com>
   7 *
   8 *  Modified: 2004, Oct     Szabolcs Gyurko
   9 *
  10 *  You may use this code as per GPL version 2
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/types.h>
  15#include <linux/init.h>
  16#include <linux/device.h>
  17#include <linux/err.h>
  18#include <linux/power_supply.h>
  19#include "power_supply.h"
  20
  21struct class *power_supply_class;
  22
  23static void power_supply_changed_work(struct work_struct *work)
  24{
  25        struct power_supply *psy = container_of(work, struct power_supply,
  26                                                changed_work);
  27        int i;
  28
  29        dev_dbg(psy->dev, "%s\n", __FUNCTION__);
  30
  31        for (i = 0; i < psy->num_supplicants; i++) {
  32                struct device *dev;
  33
  34                down(&power_supply_class->sem);
  35                list_for_each_entry(dev, &power_supply_class->devices, node) {
  36                        struct power_supply *pst = dev_get_drvdata(dev);
  37
  38                        if (!strcmp(psy->supplied_to[i], pst->name)) {
  39                                if (pst->external_power_changed)
  40                                        pst->external_power_changed(pst);
  41                        }
  42                }
  43                up(&power_supply_class->sem);
  44        }
  45
  46        power_supply_update_leds(psy);
  47
  48        kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
  49}
  50
  51void power_supply_changed(struct power_supply *psy)
  52{
  53        dev_dbg(psy->dev, "%s\n", __FUNCTION__);
  54
  55        schedule_work(&psy->changed_work);
  56}
  57
  58int power_supply_am_i_supplied(struct power_supply *psy)
  59{
  60        union power_supply_propval ret = {0,};
  61        struct device *dev;
  62
  63        down(&power_supply_class->sem);
  64        list_for_each_entry(dev, &power_supply_class->devices, node) {
  65                struct power_supply *epsy = dev_get_drvdata(dev);
  66                int i;
  67
  68                for (i = 0; i < epsy->num_supplicants; i++) {
  69                        if (!strcmp(epsy->supplied_to[i], psy->name)) {
  70                                if (epsy->get_property(epsy,
  71                                          POWER_SUPPLY_PROP_ONLINE, &ret))
  72                                        continue;
  73                                if (ret.intval)
  74                                        goto out;
  75                        }
  76                }
  77        }
  78out:
  79        up(&power_supply_class->sem);
  80
  81        dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval);
  82
  83        return ret.intval;
  84}
  85
  86int power_supply_register(struct device *parent, struct power_supply *psy)
  87{
  88        int rc = 0;
  89
  90        psy->dev = device_create(power_supply_class, parent, 0,
  91                                 "%s", psy->name);
  92        if (IS_ERR(psy->dev)) {
  93                rc = PTR_ERR(psy->dev);
  94                goto dev_create_failed;
  95        }
  96
  97        dev_set_drvdata(psy->dev, psy);
  98
  99        INIT_WORK(&psy->changed_work, power_supply_changed_work);
 100
 101        rc = power_supply_create_attrs(psy);
 102        if (rc)
 103                goto create_attrs_failed;
 104
 105        rc = power_supply_create_triggers(psy);
 106        if (rc)
 107                goto create_triggers_failed;
 108
 109        power_supply_changed(psy);
 110
 111        goto success;
 112
 113create_triggers_failed:
 114        power_supply_remove_attrs(psy);
 115create_attrs_failed:
 116        device_unregister(psy->dev);
 117dev_create_failed:
 118success:
 119        return rc;
 120}
 121
 122void power_supply_unregister(struct power_supply *psy)
 123{
 124        flush_scheduled_work();
 125        power_supply_remove_triggers(psy);
 126        power_supply_remove_attrs(psy);
 127        device_unregister(psy->dev);
 128}
 129
 130static int __init power_supply_class_init(void)
 131{
 132        power_supply_class = class_create(THIS_MODULE, "power_supply");
 133
 134        if (IS_ERR(power_supply_class))
 135                return PTR_ERR(power_supply_class);
 136
 137        power_supply_class->dev_uevent = power_supply_uevent;
 138
 139        return 0;
 140}
 141
 142static void __exit power_supply_class_exit(void)
 143{
 144        class_destroy(power_supply_class);
 145}
 146
 147EXPORT_SYMBOL_GPL(power_supply_changed);
 148EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
 149EXPORT_SYMBOL_GPL(power_supply_register);
 150EXPORT_SYMBOL_GPL(power_supply_unregister);
 151
 152/* exported for the APM Power driver, APM emulation */
 153EXPORT_SYMBOL_GPL(power_supply_class);
 154
 155subsys_initcall(power_supply_class_init);
 156module_exit(power_supply_class_exit);
 157
 158MODULE_DESCRIPTION("Universal power supply monitor class");
 159MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, "
 160              "Szabolcs Gyurko, "
 161              "Anton Vorontsov <cbou@mail.ru>");
 162MODULE_LICENSE("GPL");
 163