diff mbox series

[v2,1/2] udevng: Detect embedded qmi QRTR modems

Message ID 20240408213453.53910-1-steve.schrock@getcruise.com (mailing list archive)
State Accepted
Commit 296347f8a4f1c5809b6dfa36472931ad1f7ab266
Headers show
Series [v2,1/2] udevng: Detect embedded qmi QRTR modems | expand

Commit Message

Steve Schrock April 8, 2024, 9:34 p.m. UTC
Embedded qmi QRTR modems are identified by the existence of
rmnet_ipaX and rmnet_dataX devices. Add a new "embedded" modem type
so that these devices can be collected during enumeration and then
configured for use by the gobi plugin. Modems of this type will be
exposed as /gobiqrtr_X.
---
 plugins/gobi.c   |  19 +++++++--
 plugins/udevng.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 119 insertions(+), 5 deletions(-)

Comments

patchwork-bot+ofono@kernel.org April 8, 2024, 10:40 p.m. UTC | #1
Hello:

This series was applied to ofono.git (master)
by Denis Kenzior <denkenz@gmail.com>:

On Mon,  8 Apr 2024 16:34:38 -0500 you wrote:
> Embedded qmi QRTR modems are identified by the existence of
> rmnet_ipaX and rmnet_dataX devices. Add a new "embedded" modem type
> so that these devices can be collected during enumeration and then
> configured for use by the gobi plugin. Modems of this type will be
> exposed as /gobiqrtr_X.
> ---
>  plugins/gobi.c   |  19 +++++++--
>  plugins/udevng.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 119 insertions(+), 5 deletions(-)

Here is the summary with links:
  - [v2,1/2] udevng: Detect embedded qmi QRTR modems
    https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=296347f8a4f1
  - [v2,2/2] qmimodem: Default embedded modems endpoint ID
    https://git.kernel.org/pub/scm/network/ofono/ofono.git/?id=6d7edaf5bc5a

You are awesome, thank you!
diff mbox series

Patch

