Compare commits

..
11 Commits
Author SHA1 Message Date
SymbX befee319b4 add ability to supply kernel driver name from udev 2026-10-15 00:10:44 +03:00
Dan Williams f2b9ab1ad7 Merge request !1384 from 'mm-1-24-2'
release: bump version to 1.24.2

https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1384
2025-07-28 15:15:43 -05:00
Dan Williams 5160a4f409 release: bump version to 1.24.2
Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-07-28 15:07:18 -05:00
Dan Williams 8b51fb4385 Merge request !1383 from '1-24-suspend-bearer-timeout'
[1.24] base-manager: increase suspend timeout for each active bearer/disable unsolicited 3GPP events during quick suspend/resume

https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1383
2025-07-28 14:25:36 -05:00
Dan Williams 79d495c892 base-manager: increase suspend timeout for each active bearer
Some modems can take a very long time (~20s) to reply to bearer
disconnect requests especially in marginal signal situations where
the modem must resend messages to the network after internal
timeouts. Give the modem a chance to suspend successfully if
there are active bearers.

Related: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1311#note_2938638

Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-07-28 09:46:13 -05:00
Dan Williams e867a49d92 sleep-context: add ability to increase timeout
Track when the timeout was started, so that if it needs to be increased
we can calculate how long the new timeout should be. Then cancel the
original timeout and start a new one with.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-07-28 09:46:13 -05:00
Dan Williams b59666f484 broadband-modem,iface-modem: move bearer counting to interface and generalize
Allow counting more kinds of bearers than just multiplexed ones.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-07-28 09:46:13 -05:00
biemster d22bc4d402 iface-modem: disable unsolicited 3GPP events during quick suspend/resume
This introduces the "terse" mode during quick suspend/resume, right now
it is used by 3GPP interface to disable unsolicited events, but in
future it can be used by other interfaces as well.

This prevents device to wake-up from suspend for each unsolicited while
still allowing to wake up on calls or SMS messages.

Signed-off-by: biemster <biemster@gmail.com>
Signed-off-by: Bhushan Shah <bshah@kde.org>
2025-07-28 09:45:10 -05:00
Dan Williams 3a1184785b base-manager: rename manager/device shutdown to manager/device cleanup
In preparation for a "terse" mode, but also because "shutdown" was
kind of weird since we're not always shutting the modem down; sometimes
we're just putting it in low-power mode.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-07-28 09:39:46 -05:00
Dan Williams 4a3aba8928 Merge request !1349 from 'mm-1-24-mbim-multipart-fix'
[1.24] broadband-modem-qmi,broadband-modem-mbim: always use SMS_PART_INVALID_INDEX unstored parts

https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1349
2025-05-15 08:42:40 -05:00
Dan Williams 19f6d15edf broadband-modem-qmi,broadband-modem-mbim: always use SMS_PART_INVALID_INDEX unstored parts
MMSmsList has logic to allow multiple unstored messages as long as
they use SMS_PART_INVALID_INDEX. These messages aren't stored so
they don't have an index.

But the MBIM and QMI modems used index 0 for unstored messages,
meaning there could only ever be one and also that multipart
messages would fail to be combined.

Let's fix that by just using SMS_PART_INVALID_INDEX for every
scenario where an unstored message comes in.

Fixes: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/979

