aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksandermj@chromium.org>2023-12-01 12:45:12 +0000
committerAleksander Morgado <aleksandermj@chromium.org>2023-12-01 12:50:51 +0000
commit23033217de26fb91734fed3b999173f151195040 (patch)
treeab8ae8daad1bcf5e0cdace008d0c85eb711c920e
parent5056936b468c3213ba759b8802eaad9abd5cfeab (diff)
base-manager: add support to put modem in low power mode during suspend
Based on an earlier approach from Jack Song and Nero Zhang, see https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1050
-rw-r--r--src/main.c20
-rw-r--r--src/mm-base-manager.c94
-rw-r--r--src/mm-base-manager.h3
-rw-r--r--src/mm-context.c13
-rw-r--r--src/mm-context.h5
5 files changed, 109 insertions, 26 deletions
diff --git a/src/main.c b/src/main.c
index bdf14471..d485a939 100644
--- a/src/main.c
+++ b/src/main.c
@@ -62,7 +62,14 @@ static void
sleeping_cb (MMSleepMonitor *sleep_monitor)
{
mm_dbg ("removing devices... (sleeping)");
- mm_base_manager_shutdown (manager, FALSE);
+ mm_base_manager_shutdown (manager, FALSE, FALSE);
+}
+
+static void
+sleeping_low_power_cb (MMSleepMonitor *sleep_monitor)
+{
+ mm_dbg ("removing devices and setting low power mode... (sleeping)");
+ mm_base_manager_shutdown (manager, TRUE, TRUE);
}
static void
@@ -201,16 +208,19 @@ main (int argc, char *argv[])
{
MMSleepMonitor *sleep_monitor;
- if (mm_context_get_test_no_suspend_resume())
+ if (mm_context_get_test_no_suspend_resume ())
mm_dbg ("Suspend/resume support disabled at runtime");
- else if (mm_context_get_test_quick_suspend_resume()) {
+ else if (mm_context_get_test_quick_suspend_resume ()) {
mm_dbg ("Quick suspend/resume hooks enabled");
sleep_monitor = mm_sleep_monitor_get ();
g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_RESUMING, G_CALLBACK (resuming_quick_cb), NULL);
} else {
mm_dbg ("Full suspend/resume hooks enabled");
sleep_monitor = mm_sleep_monitor_get ();
- g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_SLEEPING, G_CALLBACK (sleeping_cb), NULL);
+ if (mm_context_get_test_radio_off_suspend_resume ())
+ g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_SLEEPING, G_CALLBACK (sleeping_low_power_cb), NULL);
+ else
+ g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_SLEEPING, G_CALLBACK (sleeping_cb), NULL);
g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_RESUMING, G_CALLBACK (resuming_cb), NULL);
}
}
@@ -228,7 +238,7 @@ main (int argc, char *argv[])
if (manager) {
GTimer *timer;
- mm_base_manager_shutdown (manager, TRUE);
+ mm_base_manager_shutdown (manager, TRUE, FALSE);
/* Wait for all modems to be disabled and removed, but don't wait
* forever: if disabling the modems takes longer than 20s, just
diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c
index e2cebccb..930cd504 100644
--- a/src/mm-base-manager.c
+++ b/src/mm-base-manager.c
@@ -57,6 +57,7 @@
#include "mm-filter.h"
#include "mm-log-object.h"
#include "mm-base-modem.h"
+#include "mm-iface-modem.h"
static void initable_iface_init (GInitableIface *iface);
static void log_object_iface_init (MMLogObjectInterface *iface);
@@ -652,39 +653,91 @@ mm_base_manager_start (MMBaseManager *self,
/*****************************************************************************/
+typedef struct {
+ MMBaseManager *self;
+ gboolean low_power;
+} DisableContext;
+
static void
-remove_disable_ready (MMBaseModem *modem,
- GAsyncResult *res,
- MMBaseManager *self)
+disable_context_free (DisableContext *ctx)
{
- MMDevice *device;
+ g_object_unref (ctx->self);
+ g_slice_free (DisableContext, ctx);
+}
- /* We don't care about errors disabling at this point */
- mm_base_modem_disable_finish (modem, res, NULL);
+static void
+remove_device_after_disable (MMBaseModem *modem,
+ DisableContext *ctx)
+{
+ MMDevice *device;
- device = find_device_by_modem (self, modem);
+ device = find_device_by_modem (ctx->self, modem);
if (device) {
g_cancellable_cancel (mm_base_modem_peek_cancellable (modem));
mm_device_remove_modem (device);
- g_hash_table_remove (self->priv->devices, mm_device_get_uid (device));
+ g_hash_table_remove (ctx->self->priv->devices, mm_device_get_uid (device));
}
+
+ disable_context_free (ctx);
}
static void
-foreach_disable (gpointer key,
- MMDevice *device,
- MMBaseManager *self)
+shutdown_low_power_ready (MMIfaceModem *modem,
+ GAsyncResult *res,
+ DisableContext *ctx)
{
- MMBaseModem *modem;
+ g_autoptr(GError) error = NULL;
+
+ if (!mm_iface_modem_set_power_state_finish (modem, res, &error))
+ mm_obj_info (ctx->self, "changing to low power state failed: %s", error->message);
+
+ remove_device_after_disable (MM_BASE_MODEM (modem), ctx);
+}
+
+static void
+shutdown_disable_ready (MMBaseModem *modem,
+ GAsyncResult *res,
+ DisableContext *ctx)
+{
+ g_autoptr(GError) error = NULL;
+
+ /* We don't care about errors disabling at this point */
+ if (!mm_base_modem_disable_finish (modem, res, &error)) {
+ mm_obj_info (ctx->self, "disabling modem failed: %s", error->message);
+ }
+ /* Bring the modem to low power mode if requested */
+ else if (ctx->low_power) {
+ mm_iface_modem_set_power_state (MM_IFACE_MODEM (modem),
+ MM_MODEM_POWER_STATE_LOW,
+ (GAsyncReadyCallback)shutdown_low_power_ready,
+ ctx);
+ return;
+ }
+
+ remove_device_after_disable (modem, ctx);
+}
+
+static void
+foreach_disable (gpointer key,
+ MMDevice *device,
+ DisableContext *foreach_ctx)
+{
+ MMBaseModem *modem;
+ DisableContext *ctx;
modem = mm_device_peek_modem (device);
- if (modem)
- mm_base_modem_disable (modem, (GAsyncReadyCallback)remove_disable_ready, self);
+ if (!modem)
+ return;
+
+ ctx = g_slice_new0 (DisableContext);
+ ctx->self = g_object_ref (foreach_ctx->self);
+ ctx->low_power = foreach_ctx->low_power;
+ mm_base_modem_disable (modem, (GAsyncReadyCallback)shutdown_disable_ready, ctx);
}
static gboolean
-foreach_remove (gpointer key,
- MMDevice *device,
+foreach_remove (gpointer key,
+ MMDevice *device,
MMBaseManager *self)
{
MMBaseModem *modem;
@@ -698,7 +751,8 @@ foreach_remove (gpointer key,
void
mm_base_manager_shutdown (MMBaseManager *self,
- gboolean disable)
+ gboolean disable,
+ gboolean low_power)
{
g_return_if_fail (self != NULL);
g_return_if_fail (MM_IS_BASE_MANAGER (self));
@@ -707,7 +761,11 @@ mm_base_manager_shutdown (MMBaseManager *self,
g_cancellable_cancel (self->priv->authp_cancellable);
if (disable) {
- g_hash_table_foreach (self->priv->devices, (GHFunc)foreach_disable, self);
+ DisableContext foreach_ctx = {
+ .self = self,
+ .low_power = low_power,
+ };
+ g_hash_table_foreach (self->priv->devices, (GHFunc)foreach_disable, &foreach_ctx);
/* Disabling may take a few iterations of the mainloop, so the caller
* has to iterate the mainloop until all devices have been disabled and
diff --git a/src/mm-base-manager.h b/src/mm-base-manager.h
index 47f9d333..b49c97d6 100644
--- a/src/mm-base-manager.h
+++ b/src/mm-base-manager.h
@@ -72,7 +72,8 @@ void mm_base_manager_start (MMBaseManager *manager,
gboolean manual_scan);
void mm_base_manager_shutdown (MMBaseManager *manager,
- gboolean disable);
+ gboolean disable,
+ gboolean power_low);
#if defined WITH_SUSPEND_RESUME
void mm_base_manager_sync (MMBaseManager *manager);
diff --git a/src/mm-context.c b/src/mm-context.c
index 65db5172..94b6e915 100644
--- a/src/mm-context.c
+++ b/src/mm-context.c
@@ -238,6 +238,7 @@ static gboolean test_no_udev;
#if defined WITH_SUSPEND_RESUME
static gboolean test_no_suspend_resume;
static gboolean test_quick_suspend_resume;
+static gboolean test_radio_off_suspend_resume;
#endif
#if defined WITH_QRTR
static gboolean test_no_qrtr;
@@ -285,6 +286,11 @@ static const GOptionEntry test_entries[] = {
"Enable quick suspend/resume support for modems which stay on during host suspension",
NULL
},
+ {
+ "test-radio-off-suspend-resume", 0, 0, G_OPTION_ARG_NONE, &test_radio_off_suspend_resume,
+ "Enable support to turn radio off during suspend/resume",
+ NULL
+},
#endif
#if defined WITH_QRTR
{
@@ -358,11 +364,18 @@ mm_context_get_test_no_suspend_resume (void)
{
return test_no_suspend_resume;
}
+
gboolean
mm_context_get_test_quick_suspend_resume (void)
{
return test_quick_suspend_resume;
}
+
+gboolean
+mm_context_get_test_radio_off_suspend_resume (void)
+{
+ return test_radio_off_suspend_resume;
+}
#endif
#if defined WITH_QRTR
diff --git a/src/mm-context.h b/src/mm-context.h
index 7ca2b7f4..456a9415 100644
--- a/src/mm-context.h
+++ b/src/mm-context.h
@@ -55,8 +55,9 @@ const gchar *mm_context_get_test_plugin_dir (void);
gboolean mm_context_get_test_no_udev (void);
#endif
#if defined WITH_SUSPEND_RESUME
-gboolean mm_context_get_test_no_suspend_resume (void);
-gboolean mm_context_get_test_quick_suspend_resume (void);
+gboolean mm_context_get_test_no_suspend_resume (void);
+gboolean mm_context_get_test_quick_suspend_resume (void);
+gboolean mm_context_get_test_radio_off_suspend_resume (void);
#endif
#if defined WITH_QRTR
gboolean mm_context_get_test_no_qrtr (void);