Advertisement
Guest User

Untitled

a guest
Dec 9th, 2022
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.03 KB | None | 0 0
  1. // control charging of battery on apple M1
  2. // tested on macbook pro 2021 model
  3. // works on linux
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include <syslog.h>
  12. #include <string.h>
  13. #include <liburing.h>
  14.  
  15. enum charge_mode {
  16. CHARGE_AUTO,
  17. CHARGE_INHIBIT_CHARGE,
  18. CHARGE_FORCE_DISCHARGE,
  19. };
  20.  
  21. static const char *chargemodes[] = {
  22. "auto",
  23. "inhibit-charge",
  24. "force-discharge",
  25. };
  26.  
  27. #define CAPACITY_FILE \
  28. "/sys/class/power_supply/macsmc-battery/capacity"
  29. #define CHARGE_BEHAVIOR_FILE \
  30. "/sys/class/power_supply/macsmc-battery/charge_behaviour"
  31.  
  32. #define LOWER_CHARGE 70
  33. #define UPPER_CHARGE 90
  34.  
  35. #define LOGNAME "charge-ctl"
  36.  
  37. static enum charge_mode last_mode = -1;
  38.  
  39. static int write_file(struct io_uring *ring, const char *filename,
  40. const char *cap)
  41. {
  42. struct io_uring_sqe *sqe;
  43. struct io_uring_cqe *cqe;
  44. int ret;
  45.  
  46. sqe = io_uring_get_sqe(ring);
  47. io_uring_prep_openat_direct(sqe, -1, filename, O_WRONLY, 0, 0);
  48. sqe->flags |= IOSQE_IO_LINK | IOSQE_CQE_SKIP_SUCCESS;
  49.  
  50. sqe = io_uring_get_sqe(ring);
  51. io_uring_prep_write(sqe, 0, cap, strlen(cap), 0);
  52. sqe->flags |= IOSQE_IO_HARDLINK | IOSQE_FIXED_FILE;
  53.  
  54. sqe = io_uring_get_sqe(ring);
  55. io_uring_prep_close_direct(sqe, 0);
  56. sqe->flags |= IOSQE_CQE_SKIP_SUCCESS;
  57.  
  58. ret = io_uring_submit(ring);
  59. if (ret != 3)
  60. return 1;
  61.  
  62. ret = io_uring_wait_cqe(ring, &cqe);
  63. if (ret)
  64. return 1;
  65.  
  66. if (cqe->res < 0)
  67. return 1;
  68. io_uring_cqe_seen(ring, cqe);
  69. return 0;
  70. }
  71.  
  72. static int read_file(struct io_uring *ring, const char *filename,
  73. char *cap, size_t size)
  74. {
  75. struct io_uring_sqe *sqe;
  76. struct io_uring_cqe *cqe;
  77. int ret;
  78.  
  79. sqe = io_uring_get_sqe(ring);
  80. io_uring_prep_openat_direct(sqe, -1, filename, O_RDONLY, 0, 0);
  81. sqe->flags |= IOSQE_IO_LINK | IOSQE_CQE_SKIP_SUCCESS;
  82.  
  83. sqe = io_uring_get_sqe(ring);
  84. io_uring_prep_read(sqe, 0, cap, size, 0);
  85. sqe->flags |= IOSQE_IO_HARDLINK | IOSQE_FIXED_FILE;
  86.  
  87. sqe = io_uring_get_sqe(ring);
  88. io_uring_prep_close_direct(sqe, 0);
  89. sqe->flags |= IOSQE_CQE_SKIP_SUCCESS;
  90.  
  91. ret = io_uring_submit(ring);
  92. if (ret != 3)
  93. return 1;
  94.  
  95. ret = io_uring_wait_cqe(ring, &cqe);
  96. if (ret)
  97. return 1;
  98.  
  99. if (cqe->res < 0)
  100. return 1;
  101. io_uring_cqe_seen(ring, cqe);
  102. return 0;
  103. }
  104.  
  105. static void set_charge_mode(struct io_uring *ring, enum charge_mode mode)
  106. {
  107. if (mode == last_mode)
  108. return;
  109.  
  110. if (write_file(ring, CHARGE_BEHAVIOR_FILE, chargemodes[mode]))
  111. exit(EXIT_FAILURE);
  112.  
  113. last_mode = mode;
  114. openlog(LOGNAME, LOG_PID, LOG_USER);
  115. syslog(LOG_USER | LOG_INFO, chargemodes[mode]);
  116. closelog();
  117. }
  118.  
  119. int main(int argc, char **argv)
  120. {
  121. int ret, option, limit = UPPER_CHARGE;
  122. struct io_uring ring;
  123. pid_t pid, sid;
  124.  
  125. while ((option = getopt(argc, argv, "l:uh")) != -1) {
  126. switch (option) {
  127. case 'h':
  128. puts("help");
  129. puts("-l limit capacity");
  130. exit(EXIT_SUCCESS);
  131. case 'l':
  132. limit = atoi(optarg);
  133. printf("limit: %d\n", limit);
  134. break;
  135. default: /* '?' */
  136. puts("unknown option");
  137. exit(EXIT_FAILURE);
  138. }
  139. }
  140.  
  141. pid = fork();
  142. if (pid < 0)
  143. exit(EXIT_FAILURE);
  144. if (pid > 0)
  145. exit(EXIT_SUCCESS);
  146.  
  147. umask(0);
  148. sid = setsid();
  149. if (sid < 0)
  150. exit(EXIT_FAILURE);
  151.  
  152. if ((chdir("/")) < 0)
  153. exit(EXIT_FAILURE);
  154.  
  155. close(STDIN_FILENO);
  156. close(STDOUT_FILENO);
  157. close(STDERR_FILENO);
  158.  
  159. ret = io_uring_queue_init(4, &ring, 0);
  160. if (ret) {
  161. fprintf(stderr, "Queue init failed: %d\n", ret);
  162. exit(EXIT_FAILURE);
  163. }
  164.  
  165. ret = io_uring_register_files_sparse(&ring, 1);
  166. if (ret) {
  167. fprintf(stderr, "File table register failed: %d\n", ret);
  168. exit(EXIT_FAILURE);
  169. }
  170.  
  171. while (1) {
  172. char cap[6];
  173. int icap;
  174.  
  175. if (read_file(&ring, CAPACITY_FILE, cap, sizeof(cap) - 1))
  176. break;
  177. icap = atoi(cap);
  178. if (icap < LOWER_CHARGE)
  179. set_charge_mode(&ring, CHARGE_AUTO);
  180. else if (icap > limit)
  181. set_charge_mode(&ring, CHARGE_FORCE_DISCHARGE);
  182. else
  183. set_charge_mode(&ring, CHARGE_INHIBIT_CHARGE);
  184.  
  185. sleep(30);
  186. }
  187.  
  188. exit(EXIT_SUCCESS);
  189. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement