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