power_supply_sysfs.c 15 KB

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