diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2013-04-06 20:45:42 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2013-04-17 15:19:37 +0200 |
commit | a0ced36f142255ffc0995e358636cf8a7b9efe07 (patch) | |
tree | 838758d29580763f0c6bfddea72deffb87100958 | |
parent | cb45de048faac153b6b49af7f98bcd4e3922a4d9 (diff) |
base-modem: allow grabbing MBIM ports
-rw-r--r-- | src/mm-base-modem.c | 249 | ||||
-rw-r--r-- | src/mm-base-modem.h | 12 |
2 files changed, 247 insertions, 14 deletions
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c index 622e4dfd..c4133932 100644 --- a/src/mm-base-modem.c +++ b/src/mm-base-modem.c @@ -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) @@ -863,6 +1030,10 @@ mm_base_modem_organize_ports (MMBaseModem *self, MMPort *qmi_primary = NULL; GList *qmi = NULL; #endif +#if defined WITH_MBIM + MMPort *mbim_primary = NULL; + GList *mbim = NULL; +#endif GList *l; g_return_val_if_fail (MM_IS_BASE_MODEM (self), FALSE); @@ -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,18 +1142,27 @@ 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 - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Failed to find primary AT port"); - return FALSE; - } else { + +#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); diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h index 95ab21f6..6eeed44b 100644 --- a/src/mm-base-modem.h +++ b/src/mm-base-modem.h @@ -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); |