Compare commits

...
21 Commits
Author SHA1 Message Date
Dan Williams 958bc69299 Merge request !1348 from '1-24-cherry-picks-05-08-25'
[1.24] stable cherry-picks 2025-05-08

https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1348
2025-05-08 18:12:47 -05:00
Dan Williams 3827a63d33 modem-helpers: report C*REG=2 AcT 9 as NB-IOT access technology
Signed-off-by: Dan Williams <dan@ioncontrol.co>
(cherry picked from commit 2e27b02004)
2025-05-08 16:08:28 -05:00
Dan Williams 46cc38570d broadband-modem: reload registration info after manual registration
This refreshes operator information after manual registration. QMI and
MBIM implementations return operator info along with registration info
so they handle this easily, while with AT-based devices we must run
additional commands to retrieve that after the manual registration has
finished.

Suggested by: Kirill Buksha <kirill.buksha@axians.rs>
Fixes: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/971

Signed-off-by: Dan Williams <dan@ioncontrol.co>
(cherry picked from commit febab17f07)
2025-05-08 16:08:21 -05:00
Dan Williams dc3a7f0d3b broadband-modem: detect old Mediatek 62xx chipsets as GSM-capable
They don't necessarily reply to +WS46 but like old Motorola ESX
devices they reply to +CGMM with a known string.

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

Signed-off-by: Dan Williams <dan@ioncontrol.co>
(cherry picked from commit 8cf25a97a1)
2025-05-08 16:07:58 -05:00
Dan Williams 9f0db52ed0 iface-modem-voice: recheck call state polling when call is started
When an outgoing call is created and added to the call list its state
is UNKNOWN. The call list emits the ADDED signal which MMIfaceModemVoice
listens for to check whether to begin polling call state.

But since UNKNOWN is not an in-progress call state polling isn't started.
And nothing was rechecking whether to start polling when the call state
changed to something other than UNKNOWN.

Do that so that we can track call progress as it dials out and is
answered.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
(cherry picked from commit 92e666e1c9)
2025-05-08 16:07:39 -05:00
Dan Williams 240a9145ad modem-helpers-cinterion: allow spaces in ^SXRAT test response
^SXRAT: (0-6), (0,2,3), (0,2,3)

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

Signed-off-by: Dan Williams <dan@ioncontrol.co>
(cherry picked from commit 6b6997362b)
2025-05-08 16:07:33 -05:00
Dan Williams 018e440848 shared-fibocom: don't assume parent implements the firmware interface
MMBroadbandModemMbimMtkFibocom doesn't, so don't assert it.

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

Signed-off-by: Dan Williams <dan@ioncontrol.co>
(cherry picked from commit 046b79a676)
2025-05-08 16:07:22 -05:00
Dan Williams 0c7d573969 modem-helpers: fix checking of CDMA/EVDO access technology
Missing ! for strncmp() meant the test was backwards and would
erroneously report 1xRTT and EVDOr0 when those access technologies
were not in use.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
(cherry picked from commit 9e205f4784)
2025-05-08 16:07:11 -05:00
Jan Alexander Steffens (heftig) 1ec2b86239 docs: Fix gtk-doc build
Fix a duplicate `id` and the inclusions of gdbus docs.

Signed-off-by: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
(cherry picked from commit 078a92cd5c)
2025-05-08 16:07:02 -05:00
Dan Williams 4fa4084600 Merge request !1347 from 'sleep-wait-1.24'
[1.24] Wait until device operations complete before dropping suspend inhibitor

https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1347
2025-05-08 16:04:02 -05:00
Dan Williams dae00a9f2f broadband-modem: close serial ports in dispose
We want ports to be closed as early as possible; so make sure they
are closed in dispose() which is run explicitly by MMDevice when
cleaning up and removing the modem. Otherwise they could stay
open longer than we want, causing problems for suspend/resume.

This caused problems with suspend because cancelling the
MMBaseModem's cancellable triggered an idle handler that held
a reference to the modem, preventing finalize() from running
until after the suspend code was finished, thus preventing
ports from being closed and cleaned up. Closing them in
dispose() handles this.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-05-08 15:44:36 -05:00
Dan Williams 3157a90c5b broadband-modem: remove invalid idle handler during dispose
base_modem_invalid_idle() needs to keep a reference to the
MMBaseModem until its done. But if the modem is cancelled during
removal right before we're trying to forget about it, keeping
that reference can prevent everything getting cleaned up by
MMBaseModem's dispose() until after the mainloop has run again
and all our removal operations are supposedly complete.

MMDevice uses an explicit dispose() trigger that mitigates
most of this (and requires it for other reasons, like breaking
reference cycles between the modem and it's various child
classes) but it's somewhat error-prone to keep the modem
around if we don't really need to.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-05-08 15:44:36 -05:00
Dan Williams 34148f8e8b broadband-modem-qmi,mbim: remove redundant port closes
This will just be done immediately after by MMBaseModem's
dispose() handler.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-05-08 15:44:36 -05:00
Dan Williams c146dd6094 base-manager: convert shutdown to steps
Make the call flow clearer.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-05-08 15:44:36 -05:00
Dan Williams d80f98da01 base-manager,device: consolidate modem cancelling into mm_device_remove_modem()
Every use of mm_device_remove_modem() was already trying to cancel the
modem's canellable, so let's just put it there and simplify the callers.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-05-08 15:44:36 -05:00
Dan Williams b97f864acd base-manager,sleep-monitor: wait for modem operations before sleeping
Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-05-08 15:44:36 -05:00
Dan Williams 5e29ece5ec base-modem: clarify port cleanup/close behavior for serial ports
Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-05-08 15:44:36 -05:00
Dan Williams e12b3adb35 base-modem: allow port teardown operation to use callbacks if needed
Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-05-08 15:44:36 -05:00
Dan Williams 649350dfff port-serial: don't log force-closes if not really being forced close
Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-05-08 15:44:36 -05:00
Dan Williams 18521b6882 Merge request !1332 from 'bump-1-24-1'
build: unstable release version bump to 1.24.1

