diff options
Diffstat (limited to 'src/mm-manager.c')
-rw-r--r-- | src/mm-manager.c | 143 |
1 files changed, 85 insertions, 58 deletions
diff --git a/src/mm-manager.c b/src/mm-manager.c index 6767353e..5f114bba 100644 --- a/src/mm-manager.c +++ b/src/mm-manager.c @@ -247,13 +247,36 @@ remove_modem (MMManager *manager, MMModem *modem) g_free (device); } +/* Return the first outstanding supports task */ +static SupportsInfo * +find_supports_info (MMManager *self, MMModem *modem) +{ + char *modem_physdev; + GHashTableIter iter; + SupportsInfo *info, *ret = NULL; + + modem_physdev = mm_modem_get_device (modem); + g_assert (modem_physdev); + + /* Check for ports that are in the process of being interrogated by plugins */ + g_hash_table_iter_init (&iter, MM_MANAGER_GET_PRIVATE (self)->supports); + while (!ret && g_hash_table_iter_next (&iter, NULL, (gpointer) &info)) { + if (g_strcmp0 (info->physdev_path, modem_physdev) == 0) + ret = info; + } + g_free (modem_physdev); + return ret; +} + static void check_export_modem (MMManager *self, MMModem *modem) { MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (self); - char *modem_physdev; - GHashTableIter iter; - gpointer value; + SupportsInfo *info; + static guint32 id = 0, vid = 0, pid = 0; + char *path, *data_device = NULL, *modem_physdev; + GUdevDevice *physdev; + const char *subsys = NULL; /* A modem is only exported to D-Bus when both of the following are true: * @@ -269,63 +292,46 @@ check_export_modem (MMManager *self, MMModem *modem) * all other ports are already handled. That chance is very small though. */ - modem_physdev = mm_modem_get_device (modem); - g_assert (modem_physdev); - - /* Check for ports that are in the process of being interrogated by plugins */ - g_hash_table_iter_init (&iter, priv->supports); - while (g_hash_table_iter_next (&iter, NULL, &value)) { - SupportsInfo *info = value; - - if (!strcmp (info->physdev_path, modem_physdev)) { - mm_dbg ("(%s/%s): outstanding support task prevents export of %s", - info->subsys, info->name, modem_physdev); - goto out; - } + info = find_supports_info (self, modem); + if (info) { + mm_dbg ("(%s/%s): outstanding support task prevents export of %s", + info->subsys, info->name, info->physdev_path); + return; } - /* Already exported? This can happen if the modem is exported and the kernel - * discovers another of the modem's ports. - */ - if (g_object_get_data (G_OBJECT (modem), DBUS_PATH_TAG)) - goto out; + /* Obviously don't re-export a modem, or try to export one that's not valid */ + if ( g_object_get_data (G_OBJECT (modem), DBUS_PATH_TAG) + || !mm_modem_get_valid (modem)) + return; + + path = g_strdup_printf (MM_DBUS_PATH "/Modems/%d", id++); + dbus_g_connection_register_g_object (priv->connection, path, G_OBJECT (modem)); + g_object_set_data_full (G_OBJECT (modem), DBUS_PATH_TAG, path, (GDestroyNotify) g_free); - /* No outstanding port tasks, so if the modem is valid we can export it */ - if (mm_modem_get_valid (modem)) { - static guint32 id = 0, vid = 0, pid = 0; - char *path, *data_device = NULL; - GUdevDevice *physdev; - const char *subsys = NULL; - - path = g_strdup_printf (MM_DBUS_PATH"/Modems/%d", id++); - dbus_g_connection_register_g_object (priv->connection, path, G_OBJECT (modem)); - g_object_set_data_full (G_OBJECT (modem), DBUS_PATH_TAG, path, (GDestroyNotify) g_free); - - mm_dbg ("Exported modem %s as %s", modem_physdev, path); - - physdev = g_udev_client_query_by_sysfs_path (priv->udev, modem_physdev); - if (physdev) - subsys = g_udev_device_get_subsystem (physdev); - - g_object_get (G_OBJECT (modem), - MM_MODEM_DATA_DEVICE, &data_device, - MM_MODEM_HW_VID, &vid, - MM_MODEM_HW_PID, &pid, - NULL); - mm_dbg ("(%s): VID 0x%04X PID 0x%04X (%s)", - path, (vid & 0xFFFF), (pid & 0xFFFF), - subsys ? subsys : "unknown"); - mm_dbg ("(%s): data port is %s", path, data_device); - g_free (data_device); - - if (physdev) - g_object_unref (physdev); - - g_signal_emit (self, signals[DEVICE_ADDED], 0, modem); - } + modem_physdev = mm_modem_get_device (modem); + g_assert (modem_physdev); + mm_dbg ("Exported modem %s as %s", modem_physdev, path); -out: + physdev = g_udev_client_query_by_sysfs_path (priv->udev, modem_physdev); g_free (modem_physdev); + if (physdev) + subsys = g_udev_device_get_subsystem (physdev); + + g_object_get (G_OBJECT (modem), + MM_MODEM_DATA_DEVICE, &data_device, + MM_MODEM_HW_VID, &vid, + MM_MODEM_HW_PID, &pid, + NULL); + mm_dbg ("(%s): VID 0x%04X PID 0x%04X (%s)", + path, (vid & 0xFFFF), (pid & 0xFFFF), + subsys ? subsys : "unknown"); + mm_dbg ("(%s): data port is %s", path, data_device); + g_free (data_device); + + if (physdev) + g_object_unref (physdev); + + g_signal_emit (self, signals[DEVICE_ADDED], 0, modem); } static void @@ -548,6 +554,7 @@ supports_cleanup (MMManager *self, { MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (self); char *key; + GError *error = NULL; g_return_if_fail (subsys != NULL); g_return_if_fail (name != NULL); @@ -556,15 +563,35 @@ supports_cleanup (MMManager *self, g_hash_table_remove (priv->supports, key); g_free (key); + if (modem == NULL) + return; + + if ( (find_supports_info (self, modem) == NULL) + && !g_object_get_data (G_OBJECT (modem), "organized")) { + /* Yay, we're done with supports tasks, tell the modem to organize + * all its ports. Guard against multiple organize calls though since + * if the kernel or udev is slow, ports may show up long after the + * first bunch of supports tasks is done. + */ + g_object_set_data (G_OBJECT (modem), "organized", GUINT_TO_POINTER (1)); + if (!mm_modem_organize_ports (modem, &error)) { + mm_err ("Failed to organize modem ports: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + remove_modem (self, modem); + return; + } + } + /* Each time a supports task is cleaned up, check whether the modem is * now completely probed/handled and should be exported to D-Bus clients. * - * IMPORTANT: this must be done after removing the supports into from + * IMPORTANT: this must be done after removing the supports info from * priv->supports since check_export_modem() searches through priv->supports * for outstanding supports tasks. */ - if (modem) - check_export_modem (self, modem); + check_export_modem (self, modem); } static gboolean |