battery_class.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * Copyright (C) 2011 Michael Buesch <m@bues.ch>
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include "battery_class.h"
  15. #include "util.h"
  16. #include "fileaccess.h"
  17. #include "log.h"
  18. #include <limits.h>
  19. #include <errno.h>
  20. #define BASEPATH "/class/power_supply"
  21. static int battery_class_update(struct battery *b)
  22. {
  23. struct battery_class *ba = container_of(b, struct battery_class, battery);
  24. int value, err, value_changed = 0;
  25. struct fileaccess *file;
  26. if (strempty(ba->ac_online_filename)) {
  27. value = -1;
  28. } else {
  29. file = sysfs_file_open(O_RDONLY, ba->ac_online_filename);
  30. if (!file) {
  31. logerr("WARNING: Failed to open ac/online file\n");
  32. return -ETXTBSY;
  33. }
  34. err = file_read_int(file, &value, 10);
  35. file_close(file);
  36. if (err) {
  37. logerr("WARNING: Failed to read ac/online file\n");
  38. return -ETXTBSY;
  39. }
  40. }
  41. if (value != ba->on_ac) {
  42. ba->on_ac = value;
  43. value_changed = 1;
  44. }
  45. value = 0;
  46. file = sysfs_file_open(O_RDONLY, ba->charge_max_filename);
  47. if (file) {
  48. err = file_read_int(file, &value, 10);
  49. file_close(file);
  50. if (err) {
  51. logerr("WARNING: Failed to read charge_max file\n");
  52. return -ETXTBSY;
  53. }
  54. }
  55. if (value != ba->charge_max) {
  56. ba->charge_max = value;
  57. value_changed = 1;
  58. }
  59. value = 0;
  60. file = sysfs_file_open(O_RDONLY, ba->charge_now_filename);
  61. if (file) {
  62. err = file_read_int(file, &value, 10);
  63. file_close(file);
  64. if (err) {
  65. logerr("WARNING: Failed to read charge_now file\n");
  66. return -ETXTBSY;
  67. }
  68. }
  69. value = min(value, ba->charge_max);
  70. if (value != ba->charge_now) {
  71. ba->charge_now = value;
  72. value_changed = 1;
  73. }
  74. if (value_changed)
  75. battery_notify_state_change(b);
  76. return 0;
  77. }
  78. static int battery_class_on_ac(struct battery *b)
  79. {
  80. struct battery_class *ba = container_of(b, struct battery_class, battery);
  81. return ba->on_ac;
  82. }
  83. static int battery_class_max_level(struct battery *b)
  84. {
  85. struct battery_class *ba = container_of(b, struct battery_class, battery);
  86. return ba->charge_max;
  87. }
  88. static int battery_class_charge_level(struct battery *b)
  89. {
  90. struct battery_class *ba = container_of(b, struct battery_class, battery);
  91. return ba->charge_now;
  92. }
  93. static void battery_class_destroy(struct battery *b)
  94. {
  95. struct battery_class *ba = container_of(b, struct battery_class, battery);
  96. free(ba->ac_online_filename);
  97. free(ba->charge_max_filename);
  98. free(ba->charge_now_filename);
  99. free(ba);
  100. }
  101. static void find_ac_file(char *ac_file, size_t ac_file_size)
  102. {
  103. LIST_HEAD(dentries);
  104. struct dir_entry *dentry;
  105. int res, ok;
  106. strncat(ac_file, BASEPATH, ac_file_size - strlen(ac_file) - 1);
  107. /* Find the AC-online file */
  108. res = list_sysfs_directory(&dentries, ac_file);
  109. if (res <= 0)
  110. goto error;
  111. ok = 0;
  112. list_for_each_entry(dentry, &dentries, list) {
  113. if ((dentry->type == DT_DIR ||
  114. dentry->type == DT_LNK) &&
  115. strncmp(dentry->name, "AC", 2) == 0) {
  116. strncat(ac_file, "/", ac_file_size - strlen(ac_file) - 1);
  117. strncat(ac_file, dentry->name, ac_file_size - strlen(ac_file) - 1);
  118. strncat(ac_file, "/online", ac_file_size - strlen(ac_file) - 1);
  119. ok = 1;
  120. break;
  121. }
  122. }
  123. dir_entries_free(&dentries);
  124. if (!ok)
  125. goto error;
  126. return;
  127. error:
  128. ac_file[0] = '\0';
  129. }
  130. static void find_battery_full_file(char *full_file, size_t full_file_size)
  131. {
  132. LIST_HEAD(dentries);
  133. struct dir_entry *dentry;
  134. int res, ok;
  135. strncat(full_file, BASEPATH, full_file_size - strlen(full_file) - 1);
  136. /* Find the battery-full file */
  137. res = list_sysfs_directory(&dentries, full_file);
  138. if (res <= 0)
  139. goto error;
  140. ok = 0;
  141. list_for_each_entry(dentry, &dentries, list) {
  142. if ((dentry->type == DT_DIR ||
  143. dentry->type == DT_LNK) &&
  144. strncmp(dentry->name, "BAT", 3) == 0) {
  145. strncat(full_file, "/", full_file_size - strlen(full_file) - 1);
  146. strncat(full_file, dentry->name, full_file_size - strlen(full_file) - 1);
  147. ok = 1;
  148. break;
  149. }
  150. }
  151. dir_entries_free(&dentries);
  152. if (!ok)
  153. goto error;
  154. res = list_sysfs_directory(&dentries, full_file);
  155. if (res <= 0)
  156. goto error;
  157. ok = 0;
  158. list_for_each_entry(dentry, &dentries, list) {
  159. if (dentry->type == DT_REG &&
  160. (strcmp(dentry->name, "charge_full") == 0 ||
  161. strcmp(dentry->name, "energy_full") == 0)) {
  162. strncat(full_file, "/", full_file_size - strlen(full_file) - 1);
  163. strncat(full_file, dentry->name, full_file_size - strlen(full_file) - 1);
  164. ok = 1;
  165. break;
  166. }
  167. }
  168. dir_entries_free(&dentries);
  169. if (!ok)
  170. goto error;
  171. return;
  172. error:
  173. full_file[0] = '\0';
  174. }
  175. static void find_battery_now_file(char *now_file, size_t now_file_size)
  176. {
  177. LIST_HEAD(dentries);
  178. struct dir_entry *dentry;
  179. int res, ok;
  180. strncat(now_file, BASEPATH, now_file_size - strlen(now_file) - 1);
  181. /* Find the battery-now file */
  182. res = list_sysfs_directory(&dentries, now_file);
  183. if (res <= 0)
  184. goto error;
  185. ok = 0;
  186. list_for_each_entry(dentry, &dentries, list) {
  187. if ((dentry->type == DT_DIR ||
  188. dentry->type == DT_LNK) &&
  189. strncmp(dentry->name, "BAT", 3) == 0) {
  190. strncat(now_file, "/", now_file_size - strlen(now_file) - 1);
  191. strncat(now_file, dentry->name, now_file_size - strlen(now_file) - 1);
  192. ok = 1;
  193. break;
  194. }
  195. }
  196. dir_entries_free(&dentries);
  197. if (!ok)
  198. goto error;
  199. res = list_sysfs_directory(&dentries, now_file);
  200. if (res <= 0)
  201. goto error;
  202. ok = 0;
  203. list_for_each_entry(dentry, &dentries, list) {
  204. if (dentry->type == DT_REG &&
  205. (strcmp(dentry->name, "charge_now") == 0 ||
  206. strcmp(dentry->name, "energy_now") == 0)) {
  207. strncat(now_file, "/", now_file_size - strlen(now_file) - 1);
  208. strncat(now_file, dentry->name, now_file_size - strlen(now_file) - 1);
  209. ok = 1;
  210. break;
  211. }
  212. }
  213. dir_entries_free(&dentries);
  214. if (!ok)
  215. goto error;
  216. return;
  217. error:
  218. now_file[0] = '\0';
  219. }
  220. static struct battery * battery_class_probe(void)
  221. {
  222. struct battery_class *ba;
  223. char ac_file[PATH_MAX + 1] = { 0, };
  224. char full_file[PATH_MAX + 1] = { 0, };
  225. char now_file[PATH_MAX + 1] = { 0, };
  226. find_ac_file(ac_file, sizeof(ac_file));
  227. find_battery_full_file(full_file, sizeof(full_file));
  228. find_battery_now_file(now_file, sizeof(now_file));
  229. if (strempty(full_file) || strempty(now_file))
  230. goto error;
  231. ba = zalloc(sizeof(*ba));
  232. if (!ba)
  233. goto error;
  234. battery_init(&ba->battery, "class");
  235. ba->battery.destroy = battery_class_destroy;
  236. ba->battery.update = battery_class_update;
  237. ba->battery.on_ac = battery_class_on_ac;
  238. ba->battery.max_level = battery_class_max_level;
  239. ba->battery.charge_level = battery_class_charge_level;
  240. ba->battery.poll_interval = 10000;
  241. ba->ac_online_filename = strdup(ac_file);
  242. ba->charge_max_filename = strdup(full_file);
  243. ba->charge_now_filename = strdup(now_file);
  244. return &ba->battery;
  245. error:
  246. return NULL;
  247. }
  248. BATTERY_PROBE(class, battery_class_probe);