power_supply_sysfs.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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. #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_TAPER] = "Taper",
  83. };
  84. static const char * const POWER_SUPPLY_HEALTH_TEXT[] = {
  85. [POWER_SUPPLY_HEALTH_UNKNOWN] = "Unknown",
  86. [POWER_SUPPLY_HEALTH_GOOD] = "Good",
  87. [POWER_SUPPLY_HEALTH_OVERHEAT] = "Overheat",
  88. [POWER_SUPPLY_HEALTH_DEAD] = "Dead",
  89. [POWER_SUPPLY_HEALTH_OVERVOLTAGE] = "Over voltage",
  90. [POWER_SUPPLY_HEALTH_UNSPEC_FAILURE] = "Unspecified failure",
  91. [POWER_SUPPLY_HEALTH_COLD] = "Cold",
  92. [POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE] = "Watchdog timer expire",
  93. [POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE] = "Safety timer expire",
  94. [POWER_SUPPLY_HEALTH_OVERCURRENT] = "Over current",
  95. [POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED] = "Calibration required",
  96. [POWER_SUPPLY_HEALTH_WARM] = "Warm",
  97. [POWER_SUPPLY_HEALTH_COOL] = "Cool",
  98. [POWER_SUPPLY_HEALTH_HOT] = "Hot",
  99. };
  100. static const char * const POWER_SUPPLY_TECHNOLOGY_TEXT[] = {
  101. [POWER_SUPPLY_TECHNOLOGY_UNKNOWN] = "Unknown",
  102. [POWER_SUPPLY_TECHNOLOGY_NiMH] = "NiMH",
  103. [POWER_SUPPLY_TECHNOLOGY_LION] = "Li-ion",
  104. [POWER_SUPPLY_TECHNOLOGY_LIPO] = "Li-poly",
  105. [POWER_SUPPLY_TECHNOLOGY_LiFe] = "LiFe",
  106. [POWER_SUPPLY_TECHNOLOGY_NiCd] = "NiCd",
  107. [POWER_SUPPLY_TECHNOLOGY_LiMn] = "LiMn",
  108. };
  109. static const char * const POWER_SUPPLY_CAPACITY_LEVEL_TEXT[] = {
  110. [POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN] = "Unknown",
  111. [POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL] = "Critical",
  112. [POWER_SUPPLY_CAPACITY_LEVEL_LOW] = "Low",
  113. [POWER_SUPPLY_CAPACITY_LEVEL_NORMAL] = "Normal",
  114. [POWER_SUPPLY_CAPACITY_LEVEL_HIGH] = "High",
  115. [POWER_SUPPLY_CAPACITY_LEVEL_FULL] = "Full",
  116. };
  117. static const char * const POWER_SUPPLY_SCOPE_TEXT[] = {
  118. [POWER_SUPPLY_SCOPE_UNKNOWN] = "Unknown",
  119. [POWER_SUPPLY_SCOPE_SYSTEM] = "System",
  120. [POWER_SUPPLY_SCOPE_DEVICE] = "Device",
  121. };
  122. static struct power_supply_attr power_supply_attrs[] = {
  123. /* Properties of type `int' */
  124. POWER_SUPPLY_ENUM_ATTR(STATUS),
  125. POWER_SUPPLY_ENUM_ATTR(CHARGE_TYPE),
  126. POWER_SUPPLY_ENUM_ATTR(HEALTH),
  127. POWER_SUPPLY_ATTR(PRESENT),
  128. POWER_SUPPLY_ATTR(ONLINE),
  129. POWER_SUPPLY_ATTR(AUTHENTIC),
  130. POWER_SUPPLY_ENUM_ATTR(TECHNOLOGY),
  131. POWER_SUPPLY_ATTR(CYCLE_COUNT),
  132. POWER_SUPPLY_ATTR(VOLTAGE_MAX),
  133. POWER_SUPPLY_ATTR(VOLTAGE_MIN),
  134. POWER_SUPPLY_ATTR(VOLTAGE_MAX_DESIGN),
  135. POWER_SUPPLY_ATTR(VOLTAGE_MIN_DESIGN),
  136. POWER_SUPPLY_ATTR(VOLTAGE_NOW),
  137. POWER_SUPPLY_ATTR(VOLTAGE_AVG),
  138. POWER_SUPPLY_ATTR(VOLTAGE_OCV),
  139. POWER_SUPPLY_ATTR(VOLTAGE_BOOT),
  140. POWER_SUPPLY_ATTR(CURRENT_MAX),
  141. POWER_SUPPLY_ATTR(CURRENT_NOW),
  142. POWER_SUPPLY_ATTR(CURRENT_AVG),
  143. POWER_SUPPLY_ATTR(CURRENT_BOOT),
  144. POWER_SUPPLY_ATTR(POWER_NOW),
  145. POWER_SUPPLY_ATTR(POWER_AVG),
  146. POWER_SUPPLY_ATTR(CHARGE_FULL_DESIGN),
  147. POWER_SUPPLY_ATTR(CHARGE_EMPTY_DESIGN),
  148. POWER_SUPPLY_ATTR(CHARGE_FULL),
  149. POWER_SUPPLY_ATTR(CHARGE_EMPTY),
  150. POWER_SUPPLY_ATTR(CHARGE_NOW),
  151. POWER_SUPPLY_ATTR(CHARGE_AVG),
  152. POWER_SUPPLY_ATTR(CHARGE_COUNTER),
  153. POWER_SUPPLY_ATTR(CONSTANT_CHARGE_CURRENT),
  154. POWER_SUPPLY_ATTR(CONSTANT_CHARGE_CURRENT_MAX),
  155. POWER_SUPPLY_ATTR(CONSTANT_CHARGE_VOLTAGE),
  156. POWER_SUPPLY_ATTR(CONSTANT_CHARGE_VOLTAGE_MAX),
  157. POWER_SUPPLY_ATTR(CHARGE_CONTROL_LIMIT),
  158. POWER_SUPPLY_ATTR(CHARGE_CONTROL_LIMIT_MAX),
  159. POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
  160. POWER_SUPPLY_ATTR(CHARGE_CONTROL_END_THRESHOLD),
  161. POWER_SUPPLY_ATTR(INPUT_CURRENT_LIMIT),
  162. POWER_SUPPLY_ATTR(INPUT_VOLTAGE_LIMIT),
  163. POWER_SUPPLY_ATTR(INPUT_POWER_LIMIT),
  164. POWER_SUPPLY_ATTR(ENERGY_FULL_DESIGN),
  165. POWER_SUPPLY_ATTR(ENERGY_EMPTY_DESIGN),
  166. POWER_SUPPLY_ATTR(ENERGY_FULL),
  167. POWER_SUPPLY_ATTR(ENERGY_EMPTY),
  168. POWER_SUPPLY_ATTR(ENERGY_NOW),
  169. POWER_SUPPLY_ATTR(ENERGY_AVG),
  170. POWER_SUPPLY_ATTR(CAPACITY),
  171. POWER_SUPPLY_ATTR(CAPACITY_ALERT_MIN),
  172. POWER_SUPPLY_ATTR(CAPACITY_ALERT_MAX),
  173. POWER_SUPPLY_ATTR(CAPACITY_ERROR_MARGIN),
  174. POWER_SUPPLY_ENUM_ATTR(CAPACITY_LEVEL),
  175. POWER_SUPPLY_ATTR(TEMP),
  176. POWER_SUPPLY_ATTR(TEMP_MAX),
  177. POWER_SUPPLY_ATTR(TEMP_MIN),
  178. POWER_SUPPLY_ATTR(TEMP_ALERT_MIN),
  179. POWER_SUPPLY_ATTR(TEMP_ALERT_MAX),
  180. POWER_SUPPLY_ATTR(TEMP_AMBIENT),
  181. POWER_SUPPLY_ATTR(TEMP_AMBIENT_ALERT_MIN),
  182. POWER_SUPPLY_ATTR(TEMP_AMBIENT_ALERT_MAX),
  183. POWER_SUPPLY_ATTR(TIME_TO_EMPTY_NOW),
  184. POWER_SUPPLY_ATTR(TIME_TO_EMPTY_AVG),
  185. POWER_SUPPLY_ATTR(TIME_TO_FULL_NOW),
  186. POWER_SUPPLY_ATTR(TIME_TO_FULL_AVG),
  187. POWER_SUPPLY_ENUM_ATTR(TYPE),
  188. POWER_SUPPLY_ATTR(USB_TYPE),
  189. POWER_SUPPLY_ENUM_ATTR(SCOPE),
  190. POWER_SUPPLY_ATTR(PRECHARGE_CURRENT),
  191. POWER_SUPPLY_ATTR(CHARGE_TERM_CURRENT),
  192. POWER_SUPPLY_ATTR(CALIBRATE),
  193. POWER_SUPPLY_ATTR(MANUFACTURE_YEAR),
  194. POWER_SUPPLY_ATTR(MANUFACTURE_MONTH),
  195. POWER_SUPPLY_ATTR(MANUFACTURE_DAY),
  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. static struct attribute *
  202. __power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
  203. static struct power_supply_attr *to_ps_attr(struct device_attribute *attr)
  204. {
  205. return container_of(attr, struct power_supply_attr, dev_attr);
  206. }
  207. static enum power_supply_property dev_attr_psp(struct device_attribute *attr)
  208. {
  209. return to_ps_attr(attr) - power_supply_attrs;
  210. }
  211. static ssize_t power_supply_show_usb_type(struct device *dev,
  212. const struct power_supply_desc *desc,
  213. union power_supply_propval *value,
  214. char *buf)
  215. {
  216. enum power_supply_usb_type usb_type;
  217. ssize_t count = 0;
  218. bool match = false;
  219. int i;
  220. for (i = 0; i < desc->num_usb_types; ++i) {
  221. usb_type = desc->usb_types[i];
  222. if (value->intval == usb_type) {
  223. count += sprintf(buf + count, "[%s] ",
  224. POWER_SUPPLY_USB_TYPE_TEXT[usb_type]);
  225. match = true;
  226. } else {
  227. count += sprintf(buf + count, "%s ",
  228. POWER_SUPPLY_USB_TYPE_TEXT[usb_type]);
  229. }
  230. }
  231. if (!match) {
  232. dev_warn(dev, "driver reporting unsupported connected type\n");
  233. return -EINVAL;
  234. }
  235. if (count)
  236. buf[count - 1] = '\n';
  237. return count;
  238. }
  239. static ssize_t power_supply_show_property(struct device *dev,
  240. struct device_attribute *attr,
  241. char *buf) {
  242. ssize_t ret;
  243. struct power_supply *psy = dev_get_drvdata(dev);
  244. struct power_supply_attr *ps_attr = to_ps_attr(attr);
  245. enum power_supply_property psp = dev_attr_psp(attr);
  246. union power_supply_propval value;
  247. if (psp == POWER_SUPPLY_PROP_TYPE) {
  248. value.intval = psy->desc->type;
  249. } else {
  250. ret = power_supply_get_property(psy, psp, &value);
  251. if (ret < 0) {
  252. if (ret == -ENODATA)
  253. dev_dbg(dev, "driver has no data for `%s' property\n",
  254. attr->attr.name);
  255. else if (ret != -ENODEV && ret != -EAGAIN)
  256. dev_err_ratelimited(dev,
  257. "driver failed to report `%s' property: %zd\n",
  258. attr->attr.name, ret);
  259. return ret;
  260. }
  261. }
  262. if (ps_attr->text_values_len > 0 &&
  263. value.intval < ps_attr->text_values_len && value.intval >= 0) {
  264. return sprintf(buf, "%s\n", ps_attr->text_values[value.intval]);
  265. }
  266. switch (psp) {
  267. case POWER_SUPPLY_PROP_USB_TYPE:
  268. ret = power_supply_show_usb_type(dev, psy->desc,
  269. &value, buf);
  270. break;
  271. case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
  272. ret = sprintf(buf, "%s\n", value.strval);
  273. break;
  274. default:
  275. ret = sprintf(buf, "%d\n", value.intval);
  276. }
  277. return ret;
  278. }
  279. static ssize_t power_supply_store_property(struct device *dev,
  280. struct device_attribute *attr,
  281. const char *buf, size_t count) {
  282. ssize_t ret;
  283. struct power_supply *psy = dev_get_drvdata(dev);
  284. struct power_supply_attr *ps_attr = to_ps_attr(attr);
  285. enum power_supply_property psp = dev_attr_psp(attr);
  286. union power_supply_propval value;
  287. ret = -EINVAL;
  288. if (ps_attr->text_values_len > 0) {
  289. ret = __sysfs_match_string(ps_attr->text_values,
  290. ps_attr->text_values_len, buf);
  291. }
  292. /*
  293. * If no match was found, then check to see if it is an integer.
  294. * Integer values are valid for enums in addition to the text value.
  295. */
  296. if (ret < 0) {
  297. long long_val;
  298. ret = kstrtol(buf, 10, &long_val);
  299. if (ret < 0)
  300. return ret;
  301. ret = long_val;
  302. }
  303. value.intval = ret;
  304. ret = power_supply_set_property(psy, psp, &value);
  305. if (ret < 0)
  306. return ret;
  307. return count;
  308. }
  309. static umode_t power_supply_attr_is_visible(struct kobject *kobj,
  310. struct attribute *attr,
  311. int attrno)
  312. {
  313. struct device *dev = kobj_to_dev(kobj);
  314. struct power_supply *psy = dev_get_drvdata(dev);
  315. umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
  316. int i;
  317. if (!power_supply_attrs[attrno].prop_name)
  318. return 0;
  319. if (attrno == POWER_SUPPLY_PROP_TYPE)
  320. return mode;
  321. for (i = 0; i < psy->desc->num_properties; i++) {
  322. int property = psy->desc->properties[i];
  323. if (property == attrno) {
  324. if (psy->desc->property_is_writeable &&
  325. psy->desc->property_is_writeable(psy, property) > 0)
  326. mode |= S_IWUSR;
  327. return mode;
  328. }
  329. }
  330. return 0;
  331. }
  332. static struct attribute_group power_supply_attr_group = {
  333. .attrs = __power_supply_attrs,
  334. .is_visible = power_supply_attr_is_visible,
  335. };
  336. static const struct attribute_group *power_supply_attr_groups[] = {
  337. &power_supply_attr_group,
  338. NULL,
  339. };
  340. static void str_to_lower(char *str)
  341. {
  342. while (*str) {
  343. *str = tolower(*str);
  344. str++;
  345. }
  346. }
  347. void power_supply_init_attrs(struct device_type *dev_type)
  348. {
  349. int i;
  350. dev_type->groups = power_supply_attr_groups;
  351. for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++) {
  352. struct device_attribute *attr;
  353. if (!power_supply_attrs[i].prop_name) {
  354. pr_warn("%s: Property %d skipped because is is missing from power_supply_attrs\n",
  355. __func__, i);
  356. sprintf(power_supply_attrs[i].attr_name, "_err_%d", i);
  357. } else {
  358. str_to_lower(power_supply_attrs[i].attr_name);
  359. }
  360. attr = &power_supply_attrs[i].dev_attr;
  361. attr->attr.name = power_supply_attrs[i].attr_name;
  362. attr->show = power_supply_show_property;
  363. attr->store = power_supply_store_property;
  364. __power_supply_attrs[i] = &attr->attr;
  365. }
  366. }
  367. static int add_prop_uevent(struct device *dev, struct kobj_uevent_env *env,
  368. enum power_supply_property prop, char *prop_buf)
  369. {
  370. int ret = 0;
  371. struct power_supply_attr *pwr_attr;
  372. struct device_attribute *dev_attr;
  373. char *line;
  374. pwr_attr = &power_supply_attrs[prop];
  375. dev_attr = &pwr_attr->dev_attr;
  376. ret = power_supply_show_property(dev, dev_attr, prop_buf);
  377. if (ret == -ENODEV || ret == -ENODATA) {
  378. /*
  379. * When a battery is absent, we expect -ENODEV. Don't abort;
  380. * send the uevent with at least the the PRESENT=0 property
  381. */
  382. return 0;
  383. }
  384. if (ret < 0)
  385. return ret;
  386. line = strchr(prop_buf, '\n');
  387. if (line)
  388. *line = 0;
  389. return add_uevent_var(env, "POWER_SUPPLY_%s=%s",
  390. pwr_attr->prop_name, prop_buf);
  391. }
  392. int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
  393. {
  394. struct power_supply *psy = dev_get_drvdata(dev);
  395. int ret = 0, j;
  396. char *prop_buf;
  397. if (!psy || !psy->desc) {
  398. dev_dbg(dev, "No power supply yet\n");
  399. return ret;
  400. }
  401. ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->desc->name);
  402. if (ret)
  403. return ret;
  404. prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
  405. if (!prop_buf)
  406. return -ENOMEM;
  407. ret = add_prop_uevent(dev, env, POWER_SUPPLY_PROP_TYPE, prop_buf);
  408. if (ret)
  409. goto out;
  410. for (j = 0; j < psy->desc->num_properties; j++) {
  411. ret = add_prop_uevent(dev, env, psy->desc->properties[j],
  412. prop_buf);
  413. if (ret)
  414. goto out;
  415. }
  416. out:
  417. free_page((unsigned long)prop_buf);
  418. return ret;
  419. }