Skip to content

Commit

Permalink
modemmanager: Fix Quectel modems initialization bug
Browse files Browse the repository at this point in the history
With the update to ModemManager version 1.22.0 we now have some Quectel modems failing
to use QMI properly:

ModemManager[1178]: [modem0] power state updated: on
ModemManager[1178]: [modem0] (quectel) modem reset detected, triggering reprobe
ModemManager[1178]: [modem0] (quectel) modem reset detected, triggering reprobe
.
.
.
ModemManager[1178]: [modem0] failed waiting for final state: Too much time waiting to get to a final state
ModemManager[1178]: [modem0] failed enabling modem: Operation was cancelled
ModemManager[1178]: [modem1] couldn't start initialization: Transaction timed out
ModemManager[1178]: [modem1] fatal error initializing: Fatal error: modem is unusable

This has been fixed upstream with the 2 patches we backport here:

ModemManager[1139]: [modem0] power state updated: on
ModemManager[1139]: [modem0] (quectel) continuing without enabling profile manager events

Signed-off-by: Florin Sarbu <[email protected]>
  • Loading branch information
floion committed Jul 24, 2024
1 parent 7c9d2c8 commit 0599e2a
Show file tree
Hide file tree
Showing 3 changed files with 309 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
From e3024ec620f2d4087c1d03579c8575b6cb988503 Mon Sep 17 00:00:00 2001
From: Lukas Voegl <[email protected]>
Date: Fri, 19 Apr 2024 11:33:06 +0200
Subject: [PATCH] quectel: disable qmi unsolicited profile manager events

Signed-off-by: Lukas Voegl <[email protected]>
---
.../quectel/mm-broadband-modem-qmi-quectel.c | 105 ++++++++++++++++--
.../quectel/mm-modem-helpers-quectel.c | 60 ++++++++++
.../quectel/mm-modem-helpers-quectel.h | 9 ++
.../tests/test-modem-helpers-quectel.c | 26 +++++
4 files changed, 193 insertions(+), 7 deletions(-)

diff --git a/src/plugins/quectel/mm-broadband-modem-qmi-quectel.c b/src/plugins/quectel/mm-broadband-modem-qmi-quectel.c
index 4b4e0c96..c6f706a5 100644
--- a/src/plugins/quectel/mm-broadband-modem-qmi-quectel.c
+++ b/src/plugins/quectel/mm-broadband-modem-qmi-quectel.c
@@ -20,26 +20,108 @@
#include "mm-iface-modem-firmware.h"
#include "mm-iface-modem-location.h"
#include "mm-iface-modem-time.h"
+#include "mm-iface-modem-3gpp-profile-manager.h"
+#include "mm-log-object.h"
+#include "mm-modem-helpers-quectel.h"
#include "mm-shared-quectel.h"

-static void iface_modem_init (MMIfaceModem *iface);
-static void iface_modem_firmware_init (MMIfaceModemFirmware *iface);
-static void iface_modem_location_init (MMIfaceModemLocation *iface);
-static void iface_modem_time_init (MMIfaceModemTime *iface);
-static void shared_quectel_init (MMSharedQuectel *iface);
+static void iface_modem_init (MMIfaceModem *iface);
+static void iface_modem_firmware_init (MMIfaceModemFirmware *iface);
+static void iface_modem_location_init (MMIfaceModemLocation *iface);
+static void iface_modem_time_init (MMIfaceModemTime *iface);
+static void iface_modem_3gpp_profile_manager_init (MMIfaceModem3gppProfileManager *iface);
+static void shared_quectel_init (MMSharedQuectel *iface);

-static MMIfaceModem *iface_modem_parent;
-static MMIfaceModemLocation *iface_modem_location_parent;
+static MMIfaceModem *iface_modem_parent;
+static MMIfaceModemLocation *iface_modem_location_parent;
+static MMIfaceModem3gppProfileManager *iface_modem_3gpp_profile_manager_parent;

G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmiQuectel, mm_broadband_modem_qmi_quectel, MM_TYPE_BROADBAND_MODEM_QMI, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_FIRMWARE, iface_modem_firmware_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP_PROFILE_MANAGER, iface_modem_3gpp_profile_manager_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_QUECTEL, shared_quectel_init))

/*****************************************************************************/

