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:
@@ -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)
|
||||||
{
|
{
|
||||||
|
@@ -112,15 +112,16 @@ gboolean mm_base_modem_has_at_port (MMBaseModem *self);
|
|||||||
gboolean mm_base_modem_organize_ports (MMBaseModem *self,
|
gboolean mm_base_modem_organize_ports (MMBaseModem *self,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
MMAtSerialPort *mm_base_modem_peek_port_primary (MMBaseModem *self);
|
MMAtSerialPort *mm_base_modem_peek_port_primary (MMBaseModem *self);
|
||||||
MMAtSerialPort *mm_base_modem_peek_port_secondary (MMBaseModem *self);
|
MMAtSerialPort *mm_base_modem_peek_port_secondary (MMBaseModem *self);
|
||||||
MMQcdmSerialPort *mm_base_modem_peek_port_qcdm (MMBaseModem *self);
|
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);
|
||||||
MMAtSerialPort *mm_base_modem_peek_best_at_port (MMBaseModem *self, GError **error);
|
MMQmiPort *mm_base_modem_peek_port_qmi_for_data (MMBaseModem *self, MMPort *data, GError **error);
|
||||||
MMPort *mm_base_modem_peek_best_data_port (MMBaseModem *self);
|
MMAtSerialPort *mm_base_modem_peek_best_at_port (MMBaseModem *self, GError **error);
|
||||||
GList *mm_base_modem_peek_data_ports (MMBaseModem *self);
|
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_primary (MMBaseModem *self);
|
||||||
MMAtSerialPort *mm_base_modem_get_port_secondary (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);
|
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);
|
||||||
|
Reference in New Issue
Block a user