From 5d4b0d3516e5178a628bfe282778b14cc650e068 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 30 May 2025 13:31:08 +0200 Subject: [PATCH] cinterion: add hardware revision read via AT for MV31 and MV32 Reading the hardware revision via the mbim interface returns an incorrect hardware revision string. The output is always set to 'h/w revision: Thales Snapdragon X55' Hardware | manufacturer: Cinterion ... | h/w revision: Thales Snapdragon X55 This is an incorrect value returned by the MBIM interface. The MV31 and MV32 does have a dedicated AT Command to get the correct hardware revision via 'AT+SKUID'. If the hardware revision is read via the AT command, the output looks as follows. Hardware | manufacturer: Cinterion ... | h/w revision: V065 Signed-off-by: Florian Eckert --- .../mm-broadband-modem-mbim-cinterion.c | 129 +++++++++++++++++- 1 file changed, 125 insertions(+), 4 deletions(-) diff --git a/src/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c b/src/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c index ec4cc91d..a23c55d5 100644 --- a/src/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c +++ b/src/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c @@ -183,6 +183,125 @@ load_revision (MMIfaceModem *self, iface_modem_parent->load_revision (self, (GAsyncReadyCallback)mbim_load_revision_ready, task); } +/*****************************************************************************/ +/* Load hardware revision (Modem interface) */ + +static gchar * +load_hardware_revision_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (res), error); +} + +static void +at_load_hardware_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 hardware revision output"); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + r = g_regex_new ("HW Revision:\\s*(.*)\\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 'HW Revision:' in reply: '%s'", + output); + g_object_unref (task); + return; + } + + if (!g_match_info_matches (match_info)) { + g_task_return_new_error ( + task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Failed to parse 'AT+SKUID' 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 hardware revision in reply: '%s'", + output); + g_object_unref (task); + return; + } + + mm_obj_dbg (self, "got AT hardware revision '%s'", revision); + g_task_return_pointer (task, g_strdup (revision), g_free); + g_object_unref (task); +} + +static void +mbim_load_hardware_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 hardware revision '%s'", revision); + g_task_return_pointer (task, revision, g_free); + g_object_unref (task); +} + +static void +load_hardware_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 or MV32 */ + if ((product_id == 0x00f1) || (product_id == 0x00b3)) { + mm_base_modem_at_command (MM_BASE_MODEM(self), + "AT+SKUID", + 3, + TRUE, + (GAsyncReadyCallback) at_load_hardware_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_hardware_revision_ready, task); +} + /*****************************************************************************/ MMBroadbandModemMbimCinterion * @@ -219,10 +338,12 @@ 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->load_revision_finish = load_revision_finish; - iface->load_revision = load_revision; + 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; + iface->load_hardware_revision_finish = load_hardware_revision_finish; + iface->load_hardware_revision = load_hardware_revision; } static MMIfaceModemInterface *