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."
This commit is contained in:
Aleksander Morgado
2012-08-30 11:01:29 +02:00
parent 3132e34dc1
commit 36733aa4de
2 changed files with 129 additions and 9 deletions

View File

@@ -20,6 +20,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <gudev/gudev.h>
#include <ModemManager.h> #include <ModemManager.h>
#include <mm-errors-types.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); 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 * MMPort *
mm_base_modem_get_best_data_port (MMBaseModem *self) mm_base_modem_get_best_data_port (MMBaseModem *self)
{ {

View File

@@ -118,6 +118,7 @@ MMQcdmSerialPort *mm_base_modem_peek_port_qcdm (MMBaseModem *self);
MMAtSerialPort *mm_base_modem_peek_port_gps_control (MMBaseModem *self); MMAtSerialPort *mm_base_modem_peek_port_gps_control (MMBaseModem *self);
MMGpsSerialPort *mm_base_modem_peek_port_gps (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 (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); MMAtSerialPort *mm_base_modem_peek_best_at_port (MMBaseModem *self, GError **error);
MMPort *mm_base_modem_peek_best_data_port (MMBaseModem *self); MMPort *mm_base_modem_peek_best_data_port (MMBaseModem *self);
GList *mm_base_modem_peek_data_ports (MMBaseModem *self); GList *mm_base_modem_peek_data_ports (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); MMAtSerialPort *mm_base_modem_get_port_gps_control (MMBaseModem *self);
MMGpsSerialPort *mm_base_modem_get_port_gps (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 (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); MMAtSerialPort *mm_base_modem_get_best_at_port (MMBaseModem *self, GError **error);
MMPort *mm_base_modem_get_best_data_port (MMBaseModem *self); MMPort *mm_base_modem_get_best_data_port (MMBaseModem *self);
GList *mm_base_modem_get_data_ports (MMBaseModem *self); GList *mm_base_modem_get_data_ports (MMBaseModem *self);