diff options
author | Richard Hughes <richard@hughsie.com> | 2007-03-19 21:14:11 +0000 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2007-03-19 21:14:11 +0000 |
commit | 7f278b8a9d38a5c0851f20f12a4709684571d3d1 (patch) | |
tree | 9fe9480066e3406b933ac06b21985be3639a3a7b | |
parent | a0af30e5d063ca863713d365b54bb0ca45814341 (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.in | 25 | ||||
-rw-r--r-- | fdi/policy/10osvendor/10-macbook-backlight.fdi | 23 | ||||
-rw-r--r-- | fdi/policy/10osvendor/Makefile.am | 4 | ||||
-rw-r--r-- | hald/linux/addons/.gitignore | 1 | ||||
-rw-r--r-- | hald/linux/addons/Makefile.am | 6 | ||||
-rw-r--r-- | hald/linux/addons/addon-macbook-backlight.c | 274 |
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; +} + |