+static gboolean
+profile_manager_check_unsolicited_support (MMBroadbandModemQmiQuectel *self)
+{
+ GError *error = NULL;
+ const gchar *revision = NULL;
+ guint release_version;
+ guint minor_version;
+
+ revision = mm_iface_modem_get_revision (MM_IFACE_MODEM (self));
+ if (!mm_quectel_get_version_from_revision (revision,
+ &release_version,
+ &minor_version,
+ &error)) {
+ mm_obj_warn (self, "parsing revision failed: %s", error->message);
+ g_error_free (error);
+
+ /* assume profile manager supported if version not parseable */
+ return TRUE;
+ }
+
+ if (!mm_quectel_is_profile_manager_supported (revision,
+ release_version,
+ minor_version)) {
+ mm_obj_dbg (self, "profile management not supported by revision %s", revision);
+ return FALSE;
+ }
+
+ /* profile management seems supported */
+ return TRUE;
+}
+
+static gboolean
+profile_manager_enable_unsolicited_events_finish (MMIfaceModem3gppProfileManager *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+parent_enable_unsolicited_events_ready (MMIfaceModem3gppProfileManager *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!iface_modem_3gpp_profile_manager_parent->enable_unsolicited_events_finish (self,
+ res,
+ &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+profile_manager_enable_unsolicited_events (MMIfaceModem3gppProfileManager *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ if (!profile_manager_check_unsolicited_support (MM_BROADBAND_MODEM_QMI_QUECTEL (self))) {
+ mm_obj_warn (self, "continuing without enabling profile manager events");
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ }
+
+ iface_modem_3gpp_profile_manager_parent->enable_unsolicited_events (
+ self,
+ (GAsyncReadyCallback)parent_enable_unsolicited_events_ready,
+ task);
+}
+
MMBroadbandModemQmiQuectel *
mm_broadband_modem_qmi_quectel_new (const gchar *device,
const gchar *physdev,
@@ -124,6 +206,15 @@ peek_parent_modem_location_interface (MMSharedQuectel *self)
return iface_modem_location_parent;
}

+static void
+iface_modem_3gpp_profile_manager_init (MMIfaceModem3gppProfileManager *iface)
+{
+ iface_modem_3gpp_profile_manager_parent = g_type_interface_peek_parent (iface);
+
+ iface->enable_unsolicited_events = profile_manager_enable_unsolicited_events;
+ iface->enable_unsolicited_events_finish = profile_manager_enable_unsolicited_events_finish;
+}
+
static void
shared_quectel_init (MMSharedQuectel *iface)
{
diff --git a/src/plugins/quectel/mm-modem-helpers-quectel.c b/src/plugins/quectel/mm-modem-helpers-quectel.c
index 4335e506..7b0fe96d 100644
--- a/src/plugins/quectel/mm-modem-helpers-quectel.c
+++ b/src/plugins/quectel/mm-modem-helpers-quectel.c
@@ -138,3 +138,63 @@ mm_quectel_check_standard_firmware_version_valid (const gchar *std_str)
}
return valid;
}
+
+gboolean
+mm_quectel_get_version_from_revision (const gchar *revision,
+ guint *release,
+ guint *minor,
+ GError **error)
+{
+ g_autoptr(GRegex) version_regex = NULL;
+ g_autoptr(GMatchInfo) match_info = NULL;
+
+ version_regex = g_regex_new ("R(\\d+)A(\\d+)",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE,
+ 0,
+ NULL);
+
+ if (!g_regex_match (version_regex, revision, 0, &match_info)) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Cannot parse revision version %s", revision);
+ return FALSE;
+ }
+ if (!mm_get_uint_from_match_info (match_info, 1, release)) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't get release version from revision %s", revision);
+ return FALSE;
+ }
+ if (!mm_get_uint_from_match_info (match_info, 2, minor)) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't get minor version from revision %s", revision);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+mm_quectel_is_profile_manager_supported (const gchar *revision,
+ guint release,
+ guint minor)
+{
+ guint i;
+ static const struct {
+ const gchar *revision_prefix;
+ guint minimum_release;
+ guint minimum_minor;
+ } profile_support_map [] = {
+ {"EC25", 6, 10},
+ };
+
+ for (i = 0; i < G_N_ELEMENTS (profile_support_map); ++i) {
+ if (g_str_has_prefix (revision, profile_support_map[i].revision_prefix)) {
+ guint minimum_release = profile_support_map[i].minimum_release;
+ guint minimum_minor = profile_support_map[i].minimum_minor;
+
+ return ((release > minimum_release) ||
+ (release == minimum_release && minor >= minimum_minor));
+ }
+ }
+
+ return TRUE;
+}
diff --git a/src/plugins/quectel/mm-modem-helpers-quectel.h b/src/plugins/quectel/mm-modem-helpers-quectel.h
index ea9ff5c1..e4bc63b9 100644
--- a/src/plugins/quectel/mm-modem-helpers-quectel.h
+++ b/src/plugins/quectel/mm-modem-helpers-quectel.h
@@ -31,4 +31,13 @@ gboolean mm_quectel_parse_ctzu_test_response (const gchar *response,

gboolean mm_quectel_check_standard_firmware_version_valid (const gchar *std_str);

+gboolean mm_quectel_get_version_from_revision (const gchar *revision,
+ guint *release,
+ guint *minor,
+ GError **error);
+
+gboolean mm_quectel_is_profile_manager_supported (const gchar *revision,
+ guint release,
+ guint minor);
+
#endif /* MM_MODEM_HELPERS_QUECTEL_H */
diff --git a/src/plugins/quectel/tests/test-modem-helpers-quectel.c b/src/plugins/quectel/tests/test-modem-helpers-quectel.c
index dee01865..6c695f00 100644
--- a/src/plugins/quectel/tests/test-modem-helpers-quectel.c
+++ b/src/plugins/quectel/tests/test-modem-helpers-quectel.c
@@ -93,6 +93,30 @@ test_firmversion (void)
g_assert_cmpuint (valid, ==, FALSE);
}

