hal: Branch 'master' - 2 commits

David Zeuthen david at kemper.freedesktop.org
Wed Aug 23 19:03:08 PDT 2006


 doc/api/tmpl/hal-unused.sgml                   |   24 
 doc/api/tmpl/logger.sgml                       |   16 
 doc/api/tmpl/util.sgml                         |   26 
 doc/spec/hal-spec-properties.xml               |  212 ++++
 fdi/policy/10osvendor/10-power-mgmt-policy.fdi |    2 
 hald/linux/addons/Makefile.am                  |    7 
 hald/linux/addons/addon-cpufreq-userspace.c    |  525 +++++++++++
 hald/linux/addons/addon-cpufreq-userspace.h    |   61 +
 hald/linux/addons/addon-cpufreq.c              | 1190 +++++++++++++++++++++++++
 hald/linux/addons/addon-cpufreq.h              |   72 +
 privileges/Makefile.am                         |    3 
 privileges/hal-power-cpufreq.privilege         |   12 
 12 files changed, 2122 insertions(+), 28 deletions(-)

New commits:
diff-tree f0471f48cdb4a8c2826e6050d69e407823af15c8 (from 18f52da6185f14b8b2d806cf17034bbda7593eee)
Author: David Zeuthen <davidz at redhat.com>
Date:   Wed Aug 23 22:01:16 2006 -0400

    fix up hal interface claiming in cpufreq addon
    
    No need to append methods to .method_names and .method_signatures, in fact
    it will break introspection, e.g.
    
      dbus-send --system --dest=org.freedesktop.Hal --print-reply \
                /org/freedesktop/Hal/devices/computer \
                org.freedesktop.DBus.Introspectable.Introspect
    
    Plus we are saving 14 roundtrips to the daemon!

