diff --git a/configure.in b/configure.in
index c479de3..ac9948e 100644
--- a/configure.in
+++ b/configure.in
@@ -540,6 +540,32 @@ elif test "x$with_macbookpro" = "x" ; th
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(nokia770, [ --with-nokia770 Whether to build Nokia 770 utils (no)])
BUILD_N770=no
if test "x$with_nokia770" = "xyes"; then
@@ -696,6 +722,7 @@ echo "
use APM: ${msg_apm}
Macbook Pro utils: ${BUILD_MACBOOKPRO} (Linux only, x86 only, requires libpci)
+ Macbook backlight support: ${BUILD_MACBOOK} (Linux only, x86 only, requires libpci)
CPU frequency scaling: ${BUILD_CPUFREQ} (Linux only)
USB wireless mouse power: ${BUILD_USBCSR} (Linux only, requires libusb)
Dell Backlight ${BUILD_DELL} (Linux only, requires libsmbios)
diff --git a/fdi/policy/10osvendor/10-macbook-backlight.fdi b/fdi/policy/10osvendor/10-macbook-backlight.fdi
new file mode 100644
index 0000000..8dba0df
--- /dev/null
+++ b/fdi/policy/10osvendor/10-macbook-backlight.fdi
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ laptop_panel
+ MacBook Backlight Control
+ custom
+ 118
+ hald-addon-macbook-backlight
+
+
+
diff --git a/fdi/policy/10osvendor/Makefile.am b/fdi/policy/10osvendor/Makefile.am
index 734eead..2fa0481 100644
--- a/fdi/policy/10osvendor/Makefile.am
+++ b/fdi/policy/10osvendor/Makefile.am
@@ -13,6 +13,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/Makefile.am b/hald/linux/addons/Makefile.am
index 32bfb4d..3a1288c 100644
--- a/hald/linux/addons/Makefile.am
+++ b/hald/linux/addons/Makefile.am
@@ -36,6 +36,12 @@ hald_addon_macbookpro_backlight_SOURCES
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 0000000..92b66ae
--- /dev/null
+++ b/hald/linux/addons/addon-macbook-backlight.c
@@ -0,0 +1,290 @@
+/*
+ * Macbook Backlight Control
+ * Copyright © 2006 Ryan Lortie
+ *
+ * HAL integration Copyright © 2007 Ryan Lortie
+ * using code Copyright © 2006 David Zeuthen
+ *
+ * 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
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+
+#include
+#include
+#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 \
+ " \n" \
+ " \n" \
+ " \n" \
+ " \n" \
+ " \n" \
+ " \n" \
+ " \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;
+}