diff options
-rw-r--r-- | .gitlab-ci.yml | 2 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | plugins/Makefile.am | 25 | ||||
-rw-r--r-- | plugins/qcom-soc/77-mm-qcom-soc.rules | 46 | ||||
-rw-r--r-- | plugins/qcom-soc/mm-broadband-modem-qmi-qcom-soc.c | 133 | ||||
-rw-r--r-- | plugins/qcom-soc/mm-broadband-modem-qmi-qcom-soc.h | 49 | ||||
-rw-r--r-- | plugins/qcom-soc/mm-plugin-qcom-soc.c | 92 | ||||
-rw-r--r-- | plugins/qcom-soc/mm-plugin-qcom-soc.h | 40 | ||||
-rw-r--r-- | plugins/tests/test-udev-rules.c | 11 |
9 files changed, 400 insertions, 2 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index af67083f..e429af6c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -108,7 +108,7 @@ build-single-plugins: dell dlink fibocom foxconn gosuncn haier huawei iridium linktop longcheer mbm motorola mtk nokia nokia-icera novatel novatel-lte option option-hso pantech - quectel samsung sierra-legacy sierra simtech + qcom-soc quectel samsung sierra-legacy sierra simtech telit thuraya tplink ublox via wavecom x22x zte; do ./configure --prefix=/usr --disable-gtk-doc --disable-all-plugins --enable-plugin-$plugin; make; diff --git a/configure.ac b/configure.ac index 069f0d83..9718c480 100644 --- a/configure.ac +++ b/configure.ac @@ -400,7 +400,7 @@ dnl----------------------------------------------------------------------------- dnl QMI support (enabled by default) dnl -LIBQMI_VERSION=1.27.1 +LIBQMI_VERSION=1.27.2 AC_ARG_WITH(qmi, AS_HELP_STRING([--without-qmi], [Build without QMI support]), [], [with_qmi=yes]) AM_CONDITIONAL(WITH_QMI, test "x$with_qmi" = "xyes") @@ -490,6 +490,7 @@ MM_ENABLE_PLUGIN([option], MM_ENABLE_PLUGIN([option-hso], [with_shared_option]) MM_ENABLE_PLUGIN([pantech]) +MM_ENABLE_PLUGIN([qcom-soc]) MM_ENABLE_PLUGIN([quectel]) MM_ENABLE_PLUGIN([samsung], [with_shared_icera]) @@ -627,6 +628,7 @@ echo " option: ${enable_plugin_option} option hso: ${enable_plugin_option_hso} pantech: ${enable_plugin_pantech} + qcom-soc: ${enable_plugin_qcom_soc} quectel: ${enable_plugin_quectel} samsung: ${enable_plugin_samsung} sierra legacy: ${enable_plugin_sierra_legacy} diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 7e08bfd2..df78beb3 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1209,6 +1209,31 @@ libmm_plugin_pantech_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS) endif ################################################################################ +# plugin: qcom-soc +################################################################################ + +if ENABLE_PLUGIN_QCOM_SOC +if WITH_QMI +pkglib_LTLIBRARIES += libmm-plugin-qcom-soc.la +libmm_plugin_qcom_soc_la_SOURCES = \ + qcom-soc/mm-plugin-qcom-soc.c \ + qcom-soc/mm-plugin-qcom-soc.h \ + qcom-soc/mm-broadband-modem-qmi-qcom-soc.c \ + qcom-soc/mm-broadband-modem-qmi-qcom-soc.h \ + $(NULL) +libmm_plugin_qcom_soc_la_CPPFLAGS = \ + $(PLUGIN_COMMON_COMPILER_FLAGS) \ + -DMM_MODULE_NAME=\"qcom-soc\" \ + $(NULL) +libmm_plugin_qcom_soc_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS) + +dist_udevrules_DATA += qcom-soc/77-mm-qcom-soc.rules + +AM_CFLAGS += -DTESTUDEVRULESDIR_QCOM_SOC=\"${srcdir}/qcom-soc/\" +endif +endif + +################################################################################ # plugin: quectel ################################################################################ diff --git a/plugins/qcom-soc/77-mm-qcom-soc.rules b/plugins/qcom-soc/77-mm-qcom-soc.rules new file mode 100644 index 00000000..772f498c --- /dev/null +++ b/plugins/qcom-soc/77-mm-qcom-soc.rules @@ -0,0 +1,46 @@ +# do not edit this file, it will be overwritten on update + +ACTION!="add|change|move|bind", GOTO="mm_qcom_soc_end" + +# Process only known net and rpmsg ports +SUBSYSTEM=="net", DRIVERS=="bam-dmux", GOTO="mm_qcom_soc_process" +SUBSYSTEM=="rpmsg", DRIVERS=="qcom-q6v5-mss", GOTO="mm_qcom_soc_process" +GOTO="mm_qcom_soc_end" + +LABEL="mm_qcom_soc_process" + +# +# Add a common physdev UID to all ports in the Qualcomm SoC, so that they +# are all bound together to the same modem object. +# +# The MSM8916, MSM8974, .... Qualcomm SoCs use the combination of RPMSG +# based control ports plus BAM-DMUX based network ports. +# +ENV{ID_MM_PHYSDEV_UID}="qcom-soc" + +# port type hints for the rpmsgexport-ed ports +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA5_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA6_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA7_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA8_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA9_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA12_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA13_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA14_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA15_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA16_CNTL", ENV{ID_MM_PORT_TYPE_QMI}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA1", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA2", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA3", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1" +SUBSYSTEM=="rpmsg", ATTR{name}=="DATA4", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1" + +# ignore every other port without explicit hints +SUBSYSTEM=="rpmsg", ENV{ID_MM_PORT_TYPE_QMI}!="1", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}!="1", ENV{ID_MM_PORT_IGNORE}="1" + +# explicitly ignore bam-dmux network ports like rmnet_usb0 +KERNEL=="rmnet_usb[0-9]*", ENV{ID_MM_PORT_IGNORE}="1" + +# flag all rpmsg ports under this plugin as candidate +KERNEL=="rpmsg[0-9]*", SUBSYSTEM=="rpmsg", ENV{ID_MM_CANDIDATE}="1" + +LABEL="mm_qcom_soc_end" diff --git a/plugins/qcom-soc/mm-broadband-modem-qmi-qcom-soc.c b/plugins/qcom-soc/mm-broadband-modem-qmi-qcom-soc.c new file mode 100644 index 00000000..58a6e5e3 --- /dev/null +++ b/plugins/qcom-soc/mm-broadband-modem-qmi-qcom-soc.c @@ -0,0 +1,133 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2020 Aleksander Morgado <aleksander@aleksander.es> + */ + +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> + +#include "ModemManager.h" +#include "mm-log.h" +#include "mm-broadband-modem-qmi-qcom-soc.h" + +G_DEFINE_TYPE (MMBroadbandModemQmiQcomSoc, mm_broadband_modem_qmi_qcom_soc, MM_TYPE_BROADBAND_MODEM_QMI) + +/*****************************************************************************/ + +static const QmiSioPort sio_port_per_port_number[] = { + QMI_SIO_PORT_A2_MUX_RMNET0, + QMI_SIO_PORT_A2_MUX_RMNET1, + QMI_SIO_PORT_A2_MUX_RMNET2, + QMI_SIO_PORT_A2_MUX_RMNET3, + QMI_SIO_PORT_A2_MUX_RMNET4, + QMI_SIO_PORT_A2_MUX_RMNET5, + QMI_SIO_PORT_A2_MUX_RMNET6, + QMI_SIO_PORT_A2_MUX_RMNET7 +}; + +static MMPortQmi * +peek_port_qmi_for_data (MMBroadbandModemQmi *self, + MMPort *data, + QmiSioPort *out_sio_port, + GError **error) +{ + GList *rpmsg_qmi_ports; + MMPortQmi *found = NULL; + MMKernelDevice *net_port; + const gchar *net_port_driver; + gint net_port_number; + + g_assert (MM_IS_BROADBAND_MODEM_QMI (self)); + g_assert (mm_port_get_subsys (data) == MM_PORT_SUBSYS_NET); + + net_port = mm_port_peek_kernel_device (data); + net_port_driver = mm_kernel_device_get_driver (net_port); + if (g_strcmp0 (net_port_driver, "bam-dmux") != 0) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unsupported QMI kernel driver for 'net/%s': %s", + mm_port_get_device (data), + net_port_driver); + return NULL; + } + + /* The dev_port notified by the bam-dmux driver indicates which SIO port we should be using */ + net_port_number = mm_kernel_device_get_attribute_as_int (net_port, "dev_port"); + if (net_port_number < 0 || net_port_number >= (gint) G_N_ELEMENTS (sio_port_per_port_number)) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_NOT_FOUND, + "Couldn't find SIO port number for 'net/%s'", + mm_port_get_device (data)); + return NULL; + } + + /* Find one QMI port, we don't care which one */ + rpmsg_qmi_ports = mm_base_modem_find_ports (MM_BASE_MODEM (self), + MM_PORT_SUBSYS_RPMSG, + MM_PORT_TYPE_QMI, + NULL); + if (!rpmsg_qmi_ports) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_NOT_FOUND, + "Couldn't find any QMI port for 'net/%s'", + mm_port_get_device (data)); + return NULL; + } + + /* Set outputs */ + *out_sio_port = sio_port_per_port_number[net_port_number]; + found = MM_PORT_QMI (rpmsg_qmi_ports->data); + + g_list_free_full (rpmsg_qmi_ports, g_object_unref); + + return found; +} + +/*****************************************************************************/ + +MMBroadbandModemQmiQcomSoc * +mm_broadband_modem_qmi_qcom_soc_new (const gchar *device, + const gchar **drivers, + const gchar *plugin, + guint16 vendor_id, + guint16 product_id) +{ + return g_object_new (MM_TYPE_BROADBAND_MODEM_QMI_QCOM_SOC, + MM_BASE_MODEM_DEVICE, device, + MM_BASE_MODEM_DRIVERS, drivers, + MM_BASE_MODEM_PLUGIN, plugin, + MM_BASE_MODEM_VENDOR_ID, vendor_id, + MM_BASE_MODEM_PRODUCT_ID, product_id, + NULL); +} + +static void +mm_broadband_modem_qmi_qcom_soc_init (MMBroadbandModemQmiQcomSoc *self) +{ +} + +static void +mm_broadband_modem_qmi_qcom_soc_class_init (MMBroadbandModemQmiQcomSocClass *klass) +{ + MMBroadbandModemQmiClass *broadband_modem_qmi_class = MM_BROADBAND_MODEM_QMI_CLASS (klass); + + broadband_modem_qmi_class->peek_port_qmi_for_data = peek_port_qmi_for_data; +} diff --git a/plugins/qcom-soc/mm-broadband-modem-qmi-qcom-soc.h b/plugins/qcom-soc/mm-broadband-modem-qmi-qcom-soc.h new file mode 100644 index 00000000..92c37beb --- /dev/null +++ b/plugins/qcom-soc/mm-broadband-modem-qmi-qcom-soc.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2020 Aleksander Morgado <aleksander@aleksander.es> + */ + +#ifndef MM_BROADBAND_MODEM_QMI_QCOM_SOC_H +#define MM_BROADBAND_MODEM_QMI_QCOM_SOC_H + +#include "mm-broadband-modem-qmi.h" + +#define MM_TYPE_BROADBAND_MODEM_QMI_QCOM_SOC (mm_broadband_modem_qmi_qcom_soc_get_type ()) +#define MM_BROADBAND_MODEM_QMI_QCOM_SOC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_QMI_QCOM_SOC, MMBroadbandModemQmiQcomSoc)) +#define MM_BROADBAND_MODEM_QMI_QCOM_SOC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_QMI_QCOM_SOC, MMBroadbandModemQmiQcomSocClass)) +#define MM_IS_BROADBAND_MODEM_QMI_QCOM_SOC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_QMI_QCOM_SOC)) +#define MM_IS_BROADBAND_MODEM_QMI_QCOM_SOC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_QMI_QCOM_SOC)) +#define MM_BROADBAND_MODEM_QMI_QCOM_SOC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_QMI_QCOM_SOC, MMBroadbandModemQmiQcomSocClass)) + +typedef struct _MMBroadbandModemQmiQcomSoc MMBroadbandModemQmiQcomSoc; +typedef struct _MMBroadbandModemQmiQcomSocClass MMBroadbandModemQmiQcomSocClass; +typedef struct _MMBroadbandModemQmiQcomSocPrivate MMBroadbandModemQmiQcomSocPrivate; + +struct _MMBroadbandModemQmiQcomSoc { + MMBroadbandModemQmi parent; + MMBroadbandModemQmiQcomSocPrivate *priv; +}; + +struct _MMBroadbandModemQmiQcomSocClass{ + MMBroadbandModemQmiClass parent; +}; + +GType mm_broadband_modem_qmi_qcom_soc_get_type (void); + +MMBroadbandModemQmiQcomSoc *mm_broadband_modem_qmi_qcom_soc_new (const gchar *device, + const gchar **drivers, + const gchar *plugin, + guint16 vendor_id, + guint16 product_id); + +#endif /* MM_BROADBAND_MODEM_QMI_QCOM_SOC_H */ diff --git a/plugins/qcom-soc/mm-plugin-qcom-soc.c b/plugins/qcom-soc/mm-plugin-qcom-soc.c new file mode 100644 index 00000000..6f2fac90 --- /dev/null +++ b/plugins/qcom-soc/mm-plugin-qcom-soc.c @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2020 Aleksander Morgado <aleksander@aleksander.es> + */ + +#include <string.h> +#include <termios.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> +#include <time.h> + +#include <gmodule.h> + +#define _LIBMM_INSIDE_MM +#include <libmm-glib.h> + +#include "mm-plugin-qcom-soc.h" +#include "mm-broadband-modem-qmi-qcom-soc.h" +#include "mm-log-object.h" + +G_DEFINE_TYPE (MMPluginQcomSoc, mm_plugin_qcom_soc, MM_TYPE_PLUGIN) + +MM_PLUGIN_DEFINE_MAJOR_VERSION +MM_PLUGIN_DEFINE_MINOR_VERSION + +/*****************************************************************************/ + +static MMBaseModem * +create_modem (MMPlugin *self, + const gchar *uid, + const gchar **drivers, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + if (!mm_port_probe_list_has_qmi_port (probes)) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Unsupported device: at least a QMI port is required"); + return NULL; + } + + mm_obj_dbg (self, "Qualcomm SoC modem found..."); + return MM_BASE_MODEM (mm_broadband_modem_qmi_qcom_soc_new (uid, + drivers, + mm_plugin_get_name (self), + vendor, + product)); +} + +/*****************************************************************************/ + +G_MODULE_EXPORT MMPlugin * +mm_plugin_create (void) +{ + static const gchar *subsystems[] = { "rpmsg", "net", NULL }; + + return MM_PLUGIN ( + g_object_new (MM_TYPE_PLUGIN_QCOM_SOC, + MM_PLUGIN_NAME, MM_MODULE_NAME, + MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems, + MM_PLUGIN_ALLOWED_AT, TRUE, + MM_PLUGIN_ALLOWED_QMI, TRUE, + NULL)); +} + +static void +mm_plugin_qcom_soc_init (MMPluginQcomSoc *self) +{ +} + +static void +mm_plugin_qcom_soc_class_init (MMPluginQcomSocClass *klass) +{ + MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass); + + plugin_class->create_modem = create_modem; +} diff --git a/plugins/qcom-soc/mm-plugin-qcom-soc.h b/plugins/qcom-soc/mm-plugin-qcom-soc.h new file mode 100644 index 00000000..54da154f --- /dev/null +++ b/plugins/qcom-soc/mm-plugin-qcom-soc.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2020 Aleksander Morgado <aleksander@aleksander.es> + */ + +#ifndef MM_PLUGIN_QCOM_SOC_H +#define MM_PLUGIN_QCOM_SOC_H + +#include "mm-plugin.h" + +#define MM_TYPE_PLUGIN_QCOM_SOC (mm_plugin_qcom_soc_get_type ()) +#define MM_PLUGIN_QCOM_SOC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_QCOM_SOC, MMPluginQcomSoc)) +#define MM_PLUGIN_QCOM_SOC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_QCOM_SOC, MMPluginQcomSocClass)) +#define MM_IS_PLUGIN_QCOM_SOC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_QCOM_SOC)) +#define MM_IS_PLUGIN_QCOM_SOC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_QCOM_SOC)) +#define MM_PLUGIN_QCOM_SOC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_QCOM_SOC, MMPluginQcomSocClass)) + +typedef struct { + MMPlugin parent; +} MMPluginQcomSoc; + +typedef struct { + MMPluginClass parent; +} MMPluginQcomSocClass; + +GType mm_plugin_qcom_soc_get_type (void); + +G_MODULE_EXPORT MMPlugin *mm_plugin_create (void); + +#endif /* MM_PLUGIN_QCOM_SOC_H */ diff --git a/plugins/tests/test-udev-rules.c b/plugins/tests/test-udev-rules.c index e1b38a9e..2f7190f1 100644 --- a/plugins/tests/test-udev-rules.c +++ b/plugins/tests/test-udev-rules.c @@ -176,6 +176,14 @@ test_gosuncn (void) } #endif +#if defined ENABLE_PLUGIN_QCOM_SOC && defined WITH_QMI +static void +test_qcom_soc (void) +{ + common_test (TESTUDEVRULESDIR_QCOM_SOC); +} +#endif + /************************************************************/ int main (int argc, char **argv) @@ -230,6 +238,9 @@ int main (int argc, char **argv) #if defined ENABLE_PLUGIN_GOSUNCN g_test_add_func ("/MM/test-udev-rules/gosuncn", test_gosuncn); #endif +#if defined ENABLE_PLUGIN_QCOM_SOC && defined WITH_QMI + g_test_add_func ("/MM/test-udev-rules/qcom-soc", test_qcom_soc); +#endif return g_test_run (); } |