backlight.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * Copyright (C) 2010-2015 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 "backlight.h"
  15. #include "log.h"
  16. #include "main.h"
  17. #include "x11lock.h"
  18. #include "util.h"
  19. #include <stdint.h>
  20. #include <errno.h>
  21. #include <string.h>
  22. #include <fcntl.h>
  23. #include <unistd.h>
  24. #include <sys/ioctl.h>
  25. #include <linux/fb.h>
  26. static int backlight_set_percentage_no_notify(struct backlight *b,
  27. unsigned int percent)
  28. {
  29. int bmin = b->min_brightness(b);
  30. int bmax = b->max_brightness(b);
  31. int err, value, range;
  32. range = bmax - bmin;
  33. value = div_round((int64_t)range * percent, (int64_t)100) + bmin;
  34. /* Set the brightness value. Do not call backlight_set_brightness here,
  35. * because it will update screen blanking, which might not be desired
  36. * here. */
  37. err = b->set_brightness(b, value);
  38. return err;
  39. }
  40. static int do_framebuffer_blank(int fd, int blank)
  41. {
  42. int ret;
  43. unsigned long arg;
  44. arg = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK;
  45. ret = ioctl(fd, FBIOBLANK, arg);
  46. if (ret)
  47. return -ENODEV;
  48. logdebug("Framebuffer %s\n", blank ? "blanked" : "unblanked");
  49. return 0;
  50. }
  51. static int framebuffer_blank(struct backlight *b, int blank)
  52. {
  53. int err;
  54. if (b->framebuffer_fd < 0)
  55. return 0;
  56. blank = !!blank;
  57. if (blank == b->fb_blanked)
  58. return 0;
  59. b->fb_blanked = blank;
  60. err = do_framebuffer_blank(b->framebuffer_fd, blank);
  61. if (err) {
  62. logerr("Failed to %s the fb device (err %d)\n",
  63. blank ? "blank" : "unblank", err);
  64. }
  65. return err;
  66. }
  67. static void fbblank_exit(struct backlight *b)
  68. {
  69. if (b->framebuffer_fd >= 0) {
  70. do_framebuffer_blank(b->framebuffer_fd, 0);
  71. close(b->framebuffer_fd);
  72. b->framebuffer_fd = -1;
  73. }
  74. }
  75. static void fbblank_init(struct backlight *b)
  76. {
  77. const char *fbdev;
  78. int err, fd;
  79. b->framebuffer_fd = -1;
  80. fbdev = config_get(backend.config, "SCREEN", "fbdev", NULL);
  81. if (!fbdev)
  82. return;
  83. fd = open(fbdev, O_RDWR);
  84. if (fd < 0) {
  85. logerr("Failed to open framebuffer dev %s: %s\n",
  86. fbdev, strerror(errno));
  87. return;
  88. }
  89. err = do_framebuffer_blank(fd, 0);
  90. if (err) {
  91. close(fd);
  92. return;
  93. }
  94. b->fb_blanked = 0;
  95. b->framebuffer_fd = fd;
  96. logdebug("Opened %s for fb blanking\n", fbdev);
  97. }
  98. static int default_min_brightness(struct backlight *b)
  99. {
  100. return 0;
  101. }
  102. static int default_max_brightness(struct backlight *b)
  103. {
  104. return 100;
  105. }
  106. static int default_brightness_step(struct backlight *b)
  107. {
  108. return 1;
  109. }
  110. static int default_current_brightness(struct backlight *b)
  111. {
  112. return 0;
  113. }
  114. static int default_set_brightness(struct backlight *b, int value)
  115. {
  116. return -EOPNOTSUPP;
  117. }
  118. static int default_screen_lock(struct backlight *b, int lock)
  119. {
  120. return -EOPNOTSUPP;
  121. }
  122. static int default_screen_is_locked(struct backlight *b)
  123. {
  124. return 0;
  125. }
  126. static void backlight_poll_callback(struct sleeptimer *timer)
  127. {
  128. struct backlight *b = container_of(timer, struct backlight, timer);
  129. b->update(b);
  130. sleeptimer_set_timeout_relative(&b->timer, b->poll_interval);
  131. sleeptimer_enqueue(&b->timer);
  132. }
  133. void backlight_init(struct backlight *b, const char *name)
  134. {
  135. memset(b, 0, sizeof(*b));
  136. b->name = name;
  137. b->min_brightness = default_min_brightness;
  138. b->max_brightness = default_max_brightness;
  139. b->brightness_step = default_brightness_step;
  140. b->current_brightness = default_current_brightness;
  141. b->set_brightness = default_set_brightness;
  142. b->screen_lock = default_screen_lock;
  143. b->screen_is_locked = default_screen_is_locked;
  144. }
  145. static void backlight_start(struct backlight *b)
  146. {
  147. int percent;
  148. if (b->poll_interval) {
  149. b->update(b);
  150. sleeptimer_init(&b->timer, "backlight", backlight_poll_callback);
  151. sleeptimer_set_timeout_relative(&b->timer, b->poll_interval);
  152. sleeptimer_enqueue(&b->timer);
  153. }
  154. percent = config_get_int(backend.config, "BACKLIGHT",
  155. "startup_percent", 100);
  156. percent = clamp(percent, 0, 100);
  157. backlight_set_percentage_no_notify(b, percent);
  158. }
  159. struct backlight * backlight_probe(void)
  160. {
  161. struct backlight *b;
  162. const struct probe *probe;
  163. for_each_probe(probe, backlight) {
  164. b = probe->func();
  165. if (b) {
  166. fbblank_init(b);
  167. backlight_start(b);
  168. logdebug("Initialized backlight driver \"%s\"\n",
  169. b->name);
  170. return b;
  171. }
  172. }
  173. logerr("Failed to find any backlight controls.\n");
  174. return NULL;
  175. }
  176. void backlight_destroy(struct backlight *b)
  177. {
  178. int percent;
  179. if (!b)
  180. return;
  181. fbblank_exit(b);
  182. b->screen_lock(b, 0);
  183. percent = config_get_int(backend.config, "BACKLIGHT",
  184. "shutdown_percent", 100);
  185. percent = clamp(percent, 0, 100);
  186. backlight_set_percentage_no_notify(b, percent);
  187. b->destroy(b);
  188. }
  189. int backlight_fill_pt_message_stat(struct backlight *b, struct pt_message *msg)
  190. {
  191. int min_brightness, max_brightness, cur_brightness, brightness_step;
  192. int autodim_enabled, autodim_ac;
  193. min_brightness = b->min_brightness(b);
  194. max_brightness = b->max_brightness(b);
  195. cur_brightness = b->current_brightness(b);
  196. brightness_step = b->brightness_step(b);
  197. autodim_enabled = b->autodim_enabled;
  198. autodim_ac = b->autodim_enabled_on_ac;
  199. if (autodim_enabled) {
  200. cur_brightness = backlight_get_percentage(b);
  201. if (cur_brightness < 0)
  202. cur_brightness = 100;
  203. min_brightness = 0;
  204. max_brightness = 100;
  205. brightness_step = 1;
  206. }
  207. msg->bl_stat.min_brightness = htonl(min_brightness);
  208. msg->bl_stat.max_brightness = htonl(max_brightness);
  209. msg->bl_stat.brightness_step = htonl(brightness_step);
  210. msg->bl_stat.brightness = htonl(cur_brightness);
  211. msg->bl_stat.flags = autodim_enabled ? htonl(PT_BL_FLG_AUTODIM) : 0;
  212. msg->bl_stat.flags |= autodim_ac ? htonl(PT_BL_FLG_AUTODIM_AC) : 0;
  213. return 0;
  214. }
  215. int backlight_notify_state_change(struct backlight *b)
  216. {
  217. struct pt_message msg = {
  218. .id = htons(PTNOTI_BL_CHANGED),
  219. };
  220. int err;
  221. err = backlight_fill_pt_message_stat(b, &msg);
  222. if (err)
  223. return err;
  224. notify_clients(&msg, PT_FLG_OK);
  225. return 0;
  226. }
  227. static void update_screen_blanking(struct backlight *b)
  228. {
  229. int brightness = b->current_brightness(b);
  230. int screen_locked = b->screen_is_locked(b);
  231. if (screen_locked || brightness == 0) {
  232. if (screen_locked)
  233. block_x11_input(&backend.x11lock);
  234. framebuffer_blank(b, 1);
  235. } else {
  236. framebuffer_blank(b, 0);
  237. unblock_x11_input(&backend.x11lock);
  238. }
  239. }
  240. int backlight_set_brightness(struct backlight *b, int value)
  241. {
  242. int err;
  243. err = b->set_brightness(b, value);
  244. if (err)
  245. return err;
  246. update_screen_blanking(b);
  247. return 0;
  248. }
  249. int backlight_screen_lock(struct backlight *b, int lock)
  250. {
  251. int err;
  252. err = b->screen_lock(b, lock);
  253. if (err)
  254. return err;
  255. update_screen_blanking(b);
  256. return 0;
  257. }
  258. int backlight_set_percentage(struct backlight *b, unsigned int percent)
  259. {
  260. int err;
  261. err = backlight_set_percentage_no_notify(b, percent);
  262. if (!err) {
  263. backlight_notify_state_change(b);
  264. update_screen_blanking(b);
  265. }
  266. return err;
  267. }
  268. int backlight_get_percentage(struct backlight *b)
  269. {
  270. int bmin = b->min_brightness(b);
  271. int bmax = b->max_brightness(b);
  272. int percent, value, range;
  273. range = bmax - bmin;
  274. value = b->current_brightness(b);
  275. if (value < 0)
  276. return value;
  277. value -= bmin;
  278. if (value < 0)
  279. return -EINVAL;
  280. if (range)
  281. percent = div_round((int64_t)value * 100, (int64_t)range);
  282. else
  283. percent = 0;
  284. percent = clamp(percent, 0, 100);
  285. return percent;
  286. }