Merge request !1367 from 'mr/20250530-cinterion'
cinterion: add MV32/MV31 udev rules and AT workarounds https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1367
This commit is contained in:
@@ -68,4 +68,22 @@ ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="02", SUBS
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="06", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
|
||||
# MV32 port types
|
||||
# ttyUSB0 (if #2): AT port
|
||||
# ttyUSB1 (if #4): GPS data port
|
||||
# ttyUSB2 (if #5): unknown
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="00f1", ENV{ID_MM_TTY_AT_PROBE_TRIES}="10"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="00f1", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="00f1", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="00f1", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
# MV31 port types
|
||||
# ttyUSB0 (if #2): AT port
|
||||
# ttyUSB1 (if #4): GPS data port
|
||||
# ttyUSB2 (if #5): unknown
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="00b3", ENV{ID_MM_TTY_AT_PROBE_TRIES}="10"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="00b3", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="00b3", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="00b3", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
LABEL="mm_cinterion_port_types_end"
|
||||
|
||||
@@ -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,255 @@ 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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 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 *
|
||||
@@ -69,6 +319,8 @@ mm_broadband_modem_mbim_cinterion_new (const gchar *device,
|
||||
MM_BASE_MODEM_PLUGIN, plugin,
|
||||
MM_BASE_MODEM_VENDOR_ID, vendor_id,
|
||||
MM_BASE_MODEM_PRODUCT_ID, product_id,
|
||||
/* include carrier information */
|
||||
MM_IFACE_MODEM_FIRMWARE_IGNORE_CARRIER, TRUE,
|
||||
/* MBIM bearer supports NET only */
|
||||
MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
|
||||
MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE,
|
||||
@@ -88,8 +340,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->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 *
|
||||
|
||||
Reference in New Issue
Block a user