backlight: Use basic ACPI sysctl knob on FreeBSD (kernel)

Summary:
Unconditionally build the suid-helper _backlight program; conditionalize
behavior on Eeze, FreeBSD (doing nothing on neither). Add logic to set
the FreeBSD sysctl in a similar manner to udev devices on Linux.

Add _bl_sys_find/_get helpers for FreeBSD that check for and consult the
video ACPI sysctl.

Test Plan:
Seems to work okay on my laptop (with EINA_CPU_FAKE=1 to workaround a threadq
race that I believe is unrelated -- T2287).

Reviewers: zmike, q66

Reviewed By: q66

Subscribers: cedric, seoz

Differential Revision: https://phab.enlightenment.org/D2337
This commit is contained in:
Conrad Meyer 2015-04-14 14:20:33 +01:00 committed by Daniel Kolesa
parent de943ddfa7
commit 4fc5495f4e
3 changed files with 163 additions and 54 deletions

View File

@ -27,6 +27,7 @@ src/bin/enlightenment_open
internal_bindir = $(libdir)/enlightenment/utils
internal_bin_PROGRAMS = \
src/bin/enlightenment_backlight \
src/bin/enlightenment_fm_op \
src/bin/enlightenment_sys \
src/bin/enlightenment_thumb \
@ -36,10 +37,6 @@ if ! HAVE_WAYLAND_ONLY
internal_bin_PROGRAMS += src/bin/enlightenment_alert
endif
if HAVE_EEZE
internal_bin_PROGRAMS += src/bin/enlightenment_backlight
endif
ENLIGHTENMENTHEADERS = \
src/bin/e_about.h \
src/bin/e_acpi.h \
@ -420,13 +417,11 @@ src/bin/e_sys_l2ping.c
src_bin_enlightenment_sys_LDADD = @SUID_LDFLAGS@ @E_SYS_LIBS@ @BLUEZ_LIBS@
src_bin_enlightenment_sys_CPPFLAGS = @SUID_CFLAGS@ @E_SYS_CFLAGS@ @BLUEZ_CFLAGS@ -DPACKAGE_SYSCONF_DIR=\"@PACKAGE_SYSCONF_DIR@\"
if HAVE_EEZE
src_bin_enlightenment_backlight_SOURCES = \
src/bin/e_backlight_main.c
src_bin_enlightenment_backlight_CPPFLAGS = @SUID_CFLAGS@ @EEZE_CFLAGS@
src_bin_enlightenment_backlight_LDADD = @SUID_LDFLAGS@ @EEZE_LIBS@
endif
src_bin_enlightenment_alert_SOURCES = \
src/bin/e_alert_main.c
@ -455,14 +450,9 @@ include src/bin/e_fm/Makefile.mk
# and before internal_bin_PROGRAMS are installed. install-data-hook is
# run after both
setuid_root_mode = a=rx,u+xs
if HAVE_EEZE
enlightenment-sys-install-data-hook:
@chmod $(setuid_root_mode) $(DESTDIR)$(libdir)/enlightenment/utils/enlightenment_sys$(EXEEXT) || true
@chmod $(setuid_root_mode) $(DESTDIR)$(libdir)/enlightenment/utils/enlightenment_backlight$(EXEEXT) || true
else
enlightenment-sys-install-data-hook:
@chmod $(setuid_root_mode) $(DESTDIR)$(libdir)/enlightenment/utils/enlightenment_sys$(EXEEXT) || true
endif
installed_headersdir = $(prefix)/include/enlightenment
installed_headers_DATA = $(ENLIGHTENMENTHEADERS) src/bin/e_fm_shared_types.h
INSTALL_DATA_HOOKS += enlightenment-sys-install-data-hook

View File