+static void
+test_parse_revision (void)
+{
+ gboolean valid;
+ guint release;
+ guint minor;
+
+ valid = mm_quectel_get_version_from_revision ("EM05GFAR07A07M1G_01.016.01.016", &release, &minor, NULL);
+ g_assert_cmpuint (valid, ==, TRUE);
+ g_assert_cmpuint (release, ==, 7);
+ g_assert_cmpuint (minor, ==, 7);
+
+ valid = mm_quectel_get_version_from_revision ("EM05GFAR10A02M1G", &release, &minor, NULL);
+ g_assert_cmpuint (valid, ==, TRUE);
+ g_assert_cmpuint (release, ==, 10);
+ g_assert_cmpuint (minor, ==, 2);
+
+ valid = mm_quectel_get_version_from_revision ("EM05GFAR07AM1G", &release, &minor, NULL);
+ g_assert_cmpuint (valid, ==, FALSE);
+
+ valid = mm_quectel_get_version_from_revision ("EM05GFARA07M1G", &release, &minor, NULL);
+ g_assert_cmpuint (valid, ==, FALSE);
+}
+
/*****************************************************************************/

int main (int argc, char **argv)
@@ -105,5 +129,7 @@ int main (int argc, char **argv)

g_test_add_func ("/MM/quectel/firmversion", test_firmversion);

+ g_test_add_func ("/MM/quectel/parse_revision", test_parse_revision);
+
return g_test_run ();
}
--
2.34.1

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
From 1e26e16168d4815a48ab77610e1c282dfc345567 Mon Sep 17 00:00:00 2001
From: Aleksander Morgado <[email protected]>
Date: Mon, 6 May 2024 13:23:30 +0000
Subject: [PATCH] broadband-modem-qmi-quectel: fix task completion when not
enabling profile manager events

Fixes e3024ec620f2d4087c1d03579c8575b6cb988503
---
src/plugins/quectel/mm-broadband-modem-qmi-quectel.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/src/plugins/quectel/mm-broadband-modem-qmi-quectel.c b/src/plugins/quectel/mm-broadband-modem-qmi-quectel.c
index c6f706a5..df990f3f 100644
--- a/src/plugins/quectel/mm-broadband-modem-qmi-quectel.c
+++ b/src/plugins/quectel/mm-broadband-modem-qmi-quectel.c
@@ -114,6 +114,7 @@ profile_manager_enable_unsolicited_events (MMIfaceModem3gppProfileManager *self,
mm_obj_warn (self, "continuing without enabling profile manager events");
g_task_return_boolean (task, TRUE);
g_object_unref (task);
+ return;
}

iface_modem_3gpp_profile_manager_parent->enable_unsolicited_events (
--
2.34.1

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ SRC_URI:append = " \
file://u-blox-switch.sh \
file://ModemManager.conf.systemd \
file://0001-increase-qmi-port-open-timeout.patch \
file://0002-quectel-disable-qmi-unsolicited-profile-manager-even.patch \
file://0003-broadband-modem-qmi-quectel-fix-task-completion-when.patch \
"

PACKAGECONFIG:remove = "polkit"
Expand Down

0 comments on commit 0599e2a

Please sign in to comment.