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 _______________________________________________ networkmanager-list mailing list networkmanager-list@gnome.org https://mail.gnome.org/mailman/listinfo/networkmanager-list