@ -2,6 +2,12 @@
#ifdef HAVE_EEZE
# include <Eeze.h>
#endif
#include <sys/param.h>
#ifdef __FreeBSD_kernel__
# include <sys/sysctl.h>
# include <errno.h>
# include <string.h>
#endif
// FIXME: backlight should be tied per zone but this implementation is just
// a signleton right now as thats 99% of use cases. but api supports
@ -25,7 +31,7 @@ static Eina_Bool bl_avail = EINA_TRUE;
#ifndef HAVE_WAYLAND_ONLY
static Eina_Bool xbl_avail = EINA_FALSE;
#endif
#ifdef HAVE_EEZE
#if defined(HAVE_EEZE) || defined(__FreeBSD_kernel__)
static double bl_delayval = 1.0;
static const char *bl_sysval = NULL;
static Ecore_Event_Handler *bl_sys_exit_handler = NULL;
@ -38,6 +44,11 @@ static void _bl_sys_level_get(void);
static Eina_Bool _e_bl_cb_exit(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
static void _bl_sys_level_set(double val);
#endif
#ifdef __FreeBSD_kernel__
static const char *bl_acpi_sysctl = "hw.acpi.video.lcd0.brightness";
static int bl_mib[CTL_MAXNAME];
static int bl_mib_len = -1;
#endif
EAPI int E_EVENT_BACKLIGHT_CHANGE = -1;
@ -240,7 +251,7 @@ _e_backlight_update(void)
return;
}
#endif
#ifdef HAVE_EEZE
#if defined(HAVE_EEZE) || defined(__FreeBSD_kernel__)
_bl_sys_find();
if (bl_sysval)
{
@ -299,7 +310,7 @@ _e_backlight_set(double val)
free(out);
}
#endif
#ifdef HAVE_EEZE
#if defined(HAVE_EEZE) || defined(__FreeBSD_kernel__)
else if (sysmode == MODE_SYS)
{
if (bl_sysval)
@ -445,7 +456,9 @@ _bl_sys_level_get(void)
e_bl_val = (double)val / (double)maxval;
// fprintf(stderr, "GET: %i/%i (%1.3f)\n", val, maxval, e_bl_val);
}
#endif // HAVE_EEZE
#if defined(HAVE_EEZE) || defined(__FreeBSD_kernel__)
static Eina_Bool
_e_bl_cb_ext_delay(void *data EINA_UNUSED)
{
@ -494,5 +507,64 @@ _bl_sys_level_set(double val)
e_prefix_lib_get(), (int)(val * 1000.0), bl_sysval);
bl_sys_set_exe = ecore_exe_run(buf, NULL);
}
#endif // HAVE_EEZE || __FreeBSD_kernel__
#endif
#ifdef __FreeBSD_kernel__
static void
_bl_sys_find(void)
{
int rc;
size_t mlen;
if (!bl_avail) return;
if (bl_mib_len >= 0) return;
mlen = sizeof(bl_mib) / sizeof(bl_mib[0]);
rc = sysctlnametomib(bl_acpi_sysctl, bl_mib, &mlen);
if (rc < 0)
{
if (errno == ENOENT) ERR("ACPI brightness sysctl '%s' not found, consider 'kldload acpi_video'", bl_acpi_sysctl);
else ERR("sysctlnametomib(%s): %s(%d)", bl_acpi_sysctl, strerror(errno), errno);
bl_avail = EINA_FALSE;
return;
}
bl_mib_len = (int)mlen;
sysmode = MODE_SYS;
eina_stringshare_replace(&bl_sysval, bl_acpi_sysctl);
}
static void
_bl_sys_level_get(void)
{
int rc, brightness;
size_t oldlen;
if (!bl_avail) return;
if (bl_mib_len < 0) return;
oldlen = sizeof(brightness);
rc = sysctl(bl_mib, bl_mib_len, &brightness, &oldlen, NULL, 0);
if (rc < 0)
{
ERR("Could not retrieve ACPI brightness: %s(%d)", strerror(errno), errno);
bl_avail = EINA_FALSE;
return;
}
if (oldlen != sizeof(brightness))
{
// This really should not happen.
ERR("!!! Brightness sysctl changed size !!!");
bl_avail = EINA_FALSE;
return;
}
if (brightness < 0 || brightness > 100)
{
// This really should not happen either.
ERR("!!! Brightness sysctl out of range !!!");
bl_avail = EINA_FALSE;
return;
}
e_bl_val = (double)brightness / 100.;
}
#endif // __FreeBSD_kernel__

