diff options
Diffstat (limited to 'cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c')
-rw-r--r-- | cpufreq/src/cpufreq-selector/cpufreq-selector-procfs.c | 243 |
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; +} |