summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2007-03-19 21:14:11 +0000
committerRichard Hughes <richard@hughsie.com>2007-03-19 21:14:11 +0000
commit7f278b8a9d38a5c0851f20f12a4709684571d3d1 (patch)
tree9fe9480066e3406b933ac06b21985be3639a3a7b
parenta0af30e5d063ca863713d365b54bb0ca45814341 (diff)
add support for the macbook backlight
Apply a patch from Ryan Lortie <desrt@desrt.ca> to support the Macbook backlight. The code was written after the AppleIntelIntegratedFramebuffer.kext kernel extension was reverse engineered by Ryan. Rebased to master, and CodingStyle corrected by me, no other changes.
-rw-r--r--configure.in25
-rw-r--r--fdi/policy/10osvendor/10-macbook-backlight.fdi23
-rw-r--r--fdi/policy/10osvendor/Makefile.am4
-rw-r--r--hald/linux/addons/.gitignore1
-rw-r--r--hald/linux/addons/Makefile.am6
-rw-r--r--hald/linux/addons/addon-macbook-backlight.c274
6 files changed, 333 insertions, 0 deletions
diff --git a/configure.in b/configure.in
index ebd79962..d9f61e6a 100644
--- a/configure.in
+++ b/configure.in
@@ -675,6 +675,30 @@ elif test "x$with_macbookpro" = "x" ; then
fi
AM_CONDITIONAL(BUILD_MACBOOKPRO, test x$BUILD_MACBOOKPRO = xyes)
+dnl macbook backlight support
+AC_ARG_WITH(macbook, [ --with-macbook Include support for Macbook backlight (auto)])
+BUILD_MACBOOK=no
+if test "x$with_macbook" = "xyes" ; then
+ BUILD_MACBOOK=yes
+elif test "x$with_macbook" = "x" ; then
+ if test "x$USE_LIBPCI" != "xno" ; then
+ case "${HALD_BACKEND}" in
+ linux)
+ case "${host}" in
+ i[[3456]]86-*-*)
+ BUILD_MACBOOK=yes
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ fi
+fi
+AM_CONDITIONAL(BUILD_MACBOOK, test x$BUILD_MACBOOK = xyes)
+
AC_ARG_WITH([omap],
[AS_HELP_STRING([--with-omap],
[Whether to build OMAP utils (auto)])])
@@ -884,6 +908,7 @@ echo "
use APM: ${msg_apm}
use Sony PIC: ${msg_sonypic}
+ Macbook backlight support: ${BUILD_MACBOOK} (Linux only, x86 only, requires libpci)
Macbook Pro utils: ${BUILD_MACBOOKPRO} (Linux only, x86 only, requires libpci)
OMAP utils: ${BUILD_OMAP} (Linux only, arm only)
CPU frequency scaling: ${BUILD_CPUFREQ} (Linux only)
diff --git a/fdi/policy/10osvendor/10-macbook-backlight.fdi b/fdi/policy/10osvendor/10-macbook-backlight.fdi
new file mode 100644
index 00000000..227bbb51
--- /dev/null
+++ b/fdi/policy/10osvendor/10-macbook-backlight.fdi
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deviceinfo version="0.2">
+ <device>
+ <match key="system.kernel.name" string="Linux">
+ <match key="smbios.system.manufacturer" string="Apple Computer, Inc.">
+ <match key="smbios.system.product" string="MacBook1,1">
+ <spawn udi="/org/freedesktop/Hal/devices/macbook_backlight"/>
+ </match>
+ </match>
+ </match>
+ </device>
+ <device>
+ <match key="info.udi" string="/org/freedesktop/Hal/devices/macbook_backlight">
+ <append key="info.capabilities" type="strlist">laptop_panel</append>
+ <merge key="info.product" type="string">MacBook Backlight Control</merge>
+ <merge key="laptop_panel.access_method" type="string">custom</merge>
+ <merge key="laptop_panel.num_levels" type="int">118</merge>
+ <append key="info.addons" type="strlist">hald-addon-macbook-backlight</append>
+ </match>
+ </device>
+</deviceinfo>
+
diff --git a/fdi/policy/10osvendor/Makefile.am b/fdi/policy/10osvendor/Makefile.am
index 55666efe..7b84aef4 100644
--- a/fdi/policy/10osvendor/Makefile.am
+++ b/fdi/policy/10osvendor/Makefile.am
@@ -14,6 +14,10 @@ if BUILD_MACBOOKPRO
dist_fdi_DATA += 10-macbookpro-utils.fdi
endif
+if BUILD_MACBOOK
+dist_fdi_DATA += 10-macbook-backlight.fdi
+endif
+
if BUILD_CPUFREQ
dist_fdi_DATA += 10-cpufreq.fdi
endif
diff --git a/hald/linux/addons/.gitignore b/hald/linux/addons/.gitignore
index 2b6fd5c9..7ecd42a9 100644
--- a/hald/linux/addons/.gitignore
+++ b/hald/linux/addons/.gitignore
@@ -11,6 +11,7 @@ hald-addon-storage
hald-addon-usb-csr
hald-addon-keyboard
hald-addon-acpi-buttons-toshiba
+hald-addon-macbook-backlight
hald-addon-macbookpro-backlight
hald-addon-cpufreq
hald-addon-dell-backlight
diff --git a/hald/linux/addons/Makefile.am b/hald/linux/addons/Makefile.am
index bea0a17d..5d987092 100644
--- a/hald/linux/addons/Makefile.am
+++ b/hald/linux/addons/Makefile.am
@@ -38,6 +38,12 @@ hald_addon_macbookpro_backlight_SOURCES = addon-macbookpro-backlight.c ../../log
hald_addon_macbookpro_backlight_LDADD = $(top_builddir)/libhal/libhal.la -lpci @GLIB_LIBS@
endif
+if BUILD_MACBOOK
+libexec_PROGRAMS += hald-addon-macbook-backlight
+hald_addon_macbook_backlight_SOURCES = addon-macbook-backlight.c ../../logger.c ../../util_helper.c
+hald_addon_macbook_backlight_LDADD = $(top_builddir)/libhal/libhal.la -lpci @GLIB_LIBS@
+endif
+
if BUILD_CPUFREQ
libexec_PROGRAMS += hald-addon-cpufreq
hald_addon_cpufreq_SOURCES = addon-cpufreq.c addon-cpufreq.h addon-cpufreq-userspace.h \
diff --git a/hald/linux/addons/addon-macbook-backlight.c b/hald/linux/addons/addon-macbook-backlight.c
new file mode 100644
index 00000000..5314f3c8
--- /dev/null
+++ b/hald/linux/addons/addon-macbook-backlight.c
@@ -0,0 +1,274 @@
+/*
+ * Macbook Backlight Control
+ * Copyright © 2006 Ryan Lortie <desrt@desrt.ca>
+ *
+ * HAL integration Copyright © 2007 Ryan Lortie <desrt@desrt.ca>
+ * using code Copyright © 2006 David Zeuthen <david@fubar.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110 USA
+ *
+ * This program was written after I reverse engineered the
+ * AppleIntelIntegratedFramebuffer.kext kernel extension in Mac OS X and
+ * played with the register at the memory location I found therein.
+ *
+ * From my experiments, the register appears to have two halves.
+ *
+ * yyyyyyyyyyyyyyy0xxxxxxxxxxxxxxx0
+ *
+ * The top (y) bits appear to be the maximum brightness level and the
+ * bottom (x) bits are the current brightness level. 0s are always 0.
+ * The brightness level is, therefore, x/y.
+ *
+ * As my Macbook boots, y is set to 0x94 and x is set to 0x1f. Going below
+ * 0x1f produces odd results. For example, if you come from above, the
+ * backlight will completely turn off at 0x12 (18). Coming from below,
+ * however, you need to get to 0x15 (21) before the backlight comes back on.
+ *
+ * Since there is no clear cut boundry, I assume that this value specifies
+ * a raw voltage. Also, it appears that the bootup value of 0x1f corresponds
+ * to the lowest level that Mac OS X will set the backlight I choose this
+ * value as a minimum.
+ *
+ * For the maximum I do not let the value exceed the value in the upper 15
+ * bits.
+ *
+ * Turning the backlight off entirely is not supported (as this is supported
+ * by the kernel itself). This utility is only for setting the brightness
+ * of the backlight when it is enabled.
+ */
+
+#include <pci/pci.h>
+
+#include <glib.h>
+
+#include <stdio.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include "libhal/libhal.h"
+#include "../../util_helper.h"
+
+#define REGISTER_OFFSET 0x00061254
+#define PAGE_SIZE 4096
+#define PAGE_MASK (PAGE_SIZE - 1)
+
+#define ACCESS_OFFSET (REGISTER_OFFSET & PAGE_MASK)
+#define ACCESS_INDEX (ACCESS_OFFSET >> 2)
+
+unsigned int *register_page;
+
+static unsigned long
+determine_video_base_address (void)
+{
+ struct pci_access *pacc;
+ struct pci_dev *pdev;
+ unsigned long address;
+ int i;
+
+ address = 0;
+
+ pacc = pci_alloc ();
+ pci_init (pacc);
+ pci_scan_bus (pacc);
+
+ for (pdev = pacc->devices; pdev; pdev = pdev->next) {
+ pci_fill_info (pdev, PCI_FILL_IDENT | PCI_FILL_BASES);
+
+ if (pdev->vendor_id == 0x8086 && pdev->device_id == 0x27a2)
+ for (i = 0; i < (int) G_N_ELEMENTS (pdev->base_addr); i++) {
+ if (pdev->size[i] == 512 * 1024) {
+ address = pdev->base_addr[i];
+ goto end;
+ }
+ }
+ }
+
+end:
+ pci_cleanup (pacc);
+
+ return address;
+}
+
+static gboolean
+map_register_page (void)
+{
+ long address;
+ int fd;
+
+ address = determine_video_base_address ();
+
+ if (address == 0) {
+ g_error ("Unable to locate video base address");
+ return FALSE;
+ }
+
+ fd = open ("/dev/mem", O_RDWR);
+
+ if (fd < 0) {
+ g_error ("failed to open /dev/mem");
+ return FALSE;
+ }
+
+ register_page = mmap (NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, (address + REGISTER_OFFSET) & ~PAGE_MASK);
+
+ close (fd);
+
+ drop_privileges (FALSE);
+
+ if (register_page == MAP_FAILED) {
+ g_error ("failed to mmap");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static unsigned long
+register_get (void)
+{
+ return register_page[ACCESS_INDEX];
+}
+
+static void
+register_set (unsigned long value)
+{
+ register_page[ACCESS_INDEX] = value;
+}
+
+static gboolean
+backlight_set (long value)
+{
+ long max;
+
+ max = register_get () >> 17;
+
+ /* sanity check: this should always be 0x94 */
+ if (max != 0x94)
+ return FALSE;
+
+ value = CLAMP (value, 0x1f, max);
+
+ register_set ((max << 17) | (value << 1));
+
+ return TRUE;
+}
+
+static long
+backlight_get (void)
+{
+ return (register_get () >> 1) & 0x7fff;
+}
+
+#define BACKLIGHT_OBJECT \
+ "/org/freedesktop/Hal/devices/macbook_backlight"
+#define BACKLIGHT_IFACE \
+ "org.freedesktop.Hal.Device.LaptopPanel"
+#define INTERFACE_DESCRIPTION \
+ " <method name=\"SetBrightness\">\n" \
+ " <arg name=\"brightness_value\" direction=\"in\" type=\"i\"/>\n" \
+ " <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n" \
+ " </method>\n" \
+ " <method name=\"GetBrightness\">\n" \
+ " <arg name=\"brightness_value\" direction=\"out\" type=\"i\"/>\n" \
+ " </method>\n"
+
+static DBusHandlerResult
+filter_function (DBusConnection * connection, DBusMessage * message, void *userdata)
+{
+ DBusMessage *reply;
+ DBusError err;
+ int level;
+ int ret;
+
+ reply = NULL;
+ ret = 0;
+
+ dbus_error_init (&err);
+
+ if (dbus_message_is_method_call (message, BACKLIGHT_IFACE, "SetBrightness")) {
+
+ if (dbus_message_get_args (message, &err, DBUS_TYPE_INT32,
+ &level, DBUS_TYPE_INVALID)) {
+ backlight_set (level + 0x1f);
+
+ if ((reply = dbus_message_new_method_return (message)))
+ dbus_message_append_args (reply, DBUS_TYPE_INT32,
+ &ret, DBUS_TYPE_INVALID);
+ }
+ } else if (dbus_message_is_method_call (message, BACKLIGHT_IFACE, "GetBrightness")) {
+ if (dbus_message_get_args (message, &err, DBUS_TYPE_INVALID)) {
+ level = backlight_get () - 0x1f;
+ level = CLAMP (level, 0, 117);
+
+ if ((reply = dbus_message_new_method_return (message)))
+ dbus_message_append_args (reply, DBUS_TYPE_INT32,
+ &level, DBUS_TYPE_INVALID);
+ }
+ }
+
+ if (reply) {
+ dbus_connection_send (connection, reply, NULL);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+int
+main (int argc, char **argv)
+{
+ LibHalContext *halctx;
+ DBusConnection *conn;
+ GMainLoop *main_loop;
+ const char *udi;
+ DBusError err;
+
+ udi = getenv ("UDI");
+
+ if (udi == NULL)
+ g_error ("no device specified");
+
+ dbus_error_init (&err);
+ if ((halctx = libhal_ctx_init_direct (&err)) == NULL)
+ g_error ("cannot connect to hald");
+
+ dbus_error_init (&err);
+ if (!libhal_device_addon_is_ready (halctx, udi, &err))
+ return -4;
+
+ if (!map_register_page ())
+ g_error ("failed to gain access to the video card");
+
+ conn = libhal_ctx_get_dbus_connection (halctx);
+ dbus_connection_setup_with_g_main (conn, NULL);
+
+ dbus_connection_add_filter (conn, filter_function, NULL, NULL);
+
+ if (!libhal_device_claim_interface (halctx, BACKLIGHT_OBJECT,
+ BACKLIGHT_IFACE, INTERFACE_DESCRIPTION, &err))
+ g_error ("cannot claim interface");
+
+ main_loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (main_loop);
+
+ return 0;
+}
+