You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
7.9 KiB
321 lines
7.9 KiB
#include "e_system.h" |
|
|
|
typedef struct |
|
{ |
|
char *dev; |
|
int val, max, val_set, val_get_count; |
|
Eina_Bool prefer : 1; |
|
Eina_Bool set : 1; |
|
} Light; |
|
|
|
static Eina_Lock _devices_lock; |
|
static Eina_List *_devices = NULL; |
|
static Eina_Semaphore _worker_sem; |
|
|
|
static void |
|
_light_set(Light *lig, int val) |
|
{ // val == 0->1000 |
|
int nval = ((lig->max * val) + 500) / 1000; |
|
if (nval < 0) nval = 0; |
|
else if (nval > lig->max) nval = lig->max; |
|
lig->val = nval; |
|
#ifdef HAVE_EEZE |
|
char buf[PATH_MAX]; |
|
snprintf(buf, sizeof(buf), "%s/brightness", lig->dev); |
|
int fd = open(buf, O_WRONLY); |
|
if (fd >= 0) |
|
{ |
|
char buf2[32]; |
|
snprintf(buf2, sizeof(buf2), "%i", lig->val); |
|
if (write(fd, buf2, strlen(buf2)) <= 0) |
|
ERR("Write failed of [%s] to [%s]\n", buf2, buf); |
|
close(fd); |
|
} |
|
#elif defined(__FreeBSD_kernel__) |
|
sysctlbyname(lig->dev, NULL, NULL, &(lig->val), sizeof(lig->val)); |
|
#endif |
|
} |
|
|
|
static void |
|
_light_get(Light *lig) |
|
{ |
|
#ifdef HAVE_EEZE |
|
const char *s; |
|
s = eeze_udev_syspath_get_sysattr(lig->dev, "brightness"); |
|
if (s) |
|
{ |
|
lig->val = atoi(s); |
|
eina_stringshare_del(s); |
|
} |
|
#elif defined(__FreeBSD_kernel__) |
|
size_t plen = sizeof(lig->val); |
|
sysctlbyname(lig->dev, &(lig->val), &plen, NULL, 0); |
|
#endif |
|
} |
|
|
|
static void |
|
_cb_worker(void *data EINA_UNUSED, Ecore_Thread *th) |
|
{ |
|
for (;;) |
|
{ |
|
Eina_List *l; |
|
Light *lig; |
|
|
|
eina_semaphore_lock(&_worker_sem); |
|
|
|
eina_lock_take(&_devices_lock); |
|
EINA_LIST_FOREACH(_devices, l, lig) |
|
{ |
|
if (lig->val_get_count > 0) |
|
{ |
|
_light_get(lig); |
|
while (lig->val_get_count > 0) |
|
{ |
|
Light *lig2 = calloc(1, sizeof(Light)); |
|
lig->val_get_count--; |
|
if (lig2) |
|
{ |
|
lig2->dev = strdup(lig->dev); |
|
lig2->max = lig->max; |
|
if (lig2->dev) |
|
{ |
|
lig2->val = lig->val; |
|
ecore_thread_feedback(th, lig2); |
|
} |
|
else free(lig2); |
|
} |
|
} |
|
} |
|
if (lig->set) |
|
{ |
|
lig->set = EINA_FALSE; |
|
lig->val = lig->val_set; |
|
_light_set(lig, lig->val); |
|
} |
|
} |
|
eina_lock_release(&_devices_lock); |
|
} |
|
} |
|
|
|
static void |
|
_cb_worker_message(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED, void *msg_data) |
|
{ |
|
Light *lig = msg_data; |
|
int val = 0; |
|
|
|
if (lig->max > 0) |
|
{ |
|
val = ((1000 * lig->val) + 500) / lig->max; |
|
if (val < 0) val = 0; |
|
else if (val > 1000) val = 1000; |
|
} |
|
e_system_inout_command_send("bklight-val", "%s %i", lig->dev, val); |
|
free(lig->dev); |
|
free(lig); |
|
} |
|
|
|
static void |
|
_cb_worker_end(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED) |
|
{ |
|
} |
|
|
|
static void |
|
_cb_worker_cancel(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED) |
|
{ |
|
} |
|
|
|
static void |
|
_light_add(const char *dev) |
|
{ |
|
Light *lig = calloc(1, sizeof(Light)); |
|
|
|
if (!lig) abort(); |
|
lig->dev = strdup(dev); |
|
if (!lig->dev) abort(); |
|
lig->val = -1; // uknown |
|
#ifdef HAVE_EEZE |
|
const char *s; |
|
|
|
s = eeze_udev_syspath_get_sysattr(lig->dev, "brightness"); |
|
if (!s) |
|
{ |
|
free(lig->dev); |
|
free(lig); |
|
return; |
|
} |
|
lig->val = atoi(s); |
|
eina_stringshare_del(s); |
|
|
|
s = eeze_udev_syspath_get_sysattr(lig->dev, "max_brightness"); |
|
if (s) |
|
{ |
|
lig->max = atoi(s); |
|
eina_stringshare_del(s); |
|
} |
|
if (lig->max <= 0) lig->max = 255; |
|
lig->prefer = eeze_udev_syspath_check_sysattr(lig->dev, "type", "firmware"); |
|
#elif defined(__FreeBSD_kernel__) |
|
size_t plen = sizeof(lig->val); |
|
sysctlbyname(lig->dev, &(lig->val), &plen, NULL, 0); |
|
lig->max = 100; |
|
#endif |
|
_devices = eina_list_append(_devices, lig); |
|
} |
|
|
|
#ifdef HAVE_EEZE |
|
static Eina_Bool |
|
_light_device_include(const char *dev) |
|
{ // filter out known undesireable devices |
|
if (strstr(dev, "::capslock")) return EINA_FALSE; |
|
if (strstr(dev, "::numlock")) return EINA_FALSE; |
|
if (strstr(dev, "::scrolllock")) return EINA_FALSE; |
|
if (strstr(dev, "::compose")) return EINA_FALSE; |
|
if (strstr(dev, "::kana")) return EINA_FALSE; |
|
return EINA_TRUE; |
|
} |
|
#endif |
|
|
|
static void |
|
_light_refresh_devices(void) |
|
{ |
|
Light *lig; |
|
|
|
EINA_LIST_FREE(_devices, lig) |
|
{ |
|
free(lig->dev); |
|
free(lig); |
|
} |
|
#ifdef HAVE_EEZE |
|
Eina_List *devs; |
|
const char *s; |
|
|
|
devs = eeze_udev_find_by_filter("backlight", NULL, NULL); |
|
EINA_LIST_FREE(devs, s) |
|
{ |
|
if (_light_device_include(s)) _light_add(s); |
|
eina_stringshare_del(s); |
|
} |
|
devs = eeze_udev_find_by_filter("leds", NULL, NULL); |
|
EINA_LIST_FREE(devs, s) |
|
{ |
|
if (_light_device_include(s)) _light_add(s); |
|
eina_stringshare_del(s); |
|
} |
|
#elif defined(__FreeBSD_kernel__) |
|
// XXX; shouldn't we scan for devices? |
|
_light_add("hw.acpi.video.lcd0.brightness"); |
|
#endif |
|
} |
|
|
|
static Light * |
|
_light_find(const char *dev) |
|
{ |
|
Eina_List *l; |
|
Light *lig; |
|
|
|
if (!dev) return NULL; |
|
EINA_LIST_FOREACH(_devices, l, lig) |
|
{ |
|
if (!strcmp(lig->dev, dev)) return lig; |
|
} |
|
return NULL; |
|
} |
|
|
|
static void |
|
_cb_bklight_list(void *data EINA_UNUSED, const char *params EINA_UNUSED) |
|
{ // reply = "dev1 -|p dev2 -|p ..." |
|
Eina_List *l; |
|
Light *lig; |
|
char *rep = NULL, *p = NULL; |
|
size_t repsize = 0; |
|
|
|
eina_lock_take(&_devices_lock); |
|
EINA_LIST_FOREACH(_devices, l, lig) |
|
{ |
|
repsize += strlen(lig->dev) + 2 + 1; |
|
} |
|
if (repsize > 0) |
|
{ |
|
rep = malloc(repsize); |
|
if (!rep) abort(); |
|
p = rep; |
|
EINA_LIST_FOREACH(_devices, l, lig) |
|
{ |
|
size_t len = strlen(lig->dev); |
|
memcpy(p, lig->dev, len + 1); |
|
p[len] = ' '; len++; |
|
if (lig->prefer) p[len] = 'p'; |
|
else p[len] = '-'; |
|
len++; |
|
if (l->next) p[len] = ' '; |
|
else p[len] = '\0'; |
|
p += len + 1; |
|
} |
|
} |
|
eina_lock_release(&_devices_lock); |
|
e_system_inout_command_send("bklight-list", "%s", rep); |
|
free(rep); |
|
} |
|
|
|
static void |
|
_cb_bklight_refresh(void *data EINA_UNUSED, const char *params EINA_UNUSED) |
|
{ |
|
eina_lock_take(&_devices_lock); |
|
_light_refresh_devices(); |
|
eina_lock_release(&_devices_lock); |
|
} |
|
|
|
static void |
|
_cb_bklight_get(void *data EINA_UNUSED, const char *params) |
|
{ |
|
Light *lig; |
|
|
|
eina_lock_take(&_devices_lock); |
|
lig = _light_find(params); |
|
if (!lig) goto done; |
|
lig->val_get_count++; |
|
eina_semaphore_release(&_worker_sem, 1); |
|
_light_get(lig); |
|
done: |
|
eina_lock_release(&_devices_lock); |
|
} |
|
|
|
static void |
|
_cb_bklight_set(void *data EINA_UNUSED, const char *params) |
|
{ |
|
Light *lig; |
|
char dev[1024] = ""; |
|
int val = 0; |
|
|
|
if (!params) return; |
|
if (sscanf(params, "%1023s %i", dev, &val) != 2) return; |
|
eina_lock_take(&_devices_lock); |
|
lig = _light_find(dev); |
|
if (!lig) goto done; |
|
lig->val_set = val; |
|
lig->set = EINA_TRUE; |
|
eina_semaphore_release(&_worker_sem, 1); |
|
done: |
|
eina_lock_release(&_devices_lock); |
|
} |
|
|
|
void |
|
e_system_backlight_init(void) |
|
{ |
|
_light_refresh_devices(); |
|
eina_lock_new(&_devices_lock); |
|
eina_semaphore_new(&_worker_sem, 0); |
|
ecore_thread_feedback_run(_cb_worker, _cb_worker_message, |
|
_cb_worker_end, _cb_worker_cancel, |
|
NULL, EINA_TRUE); |
|
e_system_inout_command_register("bklight-list", _cb_bklight_list, NULL); |
|
e_system_inout_command_register("bklight-refresh", _cb_bklight_refresh, NULL); |
|
e_system_inout_command_register("bklight-get", _cb_bklight_get, NULL); |
|
e_system_inout_command_register("bklight-set", _cb_bklight_set, NULL); |
|
} |
|
|
|
void |
|
e_system_backlight_shutdown(void) |
|
{ |
|
// only shutdown things we really have to - no need to free mem etc. |
|
}
|
|
|