diff --git a/plugins/gobi.c b/plugins/gobi.c
index 7a07b080d895..431df17e2332 100644
--- a/plugins/gobi.c
+++ b/plugins/gobi.c
@@ -420,16 +420,27 @@  static void discover_cb(void *user_data)
 static int gobi_enable(struct ofono_modem *modem)
 {
 	struct gobi_data *data = ofono_modem_get_data(modem);
-	const char *device;
+	const char *kernel_driver;
 	int r;
 
 	DBG("%p", modem);
 
-	device = ofono_modem_get_string(modem, "Device");
-	if (!device)
+	kernel_driver = ofono_modem_get_string(modem, "KernelDriver");
+	if (!kernel_driver)
 		return -EINVAL;
 
-	data->device = qmi_device_new_qmux(device);
+	if (!strcmp(kernel_driver, "qrtr"))
+		data->device = qmi_device_new_qrtr();
+	else {
+		const char *device;
+
+		device = ofono_modem_get_string(modem, "Device");
+		if (!device)
+			return -EINVAL;
+
+		data->device = qmi_device_new_qmux(device);
+	}
+
 	if (!data->device)
 		return -EIO;
 
diff --git a/plugins/udevng.c b/plugins/udevng.c
index 8bdcf0dbbccd..14ae2f392da4 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -43,6 +43,7 @@  enum modem_type {
 	MODEM_TYPE_USB,
 	MODEM_TYPE_SERIAL,
 	MODEM_TYPE_PCIE,
+	MODEM_TYPE_EMBEDDED,
 };
 
 struct modem_info {
@@ -206,7 +207,10 @@  static int setup_qmi(struct modem_info *modem, const struct device_info *qmi,
 	DBG("qmi: %s net: %s kernel_driver: %s interface_number: %s",
 		qmi->devnode, net->devnode, net->kernel_driver, net->number);
 
-	if (!qmi->kernel_driver || !net->number)
+	if (!qmi->kernel_driver)
+		return -EINVAL;
+
+	if (!net->number && modem->type != MODEM_TYPE_EMBEDDED)
 		return -EINVAL;
 
 	attr_value = udev_device_get_sysattr_value(net->udev_device,
@@ -234,6 +238,9 @@  static int setup_qmi(struct modem_info *modem, const struct device_info *qmi,
 	case MODEM_TYPE_PCIE:
 		ofono_modem_set_string(modem->modem, "Bus", "pcie");
 		break;
+	case MODEM_TYPE_EMBEDDED:
+		ofono_modem_set_string(modem->modem, "Bus", "embedded");
+		break;
 	case MODEM_TYPE_SERIAL:
 		break;
 	}
@@ -241,6 +248,75 @@  static int setup_qmi(struct modem_info *modem, const struct device_info *qmi,
 	return 0;
 }
 
+static gboolean setup_gobi_qrtr_premux(struct modem_info *modem,
+					const char *name, int premux_index)
+{
+	const char *rmnet_data_prefix = "rmnet_data";
+	int rmnet_data_prefix_length = strlen(rmnet_data_prefix);
+	char buf[256];
+	int r;
+	uint32_t data_id;
+	uint32_t mux_id;
+
+	r = l_safe_atou32(name + rmnet_data_prefix_length, &data_id);
+	if (r < 0)
+		return FALSE;
+
+	mux_id = data_id + 1;
+
+	DBG("Adding premux interface %s, mux id: %d", name, mux_id);
+	sprintf(buf, "PremuxInterface%d", premux_index);
+	ofono_modem_set_string(modem->modem, buf, name);
+	sprintf(buf, "PremuxInterface%dMuxId", premux_index);
+	ofono_modem_set_integer(modem->modem, buf, mux_id);
+
+	return TRUE;
+}
+
+static gboolean setup_gobi_qrtr(struct modem_info *modem)
+{
+	const struct device_info *ipa_info = NULL;
+	int premux_count = 0;
+	int r;
+	GSList *list;
+
+	DBG("%s", modem->syspath);
+
+	for (list = modem->devices; list; list = list->next) {
+		struct device_info *info = list->data;
+		const char *name;
+
+		name = udev_device_get_sysname(info->udev_device);
+		if (l_str_has_prefix(name, "rmnet_ipa"))
+			ipa_info = info;
+		else if (l_str_has_prefix(name, "rmnet_data")) {
+			int premux_index = premux_count + 1;
+
+			if (setup_gobi_qrtr_premux(modem, name, premux_index))
+				premux_count++;
+		}
+	}
+
+	if (premux_count < 3) {
+		DBG("Not enough rmnet_data interfaces found");
+		return FALSE;
+	}
+
+	ofono_modem_set_integer(modem->modem, "NumPremuxInterfaces",
+							premux_count);
+
+	if (!ipa_info) {
+		DBG("No rmnet_ipa interface found");
+		return FALSE;
+	}
+
+	r = setup_qmi(modem, ipa_info, ipa_info);
+	if (r < 0)
+		return FALSE;
+
+	return TRUE;
+}
+
 static gboolean setup_gobi(struct modem_info *modem)
 {
 	const struct device_info *qmi = NULL;
@@ -1594,6 +1670,7 @@  static struct {
 	{ "wavecom",	setup_wavecom		},
 	{ "tc65",	setup_tc65		},
 	{ "ehs6",	setup_ehs6		},
+	{ "gobiqrtr",	setup_gobi_qrtr		},
 	{ }
 };
 
@@ -1644,6 +1721,7 @@  static void destroy_modem(gpointer data)
 	switch (modem->type) {
 	case MODEM_TYPE_USB:
 	case MODEM_TYPE_PCIE:
+	case MODEM_TYPE_EMBEDDED:
 		for (list = modem->devices; list; list = list->next) {
 			struct device_info *info = list->data;
 
@@ -1688,6 +1766,9 @@  static gboolean check_remove(gpointer key, gpointer value, gpointer user_data)
 		if (g_strcmp0(modem->serial->devpath, devpath) == 0)
 			return TRUE;
 		break;
+	case MODEM_TYPE_EMBEDDED:
+		/* Embedded modems cannot be removed. */
+		break;
 	}
 
 	return FALSE;
@@ -2133,6 +2214,26 @@  static void check_pci_device(struct udev_device *device)
 			device, kernel_driver);
 }
 
+static void check_net_device(struct udev_device *device)
+{
+	char path[32];
+	const char *name;
+	const char *iflink;
+
+	name = udev_device_get_sysname(device);
+	if (!l_str_has_prefix(name, "rmnet_"))
+		return;
+
+	iflink = udev_device_get_sysattr_value(device, "iflink");
+	if (!iflink)
+		return;
+
+	/* Collect all rmnet devices with this iflink under a common path. */
+	sprintf(path, "/embedded/qrtr/%s", iflink);
+	add_device(path, NULL, "gobiqrtr", NULL, NULL, MODEM_TYPE_EMBEDDED,
+							device, "qrtr");
+}
+
 static void check_device(struct udev_device *device)
 {
 	const char *bus;
@@ -2149,6 +2250,8 @@  static void check_device(struct udev_device *device)
 		check_usb_device(device);
 	else if (g_str_equal(bus, "pci") == TRUE)
 		check_pci_device(device);
+	else if (g_str_equal(bus, "net") == TRUE)
+		check_net_device(device);
 	else
 		add_serial_device(device);