From a107de32a856d44d19740fb4907233c54f29cfca Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 20 Sep 2024 09:17:57 +0200 Subject: [PATCH] cinterion: add revision read via AT for the MV31 and MV32 Reading the revsion via the mbim interface returns an incorrect firmware revsion string. This contains a '\n' character so that the revision looks like this in 'mmcli'. Hardware | manufacturer: Cinterion | model: Cinterion PID 0x00F1 USB Mobile Broadband | firmware revision: FDE.F0.3.0.1.1.DT.005 | 062 | carrier config: DT The correct string without '\n' is returned via the AT interface. To fix the error, the 'mbim' revision interface is overwritten with an AT call if a MV31 or a MV32 is detected. So we get the correct output via 'mmcli'. Hardware | manufacturer: Cinterion | model: Cinterion PID 0x00F1 USB Mobile Broadband | firmware revision: FDE.F0.3.0.1.1.DT.005.062 | carrier config: DT Signed-off-by: Florian Eckert --- .../mm-broadband-modem-mbim-cinterion.c | 137 +++++++++++++++++- 1 file changed, 135 insertions(+), 2 deletions(-) diff --git a/src/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c b/src/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c index b8d765d3..ec4cc91d 100644 --- a/src/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c +++ b/src/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c @@ -28,6 +28,7 @@ #include "mm-iface-modem-firmware.h" #include "mm-iface-modem-location.h" #include "mm-iface-modem-voice.h" +#include "mm-base-modem-at.h" #include "mm-broadband-modem-mbim-cinterion.h" #include "mm-shared-cinterion.h" @@ -52,6 +53,136 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbimCinterion, mm_broadband_modem_mbim_c G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init) G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init)) +/*****************************************************************************/ +/* Load revision (Modem interface) */ + +static gchar * +load_revision_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (res), error); +} + +static void +at_load_revision_ready (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + const gchar *output = NULL; + g_autofree gchar *revision = NULL; + g_autoptr(GMatchInfo) match_info = NULL; + g_autoptr(GRegex) r = NULL; + + output = mm_base_modem_at_command_finish (self, res, &error); + if (error) { + mm_obj_dbg (self, "unable to get AT revision output"); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + /* MV31 modem replies with: '^VERSION: xxx' */ + /* MV32 modem replies with: '+VERSION: xxx' */ + r = g_regex_new ("[+^]VERSION:\\s*(.*)", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + if (!g_regex_match_full (r, output, strlen(output), 0, 0, &match_info, &error)) { + if (error) + g_task_return_error (task, error); + else + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Couldn't match '^VERSION:' or '+VERSION:' in reply: '%s'", + output); + g_object_unref (task); + } + + if (!g_match_info_matches (match_info)) { + g_task_return_new_error ( + task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Failed to parse 'AT^VERSION=1' or 'AT+VERSION=1' reply: '%s'", + output); + g_object_unref (task); + return; + } + + revision = mm_get_string_unquoted_from_match_info (match_info, 1); + if (revision == NULL) { + g_task_return_new_error ( + task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Could not find revision in reply: '%s'", + output); + g_object_unref (task); + return; + } + + mm_obj_dbg (self, "got AT revision '%s'", revision); + g_task_return_pointer (task, g_strdup (revision), g_free); + g_object_unref (task); +} + +static void +mbim_load_revision_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) +{ + gchar *revision = NULL; + + revision = iface_modem_parent->load_revision_finish (self, res, NULL); + + mm_obj_dbg (self, "got mbim revision '%s'\n", revision); + g_task_return_pointer (task, revision, g_free); + g_object_unref (task); +} + +static void +load_revision (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + MMPortSerialAt *at_port = NULL; + guint product_id; + + task = g_task_new (self, NULL, callback, user_data); + at_port = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); + product_id = mm_base_modem_get_product_id (MM_BASE_MODEM(self)); + + if (at_port) { + /* MV31 */ + if (product_id == 0x00b3) { + mm_base_modem_at_command (MM_BASE_MODEM(self), + "AT^VERSION=1", + 3, + TRUE, + (GAsyncReadyCallback) at_load_revision_ready, + task); + return; + } + /* MV32 */ + if (product_id == 0x00f1) { + mm_base_modem_at_command (MM_BASE_MODEM(self), + "AT+VERSION=1", + 3, + TRUE, + (GAsyncReadyCallback) at_load_revision_ready, + task); + return; + } + } + + /* + * Only call parent function, if no AT port is available + * or the product ID does not match + */ + iface_modem_parent->load_revision (self, (GAsyncReadyCallback)mbim_load_revision_ready, task); +} + /*****************************************************************************/ MMBroadbandModemMbimCinterion * @@ -88,8 +219,10 @@ iface_modem_init (MMIfaceModemInterface *iface) { iface_modem_parent = g_type_interface_peek_parent (iface); - iface->reset = mm_shared_cinterion_modem_reset; - iface->reset_finish = mm_shared_cinterion_modem_reset_finish; + iface->reset = mm_shared_cinterion_modem_reset; + iface->reset_finish = mm_shared_cinterion_modem_reset_finish; + iface->load_revision_finish = load_revision_finish; + iface->load_revision = load_revision; } static MMIfaceModemInterface *