https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1332
2025-04-10 01:57:37 +00:00
Dan Williams 7fc6788737 build: unstable release version bump to 1.24.1
Signed-off-by: Dan Williams <dan@ioncontrol.co>
2025-04-09 20:43:22 -05:00
25 changed files with 1101 additions and 268 deletions
@@ -92,7 +92,7 @@
This object also controls any process-wide operation, such as the log
level being used by the daemon.
</para>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.xml"/>
</chapter>
<chapter id="ref-dbus-object-modem">
@@ -129,22 +129,22 @@
or the
<link linkend="gdbus-org.freedesktop.ModemManager1.Modem.ModemCdma">CDMA interface</link>.
</para>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Simple.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.ProfileManager.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.Ussd.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.ModemCdma.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Messaging.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Location.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Time.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Voice.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.CellBroadcast.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Firmware.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Sar.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Signal.xml"/>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Oma.xml"/>
<!--xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Contacts.xml"/-->
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Simple.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.ProfileManager.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.Ussd.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.ModemCdma.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Messaging.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Location.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Time.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Voice.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.CellBroadcast.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Firmware.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Sar.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Signal.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Oma.xml"/>
<!--xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Contacts.xml"/-->
</chapter>
<chapter id="ref-dbus-object-bearer">
@@ -155,7 +155,7 @@
may expose one or more Bearer objects, which can then be used to get the
modem into connected state.
</para>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Bearer.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Bearer.xml"/>
</chapter>
<chapter id="ref-dbus-object-sim">
@@ -166,7 +166,7 @@
expose up to one SIM object, which allows SIM-specific actions such as PIN
unlocking.
</para>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Sim.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Sim.xml"/>
</chapter>
<chapter id="ref-dbus-object-sms">
@@ -176,7 +176,7 @@
<link linkend="gdbus-org.freedesktop.ModemManager1.Modem.Messaging">Messaging interface</link>
will export one SMS object for each SMS stored in the device.
</para>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Sms.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Sms.xml"/>
</chapter>
<chapter id="ref-dbus-object-call">
@@ -186,17 +186,17 @@
<link linkend="gdbus-org.freedesktop.ModemManager1.Modem.Voice">Voice interface</link>
will export one Call object for each Call managed in the device.
</para>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Call.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Call.xml"/>
</chapter>
<chapter id="ref-dbus-object-call">
<chapter id="ref-dbus-object-cbm">
<title>The <literal>/org/freedesktop/ModemManager/CBM</literal> objects</title>
<para>
Modems implementing the
<link linkend="gdbus-org.freedesktop.ModemManager1.Modem.CellBroadcast">Cell Broadcast interface</link>
will export one CBM object for each Cell Broadcast message received by the device.
</para>
<xi:include href="../../../../libmm-glib/generated/mm-gdbus-doc-org.freedesktop.ModemManager1.Call.xml"/>
<xi:include href="mm-gdbus-doc-org.freedesktop.ModemManager1.Cbm.xml"/>
</chapter>
</part>
+5
View File
@@ -22,6 +22,9 @@ expand_content_files = [
'ModemManager-overview.xml',
# FIXME: workaround because only strings can be included and not custom targets (gen_docs)
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Bearer.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Call.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Cbm.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.CellBroadcast.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Firmware.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Location.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Messaging.xml',
@@ -30,9 +33,11 @@ expand_content_files = [
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.ModemCdma.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Oma.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Sar.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Signal.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Simple.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Time.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Voice.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Sim.xml',
generated_build_dir / 'mm-gdbus-doc-org.freedesktop.ModemManager1.Sms.xml',
+1 -1
View File
@@ -3,7 +3,7 @@
project(
'ModemManager', 'c',
version: '1.24.0',
version: '1.24.1',
license: 'GPL2',
default_options: [
'buildtype=debugoptimized',
+36 -15
View File
@@ -59,14 +59,15 @@ quit_cb (gpointer user_data)
#if defined WITH_SUSPEND_RESUME
static void
sleeping_cb (MMSleepMonitor *sleep_monitor)
sleeping_cb (MMSleepMonitor *sleep_monitor,
MMSleepContext *ctx)
{
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);
mm_base_manager_shutdown (manager, TRUE, TRUE, TRUE, ctx);
} else {
mm_dbg ("removing devices... (sleeping)");
mm_base_manager_shutdown (manager, FALSE, FALSE, TRUE);
mm_base_manager_shutdown (manager, FALSE, FALSE, TRUE, ctx);
}
}
@@ -78,11 +79,16 @@ resuming_cb (MMSleepMonitor *sleep_monitor)
}
static void
sleeping_quick_cb (MMSleepMonitor *sleep_monitor)
sleeping_quick_cb (MMSleepMonitor *sleep_monitor,
MMSleepContext *ctx)
{
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);
mm_base_manager_shutdown (manager, TRUE, TRUE, FALSE, ctx);
} else {
/* Don't need to wait for anything; just suspend */
mm_dbg ("leaving modem powered... (sleeping)");
mm_sleep_context_complete (ctx, NULL);
}
}
@@ -168,6 +174,18 @@ register_dbus_errors (void)
g_dbus_error_register_error (G_IO_ERROR, G_IO_ERROR_CANCELLED, MM_CORE_ERROR_DBUS_PREFIX ".Cancelled");
}
static void
shutdown_done (MMSleepContext *sleep_ctx,
GError *error,
GMainLoop *quit_loop)
{
if (error)
mm_warn ("shutdown failed: %s", error->message);
else
mm_msg ("shutdown complete");
g_main_loop_quit (quit_loop);
}
int
main (int argc, char *argv[])
{
@@ -241,28 +259,31 @@ main (int argc, char *argv[])
loop = NULL;
if (manager) {
GTimer *timer;
MMSleepContext *ctx;
guint sleep_done_id;
mm_base_manager_shutdown (manager, TRUE, FALSE, TRUE);
ctx = mm_sleep_context_new (MAX_SHUTDOWN_TIME_SECS);
sleep_done_id = g_signal_connect (ctx,
MM_SLEEP_CONTEXT_DONE,
(GCallback)shutdown_done,
inner);
mm_base_manager_shutdown (manager, TRUE, FALSE, TRUE, ctx);
/* Wait for all modems to be disabled and removed, but don't wait
* forever: if disabling the modems takes longer than 20s, just
* shutdown anyway. */
timer = g_timer_new ();
while (mm_base_manager_num_modems (manager) &&
g_timer_elapsed (timer, NULL) < (gdouble)MAX_SHUTDOWN_TIME_SECS) {
GMainContext *ctx = g_main_loop_get_context (inner);
while (mm_base_manager_num_modems (manager))
g_main_loop_run (inner);
g_main_context_iteration (ctx, FALSE);
g_usleep (50);
}
g_signal_handler_disconnect (ctx, sleep_done_id);
g_object_unref (ctx);
if (mm_base_manager_num_modems (manager))
mm_warn ("disabling modems took too long, shutting down with %u modems around",
mm_base_manager_num_modems (manager));
g_object_unref (manager);
g_timer_destroy (timer);
}
g_main_loop_unref (inner);
+1
View File
@@ -299,6 +299,7 @@ sources = files(
'mm-port-probe-at.c',
'mm-private-boxed-types.c',
'mm-sms-list.c',
'mm-sleep-context.c',
)
sources += daemon_enums_sources
+272 -117
View File
@@ -129,23 +129,6 @@ struct _MMBaseManagerPrivate {
/*****************************************************************************/
static MMDevice *
find_device_by_modem (MMBaseManager *manager,
MMBaseModem *modem)
{
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, manager->priv->devices);
while (g_hash_table_iter_next (&iter, &key, &value)) {
MMDevice *candidate = MM_DEVICE (value);
if (modem == mm_device_peek_modem (candidate))
return candidate;
}
return NULL;
}
static MMDevice *
find_device_by_port (MMBaseManager *manager,
MMKernelDevice *port)
@@ -367,7 +350,7 @@ device_removed (MMBaseManager *self,
/* The device may have already been removed from the tracking HT, we
* just try to remove it and if it fails, we ignore it */
mm_device_remove_modem (device);
mm_device_remove_modem_quick (device);
g_hash_table_remove (self->priv->devices, mm_device_get_uid (device));
}
}
@@ -455,6 +438,19 @@ existing_port (MMBaseManager *self,
device_support_check_add_single_port (self, device, port);
}
static void
additional_port_modem_remove_ready (MMDevice *device,
GAsyncResult *res,
MMBaseManager *self)
{
g_autoptr(GError) error = NULL;
if (!mm_device_remove_modem_finish (device, res, &error))
mm_obj_warn (device, "removing modem failed: %s", error->message);
device_support_check_add_all_ports (self, device);
g_object_unref (self);
}
static void
additional_port (MMBaseManager *self,
MMDevice *device,
@@ -500,9 +496,9 @@ additional_port (MMBaseManager *self,
}
mm_obj_info (self, "last modem object creation in device '%s' succeeded, but we have a new port addition, will retry", uid);
g_cancellable_cancel (mm_base_modem_peek_cancellable (modem));
mm_device_remove_modem (device);
device_support_check_add_all_ports (self, device);
mm_device_remove_modem (device,
(GAsyncReadyCallback)additional_port_modem_remove_ready,
g_object_ref (self));
}
static void
@@ -873,146 +869,305 @@ 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;
typedef struct {
MMBaseManager *self;
gboolean low_power;
gboolean remove;
} DisableContext;
MMBaseModem *modem;
gboolean disable;
gboolean low_power;
gboolean remove;
static void
disable_context_free (DisableContext *ctx)
DeviceShutdownStep step;
} DeviceShutdownContext;
static void device_shutdown_step (GTask *task);
static DeviceShutdownContext *
device_shutdown_context_new (MMBaseModem *modem,
gboolean disable,
gboolean low_power,
gboolean remove)
{
g_object_unref (ctx->self);
g_slice_free (DisableContext, ctx);
DeviceShutdownContext *ctx;
ctx = g_slice_new0 (DeviceShutdownContext);
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;
return ctx;
}
static void
remove_device_after_disable (MMBaseModem *modem,
DisableContext *ctx)
device_shutdown_context_free (DeviceShutdownContext *ctx)
{
MMDevice *device;
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 (ctx->self->priv->devices, mm_device_get_uid (device));
}
disable_context_free (ctx);
g_clear_object (&ctx->modem);
g_slice_free (DeviceShutdownContext, ctx);
}
static void
shutdown_low_power_ready (MMIfaceModem *modem,
GAsyncResult *res,
DisableContext *ctx)
modem_remove_ready (MMDevice *device,
GAsyncResult *res,
GTask *task)
{
g_autoptr(GError) error = NULL;
DeviceShutdownContext *ctx;
g_autoptr(GError) error = NULL;
ctx = g_task_get_task_data (task);
if (!mm_device_remove_modem_finish (device, res, &error))
mm_obj_warn (device, "removing modem failed: %s", error->message);
ctx->step++;
device_shutdown_step (task);
}
static void
shutdown_low_power_ready (MMIfaceModem *modem,
GAsyncResult *res,
GTask *task)
{
DeviceShutdownContext *ctx;
g_autoptr(GError) error = NULL;
ctx = g_task_get_task_data (task);
if (!mm_iface_modem_set_power_state_finish (modem, res, NULL, &error))
mm_obj_info (ctx->self, "changing to low power state failed: %s", error->message);
mm_obj_info (modem, "changing to low power state failed: %s", error->message);
if (ctx->remove)
remove_device_after_disable (MM_BASE_MODEM (modem), ctx);
else
disable_context_free (ctx);
ctx->step++;
device_shutdown_step (task);
}
static void
shutdown_disable_ready (MMBaseModem *modem,
GAsyncResult *res,
DisableContext *ctx)
shutdown_disable_ready (MMBaseModem *modem,
GAsyncResult *res,
GTask *task)
{
g_autoptr(GError) error = NULL;
DeviceShutdownContext *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;
ctx = g_task_get_task_data (task);
if (mm_base_modem_disable_finish (modem, res, &error)) {
ctx->step++;
} else {
mm_obj_info (modem, "disabling modem failed: %s", error->message);
/* If disabling failed there's no point in trying to low-power the
* modem; just remove it.
*/
ctx->step = DEVICE_SHUTDOWN_STEP_REMOVE;
}
if (ctx->remove)
remove_device_after_disable (modem, ctx);
else
disable_context_free (ctx);
device_shutdown_step (task);
}
static void
foreach_disable (gpointer key,
MMDevice *device,
DisableContext *foreach_ctx)
device_shutdown_step (GTask *task)
{
MMBaseModem *modem;
DisableContext *ctx;
DeviceShutdownContext *ctx;
MMDevice *device;
modem = mm_device_peek_modem (device);
if (!modem)
ctx = g_task_get_task_data (task);
device = g_task_get_source_object (task);
switch (ctx->step) {
case DEVICE_SHUTDOWN_STEP_FIRST:
ctx->step++;
/* fall through */
case DEVICE_SHUTDOWN_STEP_DISABLE:
if (ctx->disable && ctx->modem) {
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,
task);
return;
}
ctx->step++;
/* fall through */
case DEVICE_SHUTDOWN_STEP_LOW_POWER:
if (ctx->low_power && ctx->modem) {
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,
task);
return;
}
ctx->step++;
/* fall through */
case DEVICE_SHUTDOWN_STEP_REMOVE:
if (ctx->remove && ctx->modem) {
mm_obj_dbg (device,
"removing modem%d",
mm_base_modem_get_dbus_id (ctx->modem));
mm_device_remove_modem (device,
(GAsyncReadyCallback)modem_remove_ready,
task);
return;
}
ctx->step++;
/* fall through */
case DEVICE_SHUTDOWN_STEP_LAST:
mm_obj_dbg (device, "device shutdown complete");
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
ctx = g_slice_new0 (DisableContext);
ctx->self = g_object_ref (foreach_ctx->self);
ctx->low_power = foreach_ctx->low_power;
ctx->remove = foreach_ctx->remove;
default:
break;
}
mm_base_modem_disable (modem,
MM_BASE_MODEM_OPERATION_LOCK_REQUIRED,
MM_BASE_MODEM_OPERATION_PRIORITY_OVERRIDE,
(GAsyncReadyCallback)shutdown_disable_ready,
ctx);
g_assert_not_reached ();
}
static gboolean
foreach_remove (gpointer key,
MMDevice *device,
MMBaseManager *self)
{
MMBaseModem *modem;
typedef struct {
MMBaseManager *self;
GSList *tasks;
GSList *devices_to_remove;
MMSleepContext *sleep_ctx;
} ManagerShutdownContext;
modem = mm_device_peek_modem (device);
if (modem)
g_cancellable_cancel (mm_base_modem_peek_cancellable (modem));
mm_device_remove_modem (device);
return TRUE;
static ManagerShutdownContext *
manager_shutdown_context_new (MMBaseManager *self,
MMSleepContext *sleep_ctx)
{
ManagerShutdownContext *ctx;
ctx = g_slice_new0 (ManagerShutdownContext);
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)
{
if (task)
ctx->tasks = g_slist_remove (ctx->tasks, task);
if (remove) {
g_assert (device);
ctx->devices_to_remove = g_slist_append (ctx->devices_to_remove, device);
}
if (ctx->tasks == NULL) {
GSList *iter;
/* Remove devices at the end to avoid modifying the hash table
* during iteration, in case a device has no modem and the steps
* all fall through.
*/
for (iter = ctx->devices_to_remove; iter; iter = iter->next)
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_sleep_context_complete (ctx->sleep_ctx, NULL);
g_object_unref (ctx->sleep_ctx);
g_object_unref (ctx->self);
g_slice_free (ManagerShutdownContext, ctx);
}
}
static void
device_shutdown_ready (MMDevice *device,
GAsyncResult *res,
ManagerShutdownContext *ctx)
{
GTask *task;
DeviceShutdownContext *dctx;
g_autoptr(GError) error = NULL;
task = G_TASK (res);
if (!g_task_propagate_boolean (task, &error)) {
mm_obj_info (ctx->self,
"failed to shutdown 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);
}
void
mm_base_manager_shutdown (MMBaseManager *self,
gboolean disable,
gboolean low_power,
gboolean remove)
mm_base_manager_shutdown (MMBaseManager *self,
gboolean disable,
gboolean low_power,
gboolean remove,
MMSleepContext *sleep_ctx)
{
ManagerShutdownContext *ctx;
GHashTableIter iter;
MMDevice *device;
g_return_if_fail (self != NULL);
g_return_if_fail (MM_IS_BASE_MANAGER (self));
/* Cancel all ongoing auth requests */
g_cancellable_cancel (self->priv->authp_cancellable);
if (disable) {
DisableContext foreach_ctx = {
.self = self,
.low_power = low_power,
.remove = remove,
};
g_hash_table_foreach (self->priv->devices, (GHFunc)foreach_disable, &foreach_ctx);
mm_obj_dbg (self,
"manager shutting down... (%s%s%s%s%s)",
disable ? "disable" : "",
disable && (low_power || remove) ? "," : "",
low_power ? "low-power" : "",
(low_power && remove) ? "," : "",
remove ? "remove" : "");
/* Disabling may take a few iterations of the mainloop, so the caller
* has to iterate the mainloop until all devices have been disabled and
* removed.
*/
return;
ctx = manager_shutdown_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;
task = g_task_new (device,
NULL,
(GAsyncReadyCallback)device_shutdown_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);
device_shutdown_step (task);
}
if (remove) {
/* Otherwise, just remove directly */
g_hash_table_foreach_remove (self->priv->devices, (GHRFunc)foreach_remove, self);
}
/* Complete shutdown if there were no devices */
manager_shutdown_context_maybe_complete (ctx, NULL, NULL, FALSE);
}
guint32
@@ -1713,7 +1868,7 @@ handle_set_profile (MmGdbusTest *skeleton,
out:
if (error) {
mm_device_remove_modem (device);
mm_device_remove_modem_quick (device);
g_hash_table_remove (self->priv->devices, mm_device_get_uid (device));
mm_dbus_method_invocation_return_gerror (invocation, error);
g_error_free (error);
+6 -4
View File
@@ -25,6 +25,7 @@
#include "mm-filter.h"
#include "mm-gdbus-manager.h"
#include "mm-sleep-context.h"
#define MM_TYPE_BASE_MANAGER (mm_base_manager_get_type ())
#define MM_BASE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BASE_MANAGER, MMBaseManager))
@@ -71,10 +72,11 @@ 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);
void mm_base_manager_shutdown (MMBaseManager *manager,
gboolean disable,
gboolean power_low,
gboolean remove,
MMSleepContext *ctx);
#if defined WITH_SUSPEND_RESUME
void mm_base_manager_sync (MMBaseManager *manager);
+177 -16
View File
@@ -87,6 +87,7 @@ struct _MMBaseModemPrivate {
* should be done by the modem. */
GCancellable *cancellable;
gulong invalid_if_cancelled;
guint invalid_from_idle;
gchar *device;
gchar *physdev;
@@ -101,6 +102,7 @@ struct _MMBaseModemPrivate {
gboolean hotplugged;
gboolean valid;
gboolean reprobe;
gboolean torn_down;
guint max_timeouts;
@@ -2132,13 +2134,22 @@ mm_base_modem_get_subsystem_device_id (MMBaseModem *self)
/*****************************************************************************/
static void
clear_invalid_from_idle (MMBaseModem *self)
{
if (self->priv->invalid_from_idle)
g_source_remove (self->priv->invalid_from_idle);
self->priv->invalid_from_idle = 0;
}
static gboolean
base_modem_invalid_idle (MMBaseModem *self)
{
clear_invalid_from_idle (self);
/* Ensure the modem is set invalid if we get the modem-wide cancellable
* cancelled */
mm_base_modem_set_valid (self, FALSE);
g_object_unref (self);
return G_SOURCE_REMOVE;
}
@@ -2146,9 +2157,14 @@ static void
base_modem_cancelled (GCancellable *cancellable,
MMBaseModem *self)
{
clear_invalid_from_idle (self);
/* NOTE: Don't call set_valid() directly here, do it in an idle, and ensure
* that we pass a valid reference of the modem object as context. */
g_idle_add ((GSourceFunc)base_modem_invalid_idle, g_object_ref (self));
self->priv->invalid_from_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
(GSourceFunc)base_modem_invalid_idle,
g_object_ref (self),
(GDestroyNotify) g_object_unref);
}
/*****************************************************************************/
@@ -2160,9 +2176,107 @@ setup_ports_table (GHashTable **ht)
*ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}
typedef struct {
volatile gint refcount;
GError *error;
/* The Context owns the GTask so that we can ensure the Task returns only
* when all ports are closed. The reference count tracks open ports and
* the context will return the Task when it reaches zero (indicating all
* outstanding operations are complete and ports are closed).
*/
GTask *task;
} TeardownContext;
static TeardownContext *
teardown_context_new (GObject *source_object,
GAsyncReadyCallback callback,
gpointer user_data)
{
TeardownContext *ctx;
ctx = g_slice_new0 (TeardownContext);
ctx->refcount = 1;
ctx->task = g_task_new (source_object, NULL, callback, user_data);
return ctx;
}
static void
cleanup_modem_port (MMBaseModem *self,
MMPort *port)
teardown_context_ref (TeardownContext *ctx)
{
g_atomic_int_inc (&ctx->refcount);
}
static void
teardown_context_unref (TeardownContext *ctx)
{
if (g_atomic_int_dec_and_test (&ctx->refcount)) {
if (ctx->error)
g_task_return_error (ctx->task, g_steal_pointer (&ctx->error));
else
g_task_return_boolean (ctx->task, TRUE);
g_clear_object (&ctx->task);
g_slice_free (TeardownContext, ctx);
}
}
#if defined (WITH_MBIM) || defined (WITH_QMI)
static void
teardown_context_add_error (TeardownContext *ctx,
MMPort *port,
GError *error)
{
if (!ctx->error) {
ctx->error = g_error_copy (error);
g_prefix_error (&ctx->error,
"[%s] teardown error: ",
mm_port_get_device (port));
} else {
g_prefix_error (&ctx->error,
"[%s] teardown error: %s; ",
mm_port_get_device (port),
error->message);
}
}
#endif
#if defined WITH_MBIM
static void
mbim_port_close_ready (MMPortMbim *port,
GAsyncResult *res,
TeardownContext *ctx)
{
g_autoptr(GError) error = NULL;
if (!mm_port_mbim_close_finish (port, res, &error))
teardown_context_add_error (ctx, MM_PORT (port), error);
teardown_context_unref (ctx);
}
#endif
#if defined WITH_QMI
static void
qmi_port_close_ready (MMPortQmi *port,
GAsyncResult *res,
TeardownContext *ctx)
{
g_autoptr(GError) error = NULL;
if (!mm_port_qmi_close_finish (port, res, &error))
teardown_context_add_error (ctx, MM_PORT (port), error);
teardown_context_unref (ctx);
}
#endif
static void
cleanup_modem_port (MMBaseModem *self,
MMPort *port,
TeardownContext *ctx)
{
mm_obj_dbg (self, "cleaning up port '%s/%s'...",
mm_port_subsys_get_string (mm_port_get_subsys (MM_PORT (port))),
@@ -2172,10 +2286,20 @@ cleanup_modem_port (MMBaseModem *self,
g_signal_handlers_disconnect_by_func (port, port_timed_out_cb, self);
g_signal_handlers_disconnect_by_func (port, port_removed_cb, self);
if (ctx)
teardown_context_ref (ctx);
/* No need to close serial ports here as they do not require a specific
* shutdown procedure with message exchanges and callbacks. They will be
* closed when the modem is invalidated or disposed.
*/
#if defined WITH_MBIM
/* We need to close the MBIM port cleanly when disposing the modem object */
if (MM_IS_PORT_MBIM (port)) {
mm_port_mbim_close (MM_PORT_MBIM (port), NULL, NULL);
mm_port_mbim_close (MM_PORT_MBIM (port),
ctx ? (GAsyncReadyCallback)mbim_port_close_ready : NULL,
ctx);
return;
}
#endif
@@ -2186,27 +2310,61 @@ cleanup_modem_port (MMBaseModem *self,
* allocating too many newer allocations will fail with client-ids-exhausted
* errors. */
if (MM_IS_PORT_QMI (port)) {
mm_port_qmi_close (MM_PORT_QMI (port), NULL, NULL);
mm_port_qmi_close (MM_PORT_QMI (port),
ctx ? (GAsyncReadyCallback)qmi_port_close_ready : NULL,
ctx);
return;
}
#endif
if (ctx)
teardown_context_unref (ctx);
}
static void
teardown_ports_table (MMBaseModem *self,
GHashTable **ht)
teardown_ports_tables (MMBaseModem *self,
TeardownContext *ctx)
{
GHashTable **tables[2] = {
&self->priv->link_ports,
&self->priv->ports,
};
GHashTableIter iter;
gpointer value;
gpointer key;
guint i;
if (!*ht)
return;
for (i = 0; i < G_N_ELEMENTS (tables); i++) {
if (*tables[i]) {
g_hash_table_iter_init (&iter, *tables[i]);
while (g_hash_table_iter_next (&iter, &key, &value))
cleanup_modem_port (self, MM_PORT (value), ctx);
g_hash_table_destroy (*tables[i]);
*tables[i] = NULL;
}
}
}
g_hash_table_iter_init (&iter, *ht);
while (g_hash_table_iter_next (&iter, &key, &value))
cleanup_modem_port (self, MM_PORT (value));
g_hash_table_destroy (g_steal_pointer (ht));
gboolean
mm_base_modem_teardown_ports_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
void
mm_base_modem_teardown_ports (MMBaseModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
TeardownContext *ctx;
self->priv->torn_down = TRUE;
ctx = teardown_context_new (G_OBJECT (self), callback, user_data);
teardown_ports_tables (self, ctx);
teardown_context_unref (ctx);
}
/*****************************************************************************/
@@ -2412,6 +2570,8 @@ dispose (GObject *object)
g_cancellable_cancel (self->priv->cancellable);
g_clear_object (&self->priv->cancellable);
clear_invalid_from_idle (self);
g_clear_object (&self->priv->primary);
g_clear_object (&self->priv->secondary);
g_list_free_full (g_steal_pointer (&self->priv->data), g_object_unref);
@@ -2426,8 +2586,9 @@ dispose (GObject *object)
g_list_free_full (g_steal_pointer (&self->priv->mbim), g_object_unref);
#endif
teardown_ports_table (self, &self->priv->link_ports);
teardown_ports_table (self, &self->priv->ports);
if (!self->priv->torn_down)
mm_obj_warn (self, "teardown not called before dispose");
teardown_ports_tables (self, NULL);
g_clear_object (&self->priv->connection);
+7
View File
@@ -307,4 +307,11 @@ gboolean mm_base_modem_sync_finish (MMBaseModem *self,
GError **error);
#endif
void mm_base_modem_teardown_ports (MMBaseModem *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_base_modem_teardown_ports_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error);
#endif /* MM_BASE_MODEM_H */
-4
View File
@@ -10416,10 +10416,6 @@ dispose (GObject *object)
/* Explicitly remove notification handler */
self->priv->setup_flags = PROCESS_NOTIFICATION_FLAG_NONE;
common_setup_cleanup_unsolicited_events_sync (self, mbim, FALSE);
/* If we did open the MBIM port during initialization, close it now */
if (mm_port_mbim_is_open (mbim))
mm_port_mbim_close (mbim, NULL, NULL);
}
g_clear_object (&self->priv->unlock_retries);
-11
View File
@@ -13994,17 +13994,6 @@ static void
dispose (GObject *object)
{
MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (object);
MMPortQmi *qmi;
/* If any port cleanup is needed, it must be done during dispose(), as
* the modem object will be affected by an explicit g_object_run_dispose()
* that will remove all port references right away */
qmi = mm_broadband_modem_qmi_peek_port_qmi (self);
if (qmi) {
/* If we did open the QMI port during initialization, close it now */
if (mm_port_qmi_is_open (qmi))
mm_port_qmi_close (qmi, NULL, NULL);
}
g_list_free_full (self->priv->firmware_list, g_object_unref);
self->priv->firmware_list = NULL;
+58 -22
View File
@@ -323,25 +323,32 @@ ports_context_ref (PortsContext *ctx)
return ctx;
}
static void
ports_context_dispose (PortsContext *ctx)
{
if (ctx->primary && ctx->primary_open) {
mm_port_serial_close (MM_PORT_SERIAL (ctx->primary));
ctx->primary_open = FALSE;
}
if (ctx->secondary && ctx->secondary_open) {
mm_port_serial_close (MM_PORT_SERIAL (ctx->secondary));
ctx->secondary_open = FALSE;
}
if (ctx->qcdm && ctx->qcdm_open) {
mm_port_serial_close (MM_PORT_SERIAL (ctx->qcdm));
ctx->qcdm_open = FALSE;
}
}
static void
ports_context_unref (PortsContext *ctx)
{
if (g_atomic_int_dec_and_test (&ctx->ref_count)) {
if (ctx->primary) {
if (ctx->primary_open)
mm_port_serial_close (MM_PORT_SERIAL (ctx->primary));
g_object_unref (ctx->primary);
}
if (ctx->secondary) {
if (ctx->secondary_open)
mm_port_serial_close (MM_PORT_SERIAL (ctx->secondary));
g_object_unref (ctx->secondary);
}
if (ctx->qcdm) {
if (ctx->qcdm_open)
mm_port_serial_close (MM_PORT_SERIAL (ctx->qcdm));
g_object_unref (ctx->qcdm);
}
ports_context_dispose (ctx);
g_clear_object (&ctx->primary);
g_clear_object (&ctx->secondary);
g_clear_object (&ctx->qcdm);
g_free (ctx);
}
}
@@ -761,11 +768,14 @@ parse_caps_cgmm (MMBaseModem *self,
if (!response)
return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE;
/* This check detects some really old Motorola GPRS dongles and phones */
/* This check detects some really old Motorola and Mediatek GPRS dongles
* and phones.
*/
if (strstr (response, "GSM900") ||
strstr (response, "GSM1800") ||
strstr (response, "GSM1900") ||
strstr (response, "GSM850")) {
strstr (response, "GSM850") ||
strstr (response, "MTK2")) {
/* At least, it's a GSM modem */
*result = g_variant_new_uint32 (MM_MODEM_CAPABILITY_GSM_UMTS);
return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS;
@@ -5584,6 +5594,21 @@ modem_3gpp_run_registration_checks_finish (MMIfaceModem3gpp *self,
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
run_registration_checks_reload_current_registration_info_ready (MMIfaceModem3gpp *modem,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
mm_iface_modem_3gpp_reload_current_registration_info_finish (modem, res, &error);
if (error)
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void run_registration_checks_context_step (GTask *task);
static void
@@ -5825,13 +5850,17 @@ run_registration_checks_context_step (GTask *task)
error = g_steal_pointer (&ctx->error_cs);
else
g_assert_not_reached ();
g_task_return_error (task, error);
g_object_unref (task);
return;
}
if (error)
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
/* When everything is done, recheck operator info as it may have changed */
mm_iface_modem_3gpp_reload_current_registration_info (
MM_IFACE_MODEM_3GPP (self),
(GAsyncReadyCallback)run_registration_checks_reload_current_registration_info_ready,
task);
}
static void
@@ -14258,6 +14287,13 @@ dispose (GObject *object)
g_clear_object (&self->priv->modem_simple_status);
g_clear_object (&self->priv->modem_cell_broadcast_cbm_list);
if (self->priv->enabled_ports_ctx)
ports_context_dispose (self->priv->enabled_ports_ctx);
if (self->priv->sim_hot_swap_ports_ctx)
ports_context_dispose (self->priv->sim_hot_swap_ports_ctx);
if (self->priv->in_call_ports_ctx)
ports_context_dispose (self->priv->in_call_ports_ctx);
G_OBJECT_CLASS (mm_broadband_modem_parent_class)->dispose (object);
}
+99 -14
View File
@@ -459,14 +459,66 @@ clear_modem (MMDevice *self)
}
}
void
mm_device_remove_modem (MMDevice *self)
gboolean
mm_device_remove_modem_finish (MMDevice *self,
GAsyncResult *res,
GError **error)
{
if (!self->priv->modem)
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
teardown_ports_ready (MMBaseModem *modem,
GAsyncResult *res,
GTask *task)
{
MMDevice *self;
GError *error = NULL;
gboolean success;
self = g_task_get_source_object (task);
success = mm_base_modem_teardown_ports_finish (modem, res, &error);
clear_modem (self);
if (!success)
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
void
mm_device_remove_modem (MMDevice *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
task = g_task_new (self, NULL, callback, user_data);
if (!self->priv->modem) {
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
unexport_modem (self);
clear_modem (self);
g_cancellable_cancel (mm_base_modem_peek_cancellable (self->priv->modem));
mm_base_modem_teardown_ports (self->priv->modem,
(GAsyncReadyCallback)teardown_ports_ready,
task);
}
/* Should only be used from testing code or when the hardware is no longer
* present and cannot be gracefully cleaned up.
*/
void
mm_device_remove_modem_quick (MMDevice *self)
{
if (self->priv->modem) {
unexport_modem (self);
clear_modem (self);
}
}
/*****************************************************************************/
@@ -491,6 +543,25 @@ reprobe (MMDevice *self)
return G_SOURCE_REMOVE;
}
static void
modem_valid_remove_ready (MMDevice *self,
GAsyncResult *res,
MMBaseModem *modem)
{
g_autoptr(GError) error = NULL;
if (!mm_device_remove_modem_finish (self, res, &error))
mm_obj_warn (self, "removing modem failed: %s", error->message);
if (mm_base_modem_get_reprobe (modem)) {
if (self->priv->reprobe_id)
g_source_remove (self->priv->reprobe_id);
self->priv->reprobe_id = g_timeout_add_seconds (REPROBE_SECS, (GSourceFunc)reprobe, self);
}
g_object_unref (modem);
}
static void
modem_valid (MMBaseModem *modem,
GParamSpec *pspec,
@@ -498,9 +569,9 @@ modem_valid (MMBaseModem *modem,
{
if (!mm_base_modem_get_valid (modem)) {
/* Modem no longer valid */
mm_device_remove_modem (self);
if (mm_base_modem_get_reprobe (modem))
self->priv->reprobe_id = g_timeout_add_seconds (REPROBE_SECS, (GSourceFunc)reprobe, self);
mm_device_remove_modem (self,
(GAsyncReadyCallback)modem_valid_remove_ready,
g_object_ref (modem));
} else {
/* Modem now valid, export it, but only if we really have it around.
* It may happen that the initialization sequence fails because the
@@ -732,6 +803,19 @@ mm_device_inhibit_finish (MMDevice *self,
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
inhibit_disable_modem_remove_ready (MMDevice *self,
GAsyncResult *res,
GTask *task)
{
g_autoptr(GError) error = NULL;
if (!mm_device_remove_modem_finish (self, res, &error))
mm_obj_warn (self, "removing modem failed: %s", error->message);
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
inhibit_disable_ready (MMBaseModem *modem,
GAsyncResult *res,
@@ -742,14 +826,15 @@ inhibit_disable_ready (MMBaseModem *modem,
self = g_task_get_source_object (task);
if (!mm_base_modem_disable_finish (modem, res, &error))
if (!mm_base_modem_disable_finish (modem, res, &error)) {
g_task_return_error (task, error);
else {
g_cancellable_cancel (mm_base_modem_peek_cancellable (modem));
mm_device_remove_modem (self);
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
g_object_unref (task);
mm_device_remove_modem (self,
(GAsyncReadyCallback)inhibit_disable_modem_remove_ready,
task);
}
void
@@ -899,7 +984,7 @@ set_property (GObject *object,
self->priv->plugin = g_value_dup_object (value);
break;
case PROP_MODEM:
clear_modem (self);
g_assert (self->priv->modem == NULL);
self->priv->modem = g_value_dup_object (value);
break;
case PROP_HOTPLUGGED:
+10 -4
View File
@@ -80,10 +80,16 @@ void mm_device_release_port_name (MMDevice *self,
const gchar *subsystem,
const gchar *name);
gboolean mm_device_create_modem (MMDevice *self,
GError **error);
void mm_device_remove_modem (MMDevice *self);
void mm_device_initialize_modem (MMDevice *self);
gboolean mm_device_create_modem (MMDevice *self,
GError **error);
void mm_device_remove_modem (MMDevice *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_device_remove_modem_finish (MMDevice *self,
GAsyncResult *res,
GError **error);
void mm_device_remove_modem_quick (MMDevice *self);
void mm_device_initialize_modem (MMDevice *self);
void mm_device_inhibit (MMDevice *self,
GAsyncReadyCallback callback,
+9
View File
@@ -32,6 +32,10 @@ static GQuark in_call_event_context_quark;
G_DEFINE_INTERFACE (MMIfaceModemVoice, mm_iface_modem_voice, MM_TYPE_IFACE_MODEM)
static void setup_call_list_polling (MMCallList *call_list,
const gchar *call_path_added,
MMIfaceModemVoice *self);
/*****************************************************************************/
void
@@ -1781,6 +1785,7 @@ typedef enum {
IN_CALL_SETUP_STEP_FIRST,
IN_CALL_SETUP_STEP_UNSOLICITED_EVENTS,
IN_CALL_SETUP_STEP_AUDIO_CHANNEL,
IN_CALL_SETUP_STEP_CHECK_POLLING,
IN_CALL_SETUP_STEP_LAST,
} InCallSetupStep;
@@ -1908,6 +1913,10 @@ in_call_setup_context_step (GTask *task)
}
ctx->step++;
/* fall-through */
case IN_CALL_SETUP_STEP_CHECK_POLLING:
setup_call_list_polling (NULL, NULL, self);
ctx->step++;
/* fall-through */
case IN_CALL_SETUP_STEP_LAST:
g_task_return_boolean (task, TRUE);
g_object_unref (task);
+5 -4
View File
@@ -1218,8 +1218,9 @@ get_mm_access_tech_from_etsi_access_tech (guint val,
return MM_MODEM_ACCESS_TECHNOLOGY_HSUPA;
case 6:
return MM_MODEM_ACCESS_TECHNOLOGY_HSPA;
case 7: /* E-UTRAN */
case 9: /* E-UTRAN (NB-S1) */
return MM_MODEM_ACCESS_TECHNOLOGY_LTE_NB_IOT;
case 7: /* E-UTRAN */
case 10: /* E-UTRA connected to a 5GCN */
return MM_MODEM_ACCESS_TECHNOLOGY_LTE;
case 11: /* NR connected to a 5G CN */
@@ -4160,11 +4161,11 @@ mm_string_to_access_tech (const gchar *string)
* are included in other strings too.
*/
len = strlen (string);
if (strncmp (string, "EVDO", 4) && (len >= 4 && !isalnum (string[4])))
if (!strncmp (string, "EVDO", 4) && (len >= 4 && !isalnum (string[4])))
act |= MM_MODEM_ACCESS_TECHNOLOGY_EVDO0;
if (strncmp (string, "CDMA", 4) && (len >= 4 && !isalnum (string[4])))
if (!strncmp (string, "CDMA", 4) && (len >= 4 && !isalnum (string[4])))
act |= MM_MODEM_ACCESS_TECHNOLOGY_1XRTT;
if (strncmp (string, "CDMA-EVDO", 9) && (len >= 9 && !isalnum (string[9])))
if (!strncmp (string, "CDMA-EVDO", 9) && (len >= 9 && !isalnum (string[9])))
act |= MM_MODEM_ACCESS_TECHNOLOGY_1XRTT | MM_MODEM_ACCESS_TECHNOLOGY_EVDO0;
return act;
+2 -2
View File
@@ -1482,8 +1482,6 @@ port_serial_close_force (MMPortSerial *self)
if (self->priv->forced_close)
return;
mm_obj_dbg (self, "forced to close port");
/* Mark as having forced the close, so that we don't warn about incorrect
* open counts */
self->priv->forced_close = TRUE;
@@ -1493,6 +1491,8 @@ port_serial_close_force (MMPortSerial *self)
/* If already closed, done */
if (self->priv->open_count > 0) {
mm_obj_dbg (self, "forced to close port");
_close_internal (self, TRUE);
/* Notify about the forced close status */
+165
View File
@@ -0,0 +1,165 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* 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 2 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:
*
* Copyright 2025 Dan Williams <dan@ioncontrol.co>
*/
#include <gio/gio.h>
#include "mm-utils.h"
#include "mm-sleep-context.h"
static void log_object_iface_init (MMLogObjectInterface *iface);
G_DEFINE_TYPE_EXTENDED (MMSleepContext, mm_sleep_context, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init))
struct _MMSleepContextPrivate {
GTask *task;
guint timeout_id;
};
enum {
DONE,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = { 0 };
/*****************************************************************************/
static gchar *
log_object_build_id (MMLogObject *_self)
{
return g_strdup_printf ("sleep-context");
}
/*****************************************************************************/
static void
timeout_cleanup (MMSleepContext *self)
{
if (self->priv->timeout_id)
g_source_remove (self->priv->timeout_id);
self->priv->timeout_id = 0;
}
void
mm_sleep_context_complete (MMSleepContext *self,
GError *error)
{
timeout_cleanup (self);
if (error) {
mm_obj_dbg (self, "completing with error '%s'", error->message);
g_task_return_error (self->priv->task, error);
} else {
mm_obj_dbg (self, "completing with success");
g_task_return_boolean (self->priv->task, TRUE);
}
g_clear_object (&self->priv->task);
}
static gboolean
operation_timeout (MMSleepContext *self)
{
mm_obj_dbg (self, "timeout");
mm_sleep_context_complete (self,
g_error_new_literal (G_IO_ERROR,
G_IO_ERROR_TIMED_OUT,
"timeout waiting for sleep preparation to complete"));
return G_SOURCE_REMOVE;
}
static void
operation_ready (MMSleepContext *self,
GAsyncResult *res)
{
g_autoptr(GError) error = NULL;
gboolean success;
mm_obj_dbg (self, "notifying listeners task is done");
success = g_task_propagate_boolean (G_TASK (res), &error);
g_assert (success || error);
g_signal_emit (self, signals[DONE], 0, error);
}
/*****************************************************************************/
MMSleepContext *
mm_sleep_context_new (guint timeout_seconds)
{
MMSleepContext *self;
self = MM_SLEEP_CONTEXT (g_object_new (MM_TYPE_SLEEP_CONTEXT, NULL));
self->priv->task = g_task_new (self,
NULL,
(GAsyncReadyCallback)operation_ready,
NULL);
self->priv->timeout_id = g_timeout_add_seconds (timeout_seconds,
(GSourceFunc)operation_timeout,
self);
mm_obj_dbg (self, "new context with %d second timeout", timeout_seconds);
return self;
}
static void
log_object_iface_init (MMLogObjectInterface *iface)
{
iface->build_id = log_object_build_id;
}
static void
mm_sleep_context_init (MMSleepContext *self)
{
/* Initialize opaque pointer to private data */
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
MM_TYPE_SLEEP_CONTEXT,
MMSleepContextPrivate);
}
static void
dispose (GObject *object)
{
MMSleepContext *self = MM_SLEEP_CONTEXT (object);
timeout_cleanup (self);
/* Task must always be completed and cleared before disposal */
g_assert (self->priv->task == NULL);
G_OBJECT_CLASS (mm_sleep_context_parent_class)->dispose (object);
}
static void
mm_sleep_context_class_init (MMSleepContextClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMSleepContextPrivate));
/* Virtual methods */
object_class->dispose = dispose;
signals[DONE] = g_signal_new (MM_SLEEP_CONTEXT_DONE,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MMSleepContextClass, done),
NULL, /* accumulator */
NULL, /* accumulator data */
g_cclosure_marshal_generic,
G_TYPE_NONE,
1,
G_TYPE_ERROR);
}
+62
View File
@@ -0,0 +1,62 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* 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 2 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:
*
* Copyright 2025 Dan Williams <dan@ioncontrol.co>
*/
#ifndef MM_SLEEP_CONTEXT_H
#define MM_SLEEP_CONTEXT_H
#include <glib-object.h>
#include <glib.h>
G_BEGIN_DECLS
#define MM_TYPE_SLEEP_CONTEXT (mm_sleep_context_get_type ())
#define MM_SLEEP_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SLEEP_CONTEXT, MMSleepContext))
#define MM_SLEEP_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SLEEP_CONTEXT, MMSleepContextClass))
#define MM_IS_SLEEP_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SLEEP_CONTEXT))
#define MM_IS_SLEEP_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SLEEP_CONTEXT))
#define MM_SLEEP_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SLEEP_CONTEXT, MMSleepContextClass))
#define MM_SLEEP_CONTEXT_DONE "done"
typedef struct _MMSleepContext MMSleepContext;
typedef struct _MMSleepContextClass MMSleepContextClass;
typedef struct _MMSleepContextPrivate MMSleepContextPrivate;
struct _MMSleepContext {
GObject parent;
MMSleepContextPrivate *priv;
};
struct _MMSleepContextClass {
GObjectClass parent;
void (*done) (MMSleepContext *ctx, GError *error);
};
GType mm_sleep_context_get_type (void);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSleepContext, g_object_unref)
MMSleepContext *mm_sleep_context_new (guint timeout_seconds);
/* The MMSleepContext assumes ownership of @error */
void mm_sleep_context_complete (MMSleepContext *self,
GError *error);
void mm_sleep_context_dispose (MMSleepContext *self);
G_END_DECLS
#endif /* MM_SLEEP_CONTEXT_H */
+49 -17
View File
@@ -29,6 +29,7 @@
#include "mm-log-object.h"
#include "mm-utils.h"
#include "mm-sleep-monitor.h"
#include "mm-sleep-context.h"
#define PD_NAME "org.chromium.PowerManager"
#define PD_PATH "/org/chromium/PowerManager"
@@ -37,13 +38,15 @@
struct _MMSleepMonitor {
GObject parent_instance;
GDBusProxy *pd_proxy;
GDBusProxy *pd_proxy;
MMSleepContext *sleep_ctx;
guint sleep_done_id;
};
struct _MMSleepMonitorClass {
GObjectClass parent_class;
void (*sleeping) (MMSleepMonitor *monitor);
void (*sleeping) (MMSleepMonitor *monitor, MMSleepContext *ctx);
void (*resuming) (MMSleepMonitor *monitor);
};
@@ -70,6 +73,26 @@ log_object_build_id (MMLogObject *_self)
/********************************************************************/
static void
cleanup_sleep_context (MMSleepMonitor *self)
{
if (self->sleep_ctx && self->sleep_done_id)
g_signal_handler_disconnect (self->sleep_ctx, self->sleep_done_id);
self->sleep_done_id = 0;
g_clear_object (&self->sleep_ctx);
}
static void
sleep_context_done (MMSleepContext *sleep_ctx,
GError *error,
MMSleepMonitor *self)
{
if (error)
mm_obj_warn (self, "sleep context failed: %s", error->message);
mm_obj_msg (self, "ready to sleep");
cleanup_sleep_context (self);
}
static void
signal_cb (GDBusProxy *proxy,
const gchar *sendername,
@@ -79,14 +102,24 @@ signal_cb (GDBusProxy *proxy,
{
MMSleepMonitor *self = data;
if (proxy == self->pd_proxy) {
if (strcmp (signalname, "SuspendImminent") == 0) {
mm_obj_msg (self, "system suspend signal from powerd");
g_signal_emit (self, signals[SLEEPING], 0);
} else if (strcmp (signalname, "SuspendDone") == 0) {
mm_obj_msg (self, "system resume signal from powerd");
g_signal_emit (self, signals[RESUMING], 0);
if (proxy != self->pd_proxy)
return;
if (strcmp (signalname, "SuspendImminent") == 0) {
if (self->sleep_ctx || self->sleep_done_id) {
mm_obj_warn (self, "clearing unfinished sleep context...");
cleanup_sleep_context (self);
}
self->sleep_ctx = mm_sleep_context_new (5);
self->sleep_done_id = g_signal_connect (self->sleep_ctx,
MM_SLEEP_CONTEXT_DONE,
(GCallback)sleep_context_done,
self);
g_signal_emit (self, signals[SLEEPING], 0, self->sleep_ctx);
} else if (strcmp (signalname, "SuspendDone") == 0) {
mm_obj_msg (self, "system resume signal from powerd");
g_signal_emit (self, signals[RESUMING], 0);
}
}
@@ -120,15 +153,14 @@ mm_sleep_monitor_init (MMSleepMonitor *self)
}
static void
finalize (GObject *object)
dispose (GObject *object)
{
MMSleepMonitor *self = MM_SLEEP_MONITOR (object);
if (self->pd_proxy)
g_object_unref (self->pd_proxy);
cleanup_sleep_context (self);
g_clear_object (&self->pd_proxy);
if (G_OBJECT_CLASS (mm_sleep_monitor_parent_class)->finalize != NULL)
G_OBJECT_CLASS (mm_sleep_monitor_parent_class)->finalize (object);
G_OBJECT_CLASS (mm_sleep_monitor_parent_class)->dispose (object);
}
static void
@@ -144,7 +176,7 @@ mm_sleep_monitor_class_init (MMSleepMonitorClass *klass)
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = finalize;
gobject_class->dispose = dispose;
signals[SLEEPING] = g_signal_new (MM_SLEEP_MONITOR_SLEEPING,
MM_TYPE_SLEEP_MONITOR,
@@ -152,8 +184,8 @@ mm_sleep_monitor_class_init (MMSleepMonitorClass *klass)
G_STRUCT_OFFSET (MMSleepMonitorClass, sleeping),
NULL, /* accumulator */
NULL, /* accumulator data */
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, G_TYPE_CANCELLABLE);
signals[RESUMING] = g_signal_new (MM_SLEEP_MONITOR_RESUMING,
MM_TYPE_SLEEP_MONITOR,
G_SIGNAL_RUN_LAST,
+53 -11
View File
@@ -29,6 +29,7 @@
#include "mm-log-object.h"
#include "mm-utils.h"
#include "mm-sleep-monitor.h"
#include "mm-sleep-context.h"
#define SD_NAME "org.freedesktop.login1"
#define SD_PATH "/org/freedesktop/login1"
@@ -37,14 +38,16 @@
struct _MMSleepMonitor {
GObject parent_instance;
GDBusProxy *sd_proxy;
gint inhibit_fd;
GDBusProxy *sd_proxy;
gint inhibit_fd;
MMSleepContext *sleep_ctx;
guint sleep_done_id;
};
struct _MMSleepMonitorClass {
GObjectClass parent_class;
void (*sleeping) (MMSleepMonitor *monitor);
void (*sleeping) (MMSleepMonitor *monitor, MMSleepContext *ctx);
void (*resuming) (MMSleepMonitor *monitor);
};
@@ -137,6 +140,27 @@ take_inhibitor (MMSleepMonitor *self)
self);
}
static void
cleanup_sleep_context (MMSleepMonitor *self)
{
if (self->sleep_ctx && self->sleep_done_id)
g_signal_handler_disconnect (self->sleep_ctx, self->sleep_done_id);
self->sleep_done_id = 0;
g_clear_object (&self->sleep_ctx);
}
static void
sleep_context_done (MMSleepContext *sleep_ctx,
GError *error,
MMSleepMonitor *self)
{
if (error)
mm_obj_warn (self, "sleep context failed: %s", error->message);
mm_obj_msg (self, "ready to sleep; dropping inhibitor");
drop_inhibitor (self);
cleanup_sleep_context (self);
}
static void
signal_cb (GDBusProxy *proxy,
const gchar *sendername,
@@ -154,8 +178,17 @@ signal_cb (GDBusProxy *proxy,
if (is_about_to_suspend) {
mm_obj_msg (self, "system is about to suspend");
g_signal_emit (self, signals[SLEEPING], 0);
drop_inhibitor (self);
if (self->sleep_ctx || self->sleep_done_id) {
mm_obj_warn (self, "clearing unfinished sleep context...");
cleanup_sleep_context (self);
}
self->sleep_ctx = mm_sleep_context_new (5);
self->sleep_done_id = g_signal_connect (self->sleep_ctx,
MM_SLEEP_CONTEXT_DONE,
(GCallback)sleep_context_done,
self);
g_signal_emit (self, signals[SLEEPING], 0, self->sleep_ctx);
} else {
mm_obj_msg (self, "system is resuming");
take_inhibitor (self);
@@ -219,17 +252,25 @@ mm_sleep_monitor_init (MMSleepMonitor *self)
(GAsyncReadyCallback) on_proxy_acquired, self);
}
static void
dispose (GObject *object)
{
MMSleepMonitor *self = MM_SLEEP_MONITOR (object);
cleanup_sleep_context (self);
g_clear_object (&self->sd_proxy);
G_OBJECT_CLASS (mm_sleep_monitor_parent_class)->dispose (object);
}
static void
finalize (GObject *object)
{
MMSleepMonitor *self = MM_SLEEP_MONITOR (object);
drop_inhibitor (self);
if (self->sd_proxy)
g_object_unref (self->sd_proxy);
if (G_OBJECT_CLASS (mm_sleep_monitor_parent_class)->finalize != NULL)
G_OBJECT_CLASS (mm_sleep_monitor_parent_class)->finalize (object);
G_OBJECT_CLASS (mm_sleep_monitor_parent_class)->finalize (object);
}
static void
@@ -245,6 +286,7 @@ mm_sleep_monitor_class_init (MMSleepMonitorClass *klass)
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = dispose;
gobject_class->finalize = finalize;
signals[SLEEPING] = g_signal_new (MM_SLEEP_MONITOR_SLEEPING,
@@ -253,8 +295,8 @@ mm_sleep_monitor_class_init (MMSleepMonitorClass *klass)
G_STRUCT_OFFSET (MMSleepMonitorClass, sleeping),
NULL, /* accumulator */
NULL, /* accumulator data */
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, MM_TYPE_SLEEP_CONTEXT);
signals[RESUMING] = g_signal_new (MM_SLEEP_MONITOR_RESUMING,
MM_TYPE_SLEEP_MONITOR,
G_SIGNAL_RUN_LAST,
@@ -794,7 +794,7 @@ mm_cinterion_parse_sxrat_test (const gchar *response,
return FALSE;
}
r = g_regex_new ("\\^SXRAT:\\s*\\(([^\\)]*)\\),\\(([^\\)]*)\\)(,\\(([^\\)]*)\\))?(?:\\r\\n)?",
r = g_regex_new ("\\^SXRAT:\\s*\\(([^\\)]*)\\),\\s*\\(([^\\)]*)\\)(,\\s*\\(([^\\)]*)\\))?(?:\\r\\n)?",
G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
0, NULL);
@@ -1826,6 +1826,38 @@ test_sxrat_response_els61 (void)
g_array_unref (expected_pref2);
}
static void
test_sxrat_response_pls63_w (void)
{
GArray *expected_rat;
GArray *expected_pref1;
GArray *expected_pref2;
const guint vals[] = { 0, 2, 3 };
guint val;
const gchar *response =
"^SXRAT: (0-6), (0,2,3), (0,2,3)\r\n"
"\r\n";
expected_rat = g_array_sized_new (FALSE, FALSE, sizeof (guint), 7);
for (val = 0; val < 7; val++)
g_array_append_val (expected_rat, val);
expected_pref1 = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3);
g_array_append_vals (expected_pref1, &vals, 3);
expected_pref2 = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3);
g_array_append_vals (expected_pref2, &vals, 3);
common_test_sxrat (response,
expected_rat,
expected_pref1,
expected_pref2);
g_array_unref (expected_rat);
g_array_unref (expected_pref1);
g_array_unref (expected_pref2);
}
static void
test_sxrat_response_other (void)
{
@@ -2177,6 +2209,7 @@ int main (int argc, char **argv)
g_test_add_func ("/MM/cinterion/sgauth", test_sgauth_response);
g_test_add_func ("/MM/cinterion/sxrat", test_sxrat);
g_test_add_func ("/MM/cinterion/sxrat/response/els61", test_sxrat_response_els61);
g_test_add_func ("/MM/cinterion/sxrat/response/pls63w", test_sxrat_response_pls63_w);
g_test_add_func ("/MM/cinterion/sxrat/response/other", test_sxrat_response_other);
g_test_add_func ("/MM/cinterion/cops/only-mode-2g", test_cops_only_mode_2g);
g_test_add_func ("/MM/cinterion/cops/only-mode-3g", test_cops_only_mode_3g);
+2 -2
View File
@@ -75,8 +75,8 @@ get_private (MMSharedFibocom *self)
priv->class_parent = MM_SHARED_FIBOCOM_GET_IFACE (self)->peek_parent_class (self);
/* Setup firmware interface of parent class */
g_assert (MM_SHARED_FIBOCOM_GET_IFACE (self)->peek_parent_firmware_interface);
priv->iface_modem_firmware_parent = MM_SHARED_FIBOCOM_GET_IFACE (self)->peek_parent_firmware_interface (self);
if (MM_SHARED_FIBOCOM_GET_IFACE (self)->peek_parent_firmware_interface)
priv->iface_modem_firmware_parent = MM_SHARED_FIBOCOM_GET_IFACE (self)->peek_parent_firmware_interface (self);
g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free);
}
+25
View File
@@ -4866,6 +4866,29 @@ test_mnc_length (void)
/*****************************************************************************/
typedef struct {
const gchar *str;
const MMModemAccessTechnology act;
} TestActData;
static const TestActData test_act_data[] = {
{ "EDGE", MM_MODEM_ACCESS_TECHNOLOGY_EDGE },
/* Ensure WCDMA does not get counted as 3GPP2 CDMA */
{ "WCDMA", MM_MODEM_ACCESS_TECHNOLOGY_UMTS },
{ "CDMA-EVDO", MM_MODEM_ACCESS_TECHNOLOGY_1XRTT | MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 },
};
static void
test_string_to_access_tech (void)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (test_act_data); i++)
g_assert_cmpint (mm_string_to_access_tech (test_act_data[i].str), ==, test_act_data[i].act);
}
/*****************************************************************************/
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (GTestFixtureFunc) t, NULL)
int main (int argc, char **argv)
@@ -5111,6 +5134,8 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_spn_to_utf8, NULL));
g_test_suite_add (suite, TESTCASE (test_mnc_length, NULL));
g_test_suite_add (suite, TESTCASE (test_string_to_access_tech, NULL));
result = g_test_run ();
reg_test_data_free (reg_data);