backlight: Use basic ACPI sysctl knob on FreeBSD (kernel)
authorConrad Meyer <cse.cem@gmail.com>
Tue, 14 Apr 2015 13:20:33 +0000 (14:20 +0100)
committerDaniel Kolesa <d.kolesa@samsung.com>
Tue, 14 Apr 2015 13:20:33 +0000 (14:20 +0100)
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

src/bin/Makefile.mk
src/bin/e_backlight.c
src/bin/e_backlight_main.c

index 105c380..5afdb4a 100644 (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
index 12e8db1..92c8a0d 100644 (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__
index 4aadbab..d2f0e20 100644 (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>
 
-   return -1;
+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