Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.3 252 lines 6.0 kB view raw
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/slab.h> 17#include <linux/device.h> 18#include <linux/err.h> 19#include <linux/power_supply.h> 20#include "power_supply.h" 21 22/* exported for the APM Power driver, APM emulation */ 23struct class *power_supply_class; 24EXPORT_SYMBOL_GPL(power_supply_class); 25 26static struct device_type power_supply_dev_type; 27 28static int __power_supply_changed_work(struct device *dev, void *data) 29{ 30 struct power_supply *psy = (struct power_supply *)data; 31 struct power_supply *pst = dev_get_drvdata(dev); 32 int i; 33 34 for (i = 0; i < psy->num_supplicants; i++) 35 if (!strcmp(psy->supplied_to[i], pst->name)) { 36 if (pst->external_power_changed) 37 pst->external_power_changed(pst); 38 } 39 return 0; 40} 41 42static void power_supply_changed_work(struct work_struct *work) 43{ 44 struct power_supply *psy = container_of(work, struct power_supply, 45 changed_work); 46 47 dev_dbg(psy->dev, "%s\n", __func__); 48 49 class_for_each_device(power_supply_class, NULL, psy, 50 __power_supply_changed_work); 51 52 power_supply_update_leds(psy); 53 54 kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); 55} 56 57void power_supply_changed(struct power_supply *psy) 58{ 59 dev_dbg(psy->dev, "%s\n", __func__); 60 61 schedule_work(&psy->changed_work); 62} 63EXPORT_SYMBOL_GPL(power_supply_changed); 64 65static int __power_supply_am_i_supplied(struct device *dev, void *data) 66{ 67 union power_supply_propval ret = {0,}; 68 struct power_supply *psy = (struct power_supply *)data; 69 struct power_supply *epsy = dev_get_drvdata(dev); 70 int i; 71 72 for (i = 0; i < epsy->num_supplicants; i++) { 73 if (!strcmp(epsy->supplied_to[i], psy->name)) { 74 if (epsy->get_property(epsy, 75 POWER_SUPPLY_PROP_ONLINE, &ret)) 76 continue; 77 if (ret.intval) 78 return ret.intval; 79 } 80 } 81 return 0; 82} 83 84int power_supply_am_i_supplied(struct power_supply *psy) 85{ 86 int error; 87 88 error = class_for_each_device(power_supply_class, NULL, psy, 89 __power_supply_am_i_supplied); 90 91 dev_dbg(psy->dev, "%s %d\n", __func__, error); 92 93 return error; 94} 95EXPORT_SYMBOL_GPL(power_supply_am_i_supplied); 96 97static int __power_supply_is_system_supplied(struct device *dev, void *data) 98{ 99 union power_supply_propval ret = {0,}; 100 struct power_supply *psy = dev_get_drvdata(dev); 101 unsigned int *count = data; 102 103 (*count)++; 104 if (psy->type != POWER_SUPPLY_TYPE_BATTERY) { 105 if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret)) 106 return 0; 107 if (ret.intval) 108 return ret.intval; 109 } 110 return 0; 111} 112 113int power_supply_is_system_supplied(void) 114{ 115 int error; 116 unsigned int count = 0; 117 118 error = class_for_each_device(power_supply_class, NULL, &count, 119 __power_supply_is_system_supplied); 120 121 /* 122 * If no power class device was found at all, most probably we are 123 * running on a desktop system, so assume we are on mains power. 124 */ 125 if (count == 0) 126 return 1; 127 128 return error; 129} 130EXPORT_SYMBOL_GPL(power_supply_is_system_supplied); 131 132int power_supply_set_battery_charged(struct power_supply *psy) 133{ 134 if (psy->type == POWER_SUPPLY_TYPE_BATTERY && psy->set_charged) { 135 psy->set_charged(psy); 136 return 0; 137 } 138 139 return -EINVAL; 140} 141EXPORT_SYMBOL_GPL(power_supply_set_battery_charged); 142 143static int power_supply_match_device_by_name(struct device *dev, void *data) 144{ 145 const char *name = data; 146 struct power_supply *psy = dev_get_drvdata(dev); 147 148 return strcmp(psy->name, name) == 0; 149} 150 151struct power_supply *power_supply_get_by_name(char *name) 152{ 153 struct device *dev = class_find_device(power_supply_class, NULL, name, 154 power_supply_match_device_by_name); 155 156 return dev ? dev_get_drvdata(dev) : NULL; 157} 158EXPORT_SYMBOL_GPL(power_supply_get_by_name); 159 160int power_supply_powers(struct power_supply *psy, struct device *dev) 161{ 162 return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers"); 163} 164EXPORT_SYMBOL_GPL(power_supply_powers); 165 166static void power_supply_dev_release(struct device *dev) 167{ 168 pr_debug("device: '%s': %s\n", dev_name(dev), __func__); 169 kfree(dev); 170} 171 172int power_supply_register(struct device *parent, struct power_supply *psy) 173{ 174 struct device *dev; 175 int rc; 176 177 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 178 if (!dev) 179 return -ENOMEM; 180 181 device_initialize(dev); 182 183 dev->class = power_supply_class; 184 dev->type = &power_supply_dev_type; 185 dev->parent = parent; 186 dev->release = power_supply_dev_release; 187 dev_set_drvdata(dev, psy); 188 psy->dev = dev; 189 190 INIT_WORK(&psy->changed_work, power_supply_changed_work); 191 192 rc = kobject_set_name(&dev->kobj, "%s", psy->name); 193 if (rc) 194 goto kobject_set_name_failed; 195 196 rc = device_add(dev); 197 if (rc) 198 goto device_add_failed; 199 200 rc = power_supply_create_triggers(psy); 201 if (rc) 202 goto create_triggers_failed; 203 204 power_supply_changed(psy); 205 206 goto success; 207 208create_triggers_failed: 209 device_del(dev); 210kobject_set_name_failed: 211device_add_failed: 212 put_device(dev); 213success: 214 return rc; 215} 216EXPORT_SYMBOL_GPL(power_supply_register); 217 218void power_supply_unregister(struct power_supply *psy) 219{ 220 cancel_work_sync(&psy->changed_work); 221 sysfs_remove_link(&psy->dev->kobj, "powers"); 222 power_supply_remove_triggers(psy); 223 device_unregister(psy->dev); 224} 225EXPORT_SYMBOL_GPL(power_supply_unregister); 226 227static int __init power_supply_class_init(void) 228{ 229 power_supply_class = class_create(THIS_MODULE, "power_supply"); 230 231 if (IS_ERR(power_supply_class)) 232 return PTR_ERR(power_supply_class); 233 234 power_supply_class->dev_uevent = power_supply_uevent; 235 power_supply_init_attrs(&power_supply_dev_type); 236 237 return 0; 238} 239 240static void __exit power_supply_class_exit(void) 241{ 242 class_destroy(power_supply_class); 243} 244 245subsys_initcall(power_supply_class_init); 246module_exit(power_supply_class_exit); 247 248MODULE_DESCRIPTION("Universal power supply monitor class"); 249MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, " 250 "Szabolcs Gyurko, " 251 "Anton Vorontsov <cbou@mail.ru>"); 252MODULE_LICENSE("GPL");