LCOV - code coverage report
Current view: top level - drivers/power - power_supply_sysfs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 81 0.0 %
Date: 2014-02-18 Functions: 0 6 0.0 %
Branches: 0 64 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *  Sysfs interface for the universal power supply monitor class
       3                 :            :  *
       4                 :            :  *  Copyright © 2007  David Woodhouse <dwmw2@infradead.org>
       5                 :            :  *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
       6                 :            :  *  Copyright © 2004  Szabolcs Gyurko
       7                 :            :  *  Copyright © 2003  Ian Molton <spyro@f2s.com>
       8                 :            :  *
       9                 :            :  *  Modified: 2004, Oct     Szabolcs Gyurko
      10                 :            :  *
      11                 :            :  *  You may use this code as per GPL version 2
      12                 :            :  */
      13                 :            : 
      14                 :            : #include <linux/ctype.h>
      15                 :            : #include <linux/device.h>
      16                 :            : #include <linux/power_supply.h>
      17                 :            : #include <linux/slab.h>
      18                 :            : #include <linux/stat.h>
      19                 :            : 
      20                 :            : #include "power_supply.h"
      21                 :            : 
      22                 :            : /*
      23                 :            :  * This is because the name "current" breaks the device attr macro.
      24                 :            :  * The "current" word resolves to "(get_current())" so instead of
      25                 :            :  * "current" "(get_current())" appears in the sysfs.
      26                 :            :  *
      27                 :            :  * The source of this definition is the device.h which calls __ATTR
      28                 :            :  * macro in sysfs.h which calls the __stringify macro.
      29                 :            :  *
      30                 :            :  * Only modification that the name is not tried to be resolved
      31                 :            :  * (as a macro let's say).
      32                 :            :  */
      33                 :            : 
      34                 :            : #define POWER_SUPPLY_ATTR(_name)                                        \
      35                 :            : {                                                                       \
      36                 :            :         .attr = { .name = #_name },                                     \
      37                 :            :         .show = power_supply_show_property,                             \
      38                 :            :         .store = power_supply_store_property,                           \
      39                 :            : }
      40                 :            : 
      41                 :            : static struct device_attribute power_supply_attrs[];
      42                 :            : 
      43                 :          0 : static ssize_t power_supply_show_property(struct device *dev,
      44                 :            :                                           struct device_attribute *attr,
      45                 :            :                                           char *buf) {
      46                 :            :         static char *type_text[] = {
      47                 :            :                 "Unknown", "Battery", "UPS", "Mains", "USB",
      48                 :            :                 "USB_DCP", "USB_CDP", "USB_ACA"
      49                 :            :         };
      50                 :            :         static char *status_text[] = {
      51                 :            :                 "Unknown", "Charging", "Discharging", "Not charging", "Full"
      52                 :            :         };
      53                 :            :         static char *charge_type[] = {
      54                 :            :                 "Unknown", "N/A", "Trickle", "Fast"
      55                 :            :         };
      56                 :            :         static char *health_text[] = {
      57                 :            :                 "Unknown", "Good", "Overheat", "Dead", "Over voltage",
      58                 :            :                 "Unspecified failure", "Cold", "Watchdog timer expire",
      59                 :            :                 "Safety timer expire"
      60                 :            :         };
      61                 :            :         static char *technology_text[] = {
      62                 :            :                 "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
      63                 :            :                 "LiMn"
      64                 :            :         };
      65                 :            :         static char *capacity_level_text[] = {
      66                 :            :                 "Unknown", "Critical", "Low", "Normal", "High", "Full"
      67                 :            :         };
      68                 :            :         static char *scope_text[] = {
      69                 :            :                 "Unknown", "System", "Device"
      70                 :            :         };
      71                 :            :         ssize_t ret = 0;
      72                 :          0 :         struct power_supply *psy = dev_get_drvdata(dev);
      73                 :          0 :         const ptrdiff_t off = attr - power_supply_attrs;
      74                 :            :         union power_supply_propval value;
      75                 :            : 
      76         [ #  # ]:          0 :         if (off == POWER_SUPPLY_PROP_TYPE)
      77                 :          0 :                 value.intval = psy->type;
      78                 :            :         else
      79                 :          0 :                 ret = psy->get_property(psy, off, &value);
      80                 :            : 
      81         [ #  # ]:          0 :         if (ret < 0) {
      82         [ #  # ]:          0 :                 if (ret == -ENODATA)
      83                 :            :                         dev_dbg(dev, "driver has no data for `%s' property\n",
      84                 :            :                                 attr->attr.name);
      85         [ #  # ]:          0 :                 else if (ret != -ENODEV)
      86                 :          0 :                         dev_err(dev, "driver failed to report `%s' property: %zd\n",
      87                 :            :                                 attr->attr.name, ret);
      88                 :          0 :                 return ret;
      89                 :            :         }
      90                 :            : 
      91         [ #  # ]:          0 :         if (off == POWER_SUPPLY_PROP_STATUS)
      92                 :          0 :                 return sprintf(buf, "%s\n", status_text[value.intval]);
      93         [ #  # ]:          0 :         else if (off == POWER_SUPPLY_PROP_CHARGE_TYPE)
      94                 :          0 :                 return sprintf(buf, "%s\n", charge_type[value.intval]);
      95         [ #  # ]:          0 :         else if (off == POWER_SUPPLY_PROP_HEALTH)
      96                 :          0 :                 return sprintf(buf, "%s\n", health_text[value.intval]);
      97         [ #  # ]:          0 :         else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
      98                 :          0 :                 return sprintf(buf, "%s\n", technology_text[value.intval]);
      99         [ #  # ]:          0 :         else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
     100                 :          0 :                 return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
     101         [ #  # ]:          0 :         else if (off == POWER_SUPPLY_PROP_TYPE)
     102                 :          0 :                 return sprintf(buf, "%s\n", type_text[value.intval]);
     103         [ #  # ]:          0 :         else if (off == POWER_SUPPLY_PROP_SCOPE)
     104                 :          0 :                 return sprintf(buf, "%s\n", scope_text[value.intval]);
     105         [ #  # ]:          0 :         else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
     106                 :          0 :                 return sprintf(buf, "%s\n", value.strval);
     107                 :            : 
     108                 :          0 :         return sprintf(buf, "%d\n", value.intval);
     109                 :            : }
     110                 :            : 
     111                 :          0 : static ssize_t power_supply_store_property(struct device *dev,
     112                 :            :                                            struct device_attribute *attr,
     113                 :            :                                            const char *buf, size_t count) {
     114                 :            :         ssize_t ret;
     115                 :          0 :         struct power_supply *psy = dev_get_drvdata(dev);
     116                 :          0 :         const ptrdiff_t off = attr - power_supply_attrs;
     117                 :            :         union power_supply_propval value;
     118                 :            :         long long_val;
     119                 :            : 
     120                 :            :         /* TODO: support other types than int */
     121                 :            :         ret = kstrtol(buf, 10, &long_val);
     122         [ #  # ]:          0 :         if (ret < 0)
     123                 :            :                 return ret;
     124                 :            : 
     125                 :          0 :         value.intval = long_val;
     126                 :            : 
     127                 :          0 :         ret = psy->set_property(psy, off, &value);
     128         [ #  # ]:          0 :         if (ret < 0)
     129                 :            :                 return ret;
     130                 :            : 
     131                 :          0 :         return count;
     132                 :            : }
     133                 :            : 
     134                 :            : /* Must be in the same order as POWER_SUPPLY_PROP_* */
     135                 :            : static struct device_attribute power_supply_attrs[] = {
     136                 :            :         /* Properties of type `int' */
     137                 :            :         POWER_SUPPLY_ATTR(status),
     138                 :            :         POWER_SUPPLY_ATTR(charge_type),
     139                 :            :         POWER_SUPPLY_ATTR(health),
     140                 :            :         POWER_SUPPLY_ATTR(present),
     141                 :            :         POWER_SUPPLY_ATTR(online),
     142                 :            :         POWER_SUPPLY_ATTR(authentic),
     143                 :            :         POWER_SUPPLY_ATTR(technology),
     144                 :            :         POWER_SUPPLY_ATTR(cycle_count),
     145                 :            :         POWER_SUPPLY_ATTR(voltage_max),
     146                 :            :         POWER_SUPPLY_ATTR(voltage_min),
     147                 :            :         POWER_SUPPLY_ATTR(voltage_max_design),
     148                 :            :         POWER_SUPPLY_ATTR(voltage_min_design),
     149                 :            :         POWER_SUPPLY_ATTR(voltage_now),
     150                 :            :         POWER_SUPPLY_ATTR(voltage_avg),
     151                 :            :         POWER_SUPPLY_ATTR(voltage_ocv),
     152                 :            :         POWER_SUPPLY_ATTR(current_max),
     153                 :            :         POWER_SUPPLY_ATTR(current_now),
     154                 :            :         POWER_SUPPLY_ATTR(current_avg),
     155                 :            :         POWER_SUPPLY_ATTR(power_now),
     156                 :            :         POWER_SUPPLY_ATTR(power_avg),
     157                 :            :         POWER_SUPPLY_ATTR(charge_full_design),
     158                 :            :         POWER_SUPPLY_ATTR(charge_empty_design),
     159                 :            :         POWER_SUPPLY_ATTR(charge_full),
     160                 :            :         POWER_SUPPLY_ATTR(charge_empty),
     161                 :            :         POWER_SUPPLY_ATTR(charge_now),
     162                 :            :         POWER_SUPPLY_ATTR(charge_avg),
     163                 :            :         POWER_SUPPLY_ATTR(charge_counter),
     164                 :            :         POWER_SUPPLY_ATTR(constant_charge_current),
     165                 :            :         POWER_SUPPLY_ATTR(constant_charge_current_max),
     166                 :            :         POWER_SUPPLY_ATTR(constant_charge_voltage),
     167                 :            :         POWER_SUPPLY_ATTR(constant_charge_voltage_max),
     168                 :            :         POWER_SUPPLY_ATTR(charge_control_limit),
     169                 :            :         POWER_SUPPLY_ATTR(charge_control_limit_max),
     170                 :            :         POWER_SUPPLY_ATTR(energy_full_design),
     171                 :            :         POWER_SUPPLY_ATTR(energy_empty_design),
     172                 :            :         POWER_SUPPLY_ATTR(energy_full),
     173                 :            :         POWER_SUPPLY_ATTR(energy_empty),
     174                 :            :         POWER_SUPPLY_ATTR(energy_now),
     175                 :            :         POWER_SUPPLY_ATTR(energy_avg),
     176                 :            :         POWER_SUPPLY_ATTR(capacity),
     177                 :            :         POWER_SUPPLY_ATTR(capacity_alert_min),
     178                 :            :         POWER_SUPPLY_ATTR(capacity_alert_max),
     179                 :            :         POWER_SUPPLY_ATTR(capacity_level),
     180                 :            :         POWER_SUPPLY_ATTR(temp),
     181                 :            :         POWER_SUPPLY_ATTR(temp_alert_min),
     182                 :            :         POWER_SUPPLY_ATTR(temp_alert_max),
     183                 :            :         POWER_SUPPLY_ATTR(temp_ambient),
     184                 :            :         POWER_SUPPLY_ATTR(temp_ambient_alert_min),
     185                 :            :         POWER_SUPPLY_ATTR(temp_ambient_alert_max),
     186                 :            :         POWER_SUPPLY_ATTR(time_to_empty_now),
     187                 :            :         POWER_SUPPLY_ATTR(time_to_empty_avg),
     188                 :            :         POWER_SUPPLY_ATTR(time_to_full_now),
     189                 :            :         POWER_SUPPLY_ATTR(time_to_full_avg),
     190                 :            :         POWER_SUPPLY_ATTR(type),
     191                 :            :         POWER_SUPPLY_ATTR(scope),
     192                 :            :         /* Local extensions */
     193                 :            :         POWER_SUPPLY_ATTR(usb_hc),
     194                 :            :         POWER_SUPPLY_ATTR(usb_otg),
     195                 :            :         POWER_SUPPLY_ATTR(charge_enabled),
     196                 :            :         /* Properties of type `const char *' */
     197                 :            :         POWER_SUPPLY_ATTR(model_name),
     198                 :            :         POWER_SUPPLY_ATTR(manufacturer),
     199                 :            :         POWER_SUPPLY_ATTR(serial_number),
     200                 :            : };
     201                 :            : 
     202                 :            : static struct attribute *
     203                 :            : __power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
     204                 :            : 
     205                 :          0 : static umode_t power_supply_attr_is_visible(struct kobject *kobj,
     206                 :            :                                            struct attribute *attr,
     207                 :            :                                            int attrno)
     208                 :            : {
     209                 :          0 :         struct device *dev = container_of(kobj, struct device, kobj);
     210                 :          0 :         struct power_supply *psy = dev_get_drvdata(dev);
     211                 :            :         umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
     212                 :            :         int i;
     213                 :            : 
     214         [ #  # ]:          0 :         if (attrno == POWER_SUPPLY_PROP_TYPE)
     215                 :            :                 return mode;
     216                 :            : 
     217         [ #  # ]:          0 :         for (i = 0; i < psy->num_properties; i++) {
     218                 :          0 :                 int property = psy->properties[i];
     219                 :            : 
     220         [ #  # ]:          0 :                 if (property == attrno) {
     221   [ #  #  #  # ]:          0 :                         if (psy->property_is_writeable &&
     222                 :          0 :                             psy->property_is_writeable(psy, property) > 0)
     223                 :            :                                 mode |= S_IWUSR;
     224                 :            : 
     225                 :          0 :                         return mode;
     226                 :            :                 }
     227                 :            :         }
     228                 :            : 
     229                 :            :         return 0;
     230                 :            : }
     231                 :            : 
     232                 :            : static struct attribute_group power_supply_attr_group = {
     233                 :            :         .attrs = __power_supply_attrs,
     234                 :            :         .is_visible = power_supply_attr_is_visible,
     235                 :            : };
     236                 :            : 
     237                 :            : static const struct attribute_group *power_supply_attr_groups[] = {
     238                 :            :         &power_supply_attr_group,
     239                 :            :         NULL,
     240                 :            : };
     241                 :            : 
     242                 :          0 : void power_supply_init_attrs(struct device_type *dev_type)
     243                 :            : {
     244                 :            :         int i;
     245                 :            : 
     246                 :          0 :         dev_type->groups = power_supply_attr_groups;
     247                 :            : 
     248         [ #  # ]:          0 :         for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
     249                 :          0 :                 __power_supply_attrs[i] = &power_supply_attrs[i].attr;
     250                 :          0 : }
     251                 :            : 
     252                 :          0 : static char *kstruprdup(const char *str, gfp_t gfp)
     253                 :            : {
     254                 :            :         char *ret, *ustr;
     255                 :            : 
     256                 :          0 :         ustr = ret = kmalloc(strlen(str) + 1, gfp);
     257                 :            : 
     258         [ #  # ]:          0 :         if (!ret)
     259                 :            :                 return NULL;
     260                 :            : 
     261         [ #  # ]:          0 :         while (*str)
     262                 :          0 :                 *ustr++ = toupper(*str++);
     263                 :            : 
     264                 :          0 :         *ustr = 0;
     265                 :            : 
     266                 :          0 :         return ret;
     267                 :            : }
     268                 :            : 
     269                 :          0 : int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
     270                 :            : {
     271                 :          0 :         struct power_supply *psy = dev_get_drvdata(dev);
     272                 :            :         int ret = 0, j;
     273                 :            :         char *prop_buf;
     274                 :            :         char *attrname;
     275                 :            : 
     276                 :            :         dev_dbg(dev, "uevent\n");
     277                 :            : 
     278 [ #  # ][ #  # ]:          0 :         if (!psy || !psy->dev) {
     279                 :            :                 dev_dbg(dev, "No power supply yet\n");
     280                 :            :                 return ret;
     281                 :            :         }
     282                 :            : 
     283                 :            :         dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
     284                 :            : 
     285                 :          0 :         ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);
     286         [ #  # ]:          0 :         if (ret)
     287                 :            :                 return ret;
     288                 :            : 
     289                 :          0 :         prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
     290         [ #  # ]:          0 :         if (!prop_buf)
     291                 :            :                 return -ENOMEM;
     292                 :            : 
     293         [ #  # ]:          0 :         for (j = 0; j < psy->num_properties; j++) {
     294                 :            :                 struct device_attribute *attr;
     295                 :            :                 char *line;
     296                 :            : 
     297                 :          0 :                 attr = &power_supply_attrs[psy->properties[j]];
     298                 :            : 
     299                 :          0 :                 ret = power_supply_show_property(dev, attr, prop_buf);
     300         [ #  # ]:          0 :                 if (ret == -ENODEV || ret == -ENODATA) {
     301                 :            :                         /* When a battery is absent, we expect -ENODEV. Don't abort;
     302                 :            :                            send the uevent with at least the the PRESENT=0 property */
     303                 :            :                         ret = 0;
     304                 :          0 :                         continue;
     305                 :            :                 }
     306                 :            : 
     307         [ #  # ]:          0 :                 if (ret < 0)
     308                 :            :                         goto out;
     309                 :            : 
     310                 :          0 :                 line = strchr(prop_buf, '\n');
     311         [ #  # ]:          0 :                 if (line)
     312                 :          0 :                         *line = 0;
     313                 :            : 
     314                 :          0 :                 attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
     315         [ #  # ]:          0 :                 if (!attrname) {
     316                 :            :                         ret = -ENOMEM;
     317                 :            :                         goto out;
     318                 :            :                 }
     319                 :            : 
     320                 :            :                 dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
     321                 :            : 
     322                 :          0 :                 ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
     323                 :          0 :                 kfree(attrname);
     324         [ #  # ]:          0 :                 if (ret)
     325                 :            :                         goto out;
     326                 :            :         }
     327                 :            : 
     328                 :            : out:
     329                 :          0 :         free_page((unsigned long)prop_buf);
     330                 :            : 
     331                 :          0 :         return ret;
     332                 :            : }

Generated by: LCOV version 1.9