diff --git a/hald/linux/addons/addon-cpufreq.c b/hald/linux/addons/addon-cpufreq.c
index a74fecb..16d04ee 100644
--- a/hald/linux/addons/addon-cpufreq.c
+++ b/hald/linux/addons/addon-cpufreq.c
@@ -1064,21 +1064,6 @@ static DBusHandlerResult dbus_filter_fun
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
-static void dbus_add_method(LibHalContext *halctx, const char *method,
-				const char *signature)
-{
-	libhal_device_property_strlist_append(halctx,
-		      "/org/freedesktop/Hal/devices/computer",
-		      "org.freedesktop.Hal.Device.CPUFreq.method_names",
-		      method,
-		      NULL);
-	libhal_device_property_strlist_append(halctx,
-		      "/org/freedesktop/Hal/devices/computer",
-		      "org.freedesktop.Hal.Device.CPUFreq.method_signatures",
-		      signature,
-		      NULL);
-}
-
 static gboolean is_supported(void)
 {
 	char *governor_file = NULL;
@@ -1114,30 +1099,30 @@ gboolean dbus_init(void)
 
 	if (!libhal_device_claim_interface(halctx, udi,
 		"org.freedesktop.Hal.Device.CPUFreq", 
-		"    <method name=\"SetCPUFreqGovernor\">"
-		"      <arg name=\"governor_string\" direction=\"in\" type=\"s\"/>"
-		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>"
-		"    </method>"
-		"    <method name=\"SetCPUFreqPerformance\">"
-		"      <arg name=\"value\" direction=\"in\" type=\"i\"/>"
-		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>"
-		"    </method>"
-		"    <method name=\"SetCPUFreqConsiderNice\">"
-		"      <arg name=\"value\" direction=\"in\" type=\"b\"/>"
-		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>"
-		"    </method>"
-		"    <method name=\"GetCPUFreqGovernor\">"
-		"      <arg name=\"return_code\" direction=\"out\" type=\"s\"/>"
-		"    </method>"
-		"    <method name=\"GetCPUFreqPerformance\">"
-		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>"
-		"    </method>"
-		"    <method name=\"GetCPUFreqConsiderNice\">"
-		"      <arg name=\"return_code\" direction=\"out\" type=\"b\"/>"
-		"    </method>"
-		"    <method name=\"GetCPUFreqAvailableGovernors\">"
-		"      <arg name=\"return_code\" direction=\"out\" type=\"as\"/>"
-		"    </method>",
+		"    <method name=\"SetCPUFreqGovernor\">\n"
+		"      <arg name=\"governor_string\" direction=\"in\" type=\"s\"/>\n"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n"
+		"    </method>\n"
+		"    <method name=\"SetCPUFreqPerformance\">\n"
+		"      <arg name=\"value\" direction=\"in\" type=\"i\"/>\n"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n"
+		"    </method>\n"
+		"    <method name=\"SetCPUFreqConsiderNice\">\n"
+		"      <arg name=\"value\" direction=\"in\" type=\"b\"/>\n"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n"
+		"    </method>\n"
+		"    <method name=\"GetCPUFreqGovernor\">\n"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"s\"/>\n"
+		"    </method>\n"
+		"    <method name=\"GetCPUFreqPerformance\">\n"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n"
+		"    </method>\n"
+		"    <method name=\"GetCPUFreqConsiderNice\">\n"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"b\"/>\n"
+		"    </method>\n"
+		"    <method name=\"GetCPUFreqAvailableGovernors\">\n"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"as\"/>\n"
+		"    </method>\n",
 		&dbus_error)) {
 
 		HAL_WARNING(("Cannot claim interface: %s", dbus_error.message));
@@ -1149,15 +1134,6 @@ gboolean dbus_init(void)
 				     "/org/freedesktop/Hal/devices/computer",
 				     "cpufreq_control",
 				     NULL);
-		
-	dbus_add_method(halctx, "SetCPUFreqGovernor", "s");
-	dbus_add_method(halctx, "SetCPUFreqPerformance", "i");
-	dbus_add_method(halctx, "SetCPUFreqConsiderNice", "b");
-	dbus_add_method(halctx, "GetCPUFreqGovernor", "");
-	dbus_add_method(halctx, "GetCPUFreqPerformance", "");
-	dbus_add_method(halctx, "GetCPUFreqConsiderNice", "");
-	dbus_add_method(halctx, "GetCPUFreqAvailableGovernors", "");
-
 
 	dbus_connection_setup_with_g_main(dbus_connection, NULL);
 	dbus_connection_add_filter(dbus_connection, dbus_filter_function, NULL, NULL);
diff-tree 18f52da6185f14b8b2d806cf17034bbda7593eee (from be78af22b72006a2209fb09f077a7421b5c637ab)
Author: Holger Macht <hmacht at suse.de>
Date:   Wed Aug 23 21:37:45 2006 -0400

    add cpu frequency scaling support to hal
    
    The following patches add CPU frequency capabilities to HAL via an addon.
    This was already discussed in another thread [1].
    
    Addon-cpufreq supports all kernel governors and also implements a
    userspace controlling mechanism. Furthermore, it is supposed to abstract
    all the different settings you can make for the different governors. It is
    unique because it gives you a fine grained control over dynamic scaling
    mechanisms via a DBus interface higher level applications like
    gnome-power-manager or kpowersave can make use of.
    
    [1] http://lists.freedesktop.org/archives/hal/2006-July/005545.html
    ---
    
    Patch adding the cpufreq addon itself.
    
    This version implements the following new things:
    
      - specific DBus errors on failure (exceptions)
      - PolicyKit integration
      - add DBus method to get a list of all available governors
    
    Signed-off-by: Holger Macht <hmacht at suse.de>
    ---
    
    Patch adding the privilege descriptor for the hal-power-cpufreq privilege.
    
    Signed-off-by: Holger Macht <hmacht at suse.de>
    ---
    
    Patch adding the documentation for all CPUFreq methods on the
    org.freedesktop.Hal.Device.SystemPowerManagement interface to the
    Hal specification.
    
    Signed-off-by: Holger Macht <hmacht at suse.de>
    ---

diff --git a/doc/api/tmpl/hal-unused.sgml b/doc/api/tmpl/hal-unused.sgml
index e4bf5ce..0f22ab2 100644
--- a/doc/api/tmpl/hal-unused.sgml
+++ b/doc/api/tmpl/hal-unused.sgml
@@ -286,6 +286,30 @@ logging
 main
 
 
+<!-- ##### SECTION ./tmpl/shared.sgml:Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/shared.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/shared.sgml:Short_Description ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/shared.sgml:Stability_Level ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/shared.sgml:Title ##### -->
+shared
+
+
 <!-- ##### SECTION ./tmpl/sysfs.sgml:Long_Description ##### -->
 <para>
 
diff --git a/doc/api/tmpl/logger.sgml b/doc/api/tmpl/logger.sgml
index 2878b23..ee46b8c 100644
--- a/doc/api/tmpl/logger.sgml
+++ b/doc/api/tmpl/logger.sgml
@@ -37,6 +37,15 @@ logger
 @Varargs: 
 
 
+<!-- ##### FUNCTION logger_forward_debug ##### -->
+<para>
+
+</para>
+
+ at format: 
+ at Varargs: 
+
+
 <!-- ##### FUNCTION logger_enable ##### -->
 <para>
 
@@ -65,6 +74,13 @@ logger
 
 
 
+<!-- ##### FUNCTION setup_logger ##### -->
+<para>
+
+</para>
+
+
+
 <!-- ##### MACRO HAL_TRACE ##### -->
 <para>
 
diff --git a/doc/api/tmpl/util.sgml b/doc/api/tmpl/util.sgml
index d2e2321..a61ab35 100644
--- a/doc/api/tmpl/util.sgml
+++ b/doc/api/tmpl/util.sgml
@@ -38,32 +38,6 @@ util
 
 
 
-<!-- ##### FUNCTION util_compute_time_remaining ##### -->
-<para>
-
-</para>
-
- at id: 
- at chargeRate: 
- at chargeLevel: 
- at chargeLastFull: 
- at isDischarging: 
- at isCharging: 
- at guessChargeRate: 
- at Returns: 
-
-
-<!-- ##### FUNCTION util_compute_percentage_charge ##### -->
-<para>
-
-</para>
-
- at id: 
- at chargeLevel: 
- at chargeLastFull: 
- at Returns: 
-
-
 <!-- ##### FUNCTION hal_util_remove_trailing_slash ##### -->
 <para>
 
diff --git a/doc/spec/hal-spec-properties.xml b/doc/spec/hal-spec-properties.xml
index 7c1eddd..b81aa9e 100644
--- a/doc/spec/hal-spec-properties.xml
+++ b/doc/spec/hal-spec-properties.xml
@@ -5491,6 +5491,218 @@
           </tbody>
         </tgroup>
       </informaltable>
+      <para>
+        The following methods exist on the interface
+        <literal>org.freedesktop.Hal.Device.CPUFreq</literal>.
+      </para>
+      <informaltable>
+        <tgroup cols="2">
+          <thead>
+            <row>
+              <entry>Method (parameter types)</entry>
+              <entry>Parameters</entry>
+              <entry>Mandatory</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>
+                <literal>SetCPUFreqGovernor</literal> (string)
+              </entry>
+              <entry>
+	        The name of the governor to set. Get a list of available governors
+		with the GetCPUFreqAvailableGovernors method.
+              </entry>
+              <entry>No</entry>
+              <entry>
+	        Sets a CPU frequency scaling governor for all CPUFreq
+		interfaces the kernel provides. If the userspace governor
+		is set, this interface also contains a proper scaling
+		mechanism. The default performance is set to 50.
+              </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>SetCPUFreqPerformance</literal> (integer)
+              </entry>
+              <entry>
+	        The performance between 1 and 100 to set in dynamic scaling modes.
+              </entry>
+              <entry>No</entry>
+              <entry>
+	        Sets the performance of the dynamic scaling mechanism. This method
+		summarizes and abstracts all the different settings which can be taken
+		for dynamic frequency adjustments, like at which load to switch up
+		frequency or how many steps the mechanism should traverse until
+		reaching the maximum frequency. The higher the value, the more
+		performance you get. Respectively, the higher the value, the sooner
+		and the more often the frequency is switched up.
+              </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>SetCPUFreqConsiderNice</literal> (boolean)
+              </entry>
+              <entry>
+	        Whether or not niced processes should be considered on CPU
+		load calculation.
+              </entry>
+              <entry>No</entry>
+              <entry>
+	        Whether or not niced processes should be considered on CPU
+		load calculation. If niced processes are considered, they can cause a
+		frequency increment although their absolute load percentage wouldn't
+		trigger the scaling mechanism to switch up the frequency. The default
+		setting is 'false'.
+              </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>GetCPUFreqGovernor</literal> (void)
+              </entry>
+              <entry>
+              </entry>
+              <entry>No</entry>
+              <entry>
+	        Get the current active governor for all CPU frequency interfaces (string).
+              </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>GetCPUFreqPerformance</literal> (void)
+              </entry>
+              <entry>
+              </entry>
+              <entry>No</entry>
+              <entry>
+	        Get the current active performance setting if a dynamic scaling
+		mechanism is in use (integer between 1 and 100).
+              </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>GetCPUFreqConsiderNice</literal> (void)
+              </entry>
+              <entry>
+              </entry>
+              <entry>No</entry>
+              <entry>
+	        Returns whether niced processed are considered during CPU load
+		calculation or not (returns boolean).
+              </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>GetCPUFreqAvailableGovernors</literal> (void)
+              </entry>
+              <entry>
+              </entry>
+              <entry>No</entry>
+              <entry>
+	        Returns a list of strings of all available governors which
+		could be set with the SetCPUFreqGovernor method.
+              </entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </informaltable>
+      <para>
+        The following errors maybe raised on the interface
+        <literal>org.freedesktop.Hal.Device.CPUFreq</literal>.
+      </para>
+      <informaltable>
+        <tgroup cols="2">
+          <thead>
+            <row>
+              <entry>Error</entry>
+              <entry>Description</entry>
+              <entry>Detail field</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>
+                <literal>GeneralError</literal>
+              </entry>
+              <entry>
+	        A general error occured.
+              </entry>
+	      <entry>
+	        The exact error.
+	      </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>UnknownMethod</literal>
+              </entry>
+              <entry>
+	        The executed method doesn't exist.
+              </entry>
+	      <entry>
+	        The method which was tried to be executed.
+	      </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>UnknownGovernor</literal>
+              </entry>
+              <entry>
+	        The governor which was tried to be set doesn't exist.
+              </entry>
+	      <entry>
+	        The governor which was tried be to set.
+	      </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>InvalidMessage</literal>
+              </entry>
+              <entry>
+	        The message that was sent to the interface is invalid.
+		For instance, a parameter is missing.
+              </entry>
+	      <entry>
+	        A DBus error message.
+	      </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>PermissionDenied</literal>
+              </entry>
+              <entry>
+	        The caller doesn't have the privilege to execute this
+		method.
+              </entry>
+	      <entry>
+	        The privilege the caller needs to execute the method.
+	      </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>NoSuitableGovernor</literal>
+              </entry>
+              <entry>
+	        The method executed doesn't exist for the current active governor.
+              </entry>
+	      <entry>
+	        The method which was tried to be executed.
+	      </entry>
+            </row>
+            <row>
+              <entry>
+                <literal>GovernorInitFailed</literal>
+              </entry>
+              <entry>
+	        The initialization of the governor failed.
+              </entry>
+	      <entry>
+	        The reason for the failure.
+	      </entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </informaltable>
     </sect2>
     <sect2 id="device-properties-tape">
       <title>
diff --git a/fdi/policy/10osvendor/10-power-mgmt-policy.fdi b/fdi/policy/10osvendor/10-power-mgmt-policy.fdi
index 2c2705a..c0b4845 100644
--- a/fdi/policy/10osvendor/10-power-mgmt-policy.fdi
+++ b/fdi/policy/10osvendor/10-power-mgmt-policy.fdi
@@ -26,6 +26,8 @@
     <match key="info.udi" string="/org/freedesktop/Hal/devices/computer">
       <append key="info.interfaces" type="strlist">org.freedesktop.Hal.Device.SystemPowerManagement</append>
 
+      <append key="info.addons" type="strlist">hald-addon-cpufreq</append>
+
       <append key="org.freedesktop.Hal.Device.SystemPowerManagement.method_names" type="strlist">Suspend</append>
       <append key="org.freedesktop.Hal.Device.SystemPowerManagement.method_signatures" type="strlist">i</append>
       <append key="org.freedesktop.Hal.Device.SystemPowerManagement.method_argnames" type="strlist">num_seconds_to_sleep</append>
diff --git a/hald/linux/addons/Makefile.am b/hald/linux/addons/Makefile.am
index 48226af..63e2d60 100644
--- a/hald/linux/addons/Makefile.am
+++ b/hald/linux/addons/Makefile.am
@@ -15,7 +15,8 @@ libexec_PROGRAMS  = 			\
 	hald-addon-hid-ups 		\
 	hald-addon-keyboard 		\
 	hald-addon-pmu			\
-	hald-addon-storage
+	hald-addon-storage		\
+	hald-addon-cpufreq
 
 if HAVE_LIBPCI
 libexec_PROGRAMS += hald-addon-macbookpro-backlight
@@ -25,6 +26,10 @@ libexec_PROGRAMS += hald-addon-usb-csr
 endif
 endif
 
+hald_addon_cpufreq_SOURCES = addon-cpufreq.c addon-cpufreq.h addon-cpufreq-userspace.h \
+	                     addon-cpufreq-userspace.c ../../logger.c
+hald_addon_cpufreq_LDADD = $(top_builddir)/libhal/libhal.la @GLIB_LIBS@ @POLKIT_LIBS@
+
 hald_addon_acpi_SOURCES = addon-acpi.c ../../logger.c ../../util_helper.c
 hald_addon_acpi_LDADD = $(top_builddir)/libhal/libhal.la
 
diff --git a/hald/linux/addons/addon-cpufreq-userspace.c b/hald/linux/addons/addon-cpufreq-userspace.c
new file mode 100644
index 0000000..953d46a
--- /dev/null
+++ b/hald/linux/addons/addon-cpufreq-userspace.c
@@ -0,0 +1,525 @@
+/***************************************************************************
+ *                                                                         *
+ *                      addon-cpufreq-userspace.c                          *
+ *                                                                         *
+ *              Copyright (C) 2006 SUSE Linux Products GmbH                *
+ *                                                                         *
+ *              Author(s): Holger Macht <hmacht at suse.de>                   *
+ *                         Speed adjustments based on code by              *
+ *                           Thomas Renninger <trenn at suse.de>              *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU General Public License as published by the   *
+ * Free Software Foundation; either version 2 of the License, or (at you   *
+ * option) any later version.                                              *
+ *                                                                         *
+ * 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., *
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA                  *
+ *                                                                         *
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "addon-cpufreq.h"
+#include "addon-cpufreq-userspace.h"
+#include "../../logger.h"
+
+/** at which load difference (in percent) we should immediately switch to
+ * the maximum possible frequency */
+#define JUMP_CPUFREQ_LIMIT_MIN		20
+/** the load difference at which we jump up to the maximum freq
+ * immediately is calculated by the UP_THRESHOLD multiplied with this
+ * relation value */
+#define THRESHOLD_JUMP_LIMIT_RELATION	0.625
+/** how many frequency steps we should consider */
+#define HYSTERESIS			5
+#define DEFAULT_CONSIDER_NICE		FALSE
+#define PROC_STAT_FILE			"/proc/stat"
+
+const char SYSFS_SCALING_SETSPEED_FILE[] =
+     "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_setspeed";
+
+const char SYSFS_SCALING_AVAILABLE_FREQS_FILE[] =
+     "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_available_frequencies";
+
+/** shortcut for g_array_index */
+#define g_a_i(a,i)	g_array_index(a, unsigned, i)
+
+struct userspace_config {
+	int up_threshold;
+	int cpu_high_limit;
+	int consider_nice;
+	int performance;
+};
+
+static struct userspace_config config = { UP_THRESHOLD_MAX,
+					  JUMP_CPUFREQ_LIMIT_MIN,
+					  DEFAULT_CONSIDER_NICE,
+					  DEFAULT_PERFORMANCE };
+
+/********************* CPU load calculation *********************/
+struct cpuload_data {
+	int		num_cpus;
+	int		*load;
+	unsigned long	*last_total_time;
+	unsigned long	*last_working_time;
+};
+static struct cpuload_data cpuload = { -1,
+				       NULL,
+				       NULL,
+				       NULL };
+
+/** frees data needed for CPU load calculation */
+void free_cpu_load_data(void)
+{
+	if (cpuload.num_cpus != -1) {
+		free(cpuload.last_working_time);
+		free(cpuload.last_total_time);
+		free(cpuload.load);
+		cpuload.num_cpus = -1;
+		cpuload.load = NULL;
+		cpuload.last_total_time = NULL;
+		cpuload.last_working_time = NULL;
+	}
+}
+
+/** calculates current cpu load and stores it in cpuload_data object */
+static int calc_cpu_load(const int consider_nice)
+{
+	unsigned long	total_elapsed, working_elapsed;
+	char		what[32];
+	unsigned long	user_time, nice_time, system_time, idle_time;
+	unsigned long	total_time, iowait_time;
+	unsigned	scan_ret;
+	char		line[256];
+	char		cpu_string[7];
+	FILE		*fp;
+	int		new_num_cpus;
+
+	new_num_cpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (new_num_cpus == -1 || new_num_cpus != cpuload.num_cpus) {
+		free_cpu_load_data();
+		cpuload.num_cpus = new_num_cpus;
+		if (cpuload.num_cpus <= 0) {
+			errno = ENODEV;
+			return -20;
+		}
+
+		cpuload.last_total_time = (unsigned long *)calloc(cpuload.num_cpus + 1,
+								  sizeof(unsigned long));
+		cpuload.last_working_time = (unsigned long *)calloc(cpuload.num_cpus + 1,
+								    sizeof(unsigned long));
+		cpuload.load = (int *)calloc(cpuload.num_cpus + 1, sizeof(int));
+	}
+
+	if ((fp = fopen(PROC_STAT_FILE, "r")) == NULL) {
+		HAL_DEBUG(("Could not open %s: %s", PROC_STAT_FILE, strerror(errno)));
+		return -1;
+	}
+
+	/* start with the first line, "overall" cpu load */
+	/* if cpuload.num_cpus == 1, we do not need to evaluate "overall" and "per-cpu" load */
+	sprintf(cpu_string, "cpu ");
+	int i;
+	for (i = 0; i <= cpuload.num_cpus - (cpuload.num_cpus == 1); i++) {
+		
+		if (fgets(line,255,fp) == NULL) {
+			HAL_WARNING(("%s too short (%s)", PROC_STAT_FILE, cpu_string));
+			fclose(fp);
+			return -1;
+		}
+		if (memcmp(line, cpu_string, strlen(cpu_string))) {
+			HAL_WARNING(("no '%s' string in %s line %d",
+				     cpu_string, PROC_STAT_FILE, i));
+			fclose(fp);
+			return -1;
+		}
+		/* initialized, since it is simply not there in 2.4 */
+		iowait_time = 0;
+		scan_ret = sscanf(line, "%s %lu %lu %lu %lu %lu", what, &user_time, &nice_time,
+			  &system_time, &idle_time, &iowait_time);
+		if (scan_ret < 5) {
+			HAL_WARNING(("only %d values in %s. Please report.",
+				     scan_ret, PROC_STAT_FILE));
+			fclose(fp);
+			return -1;
+		}
+
+		unsigned long working_time;
+		if (consider_nice) {
+			working_time = user_time + system_time + nice_time;
+			idle_time += iowait_time;
+		} else {
+			working_time = user_time + system_time;
+			idle_time += (nice_time + iowait_time);
+		}
+		total_time = working_time + idle_time;
+		total_elapsed = total_time - cpuload.last_total_time[i];
+		working_elapsed = working_time - cpuload.last_working_time[i];
+		cpuload.last_working_time[i] = working_time;
+		cpuload.last_total_time[i] = total_time;
+		
+		if (!total_elapsed) {
+			/* not once per CPU, only once per check. */
+			if (!i)
+				HAL_DEBUG(("%s not updated yet, poll slower.", PROC_STAT_FILE));
+		} else
+			cpuload.load[i] = working_elapsed * 100 / total_elapsed;
+
+		sprintf(cpu_string, "cpu%d ", i);
+	}
+	/* shortcut for UP systems */
+	if (cpuload.num_cpus == 1)
+		cpuload.load[1] = cpuload.load[0];
+
+	fclose(fp);
+	
+	return 0;
+}
+
+/** returns current cpuload which has been caluclated before */
+static int get_cpu_load(const int cpu_id)
+{
+	if (cpu_id < -1) {
+		errno = EINVAL;
+		return -10;
+	}
+
+	if (cpuload.load == NULL) {
+		HAL_WARNING(("cpuload.load uninitialized"));
+		errno = EFAULT;
+		return -40;
+	}
+
+	if (cpu_id >= cpuload.num_cpus) {
+		errno = ENODEV;
+		return -30;
+	}
+
+	return cpuload.load[cpu_id + 1];
+}
+/********************* CPU load end *********************/
+
+/********************* userspace interface *********************/
+static gboolean write_speed(unsigned kHz, int cpu_id)
+{
+	char		*speed_file	= NULL;
+
+	if (!cpu_online(cpu_id))
+		return FALSE;
+
+	speed_file = g_strdup_printf(SYSFS_SCALING_SETSPEED_FILE, cpu_id); 
+        if(!write_line(speed_file, "%u", kHz)){
+                HAL_WARNING(("Could not set speed to: %u kHz; %s", kHz, strerror(errno)));
+		g_free(speed_file);
+                return FALSE;
+        }
+	g_free(speed_file);
+	HAL_DEBUG(("Speed set to: %uKHz  for CPU %d", kHz, cpu_id));
+
+	return TRUE;
+}
+
+static void reinit_speed(struct userspace_interface *iface, int current_speed)
+{
+	if (!cpu_online(iface->base_cpu))
+		return;
+
+	write_speed(g_a_i(iface->speeds_kHz, current_speed), iface->base_cpu);
+	HAL_DEBUG(("forced speed to %d kHz", g_a_i(iface->speeds_kHz, current_speed)));
+}
+
+/** @brief set a speed with traversing all intermediary speeds */
+static int set_speed(struct userspace_interface *iface, int target_speed)
+{
+	int delta;
+	int current_speed = iface->current_speed;
+
+	if (current_speed == target_speed)
+		return -1;
+
+	if (current_speed > target_speed)
+		delta = -1;
+	else
+		delta = 1;
+
+	do {
+		current_speed += delta;
+		write_speed(g_a_i(iface->speeds_kHz, current_speed), iface->base_cpu);
+	} while (current_speed != target_speed);
+
+	return current_speed;
+}
+
+/** @brief set speed to the next higher supported value
+ *
+ * @return integer with result of increase speed
+ * @retval 0 if maximum is already reached
+ * @retval 1 if new speed could be set
+ * @retval -1 if mode is not userspace
+ */
+static int increase_speed(struct userspace_interface *iface)
+{
+	int new_speed = iface->current_speed;
+	int current_speed = iface->current_speed;
+
+	if (current_speed != 0)
+		new_speed--;
+	else
+		return current_speed;
+	if (current_speed != new_speed) {
+		HAL_DEBUG(("current: %u new: %u", g_a_i(iface->speeds_kHz, current_speed),
+			   g_a_i(iface->speeds_kHz, new_speed)));
+		set_speed(iface, new_speed);
+	}
+	return new_speed;
+}
+
+/** @brief set speed to the next lower supported value
+ *
+ * @return integer with result of increase speed
+ * @retval 0 if maximum is already reached
+ * @retval 1 if new speed could be set
+ * @retval -1 if mode is not userspace
+ */
+static int decrease_speed(struct userspace_interface *iface)
+{
+	int new_speed = iface->current_speed;
+	int current_speed = iface->current_speed;
+
+	
+	if (g_a_i(iface->speeds_kHz, new_speed + 1) != 0)
+		new_speed++;
+	else
+		return current_speed;
+	if (current_speed != new_speed) {
+		HAL_DEBUG(("current: %u new: %u", g_a_i(iface->speeds_kHz, current_speed),
+			   g_a_i(iface->speeds_kHz, new_speed)));
+		set_speed(iface, new_speed);
+	}
+	return new_speed;
+}
+
+/** increases and decreases speeds */
+static gboolean adjust_speed(struct userspace_interface *iface)
+{
+	GSList		*cpus	 = (GSList*)iface->cpus;
+	GSList		*it	 = NULL;
+	int		ret	 = 0;
+	int		cpu_load = 0;
+
+	for (it = cpus; it != NULL; it = g_slist_next(it)) {
+		HAL_DEBUG(("checking cpu %d: cpu_core: %d",
+			   GPOINTER_TO_INT(it->data), GPOINTER_TO_INT(it->data)));
+		if (get_cpu_load(GPOINTER_TO_INT(it->data)) > cpu_load)
+			 cpu_load = get_cpu_load(GPOINTER_TO_INT(it->data));
+	}
+
+	HAL_DEBUG(("cpu_max: %d cpu_high_limit: %d consider_nice: %d",
+		   config.up_threshold, config.cpu_high_limit,
+		   config.consider_nice));
+	HAL_DEBUG(("Current: %u; current speed: %u MHz", 
+		   iface->current_speed, g_a_i(iface->speeds_kHz, iface->current_speed)));
+	HAL_DEBUG(("CPU load: %d, Previous CPU load %d, cpu_load diff: %d, last_step: %d, demotion: %u",
+		   cpu_load, iface->prev_cpu_load, cpu_load - iface->prev_cpu_load, iface->last_step,
+		   g_a_i(iface->demotion, iface->current_speed)));
+
+	/* directly increase speed to maximum if cpu load jumped */
+	if (config.cpu_high_limit &&
+	    (cpu_load - iface->prev_cpu_load) > config.cpu_high_limit) {
+		if (iface->current_speed != 0) {
+			set_speed(iface, 0);
+			iface->current_speed = 0;
+			HAL_DEBUG(("jumped to max (%d kHz)", 
+				   g_a_i(iface->speeds_kHz, iface->current_speed)));
+			ret = 1;
+		}
+	} else if (cpu_load > config.up_threshold && iface->current_speed > 0) {
+		iface->current_speed = increase_speed(iface);
+		HAL_DEBUG(("increased to %d kHz", g_a_i(iface->speeds_kHz, iface->current_speed)));
+		ret = 1;
+	} else if (cpu_load < (int)g_a_i(iface->demotion, iface->current_speed) &&
+		   iface->current_speed < iface->last_step) {
+		iface->current_speed = decrease_speed(iface);
+		HAL_DEBUG(("decreased to %d kHz", g_a_i(iface->speeds_kHz, iface->current_speed)));
+		ret = -1;
+	} else {
+		ret = 0;
+		HAL_DEBUG(("Speed not changed"));
+	}
+
+	iface->prev_cpu_load = cpu_load;
+	return TRUE;
+}
+
+/** @brief create the hysteresis array */
+static void create_hysteresis_array(struct userspace_interface *iface)
+{
+	g_array_free(iface->demotion, TRUE);
+	iface->demotion = g_array_new(TRUE, TRUE, sizeof(unsigned));
+
+	int i;
+	if (iface->last_step > 0) {
+		for (i = 0; i < iface->last_step; i++) {
+			int demotion = (config.up_threshold - HYSTERESIS) *
+				g_a_i(iface->speeds_kHz, i + 1) / 
+				g_a_i(iface->speeds_kHz, i);
+			g_array_append_val(iface->demotion, demotion);
+			HAL_DEBUG(("Speed: %2u, kHz: %9u, demotion: %3u %%", i,
+				   g_a_i(iface->speeds_kHz, i), g_a_i(iface->demotion, i)));
+		}
+	}
+}
+
+static gboolean read_frequencies(struct userspace_interface *iface)
+{
+	int	num_speeds			= 0;
+	GSList	*it				= NULL;
+	GSList	*available_freqs		= NULL;
+	char	*available_frequencies_file	= NULL;
+	
+	if (!cpu_online(iface->base_cpu))
+		return FALSE;
+
+	available_frequencies_file = g_strdup_printf(SYSFS_SCALING_AVAILABLE_FREQS_FILE,
+						     iface->base_cpu); 
+	if (!read_line_int_split(available_frequencies_file, " ", &available_freqs)) {
+		g_free(available_frequencies_file);
+		return FALSE;
+	}
+	g_free(available_frequencies_file);
+	
+	if (available_freqs == NULL) {
+		iface->last_step = 0;
+		return FALSE;
+	}
+	
+	for (num_speeds = 0, it = available_freqs; it != NULL;
+	     num_speeds++, it = g_slist_next(it)) {
+
+		unsigned index = GPOINTER_TO_UINT(it->data);
+		g_array_append_val(iface->speeds_kHz, index);
+	}
+	g_slist_free(available_freqs);
+	
+	iface->last_step = num_speeds - 1;
+	HAL_DEBUG(("Number of speeds: %d, last_step: %d", num_speeds, iface->last_step));
+	
+	reinit_speed(iface, 0);
+	
+	HAL_DEBUG(("Available speeds:"));
+	for (num_speeds = 0; g_a_i(iface->speeds_kHz, num_speeds); num_speeds++) {
+		HAL_DEBUG((" %2u: %9uKHz", num_speeds, g_a_i(iface->speeds_kHz, num_speeds)));
+	}
+
+	return TRUE;
+}
+
+/** calculates current cpu load and traverses all existing interfaces */
+gboolean userspace_adjust_speeds(GSList *cpufreq_objs)
+{
+	GSList *it = NULL;
+
+	HAL_DEBUG(("Adjusting speeds..."));
+
+	if ((calc_cpu_load(DEFAULT_CONSIDER_NICE) < 0)) {
+		HAL_DEBUG(("calc_cpu_load failed. Cannot adjust speeds"));
+		return TRUE;
+	}
+
+	for (it = cpufreq_objs; it != NULL; it = g_slist_next(it)) {
+		struct cpufreq_obj *obj = it->data;
+		adjust_speed(obj->iface);
+	}
+
+	return TRUE;
+}
+
+/** inits one userspace interface with the given cores list. iface has to
+ * be allocated before passing it to that fucntion */
+gboolean userspace_init(struct userspace_interface *iface, GSList *cpus)
+{
+	if (iface == NULL)
+		return FALSE;
+
+	iface->demotion		= g_array_new(TRUE, TRUE, sizeof(unsigned));
+	iface->speeds_kHz	= g_array_new(TRUE, TRUE, sizeof(unsigned));
+	iface->last_step	= -1;
+	iface->current_speed	= 0;
+	iface->cpus		= cpus;
+	iface->prev_cpu_load	= 50;
+	iface->base_cpu		= GPOINTER_TO_INT(cpus->data);
+	
+	if (!write_governor(USERSPACE_STRING, GPOINTER_TO_INT(cpus->data))) {
+		HAL_WARNING(("Could not set userspace governor."));
+		return FALSE;
+	}
+
+	if (!read_frequencies(iface)) {
+		HAL_WARNING(("Could not read available frequencies"));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/** frees the userspace data */
+void userspace_free(void *data)
+{
+	struct userspace_interface *iface = data;
+	free_cpu_load_data();
+	g_array_free(iface->speeds_kHz, TRUE);
+	g_array_free(iface->demotion, TRUE);
+}
+
+/** sets the performance of the userspace governor. num has to be between
+ * 1 and 100 */
+gboolean userspace_set_performance(void *data, int up_threshold)
+{
+	struct userspace_interface *iface = data;
+
+	config.up_threshold = up_threshold;
+
+	config.cpu_high_limit = (int)(up_threshold * THRESHOLD_JUMP_LIMIT_RELATION);
+	if (config.cpu_high_limit < JUMP_CPUFREQ_LIMIT_MIN)
+		config.cpu_high_limit = JUMP_CPUFREQ_LIMIT_MIN;
+
+	HAL_DEBUG(("cpu_max set to %d, cpu_high_limit set to %d",
+		   config.up_threshold, config.cpu_high_limit));
+
+	create_hysteresis_array(iface);
+
+	return TRUE;
+}
+
+/** return the current performance setting */
+int userspace_get_performance(void)
+{
+	return config.up_threshold;
+}
+
+/** sets whether niced processes should be considered when calculating CPU
+ * load */
+gboolean userspace_set_consider_nice(void *data, gboolean consider)
+{
+	HAL_DEBUG(("consider nice set to %d for userspace", consider));
+	config.consider_nice = consider;
+	return TRUE;
+}
+
+/** return the current consider nice setting */
+gboolean userspace_get_consider_nice(void)
+{
+	return config.consider_nice;
+}
+/********************* userspace end *********************/
diff --git a/hald/linux/addons/addon-cpufreq-userspace.h b/hald/linux/addons/addon-cpufreq-userspace.h
new file mode 100644
index 0000000..4424de2
--- /dev/null
+++ b/hald/linux/addons/addon-cpufreq-userspace.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *                                                                         *
+ *                      addon-cpufreq-userspace.h                          *
+ *                                                                         *
+ *              Copyright (C) 2006 SUSE Linux Products GmbH                *
+ *                                                                         *
+ *               Author(s): Holger Macht <hmacht at suse.de>                  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU General Public License as published by the   *
+ * Free Software Foundation; either version 2 of the License, or (at you   *
+ * option) any later version.                                              *
+ *                                                                         *
+ * 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., *
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA                  *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef ADDON_CPUFREQ_USERSPACE_H
+#define ADDON_CPUFREQ_USERSPACE_H
+
+#define USERSPACE_STRING	"userspace"
+#define USERSPACE_POLL_INTERVAL	333
+
+struct userspace_interface {
+	int	base_cpu;
+	int	last_step;
+	int	current_speed;
+	int	g_source_id;
+	int	prev_cpu_load;
+	GSList	*cpus;
+	GArray	*speeds_kHz;
+	GArray	*demotion;
+};
+
+gboolean	userspace_adjust_speeds		(GSList *cpufreq_objs);
+
+gboolean	userspace_init			(struct userspace_interface *iface,
+						 GSList *cpus);
+
+gboolean	userspace_set_performance	(void *data,
+						 int performance);
+
+int		userspace_get_performance	(void);
+
+gboolean	userspace_set_consider_nice	(void *data,
+						 gboolean consider);
+
+gboolean	userspace_get_consider_nice	(void);
+
+void		userspace_free			(void *data);
+
+void		free_cpu_load_data		(void);
+
+#endif /* ADDON_CPUFREQ_USERSPACE_H */
diff --git a/hald/linux/addons/addon-cpufreq.c b/hald/linux/addons/addon-cpufreq.c
new file mode 100644
index 0000000..a74fecb
--- /dev/null
+++ b/hald/linux/addons/addon-cpufreq.c
@@ -0,0 +1,1214 @@
+/***************************************************************************
+ *                                                                         *
+ *                            addon-cpufreq.c                              *
+ *                                                                         *
+ *              Copyright (C) 2006 SUSE Linux Products GmbH                *
+ *                                                                         *
+ *               Author(s): Holger Macht <hmacht at suse.de>                  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU General Public License as published by the   *
+ * Free Software Foundation; either version 2 of the License, or (at you   *
+ * option) any later version.                                              *
+ *                                                                         *
+ * 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., *
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA                  *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <getopt.h>
+#include <glib/gprintf.h>
+
+#include "addon-cpufreq.h"
+#include "addon-cpufreq-userspace.h"
+#include "libhal/libhal.h"
+#include "../../logger.h"
+
+#ifdef HAVE_POLKIT
+#include <libpolkit/libpolkit.h>
+#endif
+
+#define MAX_LINE_SIZE				255
+#define CPUFREQ_POLKIT_PRIVILEGE		"hal-power-cpufreq"
+#define DBUS_INTERFACE				"org.freedesktop.Hal.Device.CPUFreq"
+
+#define CPUFREQ_ERROR_GENERAL			"GeneralError"
+#define CPUFREQ_ERROR_UNKNOWN_METHOD		"UnknownMethod"
+#define CPUFREQ_ERROR_UNKNOWN_GOVERNOR		"UnknownGovernor"
+#define CPUFREQ_ERROR_INVALID_MESSAGE		"InvalidMessage"
+#define CPUFREQ_ERROR_PERMISSION_DENIED		"PermissionDenied"
+#define CPUFREQ_ERROR_NO_SUITABLE_GOVERNOR	"NoSuitableGovernor"
+#define CPUFREQ_ERROR_GOVERNOR_INIT_FAILED	"GovernorInitFailed"
+
+const char SYSFS_GOVERNOR_FILE[] =
+     "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_governor";
+
+const char SYSFS_AVAILABLE_GOVERNORS_FILE[] =
+     "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_available_governors";
+
+const char ONDEMAND_UP_THRESHOLD_FILE[] =
+     "/sys/devices/system/cpu/cpu%u/cpufreq/ondemand/up_threshold";
+
+const char SYSFS_AFFECTED_CPUS_FILE[] =
+     "/sys/devices/system/cpu/cpu%u/cpufreq/affected_cpus";
+
+const char SYSFS_CPU_ONLINE_FILE[] =
+     "/sys/devices/system/cpu/cpu%u/online";
+
+const char ONDEMAND_IGNORE_NICE_LOAD_FILE[] =
+     "/sys/devices/system/cpu/cpu%u/cpufreq/ondemand/ignore_nice_load";
+
+static gboolean dbus_raise_error(DBusConnection *connection, DBusMessage *message,
+				 const char *error_name, char *format, ...);
+
+static gboolean dbus_raise_no_suitable_governor(DBusConnection *connection,
+						DBusMessage *message,
+						char *method);
+
+static gboolean dbus_raise_governor_init_failed(DBusConnection *connection,
+						DBusMessage *message,
+						char *governor);
+
+/** list holding all cpufreq objects (userspace, ondemand, etc.) */
+static GSList *cpufreq_objs = NULL;
+
+/******************** helper functions **********************/
+
+/** reads one integer from filename and stores it in val */
+static gboolean read_line_int(const char *filename, int *val)
+{
+	char line[MAX_LINE_SIZE + 1];
+
+	if (!read_line(filename, line, MAX_LINE_SIZE)) {
+		HAL_WARNING(("Could not read from %s", filename));
+		return FALSE;
+	}
+
+	/* strip trailing '\n' */
+	line[strlen(line) - 1] = '\0';
+	*val = atoi(line);
+
+	return TRUE;
+}
+
+/** reads one line from filename with the given length */
+gboolean read_line(const char *filename, char *line, unsigned len)
+{
+	FILE *fp = fopen(filename, "r");
+	if (!fp) {
+		HAL_WARNING(("Could not open '%s': %s", filename, strerror(errno)));
+		return FALSE;
+	}
+	if ((!fgets(line, len, fp))) {
+		HAL_WARNING(("Could not read from '%s': %s", filename, strerror(errno)));
+		fclose(fp);
+		return FALSE;
+	}
+	fclose(fp);
+	return TRUE;
+}
+
+/** writes one line with the given format to filename */
+gboolean write_line(const char *filename, const char *fmt, ...)
+{
+	va_list	ap;
+	FILE	*fp;
+
+	fp = fopen(filename, "w+");
+	if (!fp) {
+		HAL_WARNING(("Could not open file for writing: %s; %s", filename,
+			     strerror(errno)));
+		return FALSE;
+	}
+
+	va_start(ap, fmt);
+
+	if (vfprintf(fp, fmt, ap) < 0) {
+		HAL_WARNING(("Could not write to file: %s", filename));
+		fclose(fp);
+		return FALSE;
+	}
+
+	va_end(ap);
+	fclose(fp);
+	return TRUE;
+}
+
+/** reads one line from filename, splits it by delim and returns a two
+ * dimension array of strings or NULL on error */
+static gchar **read_line_str_split(char *filename, gchar *delim)
+{
+	gchar	line[MAX_LINE_SIZE];
+	int	i;
+	gchar	**l;
+
+        if(!read_line(filename, line, MAX_LINE_SIZE)) { 
+		printf("returning NULL from str split\n");
+		return NULL;
+	}
+
+	/* strip trailing '\n' */
+	line[strlen(line)-1] = '\0';
+
+	l = g_strsplit(line, delim, MAX_LINE_SIZE);
+
+	if (l[0] == NULL)
+		return NULL;
+
+	for (i = 0; l[i] != NULL; i++) {
+		if (g_strcasecmp(l[i], "") == 0) {
+			free(l[i]);
+			l[i] = NULL;
+		}
+	} 
+	return l;
+}
+
+/** reads one line from filename, splits its integers by delim and stores
+ * all items in the given list */
+gboolean read_line_int_split(char *filename, gchar *delim, GSList **list)
+{
+	gchar	**l;
+	int	i;
+
+	l = read_line_str_split(filename, delim);
+
+	for (i = 0; l[i] != NULL; i++) {
+		int value = atoi(l[i]);
+		*list = g_slist_append(*list, GINT_TO_POINTER(value));
+	} 
+	g_strfreev(l);
+	return TRUE;
+}
+
+/** gets a two dimensional list of integers and sorts out duplicates */
+static void cpu_list_unique(gpointer data, gpointer whole_list)
+{
+	GSList	**list		= (GSList**)whole_list;
+	GSList	*current	= (GSList*)data;
+	GSList	*it		= NULL;
+
+	for (it = *list; it != NULL; it = g_slist_next(it)) {
+		gboolean equal = TRUE;
+		if (current == it->data)
+			continue;
+
+		GSList *list_it = NULL;
+		GSList *current_it = NULL;
+		for (list_it = it->data, current_it = current;
+		     list_it != NULL && current_it != NULL;
+		     list_it = g_slist_next(list_it), current_it = g_slist_next(current_it)) {
+
+			HAL_DEBUG(("comparing %d with %d", GPOINTER_TO_INT(current_it->data),
+				   GPOINTER_TO_INT(list_it->data)));
+			if (GPOINTER_TO_INT(current_it->data) != GPOINTER_TO_INT(list_it->data))
+				equal = FALSE;
+		}
+
+		HAL_DEBUG(("equal? %s, %d", equal ? "yes" : "no", equal));
+		if (equal) {
+			HAL_DEBUG(("remove: %d", g_slist_length(*list)));
+			*list = g_slist_remove(*list, current);
+			HAL_DEBUG(("remove_2: %d", g_slist_length(*list)));
+			return;
+		}
+	}
+}
+
+/** @brief gets the CPUs and their dependencies */
+static gboolean get_cpu_dependencies(GSList **cpu_list, int num_cpus)
+{
+	int i;
+
+	for (i = 0; i < num_cpus; i++) {
+		GSList	*int_cpus		= NULL;
+		GSList	*affected_cpus		= NULL;
+		GSList	*it			= NULL;
+		char	*affected_cpus_file	= NULL;
+
+		affected_cpus_file = g_strdup_printf(SYSFS_AFFECTED_CPUS_FILE, i); 
+
+		if (!read_line_int_split(affected_cpus_file, " ", &affected_cpus)) {
+			g_free(affected_cpus_file);
+			return FALSE;
+		}
+		g_free(affected_cpus_file);
+
+		if (affected_cpus == NULL)
+			return FALSE;
+
+		for (it = affected_cpus; it != NULL; it = g_slist_next(it)) {
+			int_cpus = g_slist_append(int_cpus,
+						  GINT_TO_POINTER(affected_cpus->data));
+		}
+		g_slist_free(affected_cpus);
+
+		if (!g_slist_length(int_cpus)) {
+			HAL_WARNING(("failed to get affected_cpus for cpu %d", i));
+			continue;
+		}
+
+		*cpu_list = g_slist_append(*cpu_list, int_cpus);
+	}
+
+	HAL_DEBUG(("Number of CPUs before uniquing cpu_list: %d", g_slist_length(*cpu_list)));
+	g_slist_foreach(*cpu_list, (GFunc)cpu_list_unique, cpu_list);
+	HAL_DEBUG(("Number of CPUs after uniquing cpu_list: %d", g_slist_length(*cpu_list)));
+
+	if (g_slist_length(*cpu_list) == 0)
+		return FALSE;
+	return TRUE;
+}
+
+/** check if given CPU starting from 0 is online */
+gboolean cpu_online(int cpu_id)
+{
+	gboolean	online;
+	char		online_str[2];
+	char		*online_file;
+
+	online_file = g_strdup_printf(SYSFS_CPU_ONLINE_FILE, cpu_id); 
+
+	if (access(online_file, F_OK) < 0) {
+		online = TRUE;
+		goto Out;
+	}
+
+	if (!read_line(online_file, online_str, 2)) {
+		HAL_WARNING(("Unable to open file: %s", online_file));
+		online = FALSE;
+		goto Out;
+	}
+	
+	online = atoi(online_str);
+
+	if (!online)
+		online = FALSE;
+Out:
+	g_free(online_file);
+	return online;
+}
+
+/** writes the new_governor string into the sysfs interface */ 
+gboolean write_governor(char *new_governor, int cpu_id)
+{
+	gboolean	ret		= TRUE;
+	char		*governor_file  = NULL;
+	char		governor[MAX_LINE_SIZE + 1];
+
+	if (!cpu_online(cpu_id))
+		goto Out;
+
+	governor_file = g_strdup_printf(SYSFS_GOVERNOR_FILE, cpu_id); 
+	HAL_DEBUG(("Trying ot write governor %s", new_governor));
+
+	if (!write_line(governor_file, "%s", new_governor)) {
+		ret = FALSE;
+		goto Out;
+	}
+	
+	/* check if governor has been set */
+	read_line(governor_file, governor, MAX_LINE_SIZE);
+	if (strstr(governor, new_governor))
+		ret = TRUE;
+	else
+		ret = FALSE;
+Out:
+	g_free(governor_file);
+	return ret;
+}
+/******************** helper functions end ********************/
+
+/********************* ondemand interface *********************/
+#define ONDEMAND_STRING "ondemand"
+
+struct ondemand_interface {
+	int base_cpu;
+};
+
+static gboolean ondemand_set_performance(void *data, int performance)
+{
+	struct ondemand_interface	*iface		   = data;
+	char				*up_threshold_file = NULL;
+
+	up_threshold_file = g_strdup_printf(ONDEMAND_UP_THRESHOLD_FILE,
+					    iface->base_cpu);
+
+        if(!write_line(up_threshold_file, "%u", performance)){
+                HAL_WARNING(("Could not set up_threshold to %u kHz; %s", performance,
+			     strerror(errno)));
+		g_free(up_threshold_file);
+		return FALSE;
+        }
+	g_free(up_threshold_file);
+	HAL_DEBUG(("Up threshold set to %d for ondemand", performance));
+
+	return TRUE;
+}
+
+static int ondemand_get_performance(void)
+{
+	char	*governor_file;
+	int	performance	= -1;
+
+	governor_file = g_strdup_printf(ONDEMAND_UP_THRESHOLD_FILE, 0); 
+
+	if (!read_line_int(governor_file, &performance)) {
+		HAL_WARNING(("Could not read up_threshold"));
+		g_free(governor_file);
+		return -1;
+	}
+	g_free(governor_file);
+
+	return performance;
+}
+
+static gboolean ondemand_set_consider_nice(void *data, gboolean consider)
+{
+	struct ondemand_interface	*iface		= data;
+	char				*consider_file;
+
+	consider_file = g_strdup_printf(ONDEMAND_IGNORE_NICE_LOAD_FILE, iface->base_cpu); 
+
+        if(!write_line(consider_file, "%u", consider)){
+                HAL_WARNING(("Could not set ignore_nice_load to: %u kHz; %s", consider,
+			     strerror(errno)));
+		g_free(consider_file);
+                return FALSE;
+        }
+	g_free(consider_file);
+	HAL_DEBUG(("Set consider nice to %d for ondemand", consider));
+
+	return TRUE;
+}
+
+static gboolean ondemand_get_consider_nice(void)
+{
+	char		*governor_file;
+	gboolean	consider	= -1;
+
+	/* only read the setting of cpu0 */
+	governor_file = g_strdup_printf(ONDEMAND_IGNORE_NICE_LOAD_FILE, 0); 
+
+	if (!read_line_int(governor_file, &consider)) {
+		HAL_WARNING(("Could not read ignore_nice_load file"));
+		g_free(governor_file);
+		return -1;
+	}
+	g_free(governor_file);
+
+	return consider;
+}
+
+static gboolean ondemand_init(struct ondemand_interface *iface, GSList *cores)
+{
+	if (iface == NULL)
+		return FALSE;
+
+	if (!write_governor(ONDEMAND_STRING, GPOINTER_TO_INT(cores->data))) {
+		HAL_WARNING(("Could not set ondemand governor."));
+		return FALSE;
+	}
+
+	iface->base_cpu = GPOINTER_TO_INT(cores->data);
+
+	return TRUE;
+}
+
+static void ondemand_free(void *data)
+{
+	return;
+}
+
+/********************* ondemand end *********************/
+
+/********************* main interface *********************/
+
+/** sets the performance for all cpufreq objects
+ *
+ * @raises NoSuitableGoveror
+ */
+static gboolean set_performance(DBusConnection *connection, DBusMessage *message,
+				int performance)
+{
+	float	steps;
+	float	up_threshold;
+	GSList	*it		= NULL;
+
+	if (cpufreq_objs == NULL) {
+		dbus_raise_no_suitable_governor(connection, message,
+						"CPUFreqSetPerformance");
+		return FALSE;
+	}
+
+	if (performance < 1)
+		performance = 1;
+	if (performance > 100)
+		performance = 100;
+
+	if (performance >= 50) {
+		steps = UP_THRESHOLD_BASE - UP_THRESHOLD_MIN + 1;
+		up_threshold = (UP_THRESHOLD_BASE) - (((float)performance - 50.0) *
+						      (steps / 51.0)); 
+		performance = (int)up_threshold;
+	} else if (performance < 50) {
+		steps = UP_THRESHOLD_MAX - UP_THRESHOLD_BASE;
+		up_threshold = (UP_THRESHOLD_MAX + 1) - ((float)performance *
+							 (steps / 49.0)); 
+		performance = (int)up_threshold;
+	}
+
+	for (it = cpufreq_objs; it != NULL; it = g_slist_next(it)) {
+		struct cpufreq_obj *obj = it->data; 
+		obj->set_performance(obj->iface, performance);
+	}
+	return TRUE;
+}
+
+/** sets the performance for all cpufreq objects
+ *
+ * @raises (NoSuitableGoveror|GeneralError)
+ */
+static gboolean get_performance(DBusConnection *connection, DBusMessage *message,
+				int *performance)
+{
+	struct cpufreq_obj *obj;
+	float		   steps;
+	float		   perf;
+	int		   up_threshold;
+
+	if (cpufreq_objs == NULL) {
+		dbus_raise_no_suitable_governor(connection, message,
+						"CPUFreqGetPerformance");
+		return FALSE;
+	}
+
+	obj = cpufreq_objs->data;
+
+	up_threshold = obj->get_performance();
+	if (up_threshold < 0) {
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_GENERAL,
+				 "Could not read up_threshold");
+		return FALSE;
+	}
+
+	if (up_threshold < UP_THRESHOLD_BASE) {
+		steps = UP_THRESHOLD_BASE - UP_THRESHOLD_MIN + 1;
+		perf = (((UP_THRESHOLD_BASE) - up_threshold) /
+			       (steps / 51.0)) + 50.0;
+	} else if (up_threshold >= UP_THRESHOLD_BASE) {
+		steps = UP_THRESHOLD_MAX - UP_THRESHOLD_BASE;
+		perf = ((UP_THRESHOLD_MAX + 1) - up_threshold) /
+			(steps / 49.0);
+	}
+
+	*performance = (int)perf;
+
+	return TRUE;
+}
+
+/** sets the performance for all cpufreq objects
+ *
+ * @raises NoSuitableGoveror
+ */
+static gboolean set_consider_nice(DBusConnection *connection, DBusMessage *message,
+				  gboolean consider)
+{
+	GSList *it = NULL;
+
+	if (cpufreq_objs == NULL) {
+		dbus_raise_no_suitable_governor(connection, message,
+						"CPUFreqSetConsiderNice");
+		return FALSE;
+	}
+
+	for (it = cpufreq_objs; it != NULL; it = g_slist_next(it)) {
+		struct cpufreq_obj *obj= it->data; 
+		obj->set_consider_nice(obj->iface, consider);
+	}
+	return TRUE;
+}
+
+/** sets the performance for all cpufreq objects
+ *
+ * @raises NoSuitableGoveror
+ */
+static gboolean get_consider_nice(DBusConnection *connection, DBusMessage *message,
+				  int *consider)
+{
+	struct cpufreq_obj *obj;
+
+	if (cpufreq_objs == NULL) {
+		dbus_raise_no_suitable_governor(connection, message,
+						"CPUFreqGetConsiderNice");
+		return FALSE;
+	}
+	obj = cpufreq_objs->data;
+
+	*consider = obj->get_consider_nice();
+
+	return TRUE;
+}
+
+/** stores a list of all available governors in the given list.
+ *
+ * @raises GeneralError
+ */
+static gboolean get_available_governors(DBusConnection *connection, DBusMessage *message,
+					gchar ***governors)
+{
+	char *agovs_file;
+
+	agovs_file = g_strdup_printf(SYSFS_AVAILABLE_GOVERNORS_FILE, 0); 
+	*governors = read_line_str_split(agovs_file, " ");
+	g_free(agovs_file);
+
+	if (*governors == NULL) {
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_GENERAL,
+				 "No CPUFreq governors");
+		return FALSE;
+	}		
+
+	return TRUE;
+}
+
+/** sets a governor for all cpufreq objects
+ *
+ * @raises (GeneralError|UnknownGovernor|GovernorInitFailed)
+ */
+static gboolean set_governors(DBusConnection *connection, DBusMessage *message,
+				       const char *governor)
+{
+	GSList		*cpus			= NULL;
+	GSList		*it			= NULL;
+	static int	g_source_id		= -1;
+	gboolean	have_governor		= FALSE;
+	int		i;
+	int		num_cpus;
+	gchar		**available_governors;
+
+	if (!get_available_governors(connection, message, &available_governors))
+		return FALSE;
+
+	for (i = 0; available_governors[i] != NULL; i++) {
+		if (strcmp(available_governors[i], governor) == 0) {
+			have_governor = TRUE;
+			break;
+		}		
+	}
+	g_strfreev(available_governors);
+
+	if (!have_governor) {
+		dbus_raise_error(connection, message,
+				 CPUFREQ_ERROR_UNKNOWN_GOVERNOR,
+				 "No governor '%s' available", governor);
+		return FALSE;
+	}
+
+	/** clear all previous cpufreq_objs */
+	if (g_slist_length(cpufreq_objs) > 0) {
+		GSList *it = NULL;
+ 		for (it = cpufreq_objs; it != NULL; it = g_slist_next(it)) {
+			struct cpufreq_obj *obj = it->data; 
+			obj->free(obj->iface);
+			free(obj->iface);
+			free(obj);
+		}
+		g_slist_free(cpufreq_objs);
+		cpufreq_objs = NULL;
+		g_source_remove(g_source_id);
+		g_source_id = -1;
+	}
+
+	num_cpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (num_cpus < 0) {
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_GENERAL,
+				 "No CPUs found in system");
+		HAL_WARNING(("No CPUs found in system"));
+		return FALSE;
+	}
+
+	if (!get_cpu_dependencies(&cpus, num_cpus)) {
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_GENERAL,
+				 "Could not figure out cpu core dependencies");
+		HAL_WARNING(("Could not figure out cpu core dependencies"));
+		return FALSE;
+	}
+	
+	if (!strcmp(governor, USERSPACE_STRING)) {
+		struct cpufreq_obj *cpufreq_obj;
+		struct userspace_interface *iface;
+
+		for (it = cpus; it != NULL; it = g_slist_next(it)) {
+			cpufreq_obj = malloc(sizeof(struct cpufreq_obj));
+			iface = malloc(sizeof(struct userspace_interface));
+
+			if (userspace_init(iface, it->data)) {
+				cpufreq_obj->iface = iface;
+				cpufreq_obj->set_performance   = userspace_set_performance;
+				cpufreq_obj->get_performance   = userspace_get_performance;
+				cpufreq_obj->set_consider_nice = userspace_set_consider_nice;
+				cpufreq_obj->get_consider_nice = userspace_get_consider_nice;
+				cpufreq_obj->free = userspace_free;
+				cpufreq_objs = g_slist_append(cpufreq_objs, cpufreq_obj);
+				HAL_DEBUG(("added userspace interface"));
+			} else {
+				dbus_raise_governor_init_failed(connection, message,
+								(char*)governor);
+				return FALSE;
+			}
+		}
+		g_source_id = g_timeout_add(USERSPACE_POLL_INTERVAL,
+					    (GSourceFunc)userspace_adjust_speeds,
+					    cpufreq_objs);
+
+	} else if (!strcmp(governor, ONDEMAND_STRING)) {
+		struct cpufreq_obj *cpufreq_obj;
+		struct ondemand_interface *iface;
+
+		for (it = cpus; it != NULL; it = g_slist_next(it)) {
+			cpufreq_obj = malloc(sizeof(struct cpufreq_obj));
+			iface = malloc(sizeof(struct ondemand_interface));
+
+			if (ondemand_init(iface, it->data)) {
+				cpufreq_obj->iface = iface;
+				cpufreq_obj->set_performance   = ondemand_set_performance;
+				cpufreq_obj->get_performance   = ondemand_get_performance;
+				cpufreq_obj->set_consider_nice = ondemand_set_consider_nice;
+				cpufreq_obj->get_consider_nice = ondemand_get_consider_nice;
+				cpufreq_obj->free = ondemand_free;
+				cpufreq_objs = g_slist_append(cpufreq_objs, cpufreq_obj);
+				HAL_DEBUG(("added ondemand interface"));
+			} else {
+				dbus_raise_governor_init_failed(connection, message,
+								(char*)governor);
+				return FALSE;
+			}
+		}
+	} else {
+		for (it = cpus; it != NULL; it = g_slist_next(it)) {
+			if (!write_governor((char*)governor,
+					    GPOINTER_TO_INT(((GSList*)it->data)->data))) {
+				dbus_raise_governor_init_failed(connection, message,
+								(char*)governor);
+				HAL_WARNING(("Could not set %s governor.", governor));
+				return FALSE;
+			}
+		}
+	}
+	
+	set_performance(NULL, NULL, DEFAULT_PERFORMANCE);
+
+	return TRUE;
+}
+
+/** gets the current governor which is set for all cpufreq objects
+ *
+ * @raises GeneralError
+ */
+static gboolean get_governors(DBusConnection *connection, DBusMessage *message,
+			   char *governor)
+{
+	char	*governor_file;
+	int	cpu_id		= 0;
+
+	governor_file = g_strdup_printf(SYSFS_GOVERNOR_FILE, cpu_id); 
+
+	if (!read_line(governor_file, governor, MAX_LINE_SIZE)) {
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_GENERAL,
+				 "Could not read current governor");
+		g_free(governor_file);
+		return FALSE;
+	}
+	g_free(governor_file);
+
+	/* strip trailing '\n' */
+	governor[strlen(governor)-1] = '\0';
+
+	return TRUE;
+}
+/********************* main interface end *********************/
+
+/********************* DBus stuff *********************/
+
+/** raises the NoSuitableGovernor error with the given method in the
+ * detail field */
+static gboolean dbus_raise_no_suitable_governor(DBusConnection *connection,
+						DBusMessage *message,
+						char *method)
+{
+	return dbus_raise_error(connection, message,
+				CPUFREQ_ERROR_NO_SUITABLE_GOVERNOR,
+				"No '%s' setting for current governor",
+				method);
+}
+
+/** raises the GovernorInitFailed error with the given governor in the
+ * detail field */
+static gboolean dbus_raise_governor_init_failed(DBusConnection *connection,
+						DBusMessage *message,
+						char *governor)
+{
+	return dbus_raise_error(connection, message,
+				CPUFREQ_ERROR_GOVERNOR_INIT_FAILED,
+				"Initialization of %s interface failed",
+				governor);
+}
+
+/** raises the given error_name with the format in the detail field */
+static gboolean dbus_raise_error(DBusConnection *connection, DBusMessage *message,
+				 const char *error_name, char *format, ...)
+{
+	char		buf[2 * MAX_LINE_SIZE];
+	DBusMessage	*reply;
+	va_list		args;
+	char		*error = NULL;
+
+	if (connection == NULL || message == NULL)
+		return FALSE;
+
+	va_start(args, format);
+	vsnprintf(buf, sizeof buf, format, args);
+	va_end(args);
+
+	error = g_strdup_printf("%s.%s", DBUS_INTERFACE, error_name);
+	reply = dbus_message_new_error(message, error, buf);
+	g_free(error);
+	if (reply == NULL) {
+		HAL_WARNING(("No memory"));
+		return FALSE;
+	}
+
+	if (!dbus_connection_send(connection, reply, NULL)) {
+		HAL_WARNING(("No memory"));
+		dbus_message_unref(reply);
+		return FALSE;
+	}
+	dbus_message_unref(reply);
+
+	return TRUE;
+}
+
+#ifdef HAVE_POLKIT
+/** checks if caller of message possesses the CPUFREQ_POLKIT_PRIVILGE */
+static gboolean dbus_is_privileged(DBusConnection *connection, DBusMessage *message,
+				   DBusError *error)
+{
+	LibPolKitContext	*polctx			= NULL;
+	char			*caller_unix_user_str;
+	const char		*caller_dbus_name;
+	unsigned long		caller_unix_user;
+	DBusConnection		*connection_new;
+	gboolean		out_is_allowed;
+	gboolean		out_is_temporary;
+	LibPolKitResult		res;
+    
+	connection_new = dbus_bus_get(DBUS_BUS_SYSTEM, error);
+	if (dbus_error_is_set(error)) {
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_GENERAL,
+				 "Cannot get connection to system bus");
+		return FALSE;
+	}
+
+	polctx = libpolkit_new_context(connection_new);
+	if (polctx == NULL) {
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_GENERAL,
+				 "Cannot get PolicyKit context");
+		return FALSE;
+	}
+
+	caller_dbus_name = dbus_message_get_sender(message);
+	caller_unix_user = dbus_bus_get_unix_user(connection_new, caller_dbus_name, error);
+	HAL_DEBUG(("Connection name of caller: %s", caller_dbus_name));
+	HAL_DEBUG(("Unix user id of caller: %ld", caller_unix_user));
+	if (dbus_error_is_set(error)) {
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_GENERAL,
+				 "Cannot get unix user of caller");
+		dbus_error_free(error);
+		goto Error;
+	}
+
+	caller_unix_user_str = g_strdup_printf("%ld", caller_unix_user);
+	res = libpolkit_is_uid_allowed_for_privilege(polctx,
+						     caller_dbus_name,
+						     caller_unix_user_str,
+						     CPUFREQ_POLKIT_PRIVILEGE,
+						     getenv("UDI"),
+						     &out_is_allowed,
+						     &out_is_temporary,
+						     NULL);
+	g_free(caller_unix_user_str);
+
+	if (res != LIBPOLKIT_RESULT_OK) {
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_GENERAL,
+				 "Cannot lookup privilege: %d", res);
+		goto Error;
+	}
+	
+	if (!out_is_allowed) {
+		HAL_DEBUG(("caller don't possess privilege"));
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_PERMISSION_DENIED,
+				 "%s refused uid %d", CPUFREQ_POLKIT_PRIVILEGE, caller_unix_user);
+		goto Error;
+	}
+
+	HAL_DEBUG(("Caller is privileged"));
+	return out_is_allowed;
+
+Error:
+	libpolkit_free_context(polctx);
+	return FALSE;
+}
+#endif
+
+/** sends a reply to message with the given data and its dbus_type */
+static gboolean dbus_send_reply(DBusConnection *connection, DBusMessage *message,
+				int dbus_type, void *data)
+{
+	DBusMessage *reply;
+
+	if ((reply = dbus_message_new_method_return(message)) == NULL) {
+		HAL_WARNING(("Could not allocate memory for the DBus reply"));
+		return FALSE;
+	}
+
+	if (data != NULL)
+		dbus_message_append_args(reply, dbus_type, data, DBUS_TYPE_INVALID);
+
+	if (!dbus_connection_send(connection, reply, NULL)) {
+		HAL_WARNING(("Could not sent reply"));
+		return FALSE;
+	}
+	dbus_connection_flush(connection);
+	dbus_message_unref(reply);
+	
+	return TRUE;
+}
+
+/** sends a reply to message appending a list of strings */
+static gboolean dbus_send_reply_strlist(DBusConnection *connection, DBusMessage *message,
+					gchar **list)
+{
+	DBusMessage	*reply;
+	DBusMessageIter	iter;
+	DBusMessageIter	iter_array;
+	int		i;
+
+	if ((reply = dbus_message_new_method_return(message)) == NULL) {
+		HAL_WARNING(("Could not allocate memory for the DBus reply"));
+		return FALSE;
+	}
+
+	dbus_message_iter_init_append(reply, &iter);
+	dbus_message_iter_open_container(&iter, 
+					 DBUS_TYPE_ARRAY,
+					 DBUS_TYPE_STRING_AS_STRING,
+					 &iter_array);
+	
+	for (i = 0; list[i] != NULL; i++)
+		dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &list[i]);
+
+	dbus_message_iter_close_container (&iter, &iter_array);
+
+	if (!dbus_connection_send(connection, reply, NULL)) {
+		HAL_WARNING(("Could not sent reply"));
+		return FALSE;
+	}
+
+	dbus_connection_flush(connection);
+	dbus_message_unref(reply);
+
+	return TRUE;
+}
+
+/** gets one argument from message with the given dbus_type and stores it
+ * in arg
+ *
+ * @raises InvalidMessage
+ */
+static gboolean dbus_get_argument(DBusConnection *connection, DBusMessage *message,
+				  DBusError *dbus_error, int dbus_type, void *arg)
+{
+	dbus_message_get_args(message, dbus_error, dbus_type, arg,
+			      DBUS_TYPE_INVALID);
+	if (dbus_error_is_set(dbus_error)) {
+		HAL_WARNING(("Could not get argument of DBus message: %s",
+			     dbus_error->message));
+
+		dbus_raise_error(connection, message, 
+				 CPUFREQ_ERROR_INVALID_MESSAGE,
+				 "%s", dbus_error->message);
+		dbus_error_free(dbus_error);
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/** dbus filter function
+ *
+ * @raises UnknownMethod
+ */
+static DBusHandlerResult dbus_filter_function(DBusConnection *connection,
+					      DBusMessage *message,
+					      void *user_data)
+{
+	DBusError	dbus_error;
+	const char	*member		= dbus_message_get_member(message);
+	const char	*path		= dbus_message_get_path(message);
+
+	HAL_DEBUG(("Received DBus message with member %s", member));
+	HAL_DEBUG(("Received DBus message with path %s", path));
+
+	dbus_error_init(&dbus_error);
+
+#ifdef HAVE_POLKIT
+	if (!dbus_is_privileged(connection, message, &dbus_error))
+		return DBUS_HANDLER_RESULT_HANDLED;
+#endif
+
+	if (dbus_message_is_method_call(message, DBUS_INTERFACE,
+					"SetCPUFreqGovernor")) {
+		char *arg;
+
+		if (!dbus_get_argument(connection, message, &dbus_error,
+				       DBUS_TYPE_STRING, &arg)) {
+			return DBUS_HANDLER_RESULT_HANDLED;
+		}
+ 		HAL_DEBUG(("Received argument: %s", arg));
+			
+		if (set_governors(connection, message, arg))
+			dbus_send_reply(connection, message, DBUS_TYPE_INVALID, NULL);
+
+	} else if (dbus_message_is_method_call(message, DBUS_INTERFACE,
+					       "SetCPUFreqPerformance")) {
+		int arg;
+
+		if (!dbus_get_argument(connection, message, &dbus_error,
+				       DBUS_TYPE_INT32, &arg)) {
+			return DBUS_HANDLER_RESULT_HANDLED;
+		}
+ 		HAL_DEBUG(("Received argument: %d", arg));
+
+		if (set_performance(connection, message, arg))
+			dbus_send_reply(connection, message, DBUS_TYPE_INVALID, NULL);
+
+	} else if (dbus_message_is_method_call(message, DBUS_INTERFACE,
+					       "SetCPUFreqConsiderNice")) {
+		gboolean arg;
+
+		if (!dbus_get_argument(connection, message, &dbus_error,
+				       DBUS_TYPE_BOOLEAN, &arg)) {
+			return DBUS_HANDLER_RESULT_HANDLED;
+		}
+ 		HAL_DEBUG(("Received argument: %d", arg));
+
+		if (set_consider_nice(connection, message, arg))
+			dbus_send_reply(connection, message, DBUS_TYPE_INVALID, NULL);
+
+	} else if (dbus_message_is_method_call(message, DBUS_INTERFACE,
+					       "GetCPUFreqGovernor")) {
+		char governor[MAX_LINE_SIZE + 1];
+		char *gov				= governor;
+
+		if (get_governors(connection, message, governor))
+			dbus_send_reply(connection, message, DBUS_TYPE_STRING, &gov);
+
+	} else if (dbus_message_is_method_call(message, DBUS_INTERFACE,
+					       "GetCPUFreqPerformance")) {
+		int performance	= -1;
+
+		if (get_performance(connection, message, &performance))
+			dbus_send_reply(connection, message, DBUS_TYPE_INT32, &performance);
+
+	} else if (dbus_message_is_method_call(message, DBUS_INTERFACE,
+					       "GetCPUFreqConsiderNice")) {
+		int consider = -1;
+
+		if (get_consider_nice(connection, message, &consider))
+			dbus_send_reply(connection, message, DBUS_TYPE_BOOLEAN, &consider);
+
+	} else if (dbus_message_is_method_call(message, DBUS_INTERFACE,
+					       "GetCPUFreqAvailableGovernors")) {
+		gchar **governors = NULL;
+
+		if (get_available_governors(connection, message, &governors))
+			dbus_send_reply_strlist(connection, message, governors);
+		g_strfreev(governors);
+
+	} else if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
+					  "Disconnected")) {
+		HAL_DEBUG(("DBus daemon disconnected. Trying to reconnect..."));
+		dbus_connection_close(connection);
+		dbus_connection_unref(connection);
+		g_timeout_add(5000, (GSourceFunc)dbus_init, NULL);
+
+	} else
+		dbus_raise_error(connection, message, CPUFREQ_ERROR_UNKNOWN_METHOD,
+				 "No such method '%s'", member);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void dbus_add_method(LibHalContext *halctx, const char *method,
+				const char *signature)
+{
+	libhal_device_property_strlist_append(halctx,
+		      "/org/freedesktop/Hal/devices/computer",
+		      "org.freedesktop.Hal.Device.CPUFreq.method_names",
+		      method,
+		      NULL);
+	libhal_device_property_strlist_append(halctx,
+		      "/org/freedesktop/Hal/devices/computer",
+		      "org.freedesktop.Hal.Device.CPUFreq.method_signatures",
+		      signature,
+		      NULL);
+}
+
+static gboolean is_supported(void)
+{
+	char *governor_file = NULL;
+
+	governor_file = g_strdup_printf(SYSFS_GOVERNOR_FILE, 0); 
+	if (access(governor_file, F_OK) != 0) {
+		g_free(governor_file);
+		return FALSE;
+	}
+	g_free(governor_file);
+	return TRUE;
+}
+
+/** returns FALSE on success because it's used as a callback */
+gboolean dbus_init(void)
+{
+	DBusError	dbus_error;
+	DBusConnection	*dbus_connection;
+	char		*udi		= getenv("UDI");
+	LibHalContext	*halctx		= NULL;
+
+	dbus_error_init(&dbus_error);
+
+	if ((halctx = libhal_ctx_init_direct(&dbus_error)) == NULL) {
+		HAL_WARNING(("Cannot connect to hald"));
+		goto Error;
+	}
+
+	if ((dbus_connection = libhal_ctx_get_dbus_connection(halctx)) == NULL) {
+		HAL_WARNING(("Cannot get DBus connection"));
+		goto Error;
+	}
+
+	if (!libhal_device_claim_interface(halctx, udi,
+		"org.freedesktop.Hal.Device.CPUFreq", 
+		"    <method name=\"SetCPUFreqGovernor\">"
+		"      <arg name=\"governor_string\" direction=\"in\" type=\"s\"/>"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>"
+		"    </method>"
+		"    <method name=\"SetCPUFreqPerformance\">"
+		"      <arg name=\"value\" direction=\"in\" type=\"i\"/>"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>"
+		"    </method>"
+		"    <method name=\"SetCPUFreqConsiderNice\">"
+		"      <arg name=\"value\" direction=\"in\" type=\"b\"/>"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>"
+		"    </method>"
+		"    <method name=\"GetCPUFreqGovernor\">"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"s\"/>"
+		"    </method>"
+		"    <method name=\"GetCPUFreqPerformance\">"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>"
+		"    </method>"
+		"    <method name=\"GetCPUFreqConsiderNice\">"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"b\"/>"
+		"    </method>"
+		"    <method name=\"GetCPUFreqAvailableGovernors\">"
+		"      <arg name=\"return_code\" direction=\"out\" type=\"as\"/>"
+		"    </method>",
+		&dbus_error)) {
+
+		HAL_WARNING(("Cannot claim interface: %s", dbus_error.message));
+		fprintf(stderr, "direct Cannot claim interface: %s", dbus_error.message);
+		goto Error;
+	}
+
+	libhal_device_add_capability(halctx,
+				     "/org/freedesktop/Hal/devices/computer",
+				     "cpufreq_control",
+				     NULL);
+		
+	dbus_add_method(halctx, "SetCPUFreqGovernor", "s");
+	dbus_add_method(halctx, "SetCPUFreqPerformance", "i");
+	dbus_add_method(halctx, "SetCPUFreqConsiderNice", "b");
+	dbus_add_method(halctx, "GetCPUFreqGovernor", "");
+	dbus_add_method(halctx, "GetCPUFreqPerformance", "");
+	dbus_add_method(halctx, "GetCPUFreqConsiderNice", "");
+	dbus_add_method(halctx, "GetCPUFreqAvailableGovernors", "");
+
+
+	dbus_connection_setup_with_g_main(dbus_connection, NULL);
+	dbus_connection_add_filter(dbus_connection, dbus_filter_function, NULL, NULL);
+	dbus_connection_set_exit_on_disconnect(dbus_connection, 0);
+	return FALSE;
+
+Error:
+	dbus_error_free(&dbus_error);
+	return TRUE;
+}
+/********************* DBus end *********************/
+
+static void exit_handler(int i)
+{
+	GSList *it = NULL;
+
+	for (it = cpufreq_objs; it != NULL; it = g_slist_next(it)) {
+		struct cpufreq_obj *obj = it->data; 
+		obj->free(obj->iface);
+		free(obj->iface);
+		free(obj);
+	}
+	g_slist_free(cpufreq_objs);
+
+	HAL_DEBUG(("exit"));
+	exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char *argv[])
+{
+	struct sigaction	signal_action;
+	GMainLoop		*gmain;
+
+	memset(&signal_action, 0, sizeof(signal_action));
+	sigaddset(&signal_action.sa_mask, SIGTERM);
+	signal_action.sa_flags = SA_RESTART || SA_NOCLDSTOP;
+	signal_action.sa_handler = exit_handler;
+	sigaction(SIGINT, &signal_action, 0);
+	sigaction(SIGQUIT, &signal_action, 0);
+	sigaction(SIGTERM, &signal_action, 0);
+
+	if (!is_supported()) {
+		HAL_WARNING(("CPUFreq not supported. Exiting..."));
+		exit(EXIT_FAILURE);
+	}
+
+	if (dbus_init())
+		exit(EXIT_FAILURE);
+
+	gmain = g_main_loop_new(NULL, FALSE);
+	g_main_loop_run(gmain);
+
+	return 0;
+}
diff --git a/hald/linux/addons/addon-cpufreq.h b/hald/linux/addons/addon-cpufreq.h
new file mode 100644
index 0000000..d812219
--- /dev/null
+++ b/hald/linux/addons/addon-cpufreq.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ *                                                                         *
+ *                            addon-cpufreq.h                              *
+ *                                                                         *
+ *              Copyright (C) 2006 SUSE Linux Products GmbH                *
+ *                                                                         *
+ *               Author(s): Holger Macht <hmacht at suse.de>                  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU General Public License as published by the   *
+ * Free Software Foundation; either version 2 of the License, or (at you   *
+ * option) any later version.                                              *
+ *                                                                         *
+ * 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., *
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA                  *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef ADDON_CPUFREQ_H
+#define ADDON_CPUFREQ_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/** UP_THRESHOLD defines at which CPU load (in percent) we switch up */
+#define UP_THRESHOLD_MAX		99
+#define UP_THRESHOLD_MIN		11
+/** this is the kernel default up_threshold */
+#define UP_THRESHOLD_BASE		80
+#define DEFAULT_PERFORMANCE		50
+
+struct cpufreq_obj {
+	void	 *iface;
+	gboolean (*set_performance)   (void *data, int);
+	gboolean (*set_consider_nice) (void *data, gboolean);
+	int      (*get_performance)   (void);
+	gboolean (*get_consider_nice) (void);
+	void     (*free)              (void *data);
+};
+
+gboolean	write_line		(const char *filename,
+					 const char *fmt, ...);
+
+gboolean	read_line		(const char *filename,
+					 char *line,
+					 unsigned len);
+
+gboolean	read_line_int_split	(char *filename,
+					 gchar *delim,
+					 GSList **list);
+
+gboolean	cpu_online		(int cpu_id);
+
+gboolean	write_governor		(char *new_governor,
+					 int cpu_id);
+
+gboolean	dbus_init		(void);
+
+#endif /* ADDON_CPUFREQ_H */
diff --git a/privileges/Makefile.am b/privileges/Makefile.am
index f32ab1c..d300a60 100644
--- a/privileges/Makefile.am
+++ b/privileges/Makefile.am
@@ -9,7 +9,8 @@ dist_polkit_privilege_DATA =            
 	hal-power-suspend.privilege                       \
 	hal-power-hibernate.privilege                     \
 	hal-power-poweroff.privilege                      \
-	hal-power-reboot.privilege
+	hal-power-reboot.privilege                        \
+	hal-power-cpufreq.privilege
 
 clean-local :
 	rm -f *~
diff --git a/privileges/hal-power-cpufreq.privilege b/privileges/hal-power-cpufreq.privilege
new file mode 100644
index 0000000..cee08b4
--- /dev/null
+++ b/privileges/hal-power-cpufreq.privilege
@@ -0,0 +1,12 @@
+
+# This privilege specifies who is allowed to control CPUFreq
+# via the org.freedesktop.Hal.Device.CPUFreq interface
+
+[Privilege]
+RequiredPrivileges=desktop-console
+SufficientPrivileges=
+Allow=uid:__all__
+Deny=
+CanObtain=True
+CanGrant=True
+ObtainRequireRoot=False



More information about the hal-commit mailing list