[PATCH 1/2] base-modem: allow looking for the QMI port associated to a given data port



QMI and wwan ports come in pairs. Each wwan port has an associated control QMI
port, which is the only port allowed to send the Start|Stop Network QMI requests
to start|stop the connection in the given wwan interface.

Paired QMI and wwan interfaces (should) share the same parent udev device,
quoting Bjørn:

    "If we ignore the unfortunate 3.4 and 3.5 kernels, then a matching wwanX
     and cdc-wdmY set will always share the same parent USB interface on QMI
     devices.

     Having the same parent USB device is *not* sufficient.  You cannot control
     wwan0 using cdc-wdm1 in the above example."
---
 src/mm-base-modem.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/mm-base-modem.h |  20 +++++----
 2 files changed, 129 insertions(+), 9 deletions(-)

diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
index 6d2ea9c..af2e829 100644
--- a/src/mm-base-modem.c
+++ b/src/mm-base-modem.c
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <gudev/gudev.h>
 
 #include <ModemManager.h>
 #include <mm-errors-types.h>
@@ -529,6 +530,123 @@ mm_base_modem_peek_port_qmi (MMBaseModem *self)
     return (self->priv->qmi ? (MMQmiPort *)self->priv->qmi->data : NULL);
 }
 
+MMQmiPort *
+mm_base_modem_get_port_qmi_for_data (MMBaseModem *self,
+                                     MMPort *data,
+                                     GError **error)
+{
+    MMQmiPort *qmi;
+
+    qmi = mm_base_modem_peek_port_qmi_for_data (self, data, error);
+    return (qmi ? (MMQmiPort *)g_object_ref (qmi) : NULL);
+}
+
+MMQmiPort *
+mm_base_modem_peek_port_qmi_for_data (MMBaseModem *self,
+                                      MMPort *data,
+                                      GError **error)
+{
+    MMQmiPort *found;
+    GUdevClient *client;
+    GUdevDevice *data_device;
+    GUdevDevice *data_device_parent;
+    GList *l;
+
+    if (mm_port_get_subsys (data) != MM_PORT_SUBSYS_NET) {
+        g_set_error (error,
+                     MM_CORE_ERROR,
+                     MM_CORE_ERROR_UNSUPPORTED,
+                     "Cannot look for QMI port associated to a non-net data port");
+        return NULL;
+    }
+
+    /* don't listen for uevents */
+    client = g_udev_client_new (NULL);
+
+    /* Get udev device for the data port */
+    data_device = (g_udev_client_query_by_subsystem_and_name (
+                       client,
+                       "net",
+                       mm_port_get_device (data)));
+    if (!data_device) {
+        g_set_error (error,
+                     MM_CORE_ERROR,
+                     MM_CORE_ERROR_FAILED,
+                     "Couldn't find udev device for port 'net/%s'",
+                     mm_port_get_device (data));
+        g_object_unref (client);
+        return NULL;
+    }
+
+    /* Get parent of the data device */
+    data_device_parent = g_udev_device_get_parent (data_device);
+    if (!data_device_parent) {
+        g_set_error (error,
+                     MM_CORE_ERROR,
+                     MM_CORE_ERROR_FAILED,
+                     "Couldn't get udev device parent for port 'net/%s'",
+                     mm_port_get_device (data));
+        g_object_unref (data_device);
+        g_object_unref (client);
+        return NULL;
+    }
+
+    /* Now walk the list of QMI ports looking for a match */
+    found = NULL;
+    for (l = self->priv->qmi; l && !found; l = g_list_next (l)) {
+        GUdevDevice *qmi_device;
+        GUdevDevice *qmi_device_parent;
+
+        /* Get udev device for the QMI port */
+        qmi_device = (g_udev_client_query_by_subsystem_and_name (
+                          client,
+                          "usb",
+                          mm_port_get_device (MM_PORT (l->data))));
+        if (!qmi_device) {
+            qmi_device = (g_udev_client_query_by_subsystem_and_name (
+                              client,
+                              "usbmisc",
+                              mm_port_get_device (MM_PORT (l->data))));
+            if (!qmi_device) {
+                mm_warn ("Couldn't get udev device for QMI port '%s'",
+                         mm_port_get_device (MM_PORT (l->data)));
+                continue;
+            }
+        }
+
+        /* Get parent of the QMI device */
+        qmi_device_parent = g_udev_device_get_parent (qmi_device);
+        g_object_unref (qmi_device);
+
+        if (!data_device_parent) {
+            mm_warn ("Couldn't get udev device parent for QMI port '%s'",
+                     mm_port_get_device (MM_PORT (l->data)));
+            continue;
+        }
+
+        if (g_str_equal (g_udev_device_get_sysfs_path (data_device_parent),
+                         g_udev_device_get_sysfs_path (qmi_device_parent)))
+            found = MM_QMI_PORT (l->data);
+
+        g_object_unref (qmi_device_parent);
+    }
+
+    g_object_unref (data_device_parent);
+    g_object_unref (data_device);
+    g_object_unref (client);
+
+    if (!found) {
+        g_set_error (error,
+                     MM_CORE_ERROR,
+                     MM_CORE_ERROR_NOT_FOUND,
+                     "Couldn't find associated QMI port for 'net/%s'",
+                     mm_port_get_device (data));
+        return NULL;
+    }
+
+    return found;
+}
+
 MMPort *
 mm_base_modem_get_best_data_port (MMBaseModem *self)
 {
diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h
index 36a7a51..386fa8f 100644
--- a/src/mm-base-modem.h
+++ b/src/mm-base-modem.h
@@ -112,15 +112,16 @@ gboolean  mm_base_modem_has_at_port  (MMBaseModem *self);
 gboolean  mm_base_modem_organize_ports (MMBaseModem *self,
                                         GError **error);
 
-MMAtSerialPort   *mm_base_modem_peek_port_primary     (MMBaseModem *self);
-MMAtSerialPort   *mm_base_modem_peek_port_secondary   (MMBaseModem *self);
-MMQcdmSerialPort *mm_base_modem_peek_port_qcdm        (MMBaseModem *self);
-MMAtSerialPort   *mm_base_modem_peek_port_gps_control (MMBaseModem *self);
-MMGpsSerialPort  *mm_base_modem_peek_port_gps         (MMBaseModem *self);
-MMQmiPort        *mm_base_modem_peek_port_qmi         (MMBaseModem *self);
-MMAtSerialPort   *mm_base_modem_peek_best_at_port     (MMBaseModem *self, GError **error);
-MMPort           *mm_base_modem_peek_best_data_port   (MMBaseModem *self);
-GList            *mm_base_modem_peek_data_ports       (MMBaseModem *self);
+MMAtSerialPort   *mm_base_modem_peek_port_primary      (MMBaseModem *self);
+MMAtSerialPort   *mm_base_modem_peek_port_secondary    (MMBaseModem *self);
+MMQcdmSerialPort *mm_base_modem_peek_port_qcdm         (MMBaseModem *self);
+MMAtSerialPort   *mm_base_modem_peek_port_gps_control  (MMBaseModem *self);
+MMGpsSerialPort  *mm_base_modem_peek_port_gps          (MMBaseModem *self);
+MMQmiPort        *mm_base_modem_peek_port_qmi          (MMBaseModem *self);
+MMQmiPort        *mm_base_modem_peek_port_qmi_for_data (MMBaseModem *self, MMPort *data, GError **error);
+MMAtSerialPort   *mm_base_modem_peek_best_at_port      (MMBaseModem *self, GError **error);
+MMPort           *mm_base_modem_peek_best_data_port    (MMBaseModem *self);
+GList            *mm_base_modem_peek_data_ports        (MMBaseModem *self);
 
 MMAtSerialPort   *mm_base_modem_get_port_primary      (MMBaseModem *self);
 MMAtSerialPort   *mm_base_modem_get_port_secondary    (MMBaseModem *self);
@@ -128,6 +129,7 @@ MMQcdmSerialPort *mm_base_modem_get_port_qcdm         (MMBaseModem *self);
 MMAtSerialPort   *mm_base_modem_get_port_gps_control  (MMBaseModem *self);
 MMGpsSerialPort  *mm_base_modem_get_port_gps          (MMBaseModem *self);
 MMQmiPort        *mm_base_modem_get_port_qmi          (MMBaseModem *self);
+MMQmiPort        *mm_base_modem_get_port_qmi_for_data (MMBaseModem *self, MMPort *data, GError **error);
 MMAtSerialPort   *mm_base_modem_get_best_at_port      (MMBaseModem *self, GError **error);
 MMPort           *mm_base_modem_get_best_data_port    (MMBaseModem *self);
 GList            *mm_base_modem_get_data_ports        (MMBaseModem *self);
-- 
1.7.11.4



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]