smart_battery.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/fs.h>
  5. #include <linux/cdev.h>
  6. #include <linux/device.h>
  7. #include <linux/slab.h>
  8. #include <linux/uaccess.h>
  9. #include <linux/power_supply.h>
  10. #include <linux/mutex.h>
  11. #define DEVICE_NAME "smart_battery"
  12. #define CLASS_NAME "battery_acpi_class"
  13. #define BATTERY_IOC_MAGIC 'B'
  14. #define BATTERY_IOC_GET_CAPACITY _IOR(BATTERY_IOC_MAGIC, 1, int)
  15. #define BATTERY_IOC_GET_VOLTAGE _IOR(BATTERY_IOC_MAGIC, 2, int)
  16. #define BATTERY_IOC_GET_STATUS _IOR(BATTERY_IOC_MAGIC, 3, int)
  17. #define BATTERY_IOC_GET_ENERGY_NOW _IOR(BATTERY_IOC_MAGIC, 4, int)
  18. #define BATTERY_IOC_GET_ENERGY_FULL _IOR(BATTERY_IOC_MAGIC, 5, int)
  19. #define BATTERY_IOC_GET_POWER _IOR(BATTERY_IOC_MAGIC, 6, int)
  20. #define BATTERY_IOC_GET_TECHNOLOGY _IOR(BATTERY_IOC_MAGIC, 7, int)
  21. #define BATTERY_IOC_GET_SERIAL _IOR(BATTERY_IOC_MAGIC, 8, char[16])
  22. #define BATTERY_IOC_GET_PRESENT _IOR(BATTERY_IOC_MAGIC, 9, int)
  23. struct battery_acpi_device {
  24. struct cdev cdev;
  25. struct device *device;
  26. struct class *class;
  27. struct mutex lock;
  28. char battery_name[16];
  29. /* 电池数据 */
  30. int present;
  31. int capacity;
  32. int voltage;
  33. int status;
  34. int energy_now;
  35. int energy_full;
  36. int energy_full_design;
  37. int power_now;
  38. int technology;
  39. char serial[16];
  40. unsigned int read_count;
  41. unsigned int ioctl_count;
  42. };
  43. static struct battery_acpi_device *g_battery_dev;
  44. static const char* find_battery_name(void)
  45. {
  46. static char name[16];
  47. struct power_supply *psy;
  48. int i;
  49. const char *battery_names[] = {"BAT4", "BAT0", "BAT1", "BAT2", "BAT3", "BATT"};
  50. for (i = 0; i < ARRAY_SIZE(battery_names); i++) {
  51. psy = power_supply_get_by_name(battery_names[i]);
  52. if (psy) {
  53. if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY) {
  54. strcpy(name, battery_names[i]);
  55. power_supply_put(psy);
  56. pr_info("Found battery: %s\n", name);
  57. return name;
  58. }
  59. power_supply_put(psy);
  60. }
  61. }
  62. return NULL;
  63. }
  64. static int read_psy_property(const char *bat_name, enum power_supply_property prop, int *value)
  65. {
  66. struct power_supply *psy;
  67. union power_supply_propval val;
  68. int ret;
  69. psy = power_supply_get_by_name(bat_name);
  70. if (!psy)
  71. return -ENODEV;
  72. ret = power_supply_get_property(psy, prop, &val);
  73. if (ret == 0)
  74. *value = val.intval;
  75. power_supply_put(psy);
  76. return ret;
  77. }
  78. static int read_psy_property_string(const char *bat_name, enum power_supply_property prop, char *buf, size_t buf_size)
  79. {
  80. struct power_supply *psy;
  81. union power_supply_propval val;
  82. int ret;
  83. psy = power_supply_get_by_name(bat_name);
  84. if (!psy)
  85. return -ENODEV;
  86. ret = power_supply_get_property(psy, prop, &val);
  87. if (ret == 0 && val.strval) {
  88. strncpy(buf, val.strval, buf_size - 1);
  89. buf[buf_size - 1] = '\0';
  90. } else {
  91. buf[0] = '\0';
  92. }
  93. power_supply_put(psy);
  94. return ret;
  95. }
  96. static int charge_to_energy(int charge_uh, int voltage_uv)
  97. {
  98. /* energy (µWh) = charge (µAh) * voltage (µV) / 1000000 */
  99. if (charge_uh <= 0 || voltage_uv <= 0)
  100. return 0;
  101. return ((long long)charge_uh * voltage_uv) / 1000000;
  102. }
  103. static void update_battery_data(struct battery_acpi_device *dev)
  104. {
  105. const char *bat_name;
  106. int ret;
  107. int charge_now = 0, charge_full = 0;
  108. int energy_now_direct = 0, energy_full_direct = 0;
  109. int voltage = 0;
  110. mutex_lock(&dev->lock);
  111. bat_name = find_battery_name();
  112. if (!bat_name) {
  113. dev->present = 0;
  114. mutex_unlock(&dev->lock);
  115. return;
  116. }
  117. strcpy(dev->battery_name, bat_name);
  118. ret = read_psy_property(bat_name, POWER_SUPPLY_PROP_PRESENT, &dev->present);
  119. if (ret < 0)
  120. dev->present = 1;
  121. if (!dev->present) {
  122. mutex_unlock(&dev->lock);
  123. return;
  124. }
  125. read_psy_property(bat_name, POWER_SUPPLY_PROP_CAPACITY, &dev->capacity);
  126. read_psy_property(bat_name, POWER_SUPPLY_PROP_VOLTAGE_NOW, &dev->voltage);
  127. voltage = dev->voltage;
  128. read_psy_property(bat_name, POWER_SUPPLY_PROP_STATUS, &dev->status);
  129. ret = read_psy_property(bat_name, POWER_SUPPLY_PROP_ENERGY_NOW, &energy_now_direct);
  130. if (ret == 0 && energy_now_direct > 0) {
  131. dev->energy_now = energy_now_direct;
  132. pr_debug("Using ENERGY_NOW: %d µWh\n", dev->energy_now);
  133. } else {
  134. ret = read_psy_property(bat_name, POWER_SUPPLY_PROP_CHARGE_NOW, &charge_now);
  135. if (ret == 0 && charge_now > 0 && voltage > 0) {
  136. dev->energy_now = charge_to_energy(charge_now, voltage);
  137. pr_debug("Calculated from CHARGE_NOW: %d µAh * %d µV = %d µWh\n",
  138. charge_now, voltage, dev->energy_now);
  139. } else {
  140. dev->energy_now = -1;
  141. }
  142. }
  143. ret = read_psy_property(bat_name, POWER_SUPPLY_PROP_ENERGY_FULL, &energy_full_direct);
  144. if (ret == 0 && energy_full_direct > 0) {
  145. dev->energy_full = energy_full_direct;
  146. pr_debug("Using ENERGY_FULL: %d µWh\n", dev->energy_full);
  147. } else {
  148. ret = read_psy_property(bat_name, POWER_SUPPLY_PROP_CHARGE_FULL, &charge_full);
  149. if (ret == 0 && charge_full > 0 && voltage > 0) {
  150. dev->energy_full = charge_to_energy(charge_full, voltage);
  151. pr_debug("Calculated from CHARGE_FULL: %d µAh * %d µV = %d µWh\n",
  152. charge_full, voltage, dev->energy_full);
  153. } else {
  154. ret = read_psy_property(bat_name, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, &charge_full);
  155. if (ret == 0 && charge_full > 0 && voltage > 0) {
  156. dev->energy_full = charge_to_energy(charge_full, voltage);
  157. } else {
  158. dev->energy_full = -1;
  159. }
  160. }
  161. }
  162. ret = read_psy_property(bat_name, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, &dev->energy_full_design);
  163. if (ret < 0 || dev->energy_full_design <= 0) {
  164. dev->energy_full_design = dev->energy_full;
  165. }
  166. ret = read_psy_property(bat_name, POWER_SUPPLY_PROP_POWER_NOW, &dev->power_now);
  167. if (ret < 0) {
  168. int current_now;
  169. ret = read_psy_property(bat_name, POWER_SUPPLY_PROP_CURRENT_NOW, &current_now);
  170. if (ret == 0 && voltage > 0) {
  171. /* power (µW) = current (µA) * voltage (µV) / 1000000 */
  172. dev->power_now = ((long long)current_now * voltage) / 1000000;
  173. } else {
  174. dev->power_now = 0;
  175. }
  176. }
  177. read_psy_property(bat_name, POWER_SUPPLY_PROP_TECHNOLOGY, &dev->technology);
  178. read_psy_property_string(bat_name, POWER_SUPPLY_PROP_SERIAL_NUMBER, dev->serial, sizeof(dev->serial));
  179. if (dev->serial[0] == '\0')
  180. strcpy(dev->serial, "N/A");
  181. mutex_unlock(&dev->lock);
  182. pr_debug("Battery %s: capacity=%d%%, voltage=%d µV, energy_now=%d µWh, energy_full=%d µWh\n",
  183. dev->battery_name, dev->capacity, dev->voltage, dev->energy_now, dev->energy_full);
  184. }
  185. static const char* get_status_string(int status)
  186. {
  187. switch (status) {
  188. case POWER_SUPPLY_STATUS_CHARGING:
  189. return "Charging";
  190. case POWER_SUPPLY_STATUS_DISCHARGING:
  191. return "Discharging";
  192. case POWER_SUPPLY_STATUS_FULL:
  193. return "Full";
  194. case POWER_SUPPLY_STATUS_NOT_CHARGING:
  195. return "Not charging";
  196. default:
  197. return "Unknown";
  198. }
  199. }
  200. static const char* get_technology_string(int tech)
  201. {
  202. switch (tech) {
  203. case POWER_SUPPLY_TECHNOLOGY_LION:
  204. return "Lithium-ion";
  205. case POWER_SUPPLY_TECHNOLOGY_LIPO:
  206. return "Lithium-polymer";
  207. case POWER_SUPPLY_TECHNOLOGY_NiMH:
  208. return "NiMH";
  209. default:
  210. return "Unknown";
  211. }
  212. }
  213. static int battery_open(struct inode *inode, struct file *file)
  214. {
  215. struct battery_acpi_device *dev = container_of(inode->i_cdev,
  216. struct battery_acpi_device,
  217. cdev);
  218. file->private_data = dev;
  219. update_battery_data(dev);
  220. return 0;
  221. }
  222. static int battery_release(struct inode *inode, struct file *file)
  223. {
  224. return 0;
  225. }
  226. static ssize_t battery_read(struct file *file, char __user *buf,
  227. size_t count, loff_t *f_pos)
  228. {
  229. struct battery_acpi_device *dev = file->private_data;
  230. char info[512];
  231. int len;
  232. if (*f_pos > 0)
  233. return 0;
  234. update_battery_data(dev);
  235. dev->read_count++;
  236. if (!dev->present) {
  237. len = snprintf(info, sizeof(info),
  238. "=== Battery Information ===\n"
  239. " Battery: NOT PRESENT\n"
  240. " Read Count: %u\n",
  241. dev->read_count);
  242. } else {
  243. len = snprintf(info, sizeof(info),
  244. "=== Battery Information ===\n"
  245. " Battery Name: %s\n"
  246. " Present: Yes\n"
  247. " Capacity: %d%%\n"
  248. " Voltage: %d.%03d V\n"
  249. " Status: %s\n"
  250. " Energy Now: %d.%02d Wh\n"
  251. " Energy Full: %d.%02d Wh\n"
  252. " Energy Full Design:%d.%02d Wh\n"
  253. " Power Now: %d.%02d W\n"
  254. " Technology: %s\n"
  255. " Serial Number: %s\n"
  256. " Read Count: %u\n",
  257. dev->battery_name,
  258. dev->capacity,
  259. dev->voltage / 1000000,
  260. (dev->voltage % 1000000) / 1000,
  261. get_status_string(dev->status),
  262. dev->energy_now * (dev->voltage / 1000000) / 1000000,
  263. ((dev->energy_now * (dev->voltage / 1000000)) % 1000000) / 10000,
  264. dev->energy_full * (dev->voltage / 1000000) / 1000000,
  265. ((dev->energy_full * (dev->voltage / 1000000)) % 1000000) / 10000,
  266. dev->energy_full_design * (dev->voltage / 1000000) / 1000000,
  267. ((dev->energy_full_design * (dev->voltage / 1000000)) % 1000000) / 10000,
  268. dev->power_now / 1000000,
  269. (dev->power_now % 1000000) / 10000,
  270. get_technology_string(dev->technology),
  271. dev->serial,
  272. dev->read_count);
  273. }
  274. if (len > count)
  275. len = count;
  276. if (copy_to_user(buf, info, len))
  277. return -EFAULT;
  278. *f_pos += len;
  279. return len;
  280. }
  281. static long battery_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  282. {
  283. struct battery_acpi_device *dev = file->private_data;
  284. void __user *argp = (void __user *)arg;
  285. update_battery_data(dev);
  286. dev->ioctl_count++;
  287. switch (cmd) {
  288. case BATTERY_IOC_GET_PRESENT:
  289. if (copy_to_user(argp, &dev->present, sizeof(dev->present)))
  290. return -EFAULT;
  291. break;
  292. case BATTERY_IOC_GET_CAPACITY:
  293. if (copy_to_user(argp, &dev->capacity, sizeof(dev->capacity)))
  294. return -EFAULT;
  295. break;
  296. case BATTERY_IOC_GET_VOLTAGE:
  297. if (copy_to_user(argp, &dev->voltage, sizeof(dev->voltage)))
  298. return -EFAULT;
  299. break;
  300. case BATTERY_IOC_GET_STATUS:
  301. if (copy_to_user(argp, &dev->status, sizeof(dev->status)))
  302. return -EFAULT;
  303. break;
  304. case BATTERY_IOC_GET_ENERGY_NOW:
  305. if (copy_to_user(argp, &dev->energy_now, sizeof(dev->energy_now)))
  306. return -EFAULT;
  307. break;
  308. case BATTERY_IOC_GET_ENERGY_FULL:
  309. if (copy_to_user(argp, &dev->energy_full, sizeof(dev->energy_full)))
  310. return -EFAULT;
  311. break;
  312. case BATTERY_IOC_GET_POWER:
  313. if (copy_to_user(argp, &dev->power_now, sizeof(dev->power_now)))
  314. return -EFAULT;
  315. break;
  316. case BATTERY_IOC_GET_TECHNOLOGY:
  317. if (copy_to_user(argp, &dev->technology, sizeof(dev->technology)))
  318. return -EFAULT;
  319. break;
  320. case BATTERY_IOC_GET_SERIAL:
  321. if (copy_to_user(argp, dev->serial, sizeof(dev->serial)))
  322. return -EFAULT;
  323. break;
  324. default:
  325. return -ENOTTY;
  326. }
  327. return 0;
  328. }
  329. static const struct file_operations battery_fops = {
  330. .owner = THIS_MODULE,
  331. .open = battery_open,
  332. .release = battery_release,
  333. .read = battery_read,
  334. .unlocked_ioctl = battery_ioctl,
  335. };
  336. int battery_acpi_driver_init(void)
  337. {
  338. dev_t dev_num;
  339. int ret;
  340. struct battery_acpi_device *dev;
  341. pr_info("Initializing Battery Character Device Driver v2.2\n");
  342. ret = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME);
  343. if (ret < 0) {
  344. pr_err("Failed to allocate device number\n");
  345. return ret;
  346. }
  347. dev = kzalloc(sizeof(struct battery_acpi_device), GFP_KERNEL);
  348. if (!dev) {
  349. ret = -ENOMEM;
  350. goto err_alloc;
  351. }
  352. mutex_init(&dev->lock);
  353. dev->class = class_create(THIS_MODULE, CLASS_NAME);
  354. if (IS_ERR(dev->class)) {
  355. ret = PTR_ERR(dev->class);
  356. goto err_class;
  357. }
  358. dev->device = device_create(dev->class, NULL, dev_num, dev, DEVICE_NAME);
  359. if (IS_ERR(dev->device)) {
  360. ret = PTR_ERR(dev->device);
  361. goto err_device;
  362. }
  363. cdev_init(&dev->cdev, &battery_fops);
  364. dev->cdev.owner = THIS_MODULE;
  365. ret = cdev_add(&dev->cdev, dev_num, 1);
  366. if (ret < 0) {
  367. goto err_cdev;
  368. }
  369. g_battery_dev = dev;
  370. update_battery_data(dev);
  371. pr_info("Battery driver initialized: /dev/%s\n", DEVICE_NAME);
  372. return 0;
  373. err_cdev:
  374. device_destroy(dev->class, dev_num);
  375. err_device:
  376. class_destroy(dev->class);
  377. err_class:
  378. mutex_destroy(&dev->lock);
  379. kfree(dev);
  380. err_alloc:
  381. unregister_chrdev_region(dev_num, 1);
  382. return ret;
  383. }
  384. void battery_acpi_driver_exit(void)
  385. {
  386. dev_t dev_num = g_battery_dev->cdev.dev;
  387. cdev_del(&g_battery_dev->cdev);
  388. device_destroy(g_battery_dev->class, dev_num);
  389. class_destroy(g_battery_dev->class);
  390. mutex_destroy(&g_battery_dev->lock);
  391. kfree(g_battery_dev);
  392. unregister_chrdev_region(dev_num, 1);
  393. pr_info("Battery driver exited\n");
  394. }