base-modem: allow grabbing MBIM ports
This commit is contained in:
@@ -91,6 +91,11 @@ struct _MMBaseModemPrivate {
|
|||||||
/* QMI ports */
|
/* QMI ports */
|
||||||
GList *qmi;
|
GList *qmi;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
/* MBIM ports */
|
||||||
|
GList *mbim;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
@@ -238,15 +243,18 @@ mm_base_modem_grab_port (MMBaseModem *self,
|
|||||||
MM_PORT_TYPE, MM_PORT_TYPE_NET,
|
MM_PORT_TYPE, MM_PORT_TYPE_NET,
|
||||||
NULL));
|
NULL));
|
||||||
}
|
}
|
||||||
/* QMI ports... */
|
/* cdc-wdm ports... */
|
||||||
else if (g_str_has_prefix (subsys, "usb") &&
|
else if (g_str_has_prefix (subsys, "usb") &&
|
||||||
g_str_has_prefix (name, "cdc-wdm")) {
|
g_str_has_prefix (name, "cdc-wdm")) {
|
||||||
#if defined WITH_QMI
|
#if defined WITH_QMI
|
||||||
if (ptype == MM_PORT_TYPE_QMI)
|
if (ptype == MM_PORT_TYPE_QMI)
|
||||||
port = MM_PORT (mm_qmi_port_new (name));
|
port = MM_PORT (mm_qmi_port_new (name));
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
{
|
#if defined WITH_MBIM
|
||||||
|
if (!port && ptype == MM_PORT_TYPE_MBIM)
|
||||||
|
port = MM_PORT (mm_mbim_port_new (name));
|
||||||
|
#endif
|
||||||
|
if (!port) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
MM_CORE_ERROR,
|
MM_CORE_ERROR,
|
||||||
MM_CORE_ERROR_UNSUPPORTED,
|
MM_CORE_ERROR_UNSUPPORTED,
|
||||||
@@ -258,7 +266,7 @@ mm_base_modem_grab_port (MMBaseModem *self,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* We already filter out before all non-tty, non-net, non-qmi ports */
|
/* We already filter out before all non-tty, non-net, non-cdc-wdm ports */
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
|
|
||||||
mm_dbg ("(%s) type '%s' claimed by %s",
|
mm_dbg ("(%s) type '%s' claimed by %s",
|
||||||
@@ -335,6 +343,14 @@ mm_base_modem_release_port (MMBaseModem *self,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
l = g_list_find (self->priv->mbim, port);
|
||||||
|
if (l) {
|
||||||
|
g_object_unref (l->data);
|
||||||
|
self->priv->mbim = g_list_delete_link (self->priv->mbim, l);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Remove it from the tracking HT */
|
/* Remove it from the tracking HT */
|
||||||
mm_dbg ("(%s/%s) type %s released from %s",
|
mm_dbg ("(%s/%s) type %s released from %s",
|
||||||
subsys,
|
subsys,
|
||||||
@@ -701,6 +717,157 @@ mm_base_modem_peek_port_qmi_for_data (MMBaseModem *self,
|
|||||||
|
|
||||||
#endif /* WITH_QMI */
|
#endif /* WITH_QMI */
|
||||||
|
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
|
||||||
|
MMMbimPort *
|
||||||
|
mm_base_modem_get_port_mbim (MMBaseModem *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (MM_IS_BASE_MODEM (self), NULL);
|
||||||
|
|
||||||
|
/* First MBIM port in the list is the primary one always */
|
||||||
|
return (self->priv->mbim ? ((MMMbimPort *)g_object_ref (self->priv->mbim->data)) : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
MMMbimPort *
|
||||||
|
mm_base_modem_peek_port_mbim (MMBaseModem *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (MM_IS_BASE_MODEM (self), NULL);
|
||||||
|
|
||||||
|
/* First MBIM port in the list is the primary one always */
|
||||||
|
return (self->priv->mbim ? (MMMbimPort *)self->priv->mbim->data : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
MMMbimPort *
|
||||||
|
mm_base_modem_get_port_mbim_for_data (MMBaseModem *self,
|
||||||
|
MMPort *data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
MMMbimPort *mbim;
|
||||||
|
|
||||||
|
mbim = mm_base_modem_peek_port_mbim_for_data (self, data, error);
|
||||||
|
return (mbim ? (MMMbimPort *)g_object_ref (mbim) : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
MMMbimPort *
|
||||||
|
mm_base_modem_peek_port_mbim_for_data (MMBaseModem *self,
|
||||||
|
MMPort *data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
MMMbimPort *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 MBIM 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 MBIM ports looking for a match */
|
||||||
|
found = NULL;
|
||||||
|
for (l = self->priv->mbim; l && !found; l = g_list_next (l)) {
|
||||||
|
GUdevDevice *mbim_device;
|
||||||
|
GUdevDevice *mbim_device_parent;
|
||||||
|
|
||||||
|
/* Get udev device for the MBIM port */
|
||||||
|
mbim_device = (g_udev_client_query_by_subsystem_and_name (
|
||||||
|
client,
|
||||||
|
"usb",
|
||||||
|
mm_port_get_device (MM_PORT (l->data))));
|
||||||
|
if (!mbim_device) {
|
||||||
|
mbim_device = (g_udev_client_query_by_subsystem_and_name (
|
||||||
|
client,
|
||||||
|
"usbmisc",
|
||||||
|
mm_port_get_device (MM_PORT (l->data))));
|
||||||
|
if (!mbim_device) {
|
||||||
|
mm_warn ("Couldn't get udev device for MBIM port '%s'",
|
||||||
|
mm_port_get_device (MM_PORT (l->data)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get parent of the MBIM device */
|
||||||
|
mbim_device_parent = g_udev_device_get_parent (mbim_device);
|
||||||
|
g_object_unref (mbim_device);
|
||||||
|
|
||||||
|
if (!data_device_parent) {
|
||||||
|
mm_warn ("Couldn't get udev device parent for MBIM 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 (mbim_device_parent)))
|
||||||
|
found = MM_MBIM_PORT (l->data);
|
||||||
|
|
||||||
|
g_object_unref (mbim_device_parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (data_device_parent);
|
||||||
|
g_object_unref (data_device);
|
||||||
|
g_object_unref (client);
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
/* For the case where we have only 1 data port and 1 MBIM port and they
|
||||||
|
* don't match with the previous rules (e.g. in some Huawei modems),
|
||||||
|
* just return the found one */
|
||||||
|
if (g_list_length (self->priv->data) == 1 &&
|
||||||
|
g_list_length (self->priv->mbim) == 1 &&
|
||||||
|
self->priv->data->data == data) {
|
||||||
|
mm_info ("Assuming MBIM port '%s' is associated to net/%s",
|
||||||
|
mm_port_get_device (MM_PORT (self->priv->mbim->data)),
|
||||||
|
mm_port_get_device (data));
|
||||||
|
found = MM_MBIM_PORT (self->priv->mbim->data);
|
||||||
|
} else {
|
||||||
|
g_set_error (error,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_NOT_FOUND,
|
||||||
|
"Couldn't find associated MBIM port for 'net/%s'",
|
||||||
|
mm_port_get_device (data));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* WITH_MBIM */
|
||||||
|
|
||||||
MMPort *
|
MMPort *
|
||||||
mm_base_modem_get_best_data_port (MMBaseModem *self,
|
mm_base_modem_get_best_data_port (MMBaseModem *self,
|
||||||
MMPortType type)
|
MMPortType type)
|
||||||
@@ -862,6 +1029,10 @@ mm_base_modem_organize_ports (MMBaseModem *self,
|
|||||||
#if defined WITH_QMI
|
#if defined WITH_QMI
|
||||||
MMPort *qmi_primary = NULL;
|
MMPort *qmi_primary = NULL;
|
||||||
GList *qmi = NULL;
|
GList *qmi = NULL;
|
||||||
|
#endif
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
MMPort *mbim_primary = NULL;
|
||||||
|
GList *mbim = NULL;
|
||||||
#endif
|
#endif
|
||||||
GList *l;
|
GList *l;
|
||||||
|
|
||||||
@@ -953,6 +1124,16 @@ mm_base_modem_organize_ports (MMBaseModem *self,
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
case MM_PORT_TYPE_MBIM:
|
||||||
|
if (!mbim_primary)
|
||||||
|
mbim_primary = candidate;
|
||||||
|
else
|
||||||
|
/* All non-primary MBIM ports get added to the list of MBIM ports */
|
||||||
|
mbim = g_list_append (mbim, candidate);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Ignore port */
|
/* Ignore port */
|
||||||
break;
|
break;
|
||||||
@@ -961,17 +1142,26 @@ mm_base_modem_organize_ports (MMBaseModem *self,
|
|||||||
|
|
||||||
/* Fall back to a secondary port if we didn't find a primary port */
|
/* Fall back to a secondary port if we didn't find a primary port */
|
||||||
if (!primary) {
|
if (!primary) {
|
||||||
#if defined WITH_QMI
|
|
||||||
/* On QMI-based modems we do allow not having a primary AT port */
|
|
||||||
if (!secondary && !qmi_primary) {
|
|
||||||
#else
|
|
||||||
if (!secondary) {
|
if (!secondary) {
|
||||||
|
gboolean allow_modem_without_at_port = FALSE;
|
||||||
|
|
||||||
|
#if defined WITH_QMI
|
||||||
|
if (qmi_primary)
|
||||||
|
allow_modem_without_at_port = TRUE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
if (mbim_primary)
|
||||||
|
allow_modem_without_at_port = TRUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!allow_modem_without_at_port) {
|
||||||
g_set_error_literal (error,
|
g_set_error_literal (error,
|
||||||
MM_CORE_ERROR,
|
MM_CORE_ERROR,
|
||||||
MM_CORE_ERROR_FAILED,
|
MM_CORE_ERROR_FAILED,
|
||||||
"Failed to find primary AT port");
|
"Failed to find primary AT port");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
primary = secondary;
|
primary = secondary;
|
||||||
secondary = NULL;
|
secondary = NULL;
|
||||||
@@ -995,6 +1185,17 @@ mm_base_modem_organize_ports (MMBaseModem *self,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
/* On MBIM-based modems, we need to have at least a net port */
|
||||||
|
if (mbim_primary && !data_primary) {
|
||||||
|
g_set_error_literal (error,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_FAILED,
|
||||||
|
"Failed to find a net port in the MBIM modem");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Data port defaults to primary AT port */
|
/* Data port defaults to primary AT port */
|
||||||
if (!data_primary)
|
if (!data_primary)
|
||||||
data_primary = MM_PORT (primary);
|
data_primary = MM_PORT (primary);
|
||||||
@@ -1029,6 +1230,11 @@ mm_base_modem_organize_ports (MMBaseModem *self,
|
|||||||
for (l = qmi; l; l = g_list_next (l))
|
for (l = qmi; l; l = g_list_next (l))
|
||||||
log_port (self, MM_PORT (l->data), "qmi (secondary)");
|
log_port (self, MM_PORT (l->data), "qmi (secondary)");
|
||||||
#endif
|
#endif
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
log_port (self, MM_PORT (mbim_primary), "mbim (primary)");
|
||||||
|
for (l = mbim; l; l = g_list_next (l))
|
||||||
|
log_port (self, MM_PORT (l->data), "mbim (secondary)");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* We keep new refs to the objects here */
|
/* We keep new refs to the objects here */
|
||||||
self->priv->primary = (primary ? g_object_ref (primary) : NULL);
|
self->priv->primary = (primary ? g_object_ref (primary) : NULL);
|
||||||
@@ -1051,6 +1257,15 @@ mm_base_modem_organize_ports (MMBaseModem *self,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
/* Build the final list of MBIM ports, primary port first */
|
||||||
|
if (mbim_primary) {
|
||||||
|
self->priv->mbim = g_list_append (self->priv->mbim, g_object_ref (mbim_primary));
|
||||||
|
g_list_foreach (mbim, (GFunc)g_object_ref, NULL);
|
||||||
|
self->priv->mbim = g_list_concat (self->priv->mbim, mbim);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* As soon as we get the ports organized, we initialize the modem */
|
/* As soon as we get the ports organized, we initialize the modem */
|
||||||
mm_base_modem_initialize (self,
|
mm_base_modem_initialize (self,
|
||||||
(GAsyncReadyCallback)initialize_ready,
|
(GAsyncReadyCallback)initialize_ready,
|
||||||
@@ -1334,6 +1549,12 @@ dispose (GObject *object)
|
|||||||
g_list_free_full (self->priv->qmi, g_object_unref);
|
g_list_free_full (self->priv->qmi, g_object_unref);
|
||||||
self->priv->qmi = NULL;
|
self->priv->qmi = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
/* We need to close the MBIM port cleanly when disposing the modem object */
|
||||||
|
g_list_foreach (self->priv->mbim, (GFunc)mm_mbim_port_close, NULL);
|
||||||
|
g_list_free_full (self->priv->mbim, g_object_unref);
|
||||||
|
self->priv->mbim = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (self->priv->ports) {
|
if (self->priv->ports) {
|
||||||
g_hash_table_destroy (self->priv->ports);
|
g_hash_table_destroy (self->priv->ports);
|
||||||
|
@@ -35,6 +35,10 @@
|
|||||||
#include "mm-qmi-port.h"
|
#include "mm-qmi-port.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
#include "mm-mbim-port.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MM_TYPE_BASE_MODEM (mm_base_modem_get_type ())
|
#define MM_TYPE_BASE_MODEM (mm_base_modem_get_type ())
|
||||||
#define MM_BASE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BASE_MODEM, MMBaseModem))
|
#define MM_BASE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BASE_MODEM, MMBaseModem))
|
||||||
#define MM_BASE_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BASE_MODEM, MMBaseModemClass))
|
#define MM_BASE_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BASE_MODEM, MMBaseModemClass))
|
||||||
@@ -126,6 +130,10 @@ 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);
|
MMQmiPort *mm_base_modem_peek_port_qmi_for_data (MMBaseModem *self, MMPort *data, GError **error);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
MMMbimPort *mm_base_modem_peek_port_mbim (MMBaseModem *self);
|
||||||
|
MMMbimPort *mm_base_modem_peek_port_mbim_for_data (MMBaseModem *self, MMPort *data, GError **error);
|
||||||
|
#endif
|
||||||
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, MMPortType type);
|
MMPort *mm_base_modem_peek_best_data_port (MMBaseModem *self, MMPortType type);
|
||||||
GList *mm_base_modem_peek_data_ports (MMBaseModem *self);
|
GList *mm_base_modem_peek_data_ports (MMBaseModem *self);
|
||||||
@@ -139,6 +147,10 @@ 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);
|
MMQmiPort *mm_base_modem_get_port_qmi_for_data (MMBaseModem *self, MMPort *data, GError **error);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined WITH_MBIM
|
||||||
|
MMMbimPort *mm_base_modem_get_port_mbim (MMBaseModem *self);
|
||||||
|
MMMbimPort *mm_base_modem_get_port_mbim_for_data (MMBaseModem *self, MMPort *data, GError **error);
|
||||||
|
#endif
|
||||||
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, MMPortType type);
|
MMPort *mm_base_modem_get_best_data_port (MMBaseModem *self, MMPortType type);
|
||||||
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