View File

@ -4,11 +4,13 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#if defined(HAVE_EEZE)
#include <Eeze.h>
/* local subsystem functions */
@ -33,48 +35,15 @@ _bl_write_file(const char *file, int val)
return 0;
}
/* externally accessible functions */
int
main(int argc, char **argv)
static int
_bl_set(const char *dev, int level)
{
int i, level, devok = 0;
const char *f, *dev = NULL, *str;
const char *f, *str;
int maxlevel = 0, curlevel = -1;
Eina_List *devs, *l;
Eina_Bool devok = EINA_FALSE;
char buf[4096] = "";
for (i = 1; i < argc; i++)
{
if ((!strcmp(argv[i], "-h")) ||
(!strcmp(argv[i], "-help")) ||
(!strcmp(argv[i], "--help")))
{
printf("This is an internal tool for Enlightenment.\n"
"do not use it.\n");
exit(0);
}
}
if (argc == 3)
{
level = atoi(argv[1]);
dev = argv[2];
}
else
exit(1);
if (!dev) return -1;
if (setuid(0) != 0)
{
printf("ERROR: UNABLE TO ASSUME ROOT PRIVILEGES\n");
exit(5);
}
if (setgid(0) != 0)
{
printf("ERROR: UNABLE TO ASSUME ROOT GROUP PRIVILEGES\n");
exit(7);
}
eeze_init();
devs = eeze_udev_find_by_filter("backlight", NULL, NULL);
if (!devs)
@ -89,7 +58,7 @@ main(int argc, char **argv)
if (!strcmp(f, dev))
{
dev = f;
devok = 1;
devok = EINA_TRUE;
break;
}
}
@ -123,7 +92,85 @@ main(int argc, char **argv)
EINA_LIST_FREE(devs, f)
eina_stringshare_del(f);
}
#elif defined(__FreeBSD_kernel__) // !HAVE_EEZE
#include <sys/sysctl.h>
#include <errno.h>
static const char *bl_acpi_sysctl = "hw.acpi.video.lcd0.brightness";
static int
_bl_set(const char *dev, int level)
{
int rc;
level = ((100 * level) + 500) / 1000;
if (level > 100) level = 100;
else if (level < 0) level = 0;
// Be slightly careful if making this more permissive. We don't want to
// allow non-root users to set arbitrary integer sysctls between 0-100.
if (strcmp(bl_acpi_sysctl, dev) != 0)
{
printf("bad device: %s\n", dev);
return -1;
}
rc = sysctlbyname(bl_acpi_sysctl, NULL, NULL, &level, sizeof(level));
if (rc < 0)
{
perror("sysctlbyname");
return -1;
}
return 0;
}
#endif // __FreeBSD_kernel__
#if defined(HAVE_EEZE) || defined(__FreeBSD_kernel__)
int
main(int argc, char **argv)
{
const char *dev = NULL;
int i, level;
for (i = 1; i < argc; i++)
{
if ((!strcmp(argv[i], "-h")) ||
(!strcmp(argv[i], "-help")) ||
(!strcmp(argv[i], "--help")))
{
printf("This is an internal tool for Enlightenment.\n"
"do not use it.\n");
exit(0);
}
}
if (argc == 3)
{
level = atoi(argv[1]);
dev = argv[2];
}
else
exit(1);
if (!dev) return -1;
if (setuid(0) != 0)
{
printf("ERROR: UNABLE TO ASSUME ROOT PRIVILEGES\n");
exit(5);
}
if (setgid(0) != 0)
{
printf("ERROR: UNABLE TO ASSUME ROOT GROUP PRIVILEGES\n");
exit(7);
}
return _bl_set(dev, level);
}
#else // !HAVE_EEZE && !__FreeBSD_kernel__
int
main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
{
return -1;
}
#endif