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 <fe@dev.tdt.de>
This commit is contained in:
Florian Eckert
2025-07-30 12:41:22 -05:00
committed by Dan Williams
parent ebebce6111
commit a107de32a8
@@ -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 *