LCOV - code coverage report
Current view: top level - drivers/power/supply - power_supply_sysfs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 14 126 11.1 %
Date: 2022-12-09 01:23:36 Functions: 1 9 11.1 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  *  Sysfs interface for the universal power supply monitor class
       4             :  *
       5             :  *  Copyright © 2007  David Woodhouse <dwmw2@infradead.org>
       6             :  *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
       7             :  *  Copyright © 2004  Szabolcs Gyurko
       8             :  *  Copyright © 2003  Ian Molton <spyro@f2s.com>
       9             :  *
      10             :  *  Modified: 2004, Oct     Szabolcs Gyurko
      11             :  */
      12             : 
      13             : #include <linux/ctype.h>
      14             : #include <linux/device.h>
      15             : #include <linux/power_supply.h>
      16             : #include <linux/slab.h>
      17             : #include <linux/stat.h>
      18             : 
      19             : #include "power_supply.h"
      20             : 
      21             : #define MAX_PROP_NAME_LEN 30
      22             : 
      23             : struct power_supply_attr {
      24             :         const char *prop_name;
      25             :         char attr_name[MAX_PROP_NAME_LEN + 1];
      26             :         struct device_attribute dev_attr;
      27             :         const char * const *text_values;
      28             :         int text_values_len;
      29             : };
      30             : 
      31             : #define _POWER_SUPPLY_ATTR(_name, _text, _len)  \
      32             : [POWER_SUPPLY_PROP_ ## _name] =                 \
      33             : {                                               \
      34             :         .prop_name = #_name,                    \
      35             :         .attr_name = #_name "\0",             \
      36             :         .text_values = _text,                   \
      37             :         .text_values_len = _len,                \
      38             : }
      39             : 
      40             : #define POWER_SUPPLY_ATTR(_name) _POWER_SUPPLY_ATTR(_name, NULL, 0)
      41             : #define _POWER_SUPPLY_ENUM_ATTR(_name, _text)   \
      42             :         _POWER_SUPPLY_ATTR(_name, _text, ARRAY_SIZE(_text))
      43             : #define POWER_SUPPLY_ENUM_ATTR(_name)   \
      44             :         _POWER_SUPPLY_ENUM_ATTR(_name, POWER_SUPPLY_ ## _name ## _TEXT)
      45             : 
      46             : static const char * const POWER_SUPPLY_TYPE_TEXT[] = {
      47             :         [POWER_SUPPLY_TYPE_UNKNOWN]             = "Unknown",
      48             :         [POWER_SUPPLY_TYPE_BATTERY]             = "Battery",
      49             :         [POWER_SUPPLY_TYPE_UPS]                 = "UPS",
      50             :         [POWER_SUPPLY_TYPE_MAINS]               = "Mains",
      51             :         [POWER_SUPPLY_TYPE_USB]                 = "USB",
      52             :         [POWER_SUPPLY_TYPE_USB_DCP]             = "USB_DCP",
      53             :         [POWER_SUPPLY_TYPE_USB_CDP]             = "USB_CDP",
      54             :         [POWER_SUPPLY_TYPE_USB_ACA]             = "USB_ACA",
      55             :         [POWER_SUPPLY_TYPE_USB_TYPE_C]          = "USB_C",
      56             :         [POWER_SUPPLY_TYPE_USB_PD]              = "USB_PD",
      57             :         [POWER_SUPPLY_TYPE_USB_PD_DRP]          = "USB_PD_DRP",
      58             :         [POWER_SUPPLY_TYPE_APPLE_BRICK_ID]      = "BrickID",
      59             :         [POWER_SUPPLY_TYPE_WIRELESS]            = "Wireless",
      60             : };
      61             : 
      62             : static const char * const POWER_SUPPLY_USB_TYPE_TEXT[] = {
      63             :         [POWER_SUPPLY_USB_TYPE_UNKNOWN]         = "Unknown",
      64             :         [POWER_SUPPLY_USB_TYPE_SDP]             = "SDP",
      65             :         [POWER_SUPPLY_USB_TYPE_DCP]             = "DCP",
      66             :         [POWER_SUPPLY_USB_TYPE_CDP]             = "CDP",
      67             :         [POWER_SUPPLY_USB_TYPE_ACA]             = "ACA",
      68             :         [POWER_SUPPLY_USB_TYPE_C]               = "C",
      69             :         [POWER_SUPPLY_USB_TYPE_PD]              = "PD",
      70             :         [POWER_SUPPLY_USB_TYPE_PD_DRP]          = "PD_DRP",
      71             :         [POWER_SUPPLY_USB_TYPE_PD_PPS]          = "PD_PPS",
      72             :         [POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID]  = "BrickID",
      73             : };
      74             : 
      75             : static const char * const POWER_SUPPLY_STATUS_TEXT[] = {
      76             :         [POWER_SUPPLY_STATUS_UNKNOWN]           = "Unknown",
      77             :         [POWER_SUPPLY_STATUS_CHARGING]          = "Charging",
      78             :         [POWER_SUPPLY_STATUS_DISCHARGING]       = "Discharging",
      79             :         [POWER_SUPPLY_STATUS_NOT_CHARGING]      = "Not charging",
      80             :         [POWER_SUPPLY_STATUS_FULL]              = "Full",
      81             : };
      82             : 
      83             : static const char * const POWER_SUPPLY_CHARGE_TYPE_TEXT[] = {
      84             :         [POWER_SUPPLY_CHARGE_TYPE_UNKNOWN]      = "Unknown",
      85             :         [POWER_SUPPLY_CHARGE_TYPE_NONE]         = "N/A",
      86             :         [POWER_SUPPLY_CHARGE_TYPE_TRICKLE]      = "Trickle",
      87             :         [POWER_SUPPLY_CHARGE_TYPE_FAST]         = "Fast",
      88             :         [POWER_SUPPLY_CHARGE_TYPE_STANDARD]     = "Standard",
      89             :         [POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE]     = "Adaptive",
      90             :         [POWER_SUPPLY_CHARGE_TYPE_CUSTOM]       = "Custom",
      91             :         [POWER_SUPPLY_CHARGE_TYPE_LONGLIFE]     = "Long Life",
      92             :         [POWER_SUPPLY_CHARGE_TYPE_BYPASS]       = "Bypass",
      93             : };
      94             : 
      95             : static const char * const POWER_SUPPLY_HEALTH_TEXT[] = {
      96             :         [POWER_SUPPLY_HEALTH_UNKNOWN]               = "Unknown",
      97             :         [POWER_SUPPLY_HEALTH_GOOD]                  = "Good",
      98             :         [POWER_SUPPLY_HEALTH_OVERHEAT]              = "Overheat",
      99             :         [POWER_SUPPLY_HEALTH_DEAD]                  = "Dead",
     100             :         [POWER_SUPPLY_HEALTH_OVERVOLTAGE]           = "Over voltage",
     101             :         [POWER_SUPPLY_HEALTH_UNSPEC_FAILURE]        = "Unspecified failure",
     102             :         [POWER_SUPPLY_HEALTH_COLD]                  = "Cold",
     103             :         [POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE] = "Watchdog timer expire",
     104             :         [POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE]   = "Safety timer expire",
     105             :         [POWER_SUPPLY_HEALTH_OVERCURRENT]           = "Over current",
     106             :         [POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED]  = "Calibration required",
     107             :         [POWER_SUPPLY_HEALTH_WARM]                  = "Warm",
     108             :         [POWER_SUPPLY_HEALTH_COOL]                  = "Cool",
     109             :         [POWER_SUPPLY_HEALTH_HOT]                   = "Hot",
     110             :         [POWER_SUPPLY_HEALTH_NO_BATTERY]            = "No battery",
     111             : };
     112             : 
     113             : static const char * const POWER_SUPPLY_TECHNOLOGY_TEXT[] = {
     114             :         [POWER_SUPPLY_TECHNOLOGY_UNKNOWN]       = "Unknown",
     115             :         [POWER_SUPPLY_TECHNOLOGY_NiMH]          = "NiMH",
     116             :         [POWER_SUPPLY_TECHNOLOGY_LION]          = "Li-ion",
     117             :         [POWER_SUPPLY_TECHNOLOGY_LIPO]          = "Li-poly",
     118             :         [POWER_SUPPLY_TECHNOLOGY_LiFe]          = "LiFe",
     119             :         [POWER_SUPPLY_TECHNOLOGY_NiCd]          = "NiCd",
     120             :         [POWER_SUPPLY_TECHNOLOGY_LiMn]          = "LiMn",
     121             : };
     122             : 
     123             : static const char * const POWER_SUPPLY_CAPACITY_LEVEL_TEXT[] = {
     124             :         [POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN]   = "Unknown",
     125             :         [POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL]  = "Critical",
     126             :         [POWER_SUPPLY_CAPACITY_LEVEL_LOW]       = "Low",
     127             :         [POWER_SUPPLY_CAPACITY_LEVEL_NORMAL]    = "Normal",
     128             :         [POWER_SUPPLY_CAPACITY_LEVEL_HIGH]      = "High",
     129             :         [POWER_SUPPLY_CAPACITY_LEVEL_FULL]      = "Full",
     130             : };
     131             : 
     132             : static const char * const POWER_SUPPLY_SCOPE_TEXT[] = {
     133             :         [POWER_SUPPLY_SCOPE_UNKNOWN]    = "Unknown",
     134             :         [POWER_SUPPLY_SCOPE_SYSTEM]     = "System",
     135             :         [POWER_SUPPLY_SCOPE_DEVICE]     = "Device",
     136             : };
     137             : 
     138             : static const char * const POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[] = {
     139             :         [POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO]            = "auto",
     140             :         [POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE]  = "inhibit-charge",
     141             :         [POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE] = "force-discharge",
     142             : };
     143             : 
     144             : static struct power_supply_attr power_supply_attrs[] = {
     145             :         /* Properties of type `int' */
     146             :         POWER_SUPPLY_ENUM_ATTR(STATUS),
     147             :         POWER_SUPPLY_ENUM_ATTR(CHARGE_TYPE),
     148             :         POWER_SUPPLY_ENUM_ATTR(HEALTH),
     149             :         POWER_SUPPLY_ATTR(PRESENT),
     150             :         POWER_SUPPLY_ATTR(ONLINE),
     151             :         POWER_SUPPLY_ATTR(AUTHENTIC),
     152             :         POWER_SUPPLY_ENUM_ATTR(TECHNOLOGY),
     153             :         POWER_SUPPLY_ATTR(CYCLE_COUNT),
     154             :         POWER_SUPPLY_ATTR(VOLTAGE_MAX),
     155             :         POWER_SUPPLY_ATTR(VOLTAGE_MIN),
     156             :         POWER_SUPPLY_ATTR(VOLTAGE_MAX_DESIGN),
     157             :         POWER_SUPPLY_ATTR(VOLTAGE_MIN_DESIGN),
     158             :         POWER_SUPPLY_ATTR(VOLTAGE_NOW),
     159             :         POWER_SUPPLY_ATTR(VOLTAGE_AVG),
     160             :         POWER_SUPPLY_ATTR(VOLTAGE_OCV),
     161             :         POWER_SUPPLY_ATTR(VOLTAGE_BOOT),
     162             :         POWER_SUPPLY_ATTR(CURRENT_MAX),
     163             :         POWER_SUPPLY_ATTR(CURRENT_NOW),
     164             :         POWER_SUPPLY_ATTR(CURRENT_AVG),
     165             :         POWER_SUPPLY_ATTR(CURRENT_BOOT),
     166             :         POWER_SUPPLY_ATTR(POWER_NOW),
     167             :         POWER_SUPPLY_ATTR(POWER_AVG),
     168             :         POWER_SUPPLY_ATTR(CHARGE_FULL_DESIGN),
     169             :         POWER_SUPPLY_ATTR(CHARGE_EMPTY_DESIGN),
     170             :         POWER_SUPPLY_ATTR(CHARGE_FULL),
     171             :         POWER_SUPPLY_ATTR(CHARGE_EMPTY),
     172             :         POWER_SUPPLY_ATTR(CHARGE_NOW),
     173             :         POWER_SUPPLY_ATTR(CHARGE_AVG),
     174             :         POWER_SUPPLY_ATTR(CHARGE_COUNTER),
     175             :         POWER_SUPPLY_ATTR(CONSTANT_CHARGE_CURRENT),
     176             :         POWER_SUPPLY_ATTR(CONSTANT_CHARGE_CURRENT_MAX),
     177             :         POWER_SUPPLY_ATTR(CONSTANT_CHARGE_VOLTAGE),
     178             :         POWER_SUPPLY_ATTR(CONSTANT_CHARGE_VOLTAGE_MAX),
     179             :         POWER_SUPPLY_ATTR(CHARGE_CONTROL_LIMIT),
     180             :         POWER_SUPPLY_ATTR(CHARGE_CONTROL_LIMIT_MAX),
     181             :         POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
     182             :         POWER_SUPPLY_ATTR(CHARGE_CONTROL_END_THRESHOLD),
     183             :         POWER_SUPPLY_ENUM_ATTR(CHARGE_BEHAVIOUR),
     184             :         POWER_SUPPLY_ATTR(INPUT_CURRENT_LIMIT),
     185             :         POWER_SUPPLY_ATTR(INPUT_VOLTAGE_LIMIT),
     186             :         POWER_SUPPLY_ATTR(INPUT_POWER_LIMIT),
     187             :         POWER_SUPPLY_ATTR(ENERGY_FULL_DESIGN),
     188             :         POWER_SUPPLY_ATTR(ENERGY_EMPTY_DESIGN),
     189             :         POWER_SUPPLY_ATTR(ENERGY_FULL),
     190             :         POWER_SUPPLY_ATTR(ENERGY_EMPTY),
     191             :         POWER_SUPPLY_ATTR(ENERGY_NOW),
     192             :         POWER_SUPPLY_ATTR(ENERGY_AVG),
     193             :         POWER_SUPPLY_ATTR(CAPACITY),
     194             :         POWER_SUPPLY_ATTR(CAPACITY_ALERT_MIN),
     195             :         POWER_SUPPLY_ATTR(CAPACITY_ALERT_MAX),
     196             :         POWER_SUPPLY_ATTR(CAPACITY_ERROR_MARGIN),
     197             :         POWER_SUPPLY_ENUM_ATTR(CAPACITY_LEVEL),
     198             :         POWER_SUPPLY_ATTR(TEMP),
     199             :         POWER_SUPPLY_ATTR(TEMP_MAX),
     200             :         POWER_SUPPLY_ATTR(TEMP_MIN),
     201             :         POWER_SUPPLY_ATTR(TEMP_ALERT_MIN),
     202             :         POWER_SUPPLY_ATTR(TEMP_ALERT_MAX),
     203             :         POWER_SUPPLY_ATTR(TEMP_AMBIENT),
     204             :         POWER_SUPPLY_ATTR(TEMP_AMBIENT_ALERT_MIN),
     205             :         POWER_SUPPLY_ATTR(TEMP_AMBIENT_ALERT_MAX),
     206             :         POWER_SUPPLY_ATTR(TIME_TO_EMPTY_NOW),
     207             :         POWER_SUPPLY_ATTR(TIME_TO_EMPTY_AVG),
     208             :         POWER_SUPPLY_ATTR(TIME_TO_FULL_NOW),
     209             :         POWER_SUPPLY_ATTR(TIME_TO_FULL_AVG),
     210             :         POWER_SUPPLY_ENUM_ATTR(TYPE),
     211             :         POWER_SUPPLY_ATTR(USB_TYPE),
     212             :         POWER_SUPPLY_ENUM_ATTR(SCOPE),
     213             :         POWER_SUPPLY_ATTR(PRECHARGE_CURRENT),
     214             :         POWER_SUPPLY_ATTR(CHARGE_TERM_CURRENT),
     215             :         POWER_SUPPLY_ATTR(CALIBRATE),
     216             :         POWER_SUPPLY_ATTR(MANUFACTURE_YEAR),
     217             :         POWER_SUPPLY_ATTR(MANUFACTURE_MONTH),
     218             :         POWER_SUPPLY_ATTR(MANUFACTURE_DAY),
     219             :         /* Properties of type `const char *' */
     220             :         POWER_SUPPLY_ATTR(MODEL_NAME),
     221             :         POWER_SUPPLY_ATTR(MANUFACTURER),
     222             :         POWER_SUPPLY_ATTR(SERIAL_NUMBER),
     223             : };
     224             : 
     225             : static struct attribute *
     226             : __power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
     227             : 
     228             : static struct power_supply_attr *to_ps_attr(struct device_attribute *attr)
     229             : {
     230           0 :         return container_of(attr, struct power_supply_attr, dev_attr);
     231             : }
     232             : 
     233             : static enum power_supply_property dev_attr_psp(struct device_attribute *attr)
     234             : {
     235           0 :         return  to_ps_attr(attr) - power_supply_attrs;
     236             : }
     237             : 
     238           0 : static ssize_t power_supply_show_usb_type(struct device *dev,
     239             :                                           const struct power_supply_desc *desc,
     240             :                                           union power_supply_propval *value,
     241             :                                           char *buf)
     242             : {
     243             :         enum power_supply_usb_type usb_type;
     244           0 :         ssize_t count = 0;
     245           0 :         bool match = false;
     246             :         int i;
     247             : 
     248           0 :         for (i = 0; i < desc->num_usb_types; ++i) {
     249           0 :                 usb_type = desc->usb_types[i];
     250             : 
     251           0 :                 if (value->intval == usb_type) {
     252           0 :                         count += sprintf(buf + count, "[%s] ",
     253             :                                          POWER_SUPPLY_USB_TYPE_TEXT[usb_type]);
     254           0 :                         match = true;
     255             :                 } else {
     256           0 :                         count += sprintf(buf + count, "%s ",
     257             :                                          POWER_SUPPLY_USB_TYPE_TEXT[usb_type]);
     258             :                 }
     259             :         }
     260             : 
     261           0 :         if (!match) {
     262           0 :                 dev_warn(dev, "driver reporting unsupported connected type\n");
     263             :                 return -EINVAL;
     264             :         }
     265             : 
     266           0 :         if (count)
     267           0 :                 buf[count - 1] = '\n';
     268             : 
     269             :         return count;
     270             : }
     271             : 
     272           0 : static ssize_t power_supply_show_property(struct device *dev,
     273             :                                           struct device_attribute *attr,
     274             :                                           char *buf) {
     275             :         ssize_t ret;
     276           0 :         struct power_supply *psy = dev_get_drvdata(dev);
     277           0 :         struct power_supply_attr *ps_attr = to_ps_attr(attr);
     278           0 :         enum power_supply_property psp = dev_attr_psp(attr);
     279             :         union power_supply_propval value;
     280             : 
     281           0 :         if (psp == POWER_SUPPLY_PROP_TYPE) {
     282           0 :                 value.intval = psy->desc->type;
     283             :         } else {
     284           0 :                 ret = power_supply_get_property(psy, psp, &value);
     285             : 
     286           0 :                 if (ret < 0) {
     287           0 :                         if (ret == -ENODATA)
     288             :                                 dev_dbg(dev, "driver has no data for `%s' property\n",
     289             :                                         attr->attr.name);
     290           0 :                         else if (ret != -ENODEV && ret != -EAGAIN)
     291           0 :                                 dev_err_ratelimited(dev,
     292             :                                         "driver failed to report `%s' property: %zd\n",
     293             :                                         attr->attr.name, ret);
     294             :                         return ret;
     295             :                 }
     296             :         }
     297             : 
     298           0 :         if (ps_attr->text_values_len > 0 &&
     299           0 :             value.intval < ps_attr->text_values_len && value.intval >= 0) {
     300           0 :                 return sprintf(buf, "%s\n", ps_attr->text_values[value.intval]);
     301             :         }
     302             : 
     303           0 :         switch (psp) {
     304             :         case POWER_SUPPLY_PROP_USB_TYPE:
     305           0 :                 ret = power_supply_show_usb_type(dev, psy->desc,
     306             :                                                 &value, buf);
     307           0 :                 break;
     308             :         case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
     309           0 :                 ret = sprintf(buf, "%s\n", value.strval);
     310           0 :                 break;
     311             :         default:
     312           0 :                 ret = sprintf(buf, "%d\n", value.intval);
     313             :         }
     314             : 
     315             :         return ret;
     316             : }
     317             : 
     318           0 : static ssize_t power_supply_store_property(struct device *dev,
     319             :                                            struct device_attribute *attr,
     320             :                                            const char *buf, size_t count) {
     321             :         ssize_t ret;
     322           0 :         struct power_supply *psy = dev_get_drvdata(dev);
     323           0 :         struct power_supply_attr *ps_attr = to_ps_attr(attr);
     324           0 :         enum power_supply_property psp = dev_attr_psp(attr);
     325             :         union power_supply_propval value;
     326             : 
     327           0 :         ret = -EINVAL;
     328           0 :         if (ps_attr->text_values_len > 0) {
     329           0 :                 ret = __sysfs_match_string(ps_attr->text_values,
     330             :                                            ps_attr->text_values_len, buf);
     331             :         }
     332             : 
     333             :         /*
     334             :          * If no match was found, then check to see if it is an integer.
     335             :          * Integer values are valid for enums in addition to the text value.
     336             :          */
     337           0 :         if (ret < 0) {
     338             :                 long long_val;
     339             : 
     340           0 :                 ret = kstrtol(buf, 10, &long_val);
     341           0 :                 if (ret < 0)
     342           0 :                         return ret;
     343             : 
     344           0 :                 ret = long_val;
     345             :         }
     346             : 
     347           0 :         value.intval = ret;
     348             : 
     349           0 :         ret = power_supply_set_property(psy, psp, &value);
     350           0 :         if (ret < 0)
     351             :                 return ret;
     352             : 
     353           0 :         return count;
     354             : }
     355             : 
     356           0 : static umode_t power_supply_attr_is_visible(struct kobject *kobj,
     357             :                                            struct attribute *attr,
     358             :                                            int attrno)
     359             : {
     360           0 :         struct device *dev = kobj_to_dev(kobj);
     361           0 :         struct power_supply *psy = dev_get_drvdata(dev);
     362           0 :         umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
     363             :         int i;
     364             : 
     365           0 :         if (!power_supply_attrs[attrno].prop_name)
     366             :                 return 0;
     367             : 
     368           0 :         if (attrno == POWER_SUPPLY_PROP_TYPE)
     369             :                 return mode;
     370             : 
     371           0 :         for (i = 0; i < psy->desc->num_properties; i++) {
     372           0 :                 int property = psy->desc->properties[i];
     373             : 
     374           0 :                 if (property == attrno) {
     375           0 :                         if (psy->desc->property_is_writeable &&
     376           0 :                             psy->desc->property_is_writeable(psy, property) > 0)
     377           0 :                                 mode |= S_IWUSR;
     378             : 
     379             :                         return mode;
     380             :                 }
     381             :         }
     382             : 
     383             :         return 0;
     384             : }
     385             : 
     386             : static const struct attribute_group power_supply_attr_group = {
     387             :         .attrs = __power_supply_attrs,
     388             :         .is_visible = power_supply_attr_is_visible,
     389             : };
     390             : 
     391             : static const struct attribute_group *power_supply_attr_groups[] = {
     392             :         &power_supply_attr_group,
     393             :         NULL,
     394             : };
     395             : 
     396             : static void str_to_lower(char *str)
     397             : {
     398        1149 :         while (*str) {
     399        2146 :                 *str = tolower(*str);
     400        1073 :                 str++;
     401             :         }
     402             : }
     403             : 
     404           1 : void power_supply_init_attrs(struct device_type *dev_type)
     405             : {
     406             :         int i;
     407             : 
     408           1 :         dev_type->groups = power_supply_attr_groups;
     409             : 
     410          77 :         for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++) {
     411             :                 struct device_attribute *attr;
     412             : 
     413          76 :                 if (!power_supply_attrs[i].prop_name) {
     414           0 :                         pr_warn("%s: Property %d skipped because it is missing from power_supply_attrs\n",
     415             :                                 __func__, i);
     416           0 :                         sprintf(power_supply_attrs[i].attr_name, "_err_%d", i);
     417             :                 } else {
     418          76 :                         str_to_lower(power_supply_attrs[i].attr_name);
     419             :                 }
     420             : 
     421          76 :                 attr = &power_supply_attrs[i].dev_attr;
     422             : 
     423          76 :                 attr->attr.name = power_supply_attrs[i].attr_name;
     424          76 :                 attr->show = power_supply_show_property;
     425          76 :                 attr->store = power_supply_store_property;
     426          76 :                 __power_supply_attrs[i] = &attr->attr;
     427             :         }
     428           1 : }
     429             : 
     430           0 : static int add_prop_uevent(struct device *dev, struct kobj_uevent_env *env,
     431             :                            enum power_supply_property prop, char *prop_buf)
     432             : {
     433           0 :         int ret = 0;
     434             :         struct power_supply_attr *pwr_attr;
     435             :         struct device_attribute *dev_attr;
     436             :         char *line;
     437             : 
     438           0 :         pwr_attr = &power_supply_attrs[prop];
     439           0 :         dev_attr = &pwr_attr->dev_attr;
     440             : 
     441           0 :         ret = power_supply_show_property(dev, dev_attr, prop_buf);
     442           0 :         if (ret == -ENODEV || ret == -ENODATA) {
     443             :                 /*
     444             :                  * When a battery is absent, we expect -ENODEV. Don't abort;
     445             :                  * send the uevent with at least the the PRESENT=0 property
     446             :                  */
     447             :                 return 0;
     448             :         }
     449             : 
     450           0 :         if (ret < 0)
     451             :                 return ret;
     452             : 
     453           0 :         line = strchr(prop_buf, '\n');
     454           0 :         if (line)
     455           0 :                 *line = 0;
     456             : 
     457           0 :         return add_uevent_var(env, "POWER_SUPPLY_%s=%s",
     458             :                               pwr_attr->prop_name, prop_buf);
     459             : }
     460             : 
     461           0 : int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
     462             : {
     463           0 :         struct power_supply *psy = dev_get_drvdata(dev);
     464           0 :         int ret = 0, j;
     465             :         char *prop_buf;
     466             : 
     467           0 :         if (!psy || !psy->desc) {
     468             :                 dev_dbg(dev, "No power supply yet\n");
     469             :                 return ret;
     470             :         }
     471             : 
     472           0 :         ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->desc->name);
     473           0 :         if (ret)
     474             :                 return ret;
     475             : 
     476           0 :         prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
     477           0 :         if (!prop_buf)
     478             :                 return -ENOMEM;
     479             : 
     480           0 :         ret = add_prop_uevent(dev, env, POWER_SUPPLY_PROP_TYPE, prop_buf);
     481           0 :         if (ret)
     482             :                 goto out;
     483             : 
     484           0 :         for (j = 0; j < psy->desc->num_properties; j++) {
     485           0 :                 ret = add_prop_uevent(dev, env, psy->desc->properties[j],
     486             :                                       prop_buf);
     487           0 :                 if (ret)
     488             :                         goto out;
     489             :         }
     490             : 
     491             : out:
     492           0 :         free_page((unsigned long)prop_buf);
     493             : 
     494           0 :         return ret;
     495             : }
     496             : 
     497           0 : ssize_t power_supply_charge_behaviour_show(struct device *dev,
     498             :                                            unsigned int available_behaviours,
     499             :                                            enum power_supply_charge_behaviour current_behaviour,
     500             :                                            char *buf)
     501             : {
     502           0 :         bool match = false, available, active;
     503           0 :         ssize_t count = 0;
     504             :         int i;
     505             : 
     506           0 :         for (i = 0; i < ARRAY_SIZE(POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT); i++) {
     507           0 :                 available = available_behaviours & BIT(i);
     508           0 :                 active = i == current_behaviour;
     509             : 
     510           0 :                 if (available && active) {
     511           0 :                         count += sysfs_emit_at(buf, count, "[%s] ",
     512             :                                                POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[i]);
     513           0 :                         match = true;
     514           0 :                 } else if (available) {
     515           0 :                         count += sysfs_emit_at(buf, count, "%s ",
     516             :                                                POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[i]);
     517             :                 }
     518             :         }
     519             : 
     520           0 :         if (!match) {
     521           0 :                 dev_warn(dev, "driver reporting unsupported charge behaviour\n");
     522           0 :                 return -EINVAL;
     523             :         }
     524             : 
     525           0 :         if (count)
     526           0 :                 buf[count - 1] = '\n';
     527             : 
     528             :         return count;
     529             : }
     530             : EXPORT_SYMBOL_GPL(power_supply_charge_behaviour_show);
     531             : 
     532           0 : int power_supply_charge_behaviour_parse(unsigned int available_behaviours, const char *buf)
     533             : {
     534           0 :         int i = sysfs_match_string(POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT, buf);
     535             : 
     536           0 :         if (i < 0)
     537             :                 return i;
     538             : 
     539           0 :         if (available_behaviours & BIT(i))
     540             :                 return i;
     541             : 
     542           0 :         return -EINVAL;
     543             : }
     544             : EXPORT_SYMBOL_GPL(power_supply_charge_behaviour_parse);

Generated by: LCOV version 1.14