base-modem: allow grabbing MBIM ports

This commit is contained in:
Aleksander Morgado
2013-04-06 20:45:42 +02:00
parent cb45de048f
commit a0ced36f14
2 changed files with 247 additions and 14 deletions

View File

@@ -91,6 +91,11 @@ struct _MMBaseModemPrivate {
/* QMI ports */
GList *qmi;
#endif
#if defined WITH_MBIM
/* MBIM ports */
GList *mbim;
#endif
};
static gchar *
@@ -238,15 +243,18 @@ mm_base_modem_grab_port (MMBaseModem *self,
MM_PORT_TYPE, MM_PORT_TYPE_NET,
NULL));
}
/* QMI ports... */
/* cdc-wdm ports... */
else if (g_str_has_prefix (subsys, "usb") &&
g_str_has_prefix (name, "cdc-wdm")) {
#if defined WITH_QMI
if (ptype == MM_PORT_TYPE_QMI)
port = MM_PORT (mm_qmi_port_new (name));
else
#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,
MM_CORE_ERROR,
MM_CORE_ERROR_UNSUPPORTED,
@@ -258,7 +266,7 @@ mm_base_modem_grab_port (MMBaseModem *self,
}
}
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();
mm_dbg ("(%s) type '%s' claimed by %s",
@@ -335,6 +343,14 @@ mm_base_modem_release_port (MMBaseModem *self,
}
#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 */
mm_dbg ("(%s/%s) type %s released from %s",
subsys,
@@ -701,6 +717,157 @@ mm_base_modem_peek_port_qmi_for_data (MMBaseModem *self,
#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 *
mm_base_modem_get_best_data_port (MMBaseModem *self,
MMPortType type)
@@ -862,6 +1029,10 @@ mm_base_modem_organize_ports (MMBaseModem *self,
#if defined WITH_QMI
MMPort *qmi_primary = NULL;
GList *qmi = NULL;
#endif
#if defined WITH_MBIM
MMPort *mbim_primary = NULL;
GList *mbim = NULL;
#endif
GList *l;
@@ -953,6 +1124,16 @@ mm_base_modem_organize_ports (MMBaseModem *self,
break;
#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:
/* Ignore port */
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 */
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) {
gboolean allow_modem_without_at_port = FALSE;
#if defined WITH_QMI
if (qmi_primary)
allow_modem_without_at_port = TRUE;
#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,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Failed to find primary AT port");
return FALSE;
}
} else {
primary = secondary;
secondary = NULL;
@@ -995,6 +1185,17 @@ mm_base_modem_organize_ports (MMBaseModem *self,
}
#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 */
if (!data_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))
log_port (self, MM_PORT (l->data), "qmi (secondary)");
#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 */
self->priv->primary = (primary ? g_object_ref (primary) : NULL);
@@ -1051,6 +1257,15 @@ mm_base_modem_organize_ports (MMBaseModem *self,
}
#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 */
mm_base_modem_initialize (self,
(GAsyncReadyCallback)initialize_ready,
@@ -1334,6 +1549,12 @@ dispose (GObject *object)
g_list_free_full (self->priv->qmi, g_object_unref);
self->priv->qmi = NULL;
#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) {
g_hash_table_destroy (self->priv->ports);

View File

@@ -35,6 +35,10 @@
#include "mm-qmi-port.h"
#endif
#if defined WITH_MBIM
#include "mm-mbim-port.h"
#endif
#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_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_for_data (MMBaseModem *self, MMPort *data, GError **error);
#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);
MMPort *mm_base_modem_peek_best_data_port (MMBaseModem *self, MMPortType type);
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_for_data (MMBaseModem *self, MMPort *data, GError **error);
#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);
MMPort *mm_base_modem_get_best_data_port (MMBaseModem *self, MMPortType type);
GList *mm_base_modem_get_data_ports (MMBaseModem *self);