summaryrefslogtreecommitdiff
path: root/cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c')
-rw-r--r--cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c b/cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c
new file mode 100644
index 00000000..f08d681d
--- /dev/null
+++ b/cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c
@@ -0,0 +1,243 @@
+/*
+ * MATE CPUFreq Applet
+ * Copyright (C) 2004 Carlos Garcia Campos <[email protected]>
+ *
+ * This library 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 your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors : Carlos Garc�a Campos <[email protected]>
+ */
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "cpufreq-selector-procfs.h"
+
+static void cpufreq_selector_procfs_init (CPUFreqSelectorProcfs *selector);
+static void cpufreq_selector_procfs_class_init (CPUFreqSelectorProcfsClass *klass);
+
+static gboolean cpufreq_selector_procfs_set_frequency (CPUFreqSelector *selector,
+ guint frequency,
+ GError **error);
+static gboolean cpufreq_selector_procfs_set_governor (CPUFreqSelector *selector,
+ const gchar *governor,
+ GError **error);
+
+G_DEFINE_TYPE (CPUFreqSelectorProcfs, cpufreq_selector_procfs, CPUFREQ_TYPE_SELECTOR)
+
+static void
+cpufreq_selector_procfs_init (CPUFreqSelectorProcfs *selector)
+{
+}
+
+static void
+cpufreq_selector_procfs_class_init (CPUFreqSelectorProcfsClass *klass)
+{
+ CPUFreqSelectorClass *selector_class = CPUFREQ_SELECTOR_CLASS (klass);
+
+ selector_class->set_frequency = cpufreq_selector_procfs_set_frequency;
+ selector_class->set_governor = cpufreq_selector_procfs_set_governor;
+}
+
+CPUFreqSelector *
+cpufreq_selector_procfs_new (guint cpu)
+{
+ CPUFreqSelector *selector;
+
+ selector = CPUFREQ_SELECTOR (g_object_new (CPUFREQ_TYPE_SELECTOR_PROCFS,
+ "cpu", cpu,
+ NULL));
+
+ return selector;
+}
+
+static gboolean
+cpufreq_procfs_read (guint selector_cpu,
+ guint *fmax,
+ guint *pmin,
+ guint *pmax,
+ guint *fmin,
+ gchar *mode,
+ GError **error)
+{
+ gchar **lines;
+ gchar *buffer = NULL;
+ gint i;
+ guint cpu;
+ gboolean found = FALSE;
+
+ if (!g_file_get_contents ("/proc/cpufreq", &buffer, NULL, error)) {
+ return FALSE;
+ }
+
+ lines = g_strsplit (buffer, "\n", -1);
+ for (i = 0; lines[i]; i++) {
+ if (g_ascii_strncasecmp (lines[i], "CPU", 3) == 0) {
+ /* CPU 0 650000 kHz ( 81 %) - 800000 kHz (100 %) - powersave */
+ sscanf (lines[i], "CPU %u %u kHz (%u %%) - %u kHz (%u %%) - %20s",
+ &cpu, fmin, pmin, fmax, pmax, mode);
+
+ if (cpu == selector_cpu) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ g_strfreev (lines);
+ g_free (buffer);
+
+ if (!found) {
+ g_set_error (error,
+ CPUFREQ_SELECTOR_ERROR,
+ SELECTOR_ERROR_INVALID_CPU,
+ "Invalid CPU number '%d'",
+ selector_cpu);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+cpufreq_procfs_write (const gchar *path,
+ const gchar *setting,
+ GError **error)
+{
+ FILE *fd;
+
+ fd = g_fopen (path, "w");
+
+ if (!fd) {
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "Failed to open '%s' for writing: "
+ "g_fopen() failed: %s",
+ path,
+ g_strerror (errno));
+
+ return FALSE;
+ }
+
+ if (g_fprintf (fd, "%s", setting) < 0) {
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "Failed to write '%s': "
+ "g_fprintf() failed: %s",
+ path,
+ g_strerror (errno));
+
+ fclose (fd);
+
+ return FALSE;
+ }
+
+ fclose (fd);
+
+ return TRUE;
+}
+
+static gboolean
+cpufreq_selector_procfs_set_frequency (CPUFreqSelector *selector,
+ guint frequency,
+ GError **error)
+{
+ gchar *str;
+ gchar *path;
+ guint freq;
+ guint cpu;
+ guint pmin, pmax;
+ guint sc_max, sc_min;
+ gchar mode[21];
+
+ g_object_get (G_OBJECT (selector),
+ "cpu", &cpu,
+ NULL);
+
+ if (!cpufreq_procfs_read (cpu, &sc_max, &pmin, &pmax, &sc_min, mode, error)) {
+ return FALSE;
+ }
+
+ if (g_ascii_strcasecmp (mode, "userspace") != 0) {
+ if (!cpufreq_selector_procfs_set_governor (selector,
+ "userspace",
+ error)) {
+ return FALSE;
+ }
+ }
+
+ if (frequency != sc_max && frequency != sc_min) {
+ if (abs (sc_max - frequency) < abs (frequency - sc_min))
+ freq = sc_max;
+ else
+ freq = sc_min;
+ } else {
+ freq = frequency;
+ }
+
+ path = g_strdup_printf ("/proc/sys/cpu/%u/speed", cpu);
+ str = g_strdup_printf ("%u", freq);
+ if (!cpufreq_procfs_write (path, str, error)) {
+ g_free (path);
+ g_free (str);
+
+ return FALSE;
+ }
+
+ g_free (path);
+ g_free (str);
+
+ return TRUE;
+}
+
+static gboolean
+cpufreq_selector_procfs_set_governor (CPUFreqSelector *selector,
+ const gchar *governor,
+ GError **error)
+{
+ gchar *str;
+ guint cpu;
+ guint pmin, pmax;
+ guint sc_max, sc_min;
+ gchar mode[21];
+
+ g_object_get (G_OBJECT (selector),
+ "cpu", &cpu,
+ NULL);
+
+ if (!cpufreq_procfs_read (cpu, &sc_max, &pmin, &pmax, &sc_min, mode, error)) {
+ return FALSE;
+ }
+
+ if (g_ascii_strcasecmp (governor, mode) == 0)
+ return TRUE;
+
+ str = g_strdup_printf ("%u:%u:%u:%s", cpu, sc_min, sc_max, governor);
+
+ if (!cpufreq_procfs_write ("/proc/cpufreq", str, error)) {
+ g_free (str);
+
+ return FALSE;
+ }
+
+ g_free (str);
+
+ return TRUE;
+}