Signed-off-by: Dan Williams <dan@ioncontrol.co>
(cherry picked from commit 1d5cc0addb)
2025-05-08 20:44:02 -05:00
20 changed files with 717 additions and 193 deletions
+28
View File
@@ -1,3 +1,31 @@
ModemManager 1.24.2
-------------------------------------------
This is a new stable release of ModemManager.
The most important features and changes in this release are the following:
* Core:
** Wait until bearers are disconnected before allowing system to suspend
** Fix checks for CDMA/EVDO access technology in some modems
** Detect old Mediatek 62xx-based devices as GSM-capable
** Refresh registration info after manual registration for AT-based devices
** Correctly report NB-IOT access technology
** Disable unsolicited 3GPP events during quick suspend/resume
* MBIM:
** Fix re-assembly of multi-part unstored SMS messages
* QMI:
** Fix re-assembly of multi-part unstored SMS messages
* Voice interface:
** Correctly start call state polling on some modems
* Plugins:
** fibocomm: don't assert when checking for firmware interface
** cinterion: allow spaces in ^SXRAT response
ModemManager 1.24.0
-------------------------------------------
This is a new stable release of ModemManager.
+1 -1
View File
@@ -3,7 +3,7 @@
project(
'ModemManager', 'c',
version: '1.24.1',
version: '1.24.2',
license: 'GPL2',
default_options: [
'buildtype=debugoptimized',
+13 -2
View File
@@ -338,10 +338,21 @@ kernel_device_get_name (MMKernelDevice *_self)
return mm_kernel_event_properties_get_name (self->priv->properties);
}
/* Driver name for devices without one in sysfs, e.g. the virtual rmnet_ipa0 of
* Qualcomm vendor kernels, which is handled like the mainline 'ipa' driver */
#define ID_MM_KERNEL_DRIVER "ID_MM_KERNEL_DRIVER"
static const gchar *
kernel_device_get_driver (MMKernelDevice *self)
kernel_device_get_driver (MMKernelDevice *_self)
{
return MM_KERNEL_DEVICE_UDEV (self)->priv->driver;
MMKernelDeviceUdev *self;
const gchar *driver;
self = MM_KERNEL_DEVICE_UDEV (_self);
if (self->priv->device &&
(driver = g_udev_device_get_property (self->priv->device, ID_MM_KERNEL_DRIVER)) != NULL)
return driver;
return self->priv->driver;
}
static const gchar *
+17 -7
View File
@@ -64,10 +64,14 @@ sleeping_cb (MMSleepMonitor *sleep_monitor,
{
if (mm_context_get_test_low_power_suspend_resume ()) {
mm_dbg ("removing devices and setting them in low power mode... (sleeping)");
mm_base_manager_shutdown (manager, TRUE, TRUE, TRUE, ctx);
mm_base_manager_cleanup (manager,
MM_BASE_MANAGER_CLEANUP_DISABLE |
MM_BASE_MANAGER_CLEANUP_LOW_POWER |
MM_BASE_MANAGER_CLEANUP_REMOVE,
ctx);
} else {
mm_dbg ("removing devices... (sleeping)");
mm_base_manager_shutdown (manager, FALSE, FALSE, TRUE, ctx);
mm_base_manager_cleanup (manager, MM_BASE_MANAGER_CLEANUP_REMOVE, ctx);
}
}
@@ -84,11 +88,15 @@ sleeping_quick_cb (MMSleepMonitor *sleep_monitor,
{
if (mm_context_get_test_low_power_suspend_resume ()) {
mm_dbg ("setting modem in low power mode... (sleeping)");
mm_base_manager_shutdown (manager, TRUE, TRUE, FALSE, ctx);
mm_base_manager_cleanup (manager,
MM_BASE_MANAGER_CLEANUP_DISABLE |
MM_BASE_MANAGER_CLEANUP_LOW_POWER,
ctx);
} else {
/* Don't need to wait for anything; just suspend */
mm_dbg ("leaving modem powered... (sleeping)");
mm_sleep_context_complete (ctx, NULL);
mm_dbg ("setting modem in terse mode... (only send important signals (call/text))");
mm_base_manager_cleanup (manager,
MM_BASE_MANAGER_CLEANUP_TERSE,
ctx);
}
}
@@ -268,7 +276,9 @@ main (int argc, char *argv[])
(GCallback)shutdown_done,
inner);
mm_base_manager_shutdown (manager, TRUE, FALSE, TRUE, ctx);
mm_base_manager_cleanup (manager,
MM_BASE_MANAGER_CLEANUP_DISABLE | MM_BASE_MANAGER_CLEANUP_REMOVE,
ctx);
/* Wait for all modems to be disabled and removed, but don't wait
* forever: if disabling the modems takes longer than 20s, just
+157 -96
View File
@@ -17,6 +17,8 @@
* Copyright (C) 2011 - 2016 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "gio/gio.h"
#include "glib.h"
#include <config.h>
#include <string.h>
@@ -870,48 +872,42 @@ mm_base_manager_start (MMBaseManager *self,
/*****************************************************************************/
typedef enum {
DEVICE_SHUTDOWN_STEP_FIRST = 0,
DEVICE_SHUTDOWN_STEP_DISABLE,
DEVICE_SHUTDOWN_STEP_LOW_POWER,
DEVICE_SHUTDOWN_STEP_REMOVE,
DEVICE_SHUTDOWN_STEP_LAST,
} DeviceShutdownStep;
DEVICE_CLEANUP_STEP_FIRST = 0,
DEVICE_CLEANUP_STEP_DISABLE,
DEVICE_CLEANUP_STEP_LOW_POWER,
DEVICE_CLEANUP_STEP_REMOVE,
DEVICE_CLEANUP_STEP_TERSE,
DEVICE_CLEANUP_STEP_LAST,
} DeviceCleanupStep;
typedef struct {
MMBaseModem *modem;
gboolean disable;
gboolean low_power;
gboolean remove;
MMBaseModem *modem;
MMBaseManagerCleanupFlags flags;
DeviceCleanupStep step;
} DeviceCleanupContext;
DeviceShutdownStep step;
} DeviceShutdownContext;
static void device_cleanup_step (GTask *task);
static void device_shutdown_step (GTask *task);
static DeviceShutdownContext *
device_shutdown_context_new (MMBaseModem *modem,
gboolean disable,
gboolean low_power,
gboolean remove)
static DeviceCleanupContext *
device_cleanup_context_new (MMBaseModem *modem,
MMBaseManagerCleanupFlags flags)
{
DeviceShutdownContext *ctx;
DeviceCleanupContext *ctx;
ctx = g_slice_new0 (DeviceShutdownContext);
ctx = g_slice_new0 (DeviceCleanupContext);
if (modem)
ctx->modem = g_object_ref (modem);
ctx->step = DEVICE_SHUTDOWN_STEP_FIRST;
ctx->disable = disable;
ctx->low_power = low_power;
ctx->remove = remove;
ctx->step = DEVICE_CLEANUP_STEP_FIRST;
ctx->flags = flags;
return ctx;
}
static void
device_shutdown_context_free (DeviceShutdownContext *ctx)
device_cleanup_context_free (DeviceCleanupContext *ctx)
{
g_clear_object (&ctx->modem);
g_slice_free (DeviceShutdownContext, ctx);
g_slice_free (DeviceCleanupContext, ctx);
}
static void
@@ -919,7 +915,7 @@ modem_remove_ready (MMDevice *device,
GAsyncResult *res,
GTask *task)
{
DeviceShutdownContext *ctx;
DeviceCleanupContext *ctx;
g_autoptr(GError) error = NULL;
ctx = g_task_get_task_data (task);
@@ -928,15 +924,15 @@ modem_remove_ready (MMDevice *device,
mm_obj_warn (device, "removing modem failed: %s", error->message);
ctx->step++;
device_shutdown_step (task);
device_cleanup_step (task);
}
static void
shutdown_low_power_ready (MMIfaceModem *modem,
GAsyncResult *res,
GTask *task)
cleanup_low_power_ready (MMIfaceModem *modem,
GAsyncResult *res,
GTask *task)
{
DeviceShutdownContext *ctx;
DeviceCleanupContext *ctx;
g_autoptr(GError) error = NULL;
ctx = g_task_get_task_data (task);
@@ -945,15 +941,15 @@ shutdown_low_power_ready (MMIfaceModem *modem,
mm_obj_info (modem, "changing to low power state failed: %s", error->message);
ctx->step++;
device_shutdown_step (task);
device_cleanup_step (task);
}
static void
shutdown_disable_ready (MMBaseModem *modem,
GAsyncResult *res,
GTask *task)
cleanup_disable_ready (MMBaseModem *modem,
GAsyncResult *res,
GTask *task)
{
DeviceShutdownContext *ctx;
DeviceCleanupContext *ctx;
g_autoptr(GError) error = NULL;
ctx = g_task_get_task_data (task);
@@ -966,57 +962,83 @@ shutdown_disable_ready (MMBaseModem *modem,
/* If disabling failed there's no point in trying to low-power the
* modem; just remove it.
*/
ctx->step = DEVICE_SHUTDOWN_STEP_REMOVE;
ctx->step = DEVICE_CLEANUP_STEP_REMOVE;
}
device_shutdown_step (task);
device_cleanup_step (task);
}
#if defined WITH_SUSPEND_RESUME
static void
cleanup_terse_ready (MMBaseModem *modem,
GAsyncResult *res,
GTask *task)
{
DeviceCleanupContext *ctx;
g_autoptr(GError) error = NULL;
ctx = g_task_get_task_data (task);
if (!mm_base_modem_terse_finish (modem, res, &error))
mm_obj_info (modem, "setting terse failed: %s", error->message);
ctx->step++;
device_cleanup_step (task);
}
#endif
static gboolean
has_cleanup_flag (MMBaseManagerCleanupFlags flags,
MMBaseManagerCleanupFlags expected)
{
return flags & expected;
}
static void
device_shutdown_step (GTask *task)
device_cleanup_step (GTask *task)
{
DeviceShutdownContext *ctx;
DeviceCleanupContext *ctx;
MMDevice *device;
ctx = g_task_get_task_data (task);
device = g_task_get_source_object (task);
switch (ctx->step) {
case DEVICE_SHUTDOWN_STEP_FIRST:
case DEVICE_CLEANUP_STEP_FIRST:
ctx->step++;
/* fall through */
case DEVICE_SHUTDOWN_STEP_DISABLE:
if (ctx->disable && ctx->modem) {
case DEVICE_CLEANUP_STEP_DISABLE:
if (ctx->modem && has_cleanup_flag (ctx->flags, MM_BASE_MANAGER_CLEANUP_DISABLE)) {
mm_obj_dbg (device,
"disabling modem%d",
mm_base_modem_get_dbus_id (ctx->modem));
mm_base_modem_disable (ctx->modem,
MM_BASE_MODEM_OPERATION_LOCK_REQUIRED,
MM_BASE_MODEM_OPERATION_PRIORITY_OVERRIDE,
(GAsyncReadyCallback)shutdown_disable_ready,
(GAsyncReadyCallback)cleanup_disable_ready,
task);
return;
}
ctx->step++;
/* fall through */
case DEVICE_SHUTDOWN_STEP_LOW_POWER:
if (ctx->low_power && ctx->modem) {
case DEVICE_CLEANUP_STEP_LOW_POWER:
if (ctx->modem && has_cleanup_flag (ctx->flags, MM_BASE_MANAGER_CLEANUP_LOW_POWER)) {
mm_obj_dbg (device,
"setting modem%d to low-power state",
mm_base_modem_get_dbus_id (ctx->modem));
mm_iface_modem_set_power_state (MM_IFACE_MODEM (ctx->modem),
MM_MODEM_POWER_STATE_LOW,
(GAsyncReadyCallback)shutdown_low_power_ready,
(GAsyncReadyCallback)cleanup_low_power_ready,
task);
return;
}
ctx->step++;
/* fall through */
case DEVICE_SHUTDOWN_STEP_REMOVE:
if (ctx->remove && ctx->modem) {
case DEVICE_CLEANUP_STEP_REMOVE:
if (ctx->modem && has_cleanup_flag (ctx->flags, MM_BASE_MANAGER_CLEANUP_REMOVE)) {
mm_obj_dbg (device,
"removing modem%d",
mm_base_modem_get_dbus_id (ctx->modem));
@@ -1028,8 +1050,26 @@ device_shutdown_step (GTask *task)
ctx->step++;
/* fall through */
case DEVICE_SHUTDOWN_STEP_LAST:
mm_obj_dbg (device, "device shutdown complete");
case DEVICE_CLEANUP_STEP_TERSE:
#if defined WITH_SUSPEND_RESUME
if (ctx->modem && has_cleanup_flag (ctx->flags, MM_BASE_MANAGER_CLEANUP_TERSE)) {
mm_obj_dbg(device,
"settting terse on modem%d",
mm_base_modem_get_dbus_id (ctx->modem));
mm_base_modem_terse (ctx->modem,
MM_BASE_MODEM_OPERATION_LOCK_REQUIRED,
(GAsyncReadyCallback)cleanup_terse_ready,
task);
return;
}
#endif
ctx->step++;
/* fall through */
case DEVICE_CLEANUP_STEP_LAST:
mm_obj_dbg (device, "device cleanup complete");
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
@@ -1046,25 +1086,25 @@ typedef struct {
GSList *tasks;
GSList *devices_to_remove;
MMSleepContext *sleep_ctx;
} ManagerShutdownContext;
} ManagerCleanupContext;
static ManagerShutdownContext *
manager_shutdown_context_new (MMBaseManager *self,
MMSleepContext *sleep_ctx)
static ManagerCleanupContext *
manager_cleanup_context_new (MMBaseManager *self,
MMSleepContext *sleep_ctx)
{
ManagerShutdownContext *ctx;
ManagerCleanupContext *ctx;
ctx = g_slice_new0 (ManagerShutdownContext);
ctx = g_slice_new0 (ManagerCleanupContext);
ctx->self = g_object_ref (self);
ctx->sleep_ctx = g_object_ref (sleep_ctx);
return ctx;
}
static void
manager_shutdown_context_maybe_complete (ManagerShutdownContext *ctx,
GTask *task,
MMDevice *device,
gboolean remove)
manager_cleanup_context_maybe_complete (ManagerCleanupContext *ctx,
GTask *task,
MMDevice *device,
gboolean remove)
{
if (task)
ctx->tasks = g_slist_remove (ctx->tasks, task);
@@ -1085,50 +1125,49 @@ manager_shutdown_context_maybe_complete (ManagerShutdownContext *ctx,
g_hash_table_remove (ctx->self->priv->devices, mm_device_get_uid (device));
g_slist_free (ctx->devices_to_remove);
mm_obj_dbg (ctx->self, "shutdown complete");
mm_obj_dbg (ctx->self, "cleanup complete");
mm_sleep_context_complete (ctx->sleep_ctx, NULL);
g_object_unref (ctx->sleep_ctx);
g_object_unref (ctx->self);
g_slice_free (ManagerShutdownContext, ctx);
g_slice_free (ManagerCleanupContext, ctx);
}
}
static void
device_shutdown_ready (MMDevice *device,
GAsyncResult *res,
ManagerShutdownContext *ctx)
device_cleanup_ready (MMDevice *device,
GAsyncResult *res,
ManagerCleanupContext *ctx)
{
GTask *task;
DeviceShutdownContext *dctx;
DeviceCleanupContext *dctx;
g_autoptr(GError) error = NULL;
gboolean remove;
task = G_TASK (res);
if (!g_task_propagate_boolean (task, &error)) {
mm_obj_info (ctx->self,
"failed to shutdown device %s: %s",
"failed to cleanup device %s: %s",
mm_device_get_uid (device),
error->message);
}
dctx = g_task_get_task_data (task);
manager_shutdown_context_maybe_complete (ctx,
task,
device,
dctx->remove);
remove = has_cleanup_flag (dctx->flags, MM_BASE_MANAGER_CLEANUP_REMOVE);
manager_cleanup_context_maybe_complete (ctx, task, device, remove);
}
void
mm_base_manager_shutdown (MMBaseManager *self,
gboolean disable,
gboolean low_power,
gboolean remove,
MMSleepContext *sleep_ctx)
mm_base_manager_cleanup (MMBaseManager *self,
MMBaseManagerCleanupFlags flags,
MMSleepContext *sleep_ctx)
{
ManagerShutdownContext *ctx;
ManagerCleanupContext *ctx;
GHashTableIter iter;
MMDevice *device;
gboolean disable, remove, low_power, terse;
guint active_bearers = 0;
g_return_if_fail (self != NULL);
g_return_if_fail (MM_IS_BASE_MANAGER (self));
@@ -1136,38 +1175,60 @@ mm_base_manager_shutdown (MMBaseManager *self,
/* Cancel all ongoing auth requests */
g_cancellable_cancel (self->priv->authp_cancellable);
disable = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_DISABLE);
low_power = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_LOW_POWER);
remove = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_REMOVE);
terse = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_TERSE);
mm_obj_dbg (self,
"manager shutting down... (%s%s%s%s%s)",
"manager shutting down... (%s%s%s%s%s%s%s)",
disable ? "disable" : "",
disable && (low_power || remove) ? "," : "",
disable && (low_power || remove || terse) ? "," : "",
low_power ? "low-power" : "",
(low_power && remove) ? "," : "",
remove ? "remove" : "");
low_power && (remove || terse) ? "," : "",
remove ? "remove" : "",
(remove && terse) ? "," : "",
terse ? "terse" : "");
ctx = manager_shutdown_context_new (self, sleep_ctx);
ctx = manager_cleanup_context_new (self, sleep_ctx);
g_hash_table_iter_init (&iter, self->priv->devices);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) {
DeviceShutdownContext *dctx;
GTask *task;
DeviceCleanupContext *dctx;
GTask *task;
MMBaseModem *modem;
modem = mm_device_peek_modem (device);
if (modem) {
guint count = 0;
mm_iface_modem_count_bearers (MM_IFACE_MODEM (modem),
MM_IFACE_MODEM_COUNT_BEARERS_FLAG_ACTIVE,
&count,
NULL,
NULL);
active_bearers += count;
}
task = g_task_new (device,
NULL,
(GAsyncReadyCallback)device_shutdown_ready,
(GAsyncReadyCallback)device_cleanup_ready,
ctx);
ctx->tasks = g_slist_append (ctx->tasks, task);
dctx = device_shutdown_context_new (mm_device_peek_modem (device),
disable,
low_power,
remove);
g_task_set_task_data (task, dctx, (GDestroyNotify)device_shutdown_context_free);
dctx = device_cleanup_context_new (modem, flags);
g_task_set_task_data (task, dctx, (GDestroyNotify)device_cleanup_context_free);
device_shutdown_step (task);
device_cleanup_step (task);
}
/* Complete shutdown if there were no devices */
manager_shutdown_context_maybe_complete (ctx, NULL, NULL, FALSE);
/* Increase cleanup timeout for each connected bearer; disconnecting a
* bearer can take many seconds.
*/
if (active_bearers)
mm_sleep_context_timeout_backoff (sleep_ctx, active_bearers * 20);
/* Complete cleanup if there were no devices */
manager_cleanup_context_maybe_complete (ctx, NULL, NULL, FALSE);
}
guint32
+11 -5
View File
@@ -72,11 +72,17 @@ MMBaseManager *mm_base_manager_new (GDBusConnection *bus,
void mm_base_manager_start (MMBaseManager *manager,
gboolean manual_scan);
void mm_base_manager_shutdown (MMBaseManager *manager,
gboolean disable,
gboolean power_low,
gboolean remove,
MMSleepContext *ctx);
typedef enum {
MM_BASE_MANAGER_CLEANUP_NONE = 0x0,
MM_BASE_MANAGER_CLEANUP_DISABLE = 0x1,
MM_BASE_MANAGER_CLEANUP_LOW_POWER = 0x2,
MM_BASE_MANAGER_CLEANUP_REMOVE = 0x4,
MM_BASE_MANAGER_CLEANUP_TERSE = 0x8,
} MMBaseManagerCleanupFlags;
void mm_base_manager_cleanup (MMBaseManager *manager,
MMBaseManagerCleanupFlags flags,
MMSleepContext *ctx);
#if defined WITH_SUSPEND_RESUME
void mm_base_manager_sync (MMBaseManager *manager);
+29
View File
@@ -730,6 +730,7 @@ typedef enum {
STATE_OPERATION_TYPE_DISABLE,
#if defined WITH_SUSPEND_RESUME
STATE_OPERATION_TYPE_SYNC,
STATE_OPERATION_TYPE_TERSE,
#endif
} StateOperationType;
@@ -855,6 +856,12 @@ state_operation (MMBaseModem *self,
ctx->operation = MM_BASE_MODEM_GET_CLASS (self)->sync;
ctx->operation_finish = MM_BASE_MODEM_GET_CLASS (self)->sync_finish;
break;
case STATE_OPERATION_TYPE_TERSE:
operation_description = "terse";
optional = TRUE;
ctx->operation = MM_BASE_MODEM_GET_CLASS (self)->terse;
ctx->operation_finish = MM_BASE_MODEM_GET_CLASS (self)->terse_finish;
break;
#endif
default:
g_assert_not_reached ();
@@ -909,6 +916,28 @@ mm_base_modem_sync (MMBaseModem *self,
user_data);
}
gboolean
mm_base_modem_terse_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error)
{
return state_operation_finish (self, res, error);
}
void
mm_base_modem_terse (MMBaseModem *self,
MMBaseModemOperationLock operation_lock,
GAsyncReadyCallback callback,
gpointer user_data)
{
state_operation (self,
STATE_OPERATION_TYPE_TERSE,
operation_lock,
MM_BASE_MODEM_OPERATION_PRIORITY_DEFAULT,
callback,
user_data);
}
#endif /* WITH_SUSPEND_RESUME */
/******************************************************************************/
+23 -7
View File
@@ -109,6 +109,15 @@ struct _MMBaseModemClass {
* this method triggers a synchronization of all modem interfaces */
StateOperation sync;
StateOperationFinish sync_finish;
/* Modem terse.
* When suspending in quick suspend/resume mode,
* this method disables unsolicited events on the 3GPP interface only.
* This is enough for phones to suspend properly, but it
* might be useful to extend it to all other interfaces
* that support it as well */
StateOperation terse;
StateOperationFinish terse_finish;
#endif
/* Allow plugins to subclass port object creation as needed */
@@ -298,13 +307,20 @@ gboolean mm_base_modem_disable_finish (MMBaseModem *self,
GError **error);
#if defined WITH_SUSPEND_RESUME
void mm_base_modem_sync (MMBaseModem *self,
MMBaseModemOperationLock operation_lock,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_base_modem_sync_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error);
void mm_base_modem_sync (MMBaseModem *self,
MMBaseModemOperationLock operation_lock,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_base_modem_sync_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error);
void mm_base_modem_terse (MMBaseModem *self,
MMBaseModemOperationLock operation_lock,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_base_modem_terse_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error);
#endif
void mm_base_modem_teardown_ports (MMBaseModem *self,
+5 -4
View File
@@ -1458,10 +1458,11 @@ load_settings_from_bearer (MMBearerMbim *self,
guint max_multiplexed_bearers;
const gchar *data_port_driver;
if (!mm_broadband_modem_get_active_multiplexed_bearers (MM_BROADBAND_MODEM (ctx->modem),
&current_multiplexed_bearers,
&max_multiplexed_bearers,
error))
if (!mm_iface_modem_count_bearers (MM_IFACE_MODEM (ctx->modem),
MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED,
&current_multiplexed_bearers,
&max_multiplexed_bearers,
error))
return FALSE;
/* Check multiplex support in the kernel and the device */
+5 -4
View File
@@ -2424,10 +2424,11 @@ load_settings_from_bearer (MMBearerQmi *self,
guint max_multiplexed_bearers;
gboolean multiplex_supported = TRUE;
if (!mm_broadband_modem_get_active_multiplexed_bearers (MM_BROADBAND_MODEM (ctx->modem),
&current_multiplexed_bearers,
&max_multiplexed_bearers,
error))
if (!mm_iface_modem_count_bearers (MM_IFACE_MODEM (ctx->modem),
MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED,
&current_multiplexed_bearers,
&max_multiplexed_bearers,
error))
return FALSE;
/* Check multiplex support in the kernel and the device */
+26 -5
View File
@@ -5840,6 +5840,7 @@ static gboolean process_pdu_messages (MMBroadbandModemMbim *self,
guint32 messages_count,
MbimSmsPduReadRecordArray *pdu_messages,
guint expected_index,
gboolean unstored,
GError **error);
static void
@@ -5864,6 +5865,7 @@ sms_notification_read_flash_sms (MMBroadbandModemMbim *self,
messages_count,
pdu_messages,
SMS_PART_INVALID_INDEX,
TRUE,
&error))
mm_obj_dbg (self, "flash SMS message reading failed: %s", error->message);
}
@@ -5943,6 +5945,7 @@ alert_sms_read_query_ready (MbimDevice *device,
messages_count,
pdu_messages,
ctx->expected_index,
FALSE,
&error))
mm_obj_dbg (ctx->self, "SMS message reading failed: %s", error->message);
@@ -9024,12 +9027,13 @@ load_initial_sms_parts_finish (MMIfaceModemMessaging *self,
static void
add_sms_part (MMBroadbandModemMbim *self,
const MbimSmsPduReadRecord *pdu,
guint part_index,
guint expected_index)
{
MMSmsPart *part;
g_autoptr(GError) error = NULL;
part = mm_sms_part_3gpp_new_from_binary_pdu (pdu->message_index,
part = mm_sms_part_3gpp_new_from_binary_pdu (part_index,
pdu->pdu_data,
pdu->pdu_data_size,
self,
@@ -9062,6 +9066,7 @@ process_pdu_messages (MMBroadbandModemMbim *self,
guint32 messages_count,
MbimSmsPduReadRecordArray *pdu_messages,
guint expected_index,
gboolean unstored,
GError **error)
{
guint i;
@@ -9087,11 +9092,26 @@ process_pdu_messages (MMBroadbandModemMbim *self,
mm_obj_dbg (self, "%u SMS PDUs reported", messages_count);
for (i = 0; i < messages_count; i++) {
if (pdu_messages[i]) {
mm_obj_dbg (self, "processing SMS PDU %u/%u...", i+1, messages_count);
add_sms_part (self, pdu_messages[i], expected_index);
} else
guint message_index;
if (!pdu_messages[i]) {
mm_obj_dbg (self, "ignoring invalid SMS PDU %u/%u...", i+1, messages_count);
continue;
}
mm_obj_dbg (self, "processing SMS PDU %u/%u...", i+1, messages_count);
message_index = pdu_messages[i]->message_index;
if (unstored && message_index != 0) {
mm_obj_warn (self,
"processed unstored PDU with non-zero message index (%u)",
message_index);
}
add_sms_part (self,
pdu_messages[i],
unstored ? SMS_PART_INVALID_INDEX : message_index,
expected_index);
}
return TRUE;
@@ -9126,6 +9146,7 @@ sms_read_query_ready (MbimDevice *device,
messages_count,
pdu_messages,
SMS_PART_INVALID_INDEX,
FALSE,
&error))
g_task_return_error (task, error);
else
+3 -7
View File
@@ -8380,7 +8380,6 @@ messaging_event_report_indication_cb (QmiClientNas *client,
QmiWmsAckIndicator ack_ind;
guint32 transaction_id;
QmiWmsMessageFormat msg_format;
QmiWmsMessageTagType tag;
GArray *raw_data = NULL;
/* Handle transfer-route MT messages */
@@ -8425,13 +8424,10 @@ messaging_event_report_indication_cb (QmiClientNas *client,
}
/* Defaults for transfer-route messages, which are not stored anywhere */
storage = QMI_WMS_STORAGE_TYPE_NONE;
memory_index = 0;
tag = QMI_WMS_MESSAGE_TAG_TYPE_MT_NOT_READ;
add_new_read_sms_part (MM_IFACE_MODEM_MESSAGING (self),
storage,
memory_index,
tag,
QMI_WMS_STORAGE_TYPE_NONE,
SMS_PART_INVALID_INDEX,
QMI_WMS_MESSAGE_TAG_TYPE_MT_NOT_READ,
msg_format,
TRUE,
raw_data);
+99 -46
View File
@@ -13158,6 +13158,103 @@ synchronize (MMBaseModem *self,
syncing_step (task);
}
typedef enum {
TERSE_STEP_FIRST,
TERSE_STEP_DISABLE_UNSOLICITED_EVENTS_3GPP,
TERSE_STEP_LAST,
} TerseStep;
typedef struct {
TerseStep step;
} TerseContext;
static void terse_step (GTask *task);
static gboolean
terse_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
iface_modem_3gpp_terse_ready (MMIfaceModem3gpp *self,
GAsyncResult *res,
GTask *task)
{
TerseContext *ctx;
g_autoptr(GError) error = NULL;
ctx = g_task_get_task_data (task);
if (!mm_iface_modem_3gpp_terse_finish (self, res, &error))
mm_obj_warn (self, "3GPP interface disable unsolicited events failed: %s", error->message);
/* Go on to next step */
ctx->step++;
terse_step (task);
}
static void
terse_step (GTask *task)
{
MMBroadbandModem *self;
TerseContext *ctx;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
switch (ctx->step) {
case TERSE_STEP_FIRST:
ctx->step++;
/* fall through */
case TERSE_STEP_DISABLE_UNSOLICITED_EVENTS_3GPP:
if (self->priv->modem_3gpp_dbus_skeleton &&
(self->priv->modem_state >= MM_MODEM_STATE_ENABLED)) {
mm_obj_msg (self, "terse state (%d/%d): 3GPP interface disable unsolicited events",
ctx->step, TERSE_STEP_LAST);
mm_iface_modem_3gpp_terse (MM_IFACE_MODEM_3GPP (self), (GAsyncReadyCallback)iface_modem_3gpp_terse_ready, task);
return;
}
ctx->step++;
/* fall through */
case TERSE_STEP_LAST:
mm_obj_msg (self, "setting terse state (%d/%d): all done",
ctx->step, TERSE_STEP_LAST);
/* We are done without errors! */
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
default:
break;
}
g_assert_not_reached ();
}
static void
terse (MMBaseModem *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
TerseContext *ctx;
GTask *task;
task = g_task_new (self, cancellable, callback, user_data);
/* Create TerseContext */
ctx = g_new0 (TerseContext, 1);
ctx->step = TERSE_STEP_FIRST;
g_task_set_task_data (task, ctx, (GDestroyNotify)g_free);
terse_step (task);
}
#endif
/*****************************************************************************/
@@ -13702,52 +13799,6 @@ mm_broadband_modem_get_current_charset (MMBroadbandModem *self)
/*****************************************************************************/
static void
bearer_count_multiplexed_connected (MMBaseBearer *bearer,
guint *count)
{
/* The Multiplexed property is only set if connected, so it's enough to check
* that one to see if we're connected and multiplexed */
if (mm_gdbus_bearer_get_multiplexed (MM_GDBUS_BEARER (bearer)))
*count += 1;
}
gboolean
mm_broadband_modem_get_active_multiplexed_bearers (MMBroadbandModem *self,
guint *out_current,
guint *out_max,
GError **error)
{
g_autoptr(MMBearerList) list = NULL;
guint max;
guint count = 0;
g_object_get (self,
MM_IFACE_MODEM_BEARER_LIST, &list,
NULL);
if (!list) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Bearer list unavailable");
return FALSE;
}
max = mm_bearer_list_get_max_active_multiplexed (list);
mm_bearer_list_foreach (list,
(MMBearerListForeachFunc)bearer_count_multiplexed_connected,
&count);
g_assert (!(!max && count));
if (out_max)
*out_max = max;
if (out_current)
*out_current = count;
return TRUE;
}
/*****************************************************************************/
gchar *
mm_broadband_modem_create_device_identifier (MMBroadbandModem *self,
const gchar *ati,
@@ -14645,6 +14696,8 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass)
#if defined WITH_SUSPEND_RESUME
base_modem_class->sync = synchronize;
base_modem_class->sync_finish = synchronize_finish;
base_modem_class->terse = terse;
base_modem_class->terse_finish = terse_finish;
#endif
klass->setup_ports = setup_ports;
-6
View File
@@ -143,12 +143,6 @@ gboolean mm_broadband_modem_sim_hot_swap_ports_context_init (MMBroadbandModem
GError **error);
void mm_broadband_modem_sim_hot_swap_ports_context_reset (MMBroadbandModem *self);
/* Helper to manage multiplexed bearers */
gboolean mm_broadband_modem_get_active_multiplexed_bearers (MMBroadbandModem *self,
guint *out_current,
guint *out_max,
GError **error);
/* Helper to manage initial EPS bearer */
gint mm_broadband_modem_get_initial_eps_bearer_cid (MMBroadbandModem *self);
+177
View File
@@ -3232,6 +3232,8 @@ static void interface_syncing_step (GTask *task);
typedef enum {
SYNCING_STEP_FIRST,
SYNCING_STEP_ENABLE_UNSOLICITED_EVENTS,
SYNCING_STEP_ENABLE_UNSOLICITED_REGISTRATION_EVENTS,
SYNCING_STEP_REFRESH_3GPP_REGISTRATION,
SYNCING_STEP_REFRESH_EPS_BEARER,
SYNCING_STEP_LAST
@@ -3249,6 +3251,31 @@ mm_iface_modem_3gpp_sync_finish (MMIfaceModem3gpp *self,
return g_task_propagate_boolean (G_TASK (res), error);
}
#undef VOID_SYNC_REPLY_READY_FN
#define VOID_SYNC_REPLY_READY_FN(NAME,DISPLAY) \
static void \
sync_##NAME##_ready (MMIfaceModem3gpp *self, \
GAsyncResult *res, \
GTask *task) \
{ \
DisablingContext *ctx; \
g_autoptr(GError) error = NULL; \
\
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->NAME##_finish (self, res, &error); \
if (error) \
mm_obj_dbg (self, "couldn't %s: %s", DISPLAY, error->message); \
\
/* Go on to next step */ \
ctx = g_task_get_task_data (task); \
ctx->step++; \
interface_syncing_step (task); \
}
VOID_SYNC_REPLY_READY_FN (enable_unsolicited_events,
"enable unsolicited events")
VOID_SYNC_REPLY_READY_FN (enable_unsolicited_registration_events,
"enable unsolicited registration events")
static void
sync_eps_bearer_ready (MMIfaceModem3gpp *self,
GAsyncResult *res,
@@ -3327,6 +3354,33 @@ interface_syncing_step (GTask *task)
ctx->step++;
/* fall through */
case SYNCING_STEP_ENABLE_UNSOLICITED_EVENTS:
if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_events &&
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_events_finish) {
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_events (
self,
(GAsyncReadyCallback)sync_enable_unsolicited_events_ready,
task);
return;
}
ctx->step++;
/* fall through */
case SYNCING_STEP_ENABLE_UNSOLICITED_REGISTRATION_EVENTS:
if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_registration_events &&
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_registration_events_finish) {
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_registration_events (
self,
get_cs_network_supported (self),
get_ps_network_supported (self),
get_eps_network_supported (self),
(GAsyncReadyCallback)sync_enable_unsolicited_registration_events_ready,
task);
return;
}
ctx->step++;
/* fall through */
case SYNCING_STEP_REFRESH_3GPP_REGISTRATION:
/*
* Refresh registration info to verify that the modem is still registered.
@@ -3381,6 +3435,129 @@ mm_iface_modem_3gpp_sync (MMIfaceModem3gpp *self,
interface_syncing_step (task);
}
typedef struct _TerseContext TerseContext;
static void interface_terse_step (GTask *task);
typedef enum {
TERSE_STEP_FIRST,
TERSE_STEP_DISABLE_UNSOLICITED_REGISTRATION_EVENTS,
TERSE_STEP_DISABLE_UNSOLICITED_EVENTS,
TERSE_STEP_LAST
} TerseStep;
struct _TerseContext {
TerseStep step;
};
gboolean
mm_iface_modem_3gpp_terse_finish (MMIfaceModem3gpp *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
#undef VOID_TERSE_REPLY_READY_FN
#define VOID_TERSE_REPLY_READY_FN(NAME,DISPLAY) \
static void \
terse_##NAME##_ready (MMIfaceModem3gpp *self, \
GAsyncResult *res, \
GTask *task) \
{ \
TerseContext *ctx; \
g_autoptr(GError) error = NULL; \
\
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->NAME##_finish (self, res, &error); \
if (error) \
mm_obj_dbg (self, "couldn't %s: %s", DISPLAY, error->message); \
\
/* Go on to next step */ \
ctx = g_task_get_task_data (task); \
ctx->step++; \
interface_terse_step (task); \
}
VOID_TERSE_REPLY_READY_FN (disable_unsolicited_events,
"disable unsolicited events")
VOID_TERSE_REPLY_READY_FN (disable_unsolicited_registration_events,
"disable unsolicited registration events")
static void
interface_terse_step (GTask *task)
{
MMIfaceModem3gpp *self;
TerseContext *ctx;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
switch (ctx->step) {
case TERSE_STEP_FIRST:
ctx->step++;
/* fall through */
case TERSE_STEP_DISABLE_UNSOLICITED_REGISTRATION_EVENTS:
if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_registration_events &&
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_registration_events_finish) {
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_registration_events (
self,
get_cs_network_supported (self),
get_ps_network_supported (self),
get_eps_network_supported (self),
(GAsyncReadyCallback)terse_disable_unsolicited_registration_events_ready,
task);
mm_obj_msg (self, "terse state 3GPP (%d/%d): disable unsolicited registration events done",
ctx->step, TERSE_STEP_LAST);
return;
}
ctx->step++;
/* fall through */
case TERSE_STEP_DISABLE_UNSOLICITED_EVENTS:
if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_events &&
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_events_finish) {
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_events (
self,
(GAsyncReadyCallback)terse_disable_unsolicited_events_ready,
task);
mm_obj_msg (self, "terse state 3GPP (%d/%d): disable unsolicited events done",
ctx->step, TERSE_STEP_LAST);
return;
}
ctx->step++;
/* fall through */
case TERSE_STEP_LAST:
/* We are done without errors! */
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
default:
g_assert_not_reached ();
}
g_assert_not_reached ();
}
void
mm_iface_modem_3gpp_terse (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
TerseContext *ctx;
GTask *task;
/* Create SyncingContext */
ctx = g_new0 (TerseContext, 1);
ctx->step = TERSE_STEP_FIRST;
/* Create sync steps task and execute it */
task = g_task_new (self, NULL, callback, user_data);
g_task_set_task_data (task, ctx, (GDestroyNotify)g_free);
interface_terse_step (task);
}
#endif
/*****************************************************************************/
+7
View File
@@ -318,6 +318,13 @@ gboolean mm_iface_modem_3gpp_sync_finish (MMIfaceModem3gpp *self,
GAsyncResult *res,
GError **error);
void mm_iface_modem_3gpp_terse (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_iface_modem_3gpp_terse_finish (MMIfaceModem3gpp *self,
GAsyncResult *res,
GError **error);
#endif
/* Shutdown Modem 3GPP interface */
+68
View File
@@ -6720,6 +6720,74 @@ mm_iface_modem_get_current_modes (MMIfaceModem *self,
/*****************************************************************************/
typedef struct {
const MMIfaceModemCountBearersFlags flags;
guint count;
} CountBearersContext;
static void
bearer_count (MMBaseBearer *bearer,
CountBearersContext *ctx)
{
MMBearerStatus status;
status = mm_base_bearer_get_status (MM_BASE_BEARER (bearer));
if (ctx->flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED) {
/* The Multiplexed property is only set if connected, so it's enough to check
* that one to see if we're connected and multiplexed */
if (mm_gdbus_bearer_get_multiplexed (MM_GDBUS_BEARER (bearer)))
ctx->count++;
} else if (ctx->flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_CONNECTED) {
if (status == MM_BEARER_STATUS_CONNECTED)
ctx->count++;
} else if (ctx->flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_ACTIVE) {
if (status >= MM_BEARER_STATUS_CONNECTING)
ctx->count++;
} else
ctx->count++;
}
gboolean
mm_iface_modem_count_bearers (MMIfaceModem *self,
MMIfaceModemCountBearersFlags flags,
guint *out_current,
guint *out_max,
GError **error)
{
g_autoptr(MMBearerList) list = NULL;
guint max = 0;
CountBearersContext ctx = {
.flags = flags,
.count = 0,
};
g_object_get (self,
MM_IFACE_MODEM_BEARER_LIST, &list,
NULL);
if (!list) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Bearer list unavailable");
return FALSE;
}
if (flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED)
max = mm_bearer_list_get_max_active_multiplexed (list);
else
max = mm_bearer_list_get_max_active (list);
mm_bearer_list_foreach (list, (MMBearerListForeachFunc)bearer_count, &ctx);
g_assert (max >= ctx.count);
if (out_max)
*out_max = max;
if (out_current)
*out_current = ctx.count;
return TRUE;
}
/*****************************************************************************/
static void
mm_iface_modem_default_init (MMIfaceModemInterface *iface)
{
+15
View File
@@ -620,4 +620,19 @@ void mm_iface_modem_modify_sim (MMIfaceModem *self,
void mm_iface_modem_process_sim_event (MMIfaceModem *self);
typedef enum {
/* Connecting or connected bearers */
MM_IFACE_MODEM_COUNT_BEARERS_FLAG_ACTIVE = 0x1,
/* Fully connected bearers */
MM_IFACE_MODEM_COUNT_BEARERS_FLAG_CONNECTED = 0x2,
/* Multiplexed implies connected */
MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED = 0x4,
} MMIfaceModemCountBearersFlags;
gboolean mm_iface_modem_count_bearers (MMIfaceModem *self,
MMIfaceModemCountBearersFlags flags,
guint *out_current,
guint *out_max,
GError **error);
#endif /* MM_IFACE_MODEM_H */
+30 -3
View File
@@ -27,6 +27,7 @@ G_DEFINE_TYPE_EXTENDED (MMSleepContext, mm_sleep_context, G_TYPE_OBJECT, 0,
struct _MMSleepContextPrivate {
GTask *task;
guint timeout_id;
gint64 timeout_start;
};
enum {
@@ -52,6 +53,7 @@ timeout_cleanup (MMSleepContext *self)
if (self->priv->timeout_id)
g_source_remove (self->priv->timeout_id);
self->priv->timeout_id = 0;
self->priv->timeout_start = 0;
}
void
@@ -95,6 +97,33 @@ operation_ready (MMSleepContext *self,
g_signal_emit (self, signals[DONE], 0, error);
}
static void
timeout_add (MMSleepContext *self,
guint interval)
{
timeout_cleanup (self);
self->priv->timeout_start = g_get_monotonic_time ();
self->priv->timeout_id = g_timeout_add_seconds (interval,
(GSourceFunc)operation_timeout,
self);
}
void
mm_sleep_context_timeout_backoff (MMSleepContext *self,
guint more_seconds)
{
gint64 cur_time;
gint64 new_interval;
new_interval = more_seconds * G_USEC_PER_SEC;
if (self->priv->timeout_start) {
cur_time = g_get_monotonic_time ();
new_interval += (cur_time - self->priv->timeout_start);
}
timeout_add (self, new_interval / G_USEC_PER_SEC);
}
/*****************************************************************************/
MMSleepContext *
@@ -107,9 +136,7 @@ mm_sleep_context_new (guint timeout_seconds)
NULL,
(GAsyncReadyCallback)operation_ready,
NULL);
self->priv->timeout_id = g_timeout_add_seconds (timeout_seconds,
(GSourceFunc)operation_timeout,
self);
timeout_add (self, timeout_seconds);
mm_obj_dbg (self, "new context with %d second timeout", timeout_seconds);
return self;
+3
View File
@@ -51,6 +51,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSleepContext, g_object_unref)
MMSleepContext *mm_sleep_context_new (guint timeout_seconds);
void mm_sleep_context_timeout_backoff (MMSleepContext *self,
guint more_seconds);
/* The MMSleepContext assumes ownership of @error */
void mm_sleep_context_complete (MMSleepContext *self,
GError *error);