1 #include "e_system.h"
2
3 typedef struct
4 {
5 char *dev;
6 int val, max, val_set, val_get_count;
7 Eina_Bool prefer : 1;
8 Eina_Bool set : 1;
9 } Light;
10
11 static Eina_Lock _devices_lock;
12 static Eina_List *_devices = NULL;
13 static Eina_Semaphore _worker_sem;
14
15 static void
_light_set(Light * lig,int val)16 _light_set(Light *lig, int val)
17 { // val == 0->1000
18 int nval = ((lig->max * val) + 500) / 1000;
19 if (nval < 0) nval = 0;
20 else if (nval > lig->max) nval = lig->max;
21 lig->val = nval;
22 #ifdef HAVE_EEZE
23 char buf[PATH_MAX];
24 snprintf(buf, sizeof(buf), "%s/brightness", lig->dev);
25 int fd = open(buf, O_WRONLY);
26 if (fd >= 0)
27 {
28 char buf2[32];
29 snprintf(buf2, sizeof(buf2), "%i", lig->val);
30 if (write(fd, buf2, strlen(buf2)) <= 0)
31 ERR("Write failed of [%s] to [%s]\n", buf2, buf);
32 close(fd);
33 }
34 #elif defined(__FreeBSD_kernel__) || defined(__DragonFly__)
35 sysctlbyname(lig->dev, NULL, NULL, &(lig->val), sizeof(lig->val));
36 #endif
37 }
38
39 static void
_light_get(Light * lig)40 _light_get(Light *lig)
41 {
42 #ifdef HAVE_EEZE
43 const char *s;
44 s = eeze_udev_syspath_get_sysattr(lig->dev, "brightness");
45 if (s)
46 {
47 lig->val = atoi(s);
48 eina_stringshare_del(s);
49 }
50 #elif defined(__FreeBSD_kernel__) || defined(__DragonFly__)
51 size_t plen = sizeof(lig->val);
52 sysctlbyname(lig->dev, &(lig->val), &plen, NULL, 0);
53 #endif
54 }
55
56 static void
_cb_worker(void * data EINA_UNUSED,Ecore_Thread * th)57 _cb_worker(void *data EINA_UNUSED, Ecore_Thread *th)
58 {
59 for (;;)
60 {
61 Eina_List *l;
62 Light *lig;
63
64 eina_semaphore_lock(&_worker_sem);
65
66 eina_lock_take(&_devices_lock);
67 EINA_LIST_FOREACH(_devices, l, lig)
68 {
69 if (lig->val_get_count > 0)
70 {
71 _light_get(lig);
72 while (lig->val_get_count > 0)
73 {
74 Light *lig2 = calloc(1, sizeof(Light));
75 lig->val_get_count--;
76 if (lig2)
77 {
78 lig2->dev = strdup(lig->dev);
79 lig2->max = lig->max;
80 if (lig2->dev)
81 {
82 lig2->val = lig->val;
83 ecore_thread_feedback(th, lig2);
84 }
85 else free(lig2);
86 }
87 }
88 }
89 if (lig->set)
90 {
91 lig->set = EINA_FALSE;
92 lig->val = lig->val_set;
93 _light_set(lig, lig->val);
94 }
95 }
96 eina_lock_release(&_devices_lock);
97 }
98 }
99
100 static void
_cb_worker_message(void * data EINA_UNUSED,Ecore_Thread * th EINA_UNUSED,void * msg_data)101 _cb_worker_message(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED, void *msg_data)
102 {
103 Light *lig = msg_data;
104 int val = 0;
105
106 if (lig->max > 0)
107 {
108 val = ((1000 * lig->val) + 500) / lig->max;
109 if (val < 0) val = 0;
110 else if (val > 1000) val = 1000;
111 }
112 e_system_inout_command_send("bklight-val", "%s %i", lig->dev, val);
113 free(lig->dev);
114 free(lig);
115 }
116
117 static void
_cb_worker_end(void * data EINA_UNUSED,Ecore_Thread * th EINA_UNUSED)118 _cb_worker_end(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED)
119 {
120 }
121
122 static void
_cb_worker_cancel(void * data EINA_UNUSED,Ecore_Thread * th EINA_UNUSED)123 _cb_worker_cancel(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED)
124 {
125 }
126
127 static void
_light_add(const char * dev)128 _light_add(const char *dev)
129 {
130 Light *lig = calloc(1, sizeof(Light));
131
132 if (!lig) abort();
133 lig->dev = strdup(dev);
134 if (!lig->dev) abort();
135 lig->val = -1; // unknown
136 #ifdef HAVE_EEZE
137 const char *s;
138
139 s = eeze_udev_syspath_get_sysattr(lig->dev, "brightness");
140 if (!s)
141 {
142 free(lig->dev);
143 free(lig);
144 return;
145 }
146 lig->val = atoi(s);
147 eina_stringshare_del(s);
148
149 s = eeze_udev_syspath_get_sysattr(lig->dev, "max_brightness");
150 if (s)
151 {
152 lig->max = atoi(s);
153 eina_stringshare_del(s);
154 }
155 if (lig->max <= 0) lig->max = 255;
156 lig->prefer = eeze_udev_syspath_check_sysattr(lig->dev, "type", "firmware");
157 #elif defined(__FreeBSD_kernel__) || defined(__DragonFly__)
158 size_t plen = sizeof(lig->val);
159 sysctlbyname(lig->dev, &(lig->val), &plen, NULL, 0);
160 lig->max = 100;
161 #endif
162 _devices = eina_list_append(_devices, lig);
163 if (alert_backlight_reset)
164 { // set brightness to max if alert mode is on
165 eina_lock_take(&_devices_lock);
166 lig->val_set = lig->max;
167 lig->set = EINA_TRUE;
168 eina_semaphore_release(&_worker_sem, 1);
169 eina_lock_release(&_devices_lock);
170 }
171 }
172
173 #ifdef HAVE_EEZE
174 static Eina_Bool
_light_device_include(const char * dev)175 _light_device_include(const char *dev)
176 { // filter out known undesirable devices
177 fprintf(stderr, "BL: found [%s]\n", dev);
178 if (strstr(dev, "::capslock")) return EINA_FALSE;
179 if (strstr(dev, "::numlock")) return EINA_FALSE;
180 if (strstr(dev, "::scrolllock")) return EINA_FALSE;
181 if (strstr(dev, "::compose")) return EINA_FALSE;
182 if (strstr(dev, "::kana")) return EINA_FALSE;
183 return EINA_TRUE;
184 }
185 #endif
186
187 static void
_light_refresh_devices()188 _light_refresh_devices()
189 {
190 Light *lig;
191
192 EINA_LIST_FREE(_devices, lig)
193 {
194 free(lig->dev);
195 free(lig);
196 }
197 #ifdef HAVE_EEZE
198 Eina_List *devs;
199 const char *s;
200
201 devs = eeze_udev_find_by_filter("backlight", NULL, NULL);
202 fprintf(stderr, "BL: backlight devices...\n");
203 EINA_LIST_FREE(devs, s)
204 {
205 if (_light_device_include(s)) _light_add(s);
206 eina_stringshare_del(s);
207 }
208 devs = eeze_udev_find_by_filter("leds", NULL, NULL);
209 fprintf(stderr, "BL: led devices...\n");
210 EINA_LIST_FREE(devs, s)
211 {
212 if (_light_device_include(s)) _light_add(s);
213 eina_stringshare_del(s);
214 }
215 #elif defined(__FreeBSD_kernel__) || defined(__DragonFly__)
216 // XXX; shouldn't we scan for devices?
217 _light_add("hw.acpi.video.lcd0.brightness");
218 #endif
219 }
220
221 static Light *
_light_find(const char * dev)222 _light_find(const char *dev)
223 {
224 Eina_List *l;
225 Light *lig;
226
227 if (!dev) return NULL;
228 EINA_LIST_FOREACH(_devices, l, lig)
229 {
230 if (!strcmp(lig->dev, dev)) return lig;
231 }
232 return NULL;
233 }
234
235 static void
_cb_bklight_list(void * data EINA_UNUSED,const char * params EINA_UNUSED)236 _cb_bklight_list(void *data EINA_UNUSED, const char *params EINA_UNUSED)
237 { // reply = "dev1 -|p dev2 -|p ..."
238 Eina_List *l;
239 Light *lig;
240 char *rep = NULL, *p = NULL;
241 size_t repsize = 0;
242
243 eina_lock_take(&_devices_lock);
244 EINA_LIST_FOREACH(_devices, l, lig)
245 {
246 repsize += strlen(lig->dev) + 2 + 1;
247 }
248 if (repsize > 0)
249 {
250 rep = malloc(repsize);
251 if (!rep) abort();
252 p = rep;
253 EINA_LIST_FOREACH(_devices, l, lig)
254 {
255 size_t len = strlen(lig->dev);
256 memcpy(p, lig->dev, len + 1);
257 p[len] = ' '; len++;
258 if (lig->prefer) p[len] = 'p';
259 else p[len] = '-';
260 len++;
261 if (l->next) p[len] = ' ';
262 else p[len] = '\0';
263 p += len + 1;
264 }
265 }
266 eina_lock_release(&_devices_lock);
267 e_system_inout_command_send("bklight-list", "%s", rep);
268 free(rep);
269 }
270
271 static void
_cb_bklight_refresh(void * data EINA_UNUSED,const char * params EINA_UNUSED)272 _cb_bklight_refresh(void *data EINA_UNUSED, const char *params EINA_UNUSED)
273 {
274 Eina_Bool tmp = alert_backlight_reset;
275 alert_backlight_reset = EINA_FALSE;
276 eina_lock_take(&_devices_lock);
277 _light_refresh_devices();
278 eina_lock_release(&_devices_lock);
279 alert_backlight_reset = tmp;
280 }
281
282 static void
_cb_bklight_get(void * data EINA_UNUSED,const char * params)283 _cb_bklight_get(void *data EINA_UNUSED, const char *params)
284 {
285 Light *lig;
286
287 eina_lock_take(&_devices_lock);
288 lig = _light_find(params);
289 if (!lig) goto done;
290 lig->val_get_count++;
291 eina_semaphore_release(&_worker_sem, 1);
292 _light_get(lig);
293 done:
294 eina_lock_release(&_devices_lock);
295 }
296
297 static void
_cb_bklight_set(void * data EINA_UNUSED,const char * params)298 _cb_bklight_set(void *data EINA_UNUSED, const char *params)
299 {
300 Light *lig;
301 char dev[1024] = "";
302 int val = 0;
303
304 if (!params) return;
305 if (sscanf(params, "%1023s %i", dev, &val) != 2) return;
306 eina_lock_take(&_devices_lock);
307 fprintf(stderr, "BL: set [%s] -> %i\n", dev, val);
308 lig = _light_find(dev);
309 if (!lig) goto done;
310 lig->val_set = val;
311 lig->set = EINA_TRUE;
312 eina_semaphore_release(&_worker_sem, 1);
313 done:
314 eina_lock_release(&_devices_lock);
315 }
316
317 void
e_system_backlight_init(void)318 e_system_backlight_init(void)
319 {
320 eina_lock_new(&_devices_lock);
321 eina_semaphore_new(&_worker_sem, 0);
322 _light_refresh_devices();
323 ecore_thread_feedback_run(_cb_worker, _cb_worker_message,
324 _cb_worker_end, _cb_worker_cancel,
325 NULL, EINA_TRUE);
326 e_system_inout_command_register("bklight-list", _cb_bklight_list, NULL);
327 e_system_inout_command_register("bklight-refresh", _cb_bklight_refresh, NULL);
328 e_system_inout_command_register("bklight-get", _cb_bklight_get, NULL);
329 e_system_inout_command_register("bklight-set", _cb_bklight_set, NULL);
330 }
331
332 void
e_system_backlight_shutdown(void)333 e_system_backlight_shutdown(void)
334 {
335 // only shutdown things we really have to - no need to free mem etc.
336 }
337