[neon/backports-jammy/power-profiles-daemon/Neon/unstable] /: 0.8.1-1 (patches unapplied)
git-ubuntu importer
null at kde.org
Tue Sep 24 23:21:42 BST 2024
Git commit d12abf1e3d7886da6844d018423b060dc330f408 by git-ubuntu importer, on behalf of Sebastien Bacher.
Committed on 15/06/2021 at 16:37.
Pushed by carlosdem into branch 'Neon/unstable'.
0.8.1-1 (patches unapplied)
Imported using git-ubuntu import.
M +15 -0 NEWS
M +18 -4 README.md
A +82 -0 check-news.sh
M +6 -0 debian/changelog
M +1 -1 docs/meson.build
M +2 -0 docs/power-profiles-daemon-sections.txt
M +10 -2 meson.build
M +23 -3 src/meson.build
M +129 -92 src/power-profiles-daemon.c
A +151 -0 src/powerprofilesctl.in
D +0 -49 src/ppd-driver-balanced.c
M +32 -9 src/ppd-driver-fake.c
M +23 -79 src/ppd-driver-intel-pstate.c
D +0 -211 src/ppd-driver-lenovo-dytc.c
A +49 -0 src/ppd-driver-placeholder.c [License: GPL (v3)]
R +2 -2 src/ppd-driver-placeholder.h [from: src/ppd-driver-lenovo-dytc.h - 064% similarity]
A +352 -0 src/ppd-driver-platform-profile.c [License: GPL (v3)]
R +2 -2 src/ppd-driver-platform-profile.h [from: src/ppd-driver-balanced.h - 059% similarity]
D +0 -49 src/ppd-driver-power-saver.c
D +0 -15 src/ppd-driver-power-saver.h
M +92 -9 src/ppd-driver.c
M +51 -6 src/ppd-driver.h
M +61 -0 src/ppd-utils.c
M +8 -0 src/ppd-utils.h
M +130 -73 tests/integration-test
M +1 -0 tests/meson.build
https://invent.kde.org/neon/backports-jammy/power-profiles-daemon/-/commit/d12abf1e3d7886da6844d018423b060dc330f408
diff --git a/NEWS b/NEWS
index ee04942..bc8a646 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,18 @@
+0.8.1
+-----
+
+This release works-around a cosmetic issue in gnome-shell animations when
+on battery and using the intel-pstate driver.
+
+0.8
+---
+
+This release adds support for the new generic `platform_profile` kernel
+API to replace the Lenovo specific `dytc_perfmode`, meaning it should also
+support profile selection on a number of HP and Microsoft Surface devices.
+
+This release also add the `powerprofilesctl` command-line application.
+
0.1
---
diff --git a/README.md b/README.md
index 9e5a192..768a744 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,7 @@ gdbus introspect --system --dest net.hadess.PowerProfiles --object-path /net/had
You can change the selected profile by running (change `power-saver` for the
chosen profile):
```
-gdbus call --system --dest net.hadess.PowerProfiles --object-path /net/hadess/PowerProfiles --method org.freedesktop.DBus.Properties.Set 'net.hadess.PowerProfiles' 'SelectedProfile' "<'power-saver'>"
+gdbus call --system --dest net.hadess.PowerProfiles --object-path /net/hadess/PowerProfiles --method org.freedesktop.DBus.Properties.Set 'net.hadess.PowerProfiles' 'ActiveProfile' "<'power-saver'>"
```
If that doesn't work, please file an issue, make sure any running power-profiles-daemon
@@ -125,11 +125,12 @@ A fair number of the tweaks that could apply to devices running GNOME or
another free desktop are either potentially destructive (eg. some of the
SATA power-saving mode resulting in corrupted data), or working well
enough to be put into place by default (eg. audio codec power-saving), even
-if some quirks might be needed on some hardware.
+if we need to disable the power saving on some hardware that reacts
+badly to it.
-Both are good projects to use if the intent is to experiment with particular
+Both are good projects to use for the purpose of experimenting with particular
settings to see if they'd be something that can be implemented by default,
-or to put some fine-grained policies in place on server-type workloads
+or to put some fine-grained, static, policies in place on server-type workloads
which are not as fluid and changing as desktop workloads can be.
### [auto-cpufreq](https://github.com/AdnanHodzic/auto-cpufreq)
@@ -138,3 +139,16 @@ It doesn't take user-intent into account, doesn't have a D-Bus interface and
seems to want to work automatically by monitoring the CPU usage, which kind
of goes against a user's wishes as a user might still want to conserve as
much energy as possible under high-CPU usage.
+
+### [slimbookbattery](https://launchpad.net/~slimbook)
+This is **not** free software (*Source code available but not modifiable
+without express authorization.*). The application does a lot of things in
+addition to the "3 profiles" selection:
+
+- replaces part of the suspend mechanism with its own hybrid sleep implementation
+ (systemd already implements one)
+- implements charging limits for batteries
+- implements some power saving tricks, which could also be implemented
+
+A lot of those power-saving tricks could be analysed and used, but we
+obviously can't rely on "source available" software for our free desktops.
diff --git a/check-news.sh b/check-news.sh
new file mode 100644
index 0000000..11ae861
--- /dev/null
+++ b/check-news.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+# Copyright (C) 2019 Red Hat, Inc.
+# Author: Bastien Nocera <hadess at hadess.net>
+#
+# 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 3 of the License, or
+# (at your 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+# Add to your top-level meson.build to check for an updated NEWS file
+# when doing a "dist" release, similarly to automake's check-news:
+# https://www.gnu.org/software/automake/manual/html_node/List-of-Automake-options.html
+#
+# Checks NEWS for the version number:
+# meson.add_dist_script(
+# find_program('check-news.sh').path(),
+# '@0@'.format(meson.project_version())
+# )
+#
+# Checks NEWS and data/foo.appdata.xml for the version number:
+# meson.add_dist_script(
+# find_program('check-news.sh').path(),
+# '@0@'.format(meson.project_version()),
+# 'NEWS',
+# 'data/foo.appdata.xml'
+# )
+
+usage()
+{
+ echo "$0 VERSION [FILES...]"
+ exit 1
+}
+
+check_version()
+{
+ VERSION=$1
+ # Look in the first 15 lines for NEWS files, but look
+ # everywhere for other types of files
+ if [ "$2" = "NEWS" ]; then
+ DATA=`sed 15q $SRC_ROOT/"$2"`
+ else
+ DATA=`cat $SRC_ROOT/"$2"`
+ fi
+ case "$DATA" in
+ *"$VERSION"*)
+ :
+ ;;
+ *)
+ echo "$2 not updated; not releasing" 1>&2;
+ exit 1
+ ;;
+ esac
+}
+
+SRC_ROOT=${MESON_DIST_ROOT:-"./"}
+
+if [ $# -lt 1 ] ; then usage ; fi
+
+VERSION=$1
+shift
+
+if [ $# -eq 0 ] ; then
+ check_version $VERSION 'NEWS'
+ exit 0
+fi
+
+for i in $@ ; do
+ check_version $VERSION "$i"
+done
+
+exit 0
\ No newline at end of file
diff --git a/debian/changelog b/debian/changelog
index 475c4e5..3155e44 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+power-profiles-daemon (0.8.1-1) experimental; urgency=medium
+
+ * New upstream version
+
+ -- Sebastien Bacher <seb128 at ubuntu.com> Tue, 15 Jun 2021 15:29:30 +0200
+
power-profiles-daemon (0.1-5) experimental; urgency=medium
* Don't split the test into a separate binary, it's not useful
diff --git a/docs/meson.build b/docs/meson.build
index b8b10ab..cfd2406 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -24,7 +24,7 @@ private_headers = [
'ppd-driver-balanced.h',
'ppd-driver-fake.h',
'ppd-driver-intel-pstate.h',
- 'ppd-driver-lenovo-dytc.h',
+ 'ppd-driver-platform-profile.h',
'ppd-driver-power-saver.h',
'ppd-utils.h',
'power-profiles-daemon-resources.h',
diff --git a/docs/power-profiles-daemon-sections.txt b/docs/power-profiles-daemon-sections.txt
index 0ad1c3a..0063310 100644
--- a/docs/power-profiles-daemon-sections.txt
+++ b/docs/power-profiles-daemon-sections.txt
@@ -12,6 +12,8 @@ PPD_TYPE_ACTION
<TITLE>Profile Drivers</TITLE>
PpdDriverClass
PpdDriver
+PpdProbeResult
+PpdProfileActivationReason
<SUBSECTION Private>
PPD_TYPE_DRIVER
</SECTION>
diff --git a/meson.build b/meson.build
index 0a68a9e..81181f6 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
project('power-profiles-daemon', [ 'c' ],
- version: '0.1',
+ version: '0.8.1',
license: 'GPLv3+',
default_options: [
'buildtype=debugoptimized',
@@ -35,13 +35,16 @@ if systemd_system_unit_dir == 'auto'
systemd_system_unit_dir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir')
endif
gio_dep = dependency('gio-2.0')
-gudev_dep = dependency('gudev-1.0', version: '>= 232')
+gudev_dep = dependency('gudev-1.0', version: '>= 234')
upower_dep = dependency('upower-glib')
gnome = import('gnome')
add_global_arguments('-D_GNU_SOURCE=1', language: 'c')
+pylint = find_program('pylint-3', 'pylint3', 'pylint', required: false)
+pylint_flags = ['-d', 'C0116', '-d', 'C0114', '-d', 'W0707']
+
subdir('src')
subdir('data')
@@ -56,3 +59,8 @@ if get_option('gtk_doc')
endif
subdir('tests')
+
+meson.add_dist_script(
+ find_program('check-news.sh').path(),
+ '@0@'.format(meson.project_version())
+)
diff --git a/src/meson.build b/src/meson.build
index 71625d7..318f284 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -39,9 +39,8 @@ sources += [
'power-profiles-daemon.c',
'ppd-action-trickle-charge.c',
'ppd-driver-intel-pstate.c',
- 'ppd-driver-lenovo-dytc.c',
- 'ppd-driver-balanced.c',
- 'ppd-driver-power-saver.c',
+ 'ppd-driver-platform-profile.c',
+ 'ppd-driver-placeholder.c',
'ppd-driver-fake.c',
]
@@ -51,3 +50,24 @@ executable('power-profiles-daemon',
install: true,
install_dir: libexecdir
)
+
+python = import('python')
+py_installation = python.find_installation('python3', required: true)
+
+ppd_conf = configuration_data()
+ppd_conf.set('VERSION', meson.project_version())
+ppd_conf.set('PYTHON3', py_installation.path())
+
+script = configure_file(
+ input: 'powerprofilesctl.in',
+ output: 'powerprofilesctl',
+ configuration: ppd_conf,
+ install_dir: get_option('bindir')
+)
+
+if pylint.found()
+ test('pylint-powerprofilesctl',
+ pylint,
+ args: pylint_flags + [ script ],
+ )
+endif
diff --git a/src/power-profiles-daemon.c b/src/power-profiles-daemon.c
index 77c561d..c07d8a5 100644
--- a/src/power-profiles-daemon.c
+++ b/src/power-profiles-daemon.c
@@ -19,45 +19,32 @@
#define POWER_PROFILES_DBUS_PATH "/net/hadess/PowerProfiles"
#define POWER_PROFILES_IFACE_NAME POWER_PROFILES_DBUS_NAME
-GMainLoop *main_loop = NULL;
-
typedef struct {
+ GMainLoop *main_loop;
GDBusNodeInfo *introspection_data;
GDBusConnection *connection;
guint name_id;
+ gboolean was_started;
int ret;
PpdProfile active_profile;
- GPtrArray *drivers;
+ GPtrArray *probed_drivers;
+ PpdDriver *driver;
GPtrArray *actions;
} PpdApp;
-static PpdDriver *
-get_driver_for_profile (PpdApp *data,
- PpdProfile profile)
-{
- guint i;
-
- g_return_val_if_fail (ppd_profile_has_single_flag (profile), NULL);
+static PpdApp *ppd_app = NULL;
- for (i = 0; i < data->drivers->len; i++) {
- PpdDriver *driver = g_ptr_array_index (data->drivers, i);
-
- if (ppd_driver_get_profiles (driver) & profile)
- return driver;
- }
-
- return NULL;
-}
+static void stop_profile_drivers (PpdApp *data);
+static void start_profile_drivers (PpdApp *data);
-#define GET_DRIVER(p) (get_driver_for_profile (data, p))
-#define ACTIVE_DRIVER (get_driver_for_profile (data, data->active_profile))
+#define GET_DRIVER(p) (ppd_driver_get_profiles (data->driver) & p ? data->driver : NULL)
+#define ACTIVE_DRIVER (data->driver)
/* profile drivers and actions */
#include "ppd-action-trickle-charge.h"
-#include "ppd-driver-balanced.h"
-#include "ppd-driver-power-saver.h"
-#include "ppd-driver-lenovo-dytc.h"
+#include "ppd-driver-placeholder.h"
+#include "ppd-driver-platform-profile.h"
#include "ppd-driver-intel-pstate.h"
#include "ppd-driver-fake.h"
@@ -66,12 +53,11 @@ typedef GType (*GTypeGetFunc) (void);
static GTypeGetFunc objects[] = {
/* Hardware specific profile drivers */
ppd_driver_fake_get_type,
- ppd_driver_lenovo_dytc_get_type,
+ ppd_driver_platform_profile_get_type,
ppd_driver_intel_pstate_get_type,
- /* Generic profile drivers */
- ppd_driver_balanced_get_type,
- ppd_driver_power_saver_get_type,
+ /* Generic profile driver */
+ ppd_driver_placeholder_get_type,
/* Actions */
ppd_action_trickle_charge_get_type,
@@ -95,8 +81,8 @@ get_active_profile (PpdApp *data)
static const char *
get_performance_inhibited (PpdApp *data)
{
- PpdDriver *driver;
const char *ret;
+ PpdDriver *driver;
driver = GET_DRIVER(PPD_PROFILE_PERFORMANCE);
if (!driver)
@@ -220,24 +206,21 @@ actions_activate_profile (GPtrArray *actions,
}
static void
-activate_target_profile (PpdApp *data,
- PpdProfile target_profile)
+activate_target_profile (PpdApp *data,
+ PpdProfile target_profile,
+ PpdProfileActivationReason reason)
{
- guint i;
+ g_autoptr(GError) error = NULL;
- g_debug ("Setting active profile '%s' (current: '%s')",
+ g_debug ("Setting active profile '%s' for reason '%s' (current: '%s')",
ppd_profile_to_str (target_profile),
+ ppd_profile_activation_reason_to_str (reason),
ppd_profile_to_str (data->active_profile));
- for (i = 0; i < data->drivers->len; i++) {
- PpdDriver *driver = g_ptr_array_index (data->drivers, i);
- g_autoptr(GError) error = NULL;
-
- if (!ppd_driver_activate_profile (driver, target_profile, &error)) {
- g_warning ("Failed to activate driver '%s': %s",
- ppd_driver_get_driver_name (driver),
- error->message);
- }
+ if (!ppd_driver_activate_profile (data->driver, target_profile, reason, &error)) {
+ g_warning ("Failed to activate driver '%s': %s",
+ ppd_driver_get_driver_name (data->driver),
+ error->message);
}
actions_activate_profile (data->actions, target_profile);
@@ -259,11 +242,8 @@ set_active_profile (PpdApp *data,
return FALSE;
}
- if (target_profile == data->active_profile) {
- g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
- "Profile '%s' already active", profile);
- return FALSE;
- }
+ if (target_profile == data->active_profile)
+ return TRUE;
if (target_profile == PPD_PROFILE_PERFORMANCE &&
ppd_driver_is_performance_inhibited (GET_DRIVER (PPD_PROFILE_PERFORMANCE))) {
@@ -272,11 +252,10 @@ set_active_profile (PpdApp *data,
return FALSE;
}
- g_debug ("Transitioning active profile from '%s' to '%s'",
+ g_debug ("Transitioning active profile from '%s' to '%s' by user request",
ppd_profile_to_str (data->active_profile), profile);
- data->active_profile = target_profile;
- activate_target_profile (data, target_profile);
+ activate_target_profile (data, target_profile, PPD_PROFILE_ACTIVATION_REASON_USER);
send_dbus_event (data, PROP_ACTIVE_PROFILE);
return TRUE;
@@ -307,7 +286,25 @@ driver_performance_inhibited_changed_cb (GObject *gobject,
if (!ppd_driver_is_performance_inhibited (driver))
return;
- activate_target_profile (data, PPD_PROFILE_BALANCED);
+ activate_target_profile (data, PPD_PROFILE_BALANCED, PPD_PROFILE_ACTIVATION_REASON_INHIBITION);
+ send_dbus_event (data, PROP_ACTIVE_PROFILE);
+}
+
+static void
+driver_profile_changed_cb (PpdDriver *driver,
+ PpdProfile new_profile,
+ gpointer user_data)
+{
+ PpdApp *data = user_data;
+
+ g_debug ("Driver '%s' switched internally to profile '%s' (current: '%s')",
+ ppd_driver_get_driver_name (driver),
+ ppd_profile_to_str (new_profile),
+ ppd_profile_to_str (data->active_profile));
+ if (new_profile == data->active_profile)
+ return;
+
+ activate_target_profile (data, new_profile, PPD_PROFILE_ACTIVATION_REASON_INTERNAL);
send_dbus_event (data, PROP_ACTIVE_PROFILE);
}
@@ -372,8 +369,11 @@ name_lost_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
+ PpdApp *data = user_data;
g_debug ("power-profiles-daemon is already running, or it cannot own its D-Bus name. Verify installation.");
- exit (0);
+ if (!data->was_started)
+ data->ret = 1;
+ g_main_loop_quit (data->main_loop);
}
static void
@@ -409,39 +409,31 @@ has_required_drivers (PpdApp *data)
return TRUE;
}
-static gboolean
-profile_already_handled (PpdApp *data,
- PpdDriver *driver,
- PpdProfile profiles)
+static void
+driver_probe_request_cb (PpdDriver *driver,
+ gpointer user_data)
{
- guint i;
-
- for (i = 0; i < NUM_PROFILES; i++) {
- PpdDriver *existing_driver;
-
- if (!(profiles & (1 << i)))
- continue;
+ PpdApp *data = user_data;
- existing_driver = GET_DRIVER(1 << i);
- if (existing_driver) {
- g_debug ("Driver '%s' conflicts with already probed driver '%s' for profile %s",
- ppd_driver_get_driver_name (driver),
- ppd_driver_get_driver_name (existing_driver),
- ppd_profile_to_str (1 << i));
- return TRUE;
- }
- }
+ stop_profile_drivers (data);
+ start_profile_drivers (data);
+}
- return FALSE;
+static void
+stop_profile_drivers (PpdApp *data)
+{
+ g_ptr_array_set_size (data->probed_drivers, 0);
+ g_ptr_array_set_size (data->actions, 0);
+ g_clear_object (&data->driver);
}
static void
-name_acquired_handler (GDBusConnection *connection,
- const gchar *name,
- gpointer user_data)
+start_profile_drivers (PpdApp *data)
{
- PpdApp *data = user_data;
guint i;
+ PpdProfile prev_profile;
+
+ prev_profile = data->active_profile;
for (i = 0; i < G_N_ELEMENTS (objects); i++) {
GObject *object;
@@ -450,9 +442,17 @@ name_acquired_handler (GDBusConnection *connection,
if (PPD_IS_DRIVER (object)) {
PpdDriver *driver = PPD_DRIVER (object);
PpdProfile profiles;
+ PpdProbeResult result;
g_debug ("Handling driver '%s'", ppd_driver_get_driver_name (driver));
+ if (data->driver != NULL) {
+ g_debug ("Driver '%s' already probed, skipping driver '%s'",
+ ppd_driver_get_driver_name (data->driver),
+ ppd_driver_get_driver_name (driver));
+ continue;
+ }
+
profiles = ppd_driver_get_profiles (driver);
if (!(profiles & PPD_PROFILE_ALL)) {
g_warning ("Profile Driver '%s' implements invalid profiles '0x%X'",
@@ -462,22 +462,25 @@ name_acquired_handler (GDBusConnection *connection,
continue;
}
- if (profile_already_handled (data, driver, profiles)) {
- g_object_unref (object);
- continue;
- }
-
- if (!ppd_driver_probe (driver)) {
+ result = ppd_driver_probe (driver, &prev_profile);
+ if (result == PPD_PROBE_RESULT_FAIL) {
g_debug ("probe() failed for driver %s, skipping",
ppd_driver_get_driver_name (driver));
g_object_unref (object);
continue;
+ } else if (result == PPD_PROBE_RESULT_DEFER) {
+ g_signal_connect (G_OBJECT (driver), "probe-request",
+ G_CALLBACK (driver_probe_request_cb), data);
+ g_ptr_array_add (data->probed_drivers, driver);
+ continue;
}
- g_ptr_array_add (data->drivers, driver);
+ data->driver = driver;
g_signal_connect (G_OBJECT (driver), "notify::performance-inhibited",
G_CALLBACK (driver_performance_inhibited_changed_cb), data);
+ g_signal_connect (G_OBJECT (driver), "profile-changed",
+ G_CALLBACK (driver_profile_changed_cb), data);
} else if (PPD_IS_ACTION (object)) {
PpdAction *action = PPD_ACTION (object);
@@ -501,17 +504,42 @@ name_acquired_handler (GDBusConnection *connection,
goto bail;
}
+ if (prev_profile != data->active_profile) {
+ g_debug ("Using '%s' as current profile from probed driver",
+ ppd_profile_to_str (prev_profile));
+ data->active_profile = prev_profile;
+ }
+
/* Set initial state */
- activate_target_profile (data, data->active_profile);
+ activate_target_profile (data, data->active_profile, PPD_PROFILE_ACTIVATION_REASON_RESET);
send_dbus_event (data, PROP_ALL);
+ data->was_started = TRUE;
+
return;
bail:
- data->ret = 0;
+ data->ret = 1;
g_debug ("Exiting because some non recoverable error occurred during startup");
- g_main_loop_quit (main_loop);
+ g_main_loop_quit (data->main_loop);
+}
+
+void
+restart_profile_drivers (void)
+{
+ stop_profile_drivers (ppd_app);
+ start_profile_drivers (ppd_app);
+}
+
+static void
+name_acquired_handler (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ PpdApp *data = user_data;
+
+ start_profile_drivers (data);
}
static gboolean
@@ -555,13 +583,21 @@ free_app_data (PpdApp *data)
data->name_id = 0;
}
+ g_ptr_array_free (data->probed_drivers, TRUE);
g_ptr_array_free (data->actions, TRUE);
- g_ptr_array_free (data->drivers, TRUE);
+ g_clear_object (&data->driver);
+ g_clear_pointer (&data->main_loop, g_main_loop_unref);
g_clear_pointer (&data->introspection_data, g_dbus_node_info_unref);
g_clear_object (&data->connection);
- g_clear_pointer (&main_loop, g_main_loop_unref);
g_free (data);
+ ppd_app = NULL;
+}
+
+void
+main_loop_quit (void)
+{
+ g_main_loop_quit (ppd_app->main_loop);
}
int main (int argc, char **argv)
@@ -592,15 +628,16 @@ int main (int argc, char **argv)
g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
data = g_new0 (PpdApp, 1);
+ data->main_loop = g_main_loop_new (NULL, TRUE);
+ data->probed_drivers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
data->actions = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
- data->drivers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
data->active_profile = PPD_PROFILE_BALANCED;
+ ppd_app = data;
/* Set up D-Bus */
setup_dbus (data, replace);
- main_loop = g_main_loop_new (NULL, TRUE);
- g_main_loop_run (main_loop);
+ g_main_loop_run (data->main_loop);
ret = data->ret;
free_app_data (data);
diff --git a/src/powerprofilesctl.in b/src/powerprofilesctl.in
new file mode 100755
index 0000000..b525e91
--- /dev/null
+++ b/src/powerprofilesctl.in
@@ -0,0 +1,151 @@
+#!@PYTHON3@
+
+import sys
+from gi.repository import Gio, GLib
+
+VERSION = '@VERSION@'
+
+def usage_main():
+ print('Usage:')
+ print(' powerprofilesctl COMMAND [ARGS…]')
+ print('')
+ print('Commands:')
+ print(' help Print help')
+ print(' version Print version')
+ print(' get Print the currently active power profile')
+ print(' set Set the currently active power profile')
+ print(' list List available power profiles')
+ print('')
+ print('Use “powerprofilesctl help COMMAND” to get detailed help.')
+
+def usage_version():
+ print('Usage:')
+ print(' powerprofilesctl version')
+ print('')
+ print('Print version information and exit.')
+
+def usage_get():
+ print('Usage:')
+ print(' powerprofilesctl get')
+ print('')
+ print('Print the currently active power profile.')
+
+def usage_set():
+ print('Usage:')
+ print(' powerprofilesctl set PROFILE')
+ print('')
+ print('Set the currently active power profile. Must be one of the ')
+ print('available profiles.')
+
+def usage_list():
+ print('Usage:')
+ print(' powerprofilesctl list')
+ print('')
+ print('List available power profiles.')
+
+def usage(_command=None):
+ if not _command:
+ usage_main()
+ elif _command == 'get':
+ usage_get()
+ elif _command == 'set':
+ usage_set()
+ elif _command == 'list':
+ usage_list()
+ elif _command == 'version':
+ usage_version()
+ else:
+ usage_main()
+
+def version():
+ print (VERSION)
+
+def get_proxy():
+ try:
+ bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
+ proxy = Gio.DBusProxy.new_sync(bus, Gio.DBusProxyFlags.NONE, None,
+ 'net.hadess.PowerProfiles',
+ '/net/hadess/PowerProfiles',
+ 'org.freedesktop.DBus.Properties', None)
+ except:
+ raise SystemError
+ return proxy
+
+def _get():
+ proxy = get_proxy()
+ profile = proxy.Get('(ss)', 'net.hadess.PowerProfiles', 'ActiveProfile')
+ print(profile)
+
+def _set(profile):
+ proxy = get_proxy()
+ proxy.Set('(ssv)',
+ 'net.hadess.PowerProfiles',
+ 'ActiveProfile',
+ GLib.Variant.new_string(profile))
+
+def get_profiles_property(prop):
+ try:
+ proxy = get_proxy()
+ except:
+ raise SystemError
+
+ profiles = None
+ try:
+ profiles = proxy.Get('(ss)', 'net.hadess.PowerProfiles', prop)
+ except:
+ raise ReferenceError
+ else:
+ return profiles
+
+def _list():
+ try:
+ profiles = get_profiles_property('Profiles')
+ reason = get_proxy().Get('(ss)', 'net.hadess.PowerProfiles', 'PerformanceInhibited')
+ inhibited = (reason != '')
+ active = get_proxy().Get('(ss)', 'net.hadess.PowerProfiles', 'ActiveProfile')
+ except:
+ print("Couldn\'t get Profiles: ", sys.exc_info()[0])
+ raise SystemError
+ else:
+ index = 0
+ for profile in reversed(profiles):
+ if index > 0:
+ print('')
+ print(('%s %s:') % ('*' if profile['Profile'] == active else ' ', profile['Profile']))
+ print(' Driver: ', profile['Driver'])
+ if profile['Profile'] == 'performance':
+ print(' Inhibited: ', f'yes ({reason})' if inhibited else 'no')
+ index += 1
+
+def main(): # pylint: disable=too-many-branches
+ args = None
+ if len(sys.argv) == 1:
+ command = 'list'
+ elif len(sys.argv) >= 2:
+ command = sys.argv[1]
+ if command == '--help':
+ command = 'help'
+ if command == '--version':
+ command = 'version'
+ else:
+ args = sys.argv[2:]
+
+ if command == 'help':
+ if len(args) > 0:
+ usage(args[0])
+ else:
+ usage(None)
+ elif command == 'version':
+ version()
+ elif command == 'get':
+ _get()
+ elif command == 'set':
+ if len(args) != 1:
+ usage_set()
+ sys.exit(1)
+ _set(args[0])
+ elif command == 'list':
+ _list()
+
+if __name__ == '__main__':
+ main()
diff --git a/src/ppd-driver-balanced.c b/src/ppd-driver-balanced.c
deleted file mode 100644
index 6ddbac9..0000000
--- a/src/ppd-driver-balanced.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020 Bastien Nocera <hadess at hadess.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3 as published by
- * the Free Software Foundation.
- *
- */
-
-#include "ppd-driver-balanced.h"
-
-struct _PpdDriverBalanced
-{
- PpdDriver parent_instance;
-};
-
-G_DEFINE_TYPE (PpdDriverBalanced, ppd_driver_balanced, PPD_TYPE_DRIVER)
-
-static GObject*
-ppd_driver_balanced_constructor (GType type,
- guint n_construct_params,
- GObjectConstructParam *construct_params)
-{
- GObject *object;
-
- object = G_OBJECT_CLASS (ppd_driver_balanced_parent_class)->constructor (type,
- n_construct_params,
- construct_params);
- g_object_set (object,
- "driver-name", "balanced",
- "profiles", PPD_PROFILE_BALANCED,
- NULL);
-
- return object;
-}
-
-static void
-ppd_driver_balanced_class_init (PpdDriverBalancedClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS(klass);
- object_class->constructor = ppd_driver_balanced_constructor;
-}
-
-static void
-ppd_driver_balanced_init (PpdDriverBalanced *self)
-{
-}
diff --git a/src/ppd-driver-fake.c b/src/ppd-driver-fake.c
index e7d5975..431ba64 100644
--- a/src/ppd-driver-fake.c
+++ b/src/ppd-driver-fake.c
@@ -13,12 +13,14 @@
#include <stdio.h>
#include <termios.h>
-extern GMainLoop *main_loop;
+extern void main_loop_quit (void);
+void restart_profile_drivers (void);
struct _PpdDriverFake
{
PpdDriver parent_instance;
+ gboolean tio_set;
struct termios old_tio;
gboolean inhibited;
};
@@ -37,7 +39,7 @@ ppd_driver_fake_constructor (GType type,
construct_params);
g_object_set (object,
"driver-name", "fake",
- "profiles", PPD_PROFILE_PERFORMANCE,
+ "profiles", PPD_PROFILE_ALL,
NULL);
return object;
@@ -56,7 +58,7 @@ toggle_inhibition (PpdDriverFake *fake)
static void
keyboard_usage (void)
{
- g_print ("Valid keys are: i (toggle inhibition), q/x (quit)\n");
+ g_print ("Valid keys are: i (toggle inhibition), r (restart drivers), q/x (quit)\n");
}
static gboolean
@@ -82,9 +84,13 @@ check_keyboard (GIOChannel *source,
g_print ("Toggling inhibition\n");
toggle_inhibition (fake);
break;
+ case 'r':
+ g_print ("Restarting profile drivers\n");
+ restart_profile_drivers ();
+ break;
case 'q':
case 'x':
- g_main_loop_quit (main_loop);
+ main_loop_quit ();
break;
default:
keyboard_usage ();
@@ -117,6 +123,7 @@ setup_keyboard (PpdDriverFake *fake)
}
g_io_add_watch (channel, G_IO_IN, (GIOFunc) check_keyboard, fake);
+ fake->tio_set = TRUE;
return TRUE;
}
@@ -134,19 +141,33 @@ envvar_set (const char *key)
return TRUE;
}
-static gboolean
-ppd_driver_fake_probe (PpdDriver *driver)
+static PpdProbeResult
+ppd_driver_fake_probe (PpdDriver *driver,
+ PpdProfile *prev_profile)
{
PpdDriverFake *fake;
if (!envvar_set ("POWER_PROFILE_DAEMON_FAKE_DRIVER"))
- return FALSE;
+ return PPD_PROBE_RESULT_FAIL;
fake = PPD_DRIVER_FAKE (driver);
if (!setup_keyboard (fake))
- return FALSE;
+ return PPD_PROBE_RESULT_FAIL;
keyboard_usage ();
+ return PPD_PROBE_RESULT_SUCCESS;
+}
+
+static gboolean
+ppd_driver_fake_activate_profile (PpdDriver *driver,
+ PpdProfile profile,
+ PpdProfileActivationReason reason,
+ GError **error)
+{
+ g_print ("Receive '%s' profile activation for reason '%s'\n",
+ ppd_profile_to_str (profile),
+ ppd_profile_activation_reason_to_str (reason));
+
return TRUE;
}
@@ -156,7 +177,8 @@ ppd_driver_fake_finalize (GObject *object)
PpdDriverFake *fake;
fake = PPD_DRIVER_FAKE (object);
- tcsetattr(STDIN_FILENO, TCSANOW, &fake->old_tio);
+ if (fake->tio_set)
+ tcsetattr(STDIN_FILENO, TCSANOW, &fake->old_tio);
G_OBJECT_CLASS (ppd_driver_fake_parent_class)->finalize (object);
}
@@ -172,6 +194,7 @@ ppd_driver_fake_class_init (PpdDriverFakeClass *klass)
driver_class = PPD_DRIVER_CLASS(klass);
driver_class->probe = ppd_driver_fake_probe;
+ driver_class->activate_profile = ppd_driver_fake_activate_profile;
}
static void
diff --git a/src/ppd-driver-intel-pstate.c b/src/ppd-driver-intel-pstate.c
index 4d21524..de84339 100644
--- a/src/ppd-driver-intel-pstate.c
+++ b/src/ppd-driver-intel-pstate.c
@@ -12,16 +12,14 @@
#include "ppd-utils.h"
#include "ppd-driver-intel-pstate.h"
-#define CPUFREQ_POLICY_DIR "/devices/system/cpu/cpufreq/"
-#define NO_TURBO_PATH "/devices/system/cpu/intel_pstate/no_turbo"
+#define CPUFREQ_POLICY_DIR "/sys/devices/system/cpu/cpufreq/"
+#define NO_TURBO_PATH "/sys/devices/system/cpu/intel_pstate/no_turbo"
struct _PpdDriverIntelPstate
{
PpdDriver parent_instance;
- UpClient *client;
PpdProfile activated_profile;
- gboolean on_battery;
GList *devices; /* GList of paths */
GFileMonitor *no_turbo_mon;
char *no_turbo_path;
@@ -29,9 +27,10 @@ struct _PpdDriverIntelPstate
G_DEFINE_TYPE (PpdDriverIntelPstate, ppd_driver_intel_pstate, PPD_TYPE_DRIVER)
-static gboolean ppd_driver_intel_pstate_activate_profile (PpdDriver *driver,
- PpdProfile profile,
- GError **error);
+static gboolean ppd_driver_intel_pstate_activate_profile (PpdDriver *driver,
+ PpdProfile profile,
+ PpdProfileActivationReason reason,
+ GError **error);
static GObject*
ppd_driver_intel_pstate_constructor (GType type,
@@ -51,28 +50,6 @@ ppd_driver_intel_pstate_constructor (GType type,
return object;
}
-static void
-on_battery_changed (GObject *gobject,
- GParamSpec *pspec,
- gpointer user_data)
-{
- PpdDriverIntelPstate *pstate = user_data;
- gboolean old_on_battery;
-
- old_on_battery = pstate->on_battery;
- pstate->on_battery = up_client_get_on_battery (pstate->client);
-
- if (pstate->activated_profile == PPD_PROFILE_BALANCED) {
- ppd_driver_intel_pstate_activate_profile (PPD_DRIVER (pstate),
- pstate->activated_profile,
- NULL);
- }
-
- g_debug ("Battery status changed from %s to %s",
- old_on_battery ? "on battery" : "on mains",
- pstate->on_battery ? "on battery" : "on mains");
-}
-
static void
update_no_turbo (PpdDriverIntelPstate *pstate)
{
@@ -80,6 +57,7 @@ update_no_turbo (PpdDriverIntelPstate *pstate)
gboolean turbo_disabled = FALSE;
if (g_file_get_contents (pstate->no_turbo_path, &contents, NULL, NULL)) {
+ contents = g_strchomp (contents);
if (g_strcmp0 (contents, "1") == 0)
turbo_disabled = TRUE;
}
@@ -119,54 +97,30 @@ monitor_no_turbo_prop (const char *path)
return g_file_monitor (no_turbo, G_FILE_MONITOR_NONE, NULL, NULL);
}
-static char *
-get_no_turbo_path (void)
-{
- const char *root;
- g_autofree char *dir = NULL;
-
- root = g_getenv ("UMOCKDEV_DIR");
- if (!root || *root == '\0')
- root = "/sys";
-
- return g_build_filename (root, NO_TURBO_PATH, NULL);
-}
-
-static char *
-get_policy_dir (void)
-{
- const char *root;
- g_autofree char *dir = NULL;
-
- root = g_getenv ("UMOCKDEV_DIR");
- if (!root || *root == '\0')
- root = "/sys";
-
- return g_build_filename (root, CPUFREQ_POLICY_DIR, NULL);
-}
-
static GDir *
open_policy_dir (void)
{
g_autofree char *dir = NULL;
- dir = get_policy_dir ();
+ dir = ppd_utils_get_sysfs_path (CPUFREQ_POLICY_DIR);
+ g_debug ("Opening policy dir '%s'", dir);
return g_dir_open (dir, 0, NULL);
}
static gboolean
-ppd_driver_intel_pstate_probe (PpdDriver *driver)
+ppd_driver_intel_pstate_probe (PpdDriver *driver,
+ PpdProfile *prev_profile)
{
PpdDriverIntelPstate *pstate = PPD_DRIVER_INTEL_PSTATE (driver);
g_autoptr(GDir) dir = NULL;
g_autofree char *policy_dir = NULL;
const char *dirname;
- gboolean ret = FALSE;
+ PpdProbeResult ret = PPD_PROBE_RESULT_FAIL;
dir = open_policy_dir ();
if (!dir)
goto out;
- policy_dir = get_policy_dir ();
+ policy_dir = ppd_utils_get_sysfs_path (CPUFREQ_POLICY_DIR);
while ((dirname = g_dir_read_name (dir)) != NULL) {
g_autofree char *path = NULL;
@@ -178,21 +132,14 @@ ppd_driver_intel_pstate_probe (PpdDriver *driver)
continue;
pstate->devices = g_list_prepend (pstate->devices, g_steal_pointer (&path));
- ret = TRUE;
+ ret = PPD_PROBE_RESULT_SUCCESS;
}
- if (!ret)
+ if (ret != PPD_PROBE_RESULT_SUCCESS)
goto out;
- pstate->client = up_client_new ();
- if (pstate->client) {
- g_signal_connect (G_OBJECT (pstate->client), "notify::on-battery",
- G_CALLBACK (on_battery_changed), pstate);
- pstate->on_battery = up_client_get_on_battery (pstate->client);
- }
-
/* Monitor the first "no_turbo" */
- pstate->no_turbo_path = get_no_turbo_path ();
+ pstate->no_turbo_path = ppd_utils_get_sysfs_path (NO_TURBO_PATH);
pstate->no_turbo_mon = monitor_no_turbo_prop (pstate->no_turbo_path);
if (pstate->no_turbo_mon) {
g_signal_connect (G_OBJECT (pstate->no_turbo_mon), "changed",
@@ -202,13 +149,12 @@ ppd_driver_intel_pstate_probe (PpdDriver *driver)
out:
g_debug ("%s p-state settings",
- ret ? "Found" : "Didn't find");
+ ret == PPD_PROBE_RESULT_SUCCESS ? "Found" : "Didn't find");
return ret;
}
static const char *
-profile_to_pref (PpdProfile profile,
- gboolean on_battery)
+profile_to_pref (PpdProfile profile)
{
/* Note that we don't check "energy_performance_available_preferences"
* as all the values are always available */
@@ -216,8 +162,6 @@ profile_to_pref (PpdProfile profile,
case PPD_PROFILE_POWER_SAVER:
return "power";
case PPD_PROFILE_BALANCED:
- if (on_battery)
- return "balance_power";
return "balance_performance";
case PPD_PROFILE_PERFORMANCE:
return "performance";
@@ -227,9 +171,10 @@ profile_to_pref (PpdProfile profile,
}
static gboolean
-ppd_driver_intel_pstate_activate_profile (PpdDriver *driver,
- PpdProfile profile,
- GError **error)
+ppd_driver_intel_pstate_activate_profile (PpdDriver *driver,
+ PpdProfile profile,
+ PpdProfileActivationReason reason,
+ GError **error)
{
PpdDriverIntelPstate *pstate = PPD_DRIVER_INTEL_PSTATE (driver);
gboolean ret = TRUE;
@@ -238,7 +183,7 @@ ppd_driver_intel_pstate_activate_profile (PpdDriver *driver,
g_return_val_if_fail (pstate->devices != NULL, FALSE);
- pref = profile_to_pref (profile, pstate->on_battery);
+ pref = profile_to_pref (profile);
for (l = pstate->devices; l != NULL; l = l->next) {
const char *path = l->data;
@@ -261,7 +206,6 @@ ppd_driver_intel_pstate_finalize (GObject *object)
driver = PPD_DRIVER_INTEL_PSTATE (object);
g_clear_list (&driver->devices, g_free);
- g_clear_object (&driver->client);
g_clear_pointer (&driver->no_turbo_path, g_free);
g_clear_object (&driver->no_turbo_mon);
G_OBJECT_CLASS (ppd_driver_intel_pstate_parent_class)->finalize (object);
diff --git a/src/ppd-driver-lenovo-dytc.c b/src/ppd-driver-lenovo-dytc.c
deleted file mode 100644
index 422349b..0000000
--- a/src/ppd-driver-lenovo-dytc.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (c) 2020 Bastien Nocera <hadess at hadess.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3 as published by
- * the Free Software Foundation.
- *
- */
-
-#include <gudev/gudev.h>
-#include <gio/gio.h>
-
-#include "ppd-driver-lenovo-dytc.h"
-#include "ppd-utils.h"
-
-#define LAPMODE_SYSFS_NAME "dytc_lapmode"
-#define PERFMODE_SYSFS_NAME "dytc_perfmode"
-
-struct _PpdDriverLenovoDytc
-{
- PpdDriver parent_instance;
-
- GUdevClient *client;
- GUdevDevice *device;
- gboolean lapmode;
-};
-
-G_DEFINE_TYPE (PpdDriverLenovoDytc, ppd_driver_lenovo_dytc, PPD_TYPE_DRIVER)
-
-static GObject*
-ppd_driver_lenovo_dytc_constructor (GType type,
- guint n_construct_params,
- GObjectConstructParam *construct_params)
-{
- GObject *object;
-
- object = G_OBJECT_CLASS (ppd_driver_lenovo_dytc_parent_class)->constructor (type,
- n_construct_params,
- construct_params);
- g_object_set (object,
- "driver-name", "lenovo_dytc",
- "profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER,
- NULL);
-
- return object;
-}
-
-static gboolean
-sysfs_attr_as_boolean (GUdevDevice *device,
- const char *attribute)
-{
- g_autofree char *contents = NULL;
- g_autofree char *filename = NULL;
-
- filename = g_build_filename (g_udev_device_get_sysfs_path (device), attribute, NULL);
- if (!g_file_get_contents (filename, &contents, NULL, NULL))
- return FALSE;
-
- g_strdelimit (contents, "\n", '\0');
- return (g_strcmp0 (contents, "1") == 0);
-}
-
-static const char *
-profile_to_perfmode_value (PpdProfile profile)
-{
- switch (profile) {
- case PPD_PROFILE_POWER_SAVER:
- return "L";
- case PPD_PROFILE_BALANCED:
- return "M";
- case PPD_PROFILE_PERFORMANCE:
- return "H";
- }
-
- g_assert_not_reached ();
-}
-
-static void
-update_dytc_state (PpdDriverLenovoDytc *dytc)
-{
- gboolean new_lapmode;
-
- new_lapmode = sysfs_attr_as_boolean (dytc->device, LAPMODE_SYSFS_NAME);
- if (new_lapmode != dytc->lapmode) {
- dytc->lapmode = new_lapmode;
- g_debug ("dytc_lapmode is now %s, so profile is %s",
- dytc->lapmode ? "on" : "off",
- dytc->lapmode ? "inhibited" : "uninhibited");
- g_object_set (G_OBJECT (dytc),
- "performance-inhibited", dytc->lapmode ? "lap-detected" : NULL,
- NULL);
- }
-}
-
-static void
-uevent_cb (GUdevClient *client,
- gchar *action,
- GUdevDevice *device,
- gpointer user_data)
-{
- PpdDriverLenovoDytc *dytc = user_data;
-
- if (g_strcmp0 (action, "change") != 0)
- return;
-
- if (g_strcmp0 (g_udev_device_get_sysfs_path (device),
- g_udev_device_get_sysfs_path (dytc->device)) != 0)
- return;
-
- update_dytc_state (dytc);
-}
-
-static gboolean
-ppd_driver_lenovo_dytc_activate_profile (PpdDriver *driver,
- PpdProfile profile,
- GError **error)
-{
- PpdDriverLenovoDytc *dytc = PPD_DRIVER_LENOVO_DYTC (driver);
-
- g_return_val_if_fail (dytc->client, FALSE);
-
- if (profile == PPD_PROFILE_PERFORMANCE &&
- dytc->lapmode) {
- g_debug ("Can't switch to performance mode, lapmode is detected");
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Mode is inhibited");
- return FALSE;
- }
-
- if (!ppd_utils_write_sysfs (dytc->device, PERFMODE_SYSFS_NAME, profile_to_perfmode_value (profile), error)) {
- g_debug ("Failed to write to perfmode: %s", (* error)->message);
- return FALSE;
- }
-
- g_debug ("Successfully switched to profile %s", ppd_profile_to_str (profile));
- return TRUE;
-}
-
-static gboolean
-ppd_driver_lenovo_dytc_probe (PpdDriver *driver)
-{
- const gchar * const subsystem[] = { "platform", NULL };
- GList *devices, *l;
- gboolean ret = FALSE;
- PpdDriverLenovoDytc *dytc = PPD_DRIVER_LENOVO_DYTC (driver);
-
- g_return_val_if_fail (!dytc->client, FALSE);
-
- dytc->client = g_udev_client_new (subsystem);
- devices = g_udev_client_query_by_subsystem (dytc->client, "platform");
- if (devices == NULL)
- goto out;
-
- for (l = devices; l != NULL; l = l->next) {
- GUdevDevice *dev = l->data;
-
- if (g_strcmp0 (g_udev_device_get_name (dev), "thinkpad_acpi") != 0)
- continue;
-
- if (!g_udev_device_get_sysfs_attr (dev, LAPMODE_SYSFS_NAME) ||
- !g_udev_device_get_sysfs_attr (dev, PERFMODE_SYSFS_NAME))
- break;
-
- dytc->device = g_object_ref (dev);
- ret = TRUE;
- break;
- }
-
- if (ret) {
- g_signal_connect (G_OBJECT (dytc->client), "uevent",
- G_CALLBACK (uevent_cb), dytc);
- update_dytc_state (dytc);
- }
-
-out:
- g_list_free_full (devices, g_object_unref);
-
- g_debug ("%s a dytc_lapmode sysfs attribute to thinkpad_acpi",
- ret ? "Found" : "Didn't find");
- return ret;
-}
-
-static void
-ppd_driver_lenovo_dytc_finalize (GObject *object)
-{
- PpdDriverLenovoDytc *driver;
-
- driver = PPD_DRIVER_LENOVO_DYTC (object);
- g_clear_object (&driver->device);
- g_clear_object (&driver->client);
- G_OBJECT_CLASS (ppd_driver_lenovo_dytc_parent_class)->finalize (object);
-}
-
-static void
-ppd_driver_lenovo_dytc_class_init (PpdDriverLenovoDytcClass *klass)
-{
- GObjectClass *object_class;
- PpdDriverClass *driver_class;
-
- object_class = G_OBJECT_CLASS(klass);
- object_class->constructor = ppd_driver_lenovo_dytc_constructor;
- object_class->finalize = ppd_driver_lenovo_dytc_finalize;
-
- driver_class = PPD_DRIVER_CLASS(klass);
- driver_class->probe = ppd_driver_lenovo_dytc_probe;
- driver_class->activate_profile = ppd_driver_lenovo_dytc_activate_profile;
-}
-
-static void
-ppd_driver_lenovo_dytc_init (PpdDriverLenovoDytc *self)
-{
-}
diff --git a/src/ppd-driver-placeholder.c b/src/ppd-driver-placeholder.c
new file mode 100644
index 0000000..11d9e93
--- /dev/null
+++ b/src/ppd-driver-placeholder.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Bastien Nocera <hadess at hadess.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published by
+ * the Free Software Foundation.
+ *
+ */
+
+#include "ppd-driver-placeholder.h"
+
+struct _PpdDriverPlaceholder
+{
+ PpdDriver parent_instance;
+};
+
+G_DEFINE_TYPE (PpdDriverPlaceholder, ppd_driver_placeholder, PPD_TYPE_DRIVER)
+
+static GObject*
+ppd_driver_placeholder_constructor (GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+
+ object = G_OBJECT_CLASS (ppd_driver_placeholder_parent_class)->constructor (type,
+ n_construct_params,
+ construct_params);
+ g_object_set (object,
+ "driver-name", "placeholder",
+ "profiles", PPD_PROFILE_POWER_SAVER | PPD_PROFILE_BALANCED,
+ NULL);
+
+ return object;
+}
+
+static void
+ppd_driver_placeholder_class_init (PpdDriverPlaceholderClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS(klass);
+ object_class->constructor = ppd_driver_placeholder_constructor;
+}
+
+static void
+ppd_driver_placeholder_init (PpdDriverPlaceholder *self)
+{
+}
diff --git a/src/ppd-driver-lenovo-dytc.h b/src/ppd-driver-placeholder.h
similarity index 64%
rename from src/ppd-driver-lenovo-dytc.h
rename to src/ppd-driver-placeholder.h
index 64157cb..a822790 100644
--- a/src/ppd-driver-lenovo-dytc.h
+++ b/src/ppd-driver-placeholder.h
@@ -11,5 +11,5 @@
#include "ppd-driver.h"
-#define PPD_TYPE_DRIVER_LENOVO_DYTC (ppd_driver_lenovo_dytc_get_type())
-G_DECLARE_FINAL_TYPE(PpdDriverLenovoDytc, ppd_driver_lenovo_dytc, PPD, DRIVER_LENOVO_DYTC, PpdDriver)
+#define PPD_TYPE_DRIVER_PLACEHOLDER (ppd_driver_placeholder_get_type())
+G_DECLARE_FINAL_TYPE(PpdDriverPlaceholder, ppd_driver_placeholder, PPD, DRIVER_PLACEHOLDER, PpdDriver)
diff --git a/src/ppd-driver-platform-profile.c b/src/ppd-driver-platform-profile.c
new file mode 100644
index 0000000..9e20ee8
--- /dev/null
+++ b/src/ppd-driver-platform-profile.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2020 Bastien Nocera <hadess at hadess.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published by
+ * the Free Software Foundation.
+ *
+ */
+
+#include <gudev/gudev.h>
+#include <gio/gio.h>
+
+#include "ppd-driver-platform-profile.h"
+#include "ppd-utils.h"
+
+#define LAPMODE_SYSFS_NAME "dytc_lapmode"
+#define ACPI_PLATFORM_PROFILE_PATH "/sys/firmware/acpi/platform_profile"
+#define ACPI_PLATFORM_PROFILE_CHOICES_PATH "/sys/firmware/acpi/platform_profile_choices"
+
+struct _PpdDriverPlatformProfile
+{
+ PpdDriver parent_instance;
+
+ PpdProbeResult probe_result;
+ GUdevDevice *device;
+ int lapmode;
+ PpdProfile acpi_platform_profile;
+ char **profile_choices;
+ GFileMonitor *lapmode_mon;
+ GFileMonitor *acpi_platform_profile_mon;
+ guint acpi_platform_profile_changed_id;
+};
+
+G_DEFINE_TYPE (PpdDriverPlatformProfile, ppd_driver_platform_profile, PPD_TYPE_DRIVER)
+
+static GObject*
+ppd_driver_platform_profile_constructor (GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+
+ object = G_OBJECT_CLASS (ppd_driver_platform_profile_parent_class)->constructor (type,
+ n_construct_params,
+ construct_params);
+ g_object_set (object,
+ "driver-name", "platform_profile",
+ "profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER,
+ NULL);
+
+ return object;
+}
+
+static const char *
+profile_to_acpi_platform_profile_value (PpdDriverPlatformProfile *self,
+ PpdProfile profile)
+{
+ switch (profile) {
+ case PPD_PROFILE_POWER_SAVER:
+ if (g_strv_contains ((const char * const*) self->profile_choices, "low-power"))
+ return "low-power";
+ return "cool";
+ case PPD_PROFILE_BALANCED:
+ return "balanced";
+ case PPD_PROFILE_PERFORMANCE:
+ return "performance";
+ }
+
+ g_assert_not_reached ();
+}
+
+static PpdProfile
+acpi_platform_profile_value_to_profile (const char *str)
+{
+ if (str == NULL)
+ return PPD_PROFILE_UNSET;
+
+ switch (str[0]) {
+ case 'l': /* low-power */
+ case 'c': /* cool */
+ case 'q': /* quiet */
+ return PPD_PROFILE_POWER_SAVER;
+ case 'b':
+ return PPD_PROFILE_BALANCED;
+ case 'p':
+ return PPD_PROFILE_PERFORMANCE;
+ default:
+ g_debug ("Got unsupported performance_profile value '%s'", str);
+ }
+
+ return PPD_PROFILE_UNSET;
+}
+
+static PpdProfile
+read_platform_profile (void)
+{
+ g_autofree char *platform_profile_path = NULL;
+ g_autofree char *new_profile_str = NULL;
+ g_autoptr(GError) error = NULL;
+ PpdProfile new_profile;
+
+ platform_profile_path = ppd_utils_get_sysfs_path (ACPI_PLATFORM_PROFILE_PATH);
+ if (!g_file_get_contents (platform_profile_path,
+ &new_profile_str, NULL, NULL)) {
+ g_debug ("Failed to get contents for '%s': %s",
+ platform_profile_path,
+ error->message);
+ return PPD_PROFILE_UNSET;
+ }
+
+ new_profile = acpi_platform_profile_value_to_profile (new_profile_str);
+ g_debug ("ACPI performance_profile is now %c, so profile is detected as %s",
+ new_profile_str[0],
+ ppd_profile_to_str (new_profile));
+ return new_profile;
+}
+
+static gboolean
+save_platform_profile_choices (PpdDriverPlatformProfile *self)
+{
+ g_autofree char *platform_profile_choices_path = NULL;
+ g_autofree char *choices_str = NULL;
+ g_autoptr(GError) error = NULL;
+
+ platform_profile_choices_path = ppd_utils_get_sysfs_path (ACPI_PLATFORM_PROFILE_CHOICES_PATH);
+ if (!g_file_get_contents (platform_profile_choices_path,
+ &choices_str, NULL, NULL)) {
+ return FALSE;
+ }
+
+ self->profile_choices = g_strsplit_set (choices_str, " \n", -1);
+ return TRUE;
+}
+
+static PpdProbeResult
+verify_acpi_platform_profile_choices (PpdDriverPlatformProfile *self)
+{
+ const char * const *choices = (const char * const*) self->profile_choices;
+
+ if ((g_strv_contains (choices, "low-power") ||
+ g_strv_contains (choices, "cool")) &&
+ g_strv_contains (choices, "balanced") &&
+ g_strv_contains (choices, "performance"))
+ return PPD_PROBE_RESULT_SUCCESS;
+ return PPD_PROBE_RESULT_DEFER;
+}
+
+static void
+update_dytc_lapmode_state (PpdDriverPlatformProfile *self)
+{
+ int new_lapmode;
+
+ new_lapmode = g_udev_device_get_sysfs_attr_as_int_uncached (self->device, LAPMODE_SYSFS_NAME);
+ if (new_lapmode == self->lapmode)
+ return;
+
+ self->lapmode = new_lapmode;
+ g_debug ("dytc_lapmode is now %s, so profile is %s",
+ self->lapmode ? "on" : "off",
+ self->lapmode ? "inhibited" : "uninhibited");
+ g_object_set (G_OBJECT (self),
+ "performance-inhibited", self->lapmode ? "lap-detected" : NULL,
+ NULL);
+}
+
+static void
+update_acpi_platform_profile_state (PpdDriverPlatformProfile *self)
+{
+ PpdProfile new_profile;
+
+ new_profile = read_platform_profile ();
+ if (new_profile == PPD_PROFILE_UNSET ||
+ new_profile == self->acpi_platform_profile)
+ return;
+
+ self->acpi_platform_profile = new_profile;
+ ppd_driver_emit_profile_changed (PPD_DRIVER (self), new_profile);
+}
+
+static void
+lapmode_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ gpointer user_data)
+{
+ PpdDriverPlatformProfile *self = user_data;
+ g_debug (LAPMODE_SYSFS_NAME " attribute changed");
+ update_dytc_lapmode_state (self);
+}
+
+static void
+acpi_platform_profile_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ gpointer user_data)
+{
+ PpdDriverPlatformProfile *self = user_data;
+ g_debug (ACPI_PLATFORM_PROFILE_PATH " changed");
+ if (self->probe_result == PPD_PROBE_RESULT_DEFER) {
+ g_signal_emit_by_name (G_OBJECT (self), "probe-request", 0);
+ return;
+ }
+ update_acpi_platform_profile_state (self);
+}
+
+static gboolean
+ppd_driver_platform_profile_activate_profile (PpdDriver *driver,
+ PpdProfile profile,
+ PpdProfileActivationReason reason,
+ GError **error)
+{
+ PpdDriverPlatformProfile *self = PPD_DRIVER_PLATFORM_PROFILE (driver);
+ g_autofree char *platform_profile_path = NULL;
+
+ g_return_val_if_fail (self->acpi_platform_profile_mon, FALSE);
+
+ if (self->acpi_platform_profile == profile) {
+ g_debug ("Can't switch to %s mode, already there",
+ ppd_profile_to_str (profile));
+ return TRUE;
+ }
+
+ if (profile == PPD_PROFILE_PERFORMANCE &&
+ self->lapmode) {
+ g_debug ("Can't switch to performance mode, lapmode is detected");
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Mode is inhibited");
+ return FALSE;
+ }
+
+ g_signal_handler_block (G_OBJECT (self->acpi_platform_profile_mon), self->acpi_platform_profile_changed_id);
+ platform_profile_path = ppd_utils_get_sysfs_path (ACPI_PLATFORM_PROFILE_PATH);
+ if (!ppd_utils_write (platform_profile_path, profile_to_acpi_platform_profile_value (self, profile), error)) {
+ g_debug ("Failed to write to acpi_platform_profile: %s", (* error)->message);
+ g_signal_handler_unblock (G_OBJECT (self->acpi_platform_profile_mon), self->acpi_platform_profile_changed_id);
+ return FALSE;
+ }
+ g_signal_handler_unblock (G_OBJECT (self->acpi_platform_profile_mon), self->acpi_platform_profile_changed_id);
+
+ g_debug ("Successfully switched to profile %s", ppd_profile_to_str (profile));
+ self->acpi_platform_profile = profile;
+ return TRUE;
+}
+
+static int
+find_dytc (GUdevDevice *dev,
+ gpointer user_data)
+{
+ if (g_strcmp0 (g_udev_device_get_name (dev), "thinkpad_acpi") != 0)
+ return 1;
+
+ if (!g_udev_device_get_sysfs_attr (dev, LAPMODE_SYSFS_NAME))
+ return 1;
+
+ return 0;
+}
+
+static PpdProbeResult
+ppd_driver_platform_profile_probe (PpdDriver *driver,
+ PpdProfile *prev_profile)
+{
+ PpdDriverPlatformProfile *self = PPD_DRIVER_PLATFORM_PROFILE (driver);
+ g_autoptr(GFile) acpi_platform_profile = NULL;
+ g_autofree char *platform_profile_path = NULL;
+
+ g_return_val_if_fail (self->probe_result == PPD_PROBE_RESULT_UNSET, PPD_PROBE_RESULT_FAIL);
+
+ /* Profile interface */
+ platform_profile_path = ppd_utils_get_sysfs_path (ACPI_PLATFORM_PROFILE_PATH);
+ if (!g_file_test (platform_profile_path, G_FILE_TEST_EXISTS)) {
+ g_debug ("No platform_profile sysfs file");
+ return PPD_PROBE_RESULT_FAIL;
+ }
+ if (!save_platform_profile_choices (self))
+ return PPD_PROBE_RESULT_FAIL;
+ self->probe_result = verify_acpi_platform_profile_choices (self);
+ if (self->probe_result == PPD_PROBE_RESULT_FAIL) {
+ g_debug ("No supported platform_profile choices");
+ return self->probe_result;
+ }
+
+ acpi_platform_profile = g_file_new_for_path (platform_profile_path);
+ self->acpi_platform_profile_mon = g_file_monitor (acpi_platform_profile,
+ G_FILE_MONITOR_NONE,
+ NULL,
+ NULL);
+ self->acpi_platform_profile_changed_id =
+ g_signal_connect (G_OBJECT (self->acpi_platform_profile_mon), "changed",
+ G_CALLBACK (acpi_platform_profile_changed), self);
+ if (self->probe_result == PPD_PROBE_RESULT_DEFER) {
+ g_debug ("Monitoring platform_profile sysfs file");
+ return self->probe_result;
+ }
+
+ *prev_profile = read_platform_profile ();
+
+ /* Lenovo-specific proximity sensor */
+ self->device = ppd_utils_find_device ("platform",
+ (GCompareFunc) find_dytc,
+ NULL);
+ if (!self->device)
+ goto out;
+
+ self->lapmode_mon = ppd_utils_monitor_sysfs_attr (self->device,
+ LAPMODE_SYSFS_NAME,
+ NULL);
+ g_signal_connect (G_OBJECT (self->lapmode_mon), "changed",
+ G_CALLBACK (lapmode_changed), self);
+ update_dytc_lapmode_state (self);
+
+out:
+ update_acpi_platform_profile_state (self);
+
+ g_debug ("%s a dytc_lapmode sysfs attribute to thinkpad_acpi",
+ self->device ? "Found" : "Didn't find");
+ return PPD_PROBE_RESULT_SUCCESS;
+}
+
+static void
+ppd_driver_platform_profile_finalize (GObject *object)
+{
+ PpdDriverPlatformProfile *driver;
+
+ driver = PPD_DRIVER_PLATFORM_PROFILE (object);
+ g_clear_pointer (&driver->profile_choices, g_strfreev);
+ g_clear_object (&driver->device);
+ g_clear_object (&driver->lapmode_mon);
+ g_clear_object (&driver->acpi_platform_profile_mon);
+ G_OBJECT_CLASS (ppd_driver_platform_profile_parent_class)->finalize (object);
+}
+
+static void
+ppd_driver_platform_profile_class_init (PpdDriverPlatformProfileClass *klass)
+{
+ GObjectClass *object_class;
+ PpdDriverClass *driver_class;
+
+ object_class = G_OBJECT_CLASS(klass);
+ object_class->constructor = ppd_driver_platform_profile_constructor;
+ object_class->finalize = ppd_driver_platform_profile_finalize;
+
+ driver_class = PPD_DRIVER_CLASS(klass);
+ driver_class->probe = ppd_driver_platform_profile_probe;
+ driver_class->activate_profile = ppd_driver_platform_profile_activate_profile;
+}
+
+static void
+ppd_driver_platform_profile_init (PpdDriverPlatformProfile *self)
+{
+ self->probe_result = PPD_PROBE_RESULT_UNSET;
+}
diff --git a/src/ppd-driver-balanced.h b/src/ppd-driver-platform-profile.h
similarity index 59%
rename from src/ppd-driver-balanced.h
rename to src/ppd-driver-platform-profile.h
index ce829ad..916fd7e 100644
--- a/src/ppd-driver-balanced.h
+++ b/src/ppd-driver-platform-profile.h
@@ -11,5 +11,5 @@
#include "ppd-driver.h"
-#define PPD_TYPE_DRIVER_BALANCED (ppd_driver_balanced_get_type())
-G_DECLARE_FINAL_TYPE(PpdDriverBalanced, ppd_driver_balanced, PPD, DRIVER_BALANCED, PpdDriver)
+#define PPD_TYPE_DRIVER_PLATFORM_PROFILE (ppd_driver_platform_profile_get_type())
+G_DECLARE_FINAL_TYPE(PpdDriverPlatformProfile, ppd_driver_platform_profile, PPD, DRIVER_PLATFORM_PROFILE, PpdDriver)
diff --git a/src/ppd-driver-power-saver.c b/src/ppd-driver-power-saver.c
deleted file mode 100644
index d0ab9df..0000000
--- a/src/ppd-driver-power-saver.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020 Bastien Nocera <hadess at hadess.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3 as published by
- * the Free Software Foundation.
- *
- */
-
-#include "ppd-driver-power-saver.h"
-
-struct _PpdDriverPowerSaver
-{
- PpdDriver parent_instance;
-};
-
-G_DEFINE_TYPE (PpdDriverPowerSaver, ppd_driver_power_saver, PPD_TYPE_DRIVER)
-
-static GObject*
-ppd_driver_power_saver_constructor (GType type,
- guint n_construct_params,
- GObjectConstructParam *construct_params)
-{
- GObject *object;
-
- object = G_OBJECT_CLASS (ppd_driver_power_saver_parent_class)->constructor (type,
- n_construct_params,
- construct_params);
- g_object_set (object,
- "driver-name", "power-saver",
- "profiles", PPD_PROFILE_POWER_SAVER,
- NULL);
-
- return object;
-}
-
-static void
-ppd_driver_power_saver_class_init (PpdDriverPowerSaverClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS(klass);
- object_class->constructor = ppd_driver_power_saver_constructor;
-}
-
-static void
-ppd_driver_power_saver_init (PpdDriverPowerSaver *self)
-{
-}
diff --git a/src/ppd-driver-power-saver.h b/src/ppd-driver-power-saver.h
deleted file mode 100644
index 7b1ee49..0000000
--- a/src/ppd-driver-power-saver.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2020 Bastien Nocera <hadess at hadess.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3 as published by
- * the Free Software Foundation.
- *
- */
-
-#pragma once
-
-#include "ppd-driver.h"
-
-#define PPD_TYPE_DRIVER_POWER_SAVER (ppd_driver_power_saver_get_type())
-G_DECLARE_FINAL_TYPE(PpdDriverPowerSaver, ppd_driver_power_saver, PPD, DRIVER_POWER_SAVER, PpdDriver)
diff --git a/src/ppd-driver.c b/src/ppd-driver.c
index 0bfc2bf..8ccd305 100644
--- a/src/ppd-driver.c
+++ b/src/ppd-driver.c
@@ -53,6 +53,14 @@ enum {
PROP_PERFORMANCE_INHIBITED
};
+enum {
+ PROFILE_CHANGED,
+ PROBE_REQUEST,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
#define PPD_DRIVER_GET_PRIVATE(o) (ppd_driver_get_instance_private (o))
G_DEFINE_TYPE_WITH_PRIVATE (PpdDriver, ppd_driver, G_TYPE_OBJECT)
@@ -128,6 +136,41 @@ ppd_driver_class_init (PpdDriverClass *klass)
object_class->get_property = ppd_driver_get_property;
object_class->set_property = ppd_driver_set_property;
+ /**
+ * PpdDriver::profile-changed:
+ * @profile: the updated #PpdProfile
+ *
+ * Emitted when the profile was changed from the outside, usually
+ * by key combinations implemented in firmware.
+ */
+ signals[PROFILE_CHANGED] = g_signal_new ("profile-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 1,
+ PPD_TYPE_PROFILE);
+
+
+ /**
+ * PpdDriver::probe-request
+ *
+ * The driver requested to be reprobed, because it became available.
+ */
+ signals[PROBE_REQUEST] = g_signal_new ("probe-request",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 0,
+ G_TYPE_NONE);
+
/**
* PpdDriver::driver-name:
*
@@ -172,21 +215,32 @@ ppd_driver_init (PpdDriver *self)
{
}
-gboolean
-ppd_driver_probe (PpdDriver *driver)
+PpdProbeResult
+ppd_driver_probe (PpdDriver *driver,
+ PpdProfile *previous_profile)
{
+ PpdProfile profile = PPD_PROFILE_UNSET;
+ PpdProbeResult ret;
+
g_return_val_if_fail (PPD_IS_DRIVER (driver), FALSE);
+ g_return_val_if_fail (previous_profile != NULL, FALSE);
if (!PPD_DRIVER_GET_CLASS (driver)->probe)
- return TRUE;
-
- return PPD_DRIVER_GET_CLASS (driver)->probe (driver);
+ return PPD_PROBE_RESULT_SUCCESS;
+
+ ret = PPD_DRIVER_GET_CLASS (driver)->probe (driver, &profile);
+ if (ret == PPD_PROBE_RESULT_SUCCESS &&
+ profile != PPD_PROFILE_UNSET &&
+ ppd_profile_has_single_flag (profile))
+ *previous_profile = profile;
+ return ret;
}
gboolean
-ppd_driver_activate_profile (PpdDriver *driver,
- PpdProfile profile,
- GError **error)
+ppd_driver_activate_profile (PpdDriver *driver,
+ PpdProfile profile,
+ PpdProfileActivationReason reason,
+ GError **error)
{
g_return_val_if_fail (PPD_IS_DRIVER (driver), FALSE);
g_return_val_if_fail (ppd_profile_has_single_flag (profile), FALSE);
@@ -194,7 +248,7 @@ ppd_driver_activate_profile (PpdDriver *driver,
if (!PPD_DRIVER_GET_CLASS (driver)->activate_profile)
return TRUE;
- return PPD_DRIVER_GET_CLASS (driver)->activate_profile (driver, profile, error);
+ return PPD_DRIVER_GET_CLASS (driver)->activate_profile (driver, profile, reason, error);
}
const char *
@@ -252,3 +306,32 @@ ppd_driver_is_performance_inhibited (PpdDriver *driver)
return (priv->performance_inhibited != NULL);
}
+
+void
+ppd_driver_emit_profile_changed (PpdDriver *driver,
+ PpdProfile profile)
+{
+ g_return_if_fail (PPD_IS_DRIVER (driver));
+ g_return_if_fail (ppd_profile_has_single_flag (profile));
+
+ g_signal_emit_by_name (G_OBJECT (driver),
+ "profile-changed",
+ profile);
+}
+
+const char *
+ppd_profile_activation_reason_to_str (PpdProfileActivationReason reason)
+{
+ switch (reason) {
+ case PPD_PROFILE_ACTIVATION_REASON_INHIBITION:
+ return "inhibition";
+ case PPD_PROFILE_ACTIVATION_REASON_INTERNAL:
+ return "internal";
+ case PPD_PROFILE_ACTIVATION_REASON_RESET:
+ return "reset";
+ case PPD_PROFILE_ACTIVATION_REASON_USER:
+ return "user";
+ default:
+ g_assert_not_reached ();
+ }
+}
diff --git a/src/ppd-driver.h b/src/ppd-driver.h
index b405fe4..7885c1e 100644
--- a/src/ppd-driver.h
+++ b/src/ppd-driver.h
@@ -15,6 +15,46 @@
#define PPD_TYPE_DRIVER (ppd_driver_get_type())
G_DECLARE_DERIVABLE_TYPE(PpdDriver, ppd_driver, PPD, DRIVER, GObject)
+/**
+ * PpdProbeResult:
+ * @PPD_PROBE_RESULT_UNSET: unset
+ * @PPD_PROBE_RESULT_DEFER: driver should be kept alive, as kernel
+ * support might appear.
+ * @PPD_PROBE_RESULT_FAIL: driver failed to load.
+ * @PPD_PROBE_RESULT_SUCCESS: driver successfully loaded.
+ *
+ * Those are the three possible values returned by a driver probe,
+ * along with an unset value for convenience.
+ */
+typedef enum {
+ PPD_PROBE_RESULT_UNSET = -2,
+ PPD_PROBE_RESULT_DEFER = -1,
+ PPD_PROBE_RESULT_FAIL = 0,
+ PPD_PROBE_RESULT_SUCCESS = 1
+} PpdProbeResult;
+
+/**
+ * PpdProfileActivationReason:
+ * PPD_PROFILE_ACTIVATION_REASON_INHIBITION: switching profiles because
+ * of performance profile inhibition.
+ * PPD_PROFILE_ACTIVATION_REASON_INTERNAL: the driver profile changed
+ * internally, usually because of a key combination.
+ * PPD_PROFILE_ACTIVATION_REASON_RESET: setting profile on startup, or
+ * because drivers are getting reprobed.
+ * PPD_PROFILE_ACTIVATION_REASON_USER: setting profile because the user
+ * requested it.
+ *
+ * Those are possible reasons for a profile being activated. Based on those
+ * reasons, drivers can choose whether or not that changes the effective
+ * profile internally.
+ */
+typedef enum{
+ PPD_PROFILE_ACTIVATION_REASON_INHIBITION = 0,
+ PPD_PROFILE_ACTIVATION_REASON_INTERNAL,
+ PPD_PROFILE_ACTIVATION_REASON_RESET,
+ PPD_PROFILE_ACTIVATION_REASON_USER
+} PpdProfileActivationReason;
+
/**
* PpdDriverClass:
* @parent_class: The parent class.
@@ -28,17 +68,22 @@ struct _PpdDriverClass
{
GObjectClass parent_class;
- gboolean (* probe) (PpdDriver *driver);
- gboolean (* activate_profile) (PpdDriver *driver,
- PpdProfile profile,
- GError **error);
+ PpdProbeResult (* probe) (PpdDriver *driver,
+ PpdProfile *previous_profile);
+ gboolean (* activate_profile) (PpdDriver *driver,
+ PpdProfile profile,
+ PpdProfileActivationReason reason,
+ GError **error);
};
#ifndef __GTK_DOC_IGNORE__
-gboolean ppd_driver_probe (PpdDriver *driver);
-gboolean ppd_driver_activate_profile (PpdDriver *driver, PpdProfile profile, GError **error);
+PpdProbeResult ppd_driver_probe (PpdDriver *driver, PpdProfile *previous_profile);
+gboolean ppd_driver_activate_profile (PpdDriver *driver,
+ PpdProfile profile, PpdProfileActivationReason reason, GError **error);
const char *ppd_driver_get_driver_name (PpdDriver *driver);
PpdProfile ppd_driver_get_profiles (PpdDriver *driver);
const char *ppd_driver_get_performance_inhibited (PpdDriver *driver);
gboolean ppd_driver_is_performance_inhibited (PpdDriver *driver);
+void ppd_driver_emit_profile_changed (PpdDriver *driver, PpdProfile profile);
+const char *ppd_profile_activation_reason_to_str (PpdProfileActivationReason reason);
#endif
diff --git a/src/ppd-utils.c b/src/ppd-utils.c
index d80e7cf..553a1e0 100644
--- a/src/ppd-utils.c
+++ b/src/ppd-utils.c
@@ -12,6 +12,18 @@
#include <stdio.h>
#include <errno.h>
+char *
+ppd_utils_get_sysfs_path (const char *filename)
+{
+ const char *root;
+
+ root = g_getenv ("UMOCKDEV_DIR");
+ if (!root || *root == '\0')
+ root = "/";
+
+ return g_build_filename (root, filename, NULL);
+}
+
gboolean ppd_utils_write (const char *filename,
const char *value,
GError **error)
@@ -54,3 +66,52 @@ gboolean ppd_utils_write_sysfs (GUdevDevice *device,
filename = g_build_filename (g_udev_device_get_sysfs_path (device), attribute, NULL);
return ppd_utils_write (filename, value, error);
}
+
+GFileMonitor *
+ppd_utils_monitor_sysfs_attr (GUdevDevice *device,
+ const char *attribute,
+ GError **error)
+{
+ g_autofree char *path = NULL;
+ g_autoptr(GFile) file = NULL;
+
+ path = g_build_filename (g_udev_device_get_sysfs_path (device), attribute, NULL);
+ file = g_file_new_for_path (path);
+ return g_file_monitor_file (file,
+ G_FILE_MONITOR_NONE,
+ NULL,
+ error);
+}
+
+GUdevDevice *
+ppd_utils_find_device (const char *subsystem,
+ GCompareFunc func,
+ gpointer user_data)
+{
+ const gchar * subsystems[] = { NULL, NULL };
+ g_autoptr(GUdevClient) client = NULL;
+ GUdevDevice *ret = NULL;
+ GList *devices, *l;
+
+ g_return_val_if_fail (subsystem != NULL, NULL);
+ g_return_val_if_fail (func != NULL, NULL);
+
+ subsystems[0] = subsystem;
+ client = g_udev_client_new (subsystems);
+ devices = g_udev_client_query_by_subsystem (client, subsystem);
+ if (devices == NULL)
+ return NULL;
+
+ for (l = devices; l != NULL; l = l->next) {
+ GUdevDevice *dev = l->data;
+
+ if ((func) (dev, user_data) != 0)
+ continue;
+
+ ret = g_object_ref (dev);
+ break;
+ }
+ g_list_free_full (devices, g_object_unref);
+
+ return ret;
+}
diff --git a/src/ppd-utils.h b/src/ppd-utils.h
index bee7f5a..9b12e5b 100644
--- a/src/ppd-utils.h
+++ b/src/ppd-utils.h
@@ -10,7 +10,9 @@
#pragma once
#include <gudev/gudev.h>
+#include <gio/gio.h>
+char * ppd_utils_get_sysfs_path (const char *filename);
gboolean ppd_utils_write (const char *filename,
const char *value,
GError **error);
@@ -18,3 +20,9 @@ gboolean ppd_utils_write_sysfs (GUdevDevice *device,
const char *attribute,
const char *value,
GError **error);
+GFileMonitor *ppd_utils_monitor_sysfs_attr (GUdevDevice *device,
+ const char *attribute,
+ GError **error);
+GUdevDevice *ppd_utils_find_device (const char *subsystem,
+ GCompareFunc func,
+ gpointer user_data);
diff --git a/tests/integration-test b/tests/integration-test
index 54eec01..3ca5643 100755
--- a/tests/integration-test
+++ b/tests/integration-test
@@ -59,12 +59,10 @@ class Tests(dbusmock.DBusTestCase):
if os.access(os.path.join(builddir, 'src', 'power-profiles-daemon'), os.X_OK):
cls.daemon_path = os.path.join(builddir, 'src', 'power-profiles-daemon')
print('Testing binaries from local build tree (%s)' % cls.daemon_path)
- cls.local_daemon = True
elif os.environ.get('UNDER_JHBUILD', False):
jhbuild_prefix = os.environ['JHBUILD_PREFIX']
cls.daemon_path = os.path.join(jhbuild_prefix, 'libexec', 'power-profiles-daemon')
print('Testing binaries from JHBuild (%s)' % cls.daemon_path)
- cls.local_daemon = False
else:
cls.daemon_path = None
with open('/usr/lib/systemd/system/power-profiles-daemon.service') as f:
@@ -73,13 +71,13 @@ class Tests(dbusmock.DBusTestCase):
cls.daemon_path = line.split('=', 1)[1].strip()
break
assert cls.daemon_path, 'could not determine daemon path from systemd .service file'
- cls.local_daemon = False
print('Testing installed system binary (%s)' % cls.daemon_path)
- # fail on CRITICALs on client side
+ # fail on CRITICALs on client and server side
GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_WARNING |
GLib.LogLevelFlags.LEVEL_ERROR |
GLib.LogLevelFlags.LEVEL_CRITICAL)
+ os.environ['G_DEBUG'] = 'fatal_warnings'
# set up a fake system D-BUS
cls.test_bus = Gio.TestDBus.new(Gio.TestDBusFlags.NONE)
@@ -109,9 +107,13 @@ class Tests(dbusmock.DBusTestCase):
self.log = None
self.daemon = None
+ # Used for dytc devices
+ self.tp_acpi = None
+
def tearDown(self):
del self.testbed
self.stop_daemon()
+ del self.tp_acpi
# on failures, print daemon log
errors = [x[1] for x in self._outcome.errors if x[1]]
@@ -138,10 +140,7 @@ class Tests(dbusmock.DBusTestCase):
env['UMOCKDEV_DIR'] = self.testbed.get_root_dir()
self.log = tempfile.NamedTemporaryFile()
if os.getenv('VALGRIND') != None:
- if self.local_daemon:
- daemon_path = ['libtool', '--mode=execute', 'valgrind', self.daemon_path, '-v']
- else:
- daemon_path = ['valgrind', self.daemon_path, '-v']
+ daemon_path = ['valgrind', self.daemon_path, '-v']
else:
daemon_path = [self.daemon_path, '-v']
@@ -203,16 +202,33 @@ class Tests(dbusmock.DBusTestCase):
with open(self.log.name) as f:
return f.read().count(text)
- def read_sysfs_attr(self, device, attribute):
- with open(os.path.join(self.testbed.get_root_dir() + device, attribute), 'rb') as f:
- return f.read()
+ def read_sysfs_file(self, path):
+ with open(self.testbed.get_root_dir() + '/' + path, 'rb') as f:
+ return f.read().rstrip()
return None
+ def read_sysfs_attr(self, device, attribute):
+ return self.read_sysfs_file(device + '/' + attribute)
+
def read_file(self, path):
with open(path, 'rb') as f:
return f.read()
return None
+ def create_dytc_device(self):
+ self.tp_acpi = self.testbed.add_device('platform', 'thinkpad_acpi', None,
+ ['dytc_lapmode', '0\n'],
+ [ 'DEVPATH', '/devices/platform/thinkpad_acpi' ]
+ )
+
+ def create_platform_profile(self):
+ acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
+ os.makedirs(acpi_dir)
+ with open(os.path.join(acpi_dir, "platform_profile") ,'w') as profile:
+ profile.write("performance\n")
+ with open(os.path.join(acpi_dir, "platform_profile_choices") ,'w') as choices:
+ choices.write("low-power balanced performance\n")
+
def assertEventually(self, condition, message=None, timeout=50):
'''Assert that condition function eventually returns True.
@@ -233,6 +249,13 @@ class Tests(dbusmock.DBusTestCase):
#
# Actual test cases
#
+ def test_dbus_startup_error(self):
+ '''D-Bus startup error'''
+
+ self.start_daemon()
+ out = subprocess.run([self.daemon_path], capture_output=True)
+ self.assertEqual(out.returncode, 1, "power-profile-daemon started but should have failed")
+ self.stop_daemon()
def test_no_performance_driver(self):
'''no performance driver'''
@@ -243,8 +266,8 @@ class Tests(dbusmock.DBusTestCase):
profiles = self.get_dbus_property('Profiles')
self.assertEqual(len(profiles), 2)
- self.assertEqual(profiles[1]['Driver'], 'balanced')
- self.assertEqual(profiles[0]['Driver'], 'power-saver')
+ self.assertEqual(profiles[1]['Driver'], 'placeholder')
+ self.assertEqual(profiles[0]['Driver'], 'placeholder')
self.assertEqual(profiles[1]['Profile'], 'balanced')
self.assertEqual(profiles[0]['Profile'], 'power-saver')
@@ -259,23 +282,20 @@ class Tests(dbusmock.DBusTestCase):
def test_inhibited_transition(self):
'''Test that transitions work as expected when inhibited'''
- tp_acpi = self.testbed.add_device('platform', 'thinkpad_acpi', None,
- ['dytc_lapmode', '0', 'dytc_perfmode', 'H'],
- [ 'DEVPATH', '/devices/platform/thinkpad_acpi' ]
- )
-
+ self.create_dytc_device()
+ self.create_platform_profile()
self.start_daemon()
profiles = self.get_dbus_property('Profiles')
self.assertEqual(len(profiles), 3)
- self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
+ self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
+ self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('balanced'))
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance'))
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
# Inhibit
- self.testbed.set_attribute(tp_acpi, 'dytc_lapmode', '1')
- self.testbed.uevent(tp_acpi, 'change')
+ self.testbed.set_attribute(self.tp_acpi, 'dytc_lapmode', '1\n')
self.assertEventually(lambda: self.have_text_in_log('dytc_lapmode is now on'))
self.assertEqual(self.get_dbus_property('PerformanceInhibited'), 'lap-detected')
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
@@ -288,20 +308,20 @@ class Tests(dbusmock.DBusTestCase):
'''Intel P-State driver (no UPower)'''
# Create 2 CPUs with preferences
- dir1 = os.path.join(self.testbed.get_root_dir(), "devices/system/cpu/cpufreq/policy0/")
+ dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/")
os.makedirs(dir1)
with open(os.path.join(dir1, "energy_performance_preference") ,'w') as prefs:
- prefs.write("performance")
- dir2 = os.path.join(self.testbed.get_root_dir(), "devices/system/cpu/cpufreq/policy1/")
+ prefs.write("performance\n")
+ dir2 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy1/")
os.makedirs(dir2)
with open(os.path.join(dir2, "energy_performance_preference") ,'w') as prefs:
- prefs.write("performance")
+ prefs.write("performance\n")
# Create no_turbo pref
- pstate_dir = os.path.join(self.testbed.get_root_dir(), "devices/system/cpu/intel_pstate")
+ pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/intel_pstate")
os.makedirs(pstate_dir)
with open(os.path.join(pstate_dir, "no_turbo") ,'w') as no_turbo:
- no_turbo.write("0")
+ no_turbo.write("0\n")
self.start_daemon()
@@ -326,7 +346,7 @@ class Tests(dbusmock.DBusTestCase):
# Disable turbo
with open(os.path.join(pstate_dir, "no_turbo") ,'w') as no_turbo:
- no_turbo.write("1")
+ no_turbo.write("1\n")
self.assertEventually(lambda: self.have_text_in_log('File monitor change happened for '))
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
@@ -335,25 +355,21 @@ class Tests(dbusmock.DBusTestCase):
self.stop_daemon()
# Verify that the Lenovo DYTC driver still gets preferred
- tp_acpi = self.testbed.add_device('platform', 'thinkpad_acpi', None,
- ['dytc_lapmode', '0', 'dytc_perfmode', 'H'],
- [ 'DEVPATH', '/devices/platform/thinkpad_acpi' ]
- )
-
+ self.create_platform_profile()
self.start_daemon()
profiles = self.get_dbus_property('Profiles')
self.assertEqual(len(profiles), 3)
- self.assertEqual(profiles[0]['Driver'], 'lenovo_dytc')
+ self.assertEqual(profiles[0]['Driver'], 'platform_profile')
def test_intel_pstate_balance(self):
'''Intel P-State driver (balance)'''
# Create CPU with preference
- dir1 = os.path.join(self.testbed.get_root_dir(), "devices/system/cpu/cpufreq/policy0/")
+ dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/")
os.makedirs(dir1)
with open(os.path.join(dir1, "energy_performance_preference") ,'w') as prefs:
- prefs.write("performance")
+ prefs.write("performance\n")
upowerd, obj_upower = self.spawn_server_template(
'upower', {'DaemonVersion': '0.99', 'OnBattery': False}, stdout=subprocess.PIPE)
@@ -368,79 +384,65 @@ class Tests(dbusmock.DBusTestCase):
contents = None
with open(os.path.join(dir1, "energy_performance_preference"), 'rb') as f:
contents = f.read()
+ # This matches what's written by ppd-driver-intel-pstate.c
self.assertEqual(contents, b'balance_performance')
- # Unplug from the mains
- obj_upower.Set('org.freedesktop.UPower', 'OnBattery', True)
- obj_upower.EmitSignal('', 'Changed', '', [], dbus_interface='org.freedesktop.DBus.Mock')
-
- contents = None
- self.assertEventually(lambda: self.read_file(os.path.join(dir1, "energy_performance_preference")) == b'balance_power')
-
self.stop_daemon()
upowerd.terminate()
upowerd.wait()
+ upowerd.stdout.close()
def test_dytc_performance_driver(self):
'''Lenovo DYTC performance driver'''
- tp_acpi = self.testbed.add_device('platform', 'thinkpad_acpi', None,
- ['dytc_lapmode', '0', 'dytc_perfmode', 'H'],
- [ 'DEVPATH', '/devices/platform/thinkpad_acpi' ]
- )
-
+ self.create_dytc_device()
+ self.create_platform_profile()
self.start_daemon()
profiles = self.get_dbus_property('Profiles')
self.assertEqual(len(profiles), 3)
- self.assertEqual(profiles[0]['Driver'], 'lenovo_dytc')
+ self.assertEqual(profiles[0]['Driver'], 'platform_profile')
self.assertEqual(profiles[0]['Profile'], 'power-saver')
- self.assertEqual(profiles[2]['Driver'], 'lenovo_dytc')
+ self.assertEqual(profiles[2]['Driver'], 'platform_profile')
self.assertEqual(profiles[2]['Profile'], 'performance')
- self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
-
- # Verify that perfmode got reset
- self.assertEventually(lambda: self.read_sysfs_attr(tp_acpi, 'dytc_perfmode') == b'M')
+ self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
# lapmode detected, but performance wasn't selected anyway
- self.testbed.set_attribute(tp_acpi, 'dytc_lapmode', '1')
- self.testbed.uevent(tp_acpi, 'change')
- self.assertEventually(lambda: self.have_text_in_log('dytc_lapmode is now on'))
-
+ self.testbed.set_attribute(self.tp_acpi, 'dytc_lapmode', '1\n')
+ self.assertEventually(lambda: self.get_dbus_property('PerformanceInhibited') == 'lap-detected')
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
- self.assertEqual(self.get_dbus_property('PerformanceInhibited'), 'lap-detected')
# Reset lapmode
- self.testbed.set_attribute(tp_acpi, 'dytc_lapmode', '0')
- self.testbed.uevent(tp_acpi, 'change')
- self.assertEventually(lambda: self.have_text_in_log('dytc_lapmode is now off'))
+ self.testbed.set_attribute(self.tp_acpi, 'dytc_lapmode', '0\n')
+ self.assertEventually(lambda: self.get_dbus_property('PerformanceInhibited') == '')
# Set performance mode
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance'))
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
- self.assertEventually(lambda: self.read_sysfs_attr(tp_acpi, 'dytc_perfmode') == b'H')
+ self.assertEventually(lambda: self.read_sysfs_file("sys/firmware/acpi/platform_profile") == b'performance')
# And turn on lapmode
- self.testbed.set_attribute(tp_acpi, 'dytc_lapmode', '1')
- self.testbed.uevent(tp_acpi, 'change')
- self.assertEventually(lambda: self.have_text_in_log('dytc_lapmode is now on'))
- self.assertEventually(lambda: self.read_sysfs_attr(tp_acpi, 'dytc_perfmode') == b'M')
+ self.testbed.set_attribute(self.tp_acpi, 'dytc_lapmode', '1\n')
+ self.assertEventually(lambda: self.read_sysfs_file("sys/firmware/acpi/platform_profile") == b'balanced')
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
self.assertEqual(self.get_dbus_property('PerformanceInhibited'), 'lap-detected')
# Turn off lapmode, profile stays balanced
- self.testbed.set_attribute(tp_acpi, 'dytc_lapmode', '0')
- self.testbed.uevent(tp_acpi, 'change')
- self.assertEventually(lambda: self.have_text_in_log('dytc_lapmode is now off'))
- self.assertEventually(lambda: self.read_sysfs_attr(tp_acpi, 'dytc_perfmode') == b'M')
+ self.testbed.set_attribute(self.tp_acpi, 'dytc_lapmode', '0\n')
+ self.assertEventually(lambda: self.get_dbus_property('PerformanceInhibited') == '')
+ self.assertEventually(lambda: self.read_sysfs_file("sys/firmware/acpi/platform_profile") == b'balanced')
# Switch to power-saver mode
self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
+ self.assertEventually(lambda: self.read_sysfs_file("sys/firmware/acpi/platform_profile") == b'low-power')
self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
- self.assertEqual(self.get_dbus_property('PerformanceInhibited'), '')
- self.assertEventually(lambda: self.read_sysfs_attr(tp_acpi, 'dytc_perfmode') == b'L')
+
+ # And mimick a user pressing a Fn+H
+ with open(os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/platform_profile"), 'w') as platform_profile:
+ platform_profile.write('performance\n')
+ self.assertEventually(lambda: self.get_dbus_property('ActiveProfile') == 'performance')
def test_fake_driver(self):
'''Test that the fake driver works'''
@@ -484,6 +486,61 @@ class Tests(dbusmock.DBusTestCase):
# self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance'))
# self.assertEqual(self.read_sysfs_attr(fastcharge, 'charge_type'), 'Fast')
+ def test_platform_driver_late_load(self):
+ '''Test that we can handle the platform_profile driver getting loaded late'''
+ acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
+ os.makedirs(acpi_dir)
+ with open(os.path.join(acpi_dir, "platform_profile") ,'w') as profile:
+ profile.write('\n')
+ with open(os.path.join(acpi_dir, "platform_profile_choices") ,'w') as choices:
+ choices.write('\n')
+
+ self.start_daemon()
+
+ profiles = self.get_dbus_property('Profiles')
+ self.assertEqual(len(profiles), 2)
+
+ with open(os.path.join(acpi_dir, "platform_profile_choices") ,'w') as choices:
+ choices.write("low-power\nbalanced\nperformance\n")
+ with open(os.path.join(acpi_dir, "platform_profile") ,'w') as profile:
+ profile.write("performance\n")
+
+ # Wait for profiles to get reloaded
+ self.assertEventually(lambda: len(self.get_dbus_property('Profiles')) == 3)
+ profiles = self.get_dbus_property('Profiles')
+ self.assertEqual(len(profiles), 3)
+ # Was set in platform_profile before we loaded the drivers
+ self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance')
+ self.assertEqual(self.get_dbus_property('PerformanceInhibited'), '')
+
+ self.stop_daemon()
+
+ def test_hp_wmi(self):
+
+ # Uses cool instead of low-power
+ acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
+ os.makedirs(acpi_dir)
+ with open(os.path.join(acpi_dir, "platform_profile") ,'w') as profile:
+ profile.write("cool\n")
+ with open(os.path.join(acpi_dir, "platform_profile_choices") ,'w') as choices:
+ choices.write("cool balanced performance\n")
+
+ self.start_daemon()
+ profiles = self.get_dbus_property('Profiles')
+ self.assertEqual(len(profiles), 3)
+ self.assertEqual(profiles[0]['Driver'], 'platform_profile')
+ self.assertEqual(profiles[0]['Profile'], 'power-saver')
+ self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
+ self.assertEqual(self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b'cool')
+
+ # Check that we can set the power-saver/cool profile again
+ self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('balanced'))
+ self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
+ self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
+ self.assertEqual(self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b'cool')
+
+ self.stop_daemon()
+
#
# Helper methods
#
diff --git a/tests/meson.build b/tests/meson.build
index baf4699..462c3aa 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -2,6 +2,7 @@ integration_test = find_program('integration-test')
envs = environment()
envs.set ('top_builddir', meson.build_root())
+envs.set ('top_srcdir', meson.source_root())
test('power-profiles-daemon-integration-test',
integration_test,
More information about the Neon-commits
mailing list