diff options
author | Aleksander Morgado <aleksandermj@chromium.org> | 2023-12-01 12:45:12 +0000 |
---|---|---|
committer | Aleksander Morgado <aleksandermj@chromium.org> | 2023-12-01 12:50:51 +0000 |
commit | 23033217de26fb91734fed3b999173f151195040 (patch) | |
tree | ab8ae8daad1bcf5e0cdace008d0c85eb711c920e | |
parent | 5056936b468c3213ba759b8802eaad9abd5cfeab (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.c | 20 | ||||
-rw-r--r-- | src/mm-base-manager.c | 94 | ||||
-rw-r--r-- | src/mm-base-manager.h | 3 | ||||
-rw-r--r-- | src/mm-context.c | 13 | ||||
-rw-r--r-- | src/mm-context.h | 5 |
5 files changed, 109 insertions, 26 deletions
@@ -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); |